Added MP3::Info.pm inside script to make it standalone.
[kugel-rb.git] / apps / dbtree.c
blobf9bd95005703d4122876cbefce3336d6caaf61c4
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Björn Stenberg
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 #include <stdio.h>
20 #include <string.h>
21 #include "file.h"
22 #include "screens.h"
23 #include "kernel.h"
24 #include "tree.h"
25 #include "lcd.h"
26 #include "font.h"
27 #include "settings.h"
28 #include "icons.h"
29 #include "status.h"
30 #include "debug.h"
31 #include "button.h"
32 #include "menu.h"
33 #include "main_menu.h"
34 #include "mpeg.h"
35 #include "misc.h"
36 #include "ata.h"
37 #include "wps.h"
38 #include "filetypes.h"
39 #include "applimits.h"
40 #include "dbtree.h"
41 #include "icons.h"
43 #ifdef LITTLE_ENDIAN
44 #include <netinet/in.h>
45 #define BE32(_x_) htonl(_x_)
46 #else
47 #define BE32(_x_) _x_
48 #endif
50 static int fd;
52 static int
53 songstart, albumstart, artiststart,
54 songcount, albumcount, artistcount,
55 songlen, songarraylen,
56 albumlen, albumarraylen,
57 artistlen;
59 int db_init(void)
61 unsigned int version;
62 unsigned int buf[12];
64 fd = open(ROCKBOX_DIR "/rockbox.id3db", O_RDONLY);
65 if (fd < 0) {
66 DEBUGF("Failed opening database\n");
67 return -1;
69 read(fd, buf, 48);
71 version = BE32(buf[0]) & 0xff;
72 DEBUGF("Version: RDB%d\n", version);
74 songstart = BE32(buf[1]);
75 songcount = BE32(buf[2]);
76 songlen = BE32(buf[3]);
77 DEBUGF("Number of songs: %d\n", songcount);
78 DEBUGF("Songstart: %x\n", songstart);
79 DEBUGF("Songlen: %d\n", songlen);
81 albumstart = BE32(buf[4]);
82 albumcount = BE32(buf[5]);
83 albumlen = BE32(buf[6]);
84 songarraylen = BE32(buf[7]);
85 DEBUGF("Number of albums: %d\n", albumcount);
86 DEBUGF("Albumstart: %x\n", albumstart);
87 DEBUGF("Albumlen: %d\n", albumlen);
89 artiststart = BE32(buf[8]);
90 artistcount = BE32(buf[9]);
91 artistlen = BE32(buf[10]);
92 albumarraylen = BE32(buf[11]);
93 DEBUGF("Number of artists: %d\n", artistcount);
94 DEBUGF("Artiststart: %x\n", artiststart);
95 DEBUGF("Artistlen: %d\n", artistlen);
97 return 0;
100 int db_load(struct tree_context* c, bool* dir_buffer_full)
102 int i, offset, len, rc;
103 int dcachesize = global_settings.max_files_in_dir * sizeof(struct entry);
104 int max_items, itemcount, stringlen;
105 unsigned int* nptr = (void*) c->name_buffer;
106 unsigned int* dptr = c->dircache;
107 unsigned int* safeplace = NULL;
109 int table = c->currtable;
110 int extra = c->currextra;
111 c->dentry_size = 2 * sizeof(int);
113 DEBUGF("db_load(%d, %x)\n", table, extra);
115 if (!table) {
116 table = allartists;
117 c->currtable = table;
120 switch (table) {
121 case allsongs:
122 offset = songstart;
123 itemcount = songcount;
124 stringlen = songlen;
125 break;
127 case allalbums:
128 offset = albumstart;
129 itemcount = albumcount;
130 stringlen = albumlen;
131 break;
133 case allartists:
134 offset = artiststart;
135 itemcount = artistcount;
136 stringlen = artistlen;
137 break;
139 case albums:
140 /* 'extra' is offset to the artist */
141 len = albumarraylen * 4;
142 safeplace = (void*)(c->name_buffer + c->name_buffer_size - len);
143 //DEBUGF("Seeking to %x\n", extra + artistlen);
144 lseek(fd, extra + artistlen, SEEK_SET);
145 rc = read(fd, safeplace, len);
146 if (rc < len)
147 return -1;
149 #ifdef LITTLE_ENDIAN
150 for (i=0; i<albumarraylen; i++)
151 safeplace[i] = BE32(safeplace[i]);
152 #endif
154 offset = safeplace[0];
155 itemcount = albumarraylen;
156 stringlen = albumlen;
157 break;
159 case songs:
160 /* 'extra' is offset to the album */
161 len = songarraylen * 4;
162 safeplace = (void*)(c->name_buffer + c->name_buffer_size - len);
163 //DEBUGF("Seeking to %x\n", extra + albumlen + 4);
164 lseek(fd, extra + albumlen + 4, SEEK_SET);
165 rc = read(fd, safeplace, len);
166 if (rc < len)
167 return -1;
169 #ifdef LITTLE_ENDIAN
170 for (i=0; i<songarraylen; i++)
171 safeplace[i] = BE32(safeplace[i]);
172 #endif
173 offset = safeplace[0];
174 itemcount = songarraylen;
175 stringlen = songlen;
176 break;
178 default:
179 DEBUGF("Unsupported table %d\n", table);
180 return -1;
182 max_items = dcachesize / c->dentry_size;
184 if (!safeplace) {
185 //DEBUGF("Seeking to %x\n", offset);
186 lseek(fd, offset, SEEK_SET);
189 /* name_buffer (nptr) contains only names, null terminated.
190 the first word of dcache (dptr) is a pointer to the name,
191 the rest is table specific. see below. */
193 if (itemcount > max_items)
194 if (dir_buffer_full)
195 *dir_buffer_full = true;
197 if (max_items > itemcount) {
198 max_items = itemcount;
201 for ( i=0; i < max_items; i++ ) {
202 int rc, skip=0;
204 if (safeplace) {
205 if (!safeplace[i])
206 break;
207 //DEBUGF("Seeking to %x\n", safeplace[i]);
208 lseek(fd, safeplace[i], SEEK_SET);
209 offset = safeplace[i];
212 /* read name */
213 rc = read(fd, nptr, stringlen);
214 if (rc < stringlen)
216 DEBUGF("%d read(%d) returned %d\n", i, stringlen, rc);
217 return -1;
220 /* store name pointer in dir cache */
221 dptr[0] = (unsigned int)nptr;
223 switch (table) {
224 case songs:
225 case allsongs:
226 /* save offset of this song */
227 skip = 12;
228 dptr[1] = offset;
229 break;
231 case allalbums:
232 case albums:
233 /* save offset of this album */
234 skip = songarraylen * 4 + 4;
235 dptr[1] = offset;
236 break;
238 case allartists:
239 /* save offset of this artist */
240 skip = albumarraylen * 4;
241 dptr[1] = offset;
242 break;
245 //DEBUGF("%x: %s\n", dptr[1], dptr[0]);
247 if (skip)
248 lseek(fd, skip, SEEK_CUR);
250 /* next name is stored immediately after this */
251 nptr = (void*)nptr + strlen((char*)nptr) + 1;
252 if ((void*)nptr > (void*)c->name_buffer + c->name_buffer_size) {
253 DEBUGF("Name buffer overflow (%d)\n",i);
254 break;
256 dptr = (void*)dptr + c->dentry_size;
258 if (!safeplace)
259 offset += stringlen + skip;
262 c->filesindir = i;
264 return i;
267 void db_enter(struct tree_context* c)
269 switch (c->currtable) {
270 case allartists:
271 case albums:
272 c->dirpos[c->dirlevel] = c->dirstart;
273 c->cursorpos[c->dirlevel] = c->dircursor;
274 c->table_history[c->dirlevel] = c->currtable;
275 c->extra_history[c->dirlevel] = c->currextra;
276 c->dirlevel++;
277 break;
279 default:
280 break;
283 switch (c->currtable) {
284 case allartists:
285 c->currtable = albums;
286 c->currextra = ((int*)c->dircache)[(c->dircursor + c->dirstart)*2 + 1];
287 break;
289 case albums:
290 c->currtable = songs;
291 c->currextra = ((int*)c->dircache)[(c->dircursor + c->dirstart)*2 + 1];
292 break;
294 case songs:
295 splash(HZ,true,"No playing implemented yet");
296 #if 0
297 /* find filenames, build playlist, play */
298 playlist_create(NULL,NULL);
299 #endif
300 break;
302 default:
303 break;
306 c->dirstart = c->dircursor = 0;
309 void db_exit(struct tree_context* c)
311 c->dirlevel--;
312 c->dirstart = c->dirpos[c->dirlevel];
313 c->dircursor = c->cursorpos[c->dirlevel];
314 c->currtable = c->table_history[c->dirlevel];
315 c->currextra = c->extra_history[c->dirlevel];
318 #ifdef HAVE_LCD_BITMAP
319 const char* db_get_icon(struct tree_context* c)
321 int icon;
323 switch (c->currtable)
325 case allsongs:
326 case songs:
327 icon = File;
328 break;
330 default:
331 icon = Folder;
332 break;
335 return bitmap_icons_6x8[icon];
337 #else
338 int db_get_icon(struct tree_context* c)
340 (void)c;
341 return Folder;
343 #endif