1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2005 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 ****************************************************************************/
33 #include "main_menu.h"
38 #include "filetypes.h"
39 #include "applimits.h"
45 #include <netinet/in.h>
46 #define BE32(_x_) htonl(_x_)
51 #define ID3DB_VERSION 1
56 songstart
, albumstart
, artiststart
,
57 songcount
, albumcount
, artistcount
,
58 songlen
, songarraylen
,
59 albumlen
, albumarraylen
,
60 artistlen
, initialized
= 0;
62 static int db_play_folder(struct tree_context
* c
);
68 unsigned char* ptr
= (char*)buf
;
70 fd
= open(ROCKBOX_DIR
"/rockbox.id3db", O_RDONLY
);
72 DEBUGF("Failed opening database\n");
81 DEBUGF("File is not a rockbox id3 database, aborting\n");
85 version
= BE32(buf
[0]) & 0xff;
86 if (version
!= ID3DB_VERSION
)
88 DEBUGF("Unsupported database version %d, aborting.\n");
91 DEBUGF("Version: RDB%d\n", version
);
93 songstart
= BE32(buf
[1]);
94 songcount
= BE32(buf
[2]);
95 songlen
= BE32(buf
[3]);
96 DEBUGF("Number of songs: %d\n", songcount
);
97 DEBUGF("Songstart: %x\n", songstart
);
98 DEBUGF("Songlen: %d\n", songlen
);
100 albumstart
= BE32(buf
[4]);
101 albumcount
= BE32(buf
[5]);
102 albumlen
= BE32(buf
[6]);
103 songarraylen
= BE32(buf
[7]);
104 DEBUGF("Number of albums: %d\n", albumcount
);
105 DEBUGF("Albumstart: %x\n", albumstart
);
106 DEBUGF("Albumlen: %d\n", albumlen
);
108 artiststart
= BE32(buf
[8]);
109 artistcount
= BE32(buf
[9]);
110 artistlen
= BE32(buf
[10]);
111 albumarraylen
= BE32(buf
[11]);
112 DEBUGF("Number of artists: %d\n", artistcount
);
113 DEBUGF("Artiststart: %x\n", artiststart
);
114 DEBUGF("Artistlen: %d\n", artistlen
);
116 if (songstart
> albumstart
||
117 albumstart
> artiststart
)
119 DEBUGF("Corrupt id3db database, aborting.\n");
127 int db_load(struct tree_context
* c
)
130 int dcachesize
= global_settings
.max_files_in_dir
* sizeof(struct entry
);
131 int max_items
, itemcount
, stringlen
;
132 unsigned int* nptr
= (void*) c
->name_buffer
;
133 unsigned int* dptr
= c
->dircache
;
134 unsigned int* safeplace
= NULL
;
135 int safeplacelen
= 0;
137 int table
= c
->currtable
;
138 int extra
= c
->currextra
;
140 char* end_of_nbuf
= c
->name_buffer
+ c
->name_buffer_size
;
143 DEBUGF("ID3 database is not initialized.\n");
151 DEBUGF("db_load(%d, %x, %d)\n", table
, extra
, c
->firstpos
);
155 c
->currtable
= table
;
160 static const int tables
[] = {allartists
, allalbums
, allsongs
};
161 char* nbuf
= (char*)nptr
;
162 char* labels
[] = { str(LANG_ID3DB_ARTISTS
),
163 str(LANG_ID3DB_ALBUMS
),
164 str(LANG_ID3DB_SONGS
)};
166 for (i
=0; i
< 3; i
++) {
167 strcpy(nbuf
, labels
[i
]);
168 dptr
[0] = (unsigned int)nbuf
;
170 nbuf
+= strlen(nbuf
) + 1;
173 c
->dirlength
= c
->filesindir
= i
;
178 offset
= songstart
+ c
->firstpos
* (songlen
+ 12);
179 itemcount
= songcount
;
185 offset
= albumstart
+
186 c
->firstpos
* (albumlen
+ 4 + songarraylen
* 4);
187 itemcount
= albumcount
;
188 stringlen
= albumlen
;
192 offset
= artiststart
+
193 c
->firstpos
* (artistlen
+ albumarraylen
* 4);
194 itemcount
= artistcount
;
195 stringlen
= artistlen
;
199 /* 'extra' is offset to the artist */
200 safeplacelen
= albumarraylen
* 4;
201 safeplace
= (void*)(end_of_nbuf
- safeplacelen
);
202 lseek(fd
, extra
+ artistlen
, SEEK_SET
);
203 rc
= read(fd
, safeplace
, safeplacelen
);
204 if (rc
< safeplacelen
)
208 for (i
=0; i
<albumarraylen
; i
++)
209 safeplace
[i
] = BE32(safeplace
[i
]);
211 offset
= safeplace
[0];
212 itemcount
= albumarraylen
;
213 stringlen
= albumlen
;
217 /* 'extra' is offset to the album */
218 safeplacelen
= songarraylen
* 4;
219 safeplace
= (void*)(end_of_nbuf
- safeplacelen
);
220 lseek(fd
, extra
+ albumlen
+ 4, SEEK_SET
);
221 rc
= read(fd
, safeplace
, safeplacelen
);
222 if (rc
< safeplacelen
)
226 for (i
=0; i
<songarraylen
; i
++)
227 safeplace
[i
] = BE32(safeplace
[i
]);
229 offset
= safeplace
[0];
230 itemcount
= songarraylen
;
236 DEBUGF("Unsupported table %d\n", table
);
239 max_items
= dcachesize
/ (c
->dentry_size
* sizeof(int));
240 end_of_nbuf
-= safeplacelen
;
242 c
->dirlength
= itemcount
;
243 itemcount
-= c
->firstpos
;
246 //DEBUGF("Seeking to %x\n", offset);
247 lseek(fd
, offset
, SEEK_SET
);
250 /* name_buffer (nptr) contains only names, null terminated.
251 the first word of dcache (dptr) is a pointer to the name,
252 the rest is table specific. see below. */
254 if (itemcount
> max_items
)
257 if (max_items
> itemcount
) {
258 max_items
= itemcount
;
261 for ( i
=0; i
< max_items
; i
++ ) {
270 //DEBUGF("Seeking to %x\n", safeplace[i]);
271 lseek(fd
, safeplace
[i
], SEEK_SET
);
272 offset
= safeplace
[i
];
276 rc
= read(fd
, nptr
, stringlen
);
279 DEBUGF("%d read(%d) returned %d\n", i
, stringlen
, rc
);
283 /* store name pointer in dir cache */
284 dptr
[0] = (unsigned int)nptr
;
289 /* save offset of this song */
292 rc
= read(fd
, intbuf
, 12);
294 DEBUGF("%d read(%d) returned %d\n", i
, 12, rc
);
297 /* save offset of filename */
298 dptr
[2] = BE32(intbuf
[2]);
303 /* save offset of this album */
304 skip
= songarraylen
* 4 + 4;
309 /* save offset of this artist */
310 skip
= albumarraylen
* 4;
316 lseek(fd
, skip
, SEEK_CUR
);
318 /* next name is stored immediately after this */
319 nptr
= (void*)nptr
+ strlen((char*)nptr
) + 1;
320 if ((void*)nptr
+ stringlen
> (void*)end_of_nbuf
) {
324 dptr
= (void*)dptr
+ c
->dentry_size
* sizeof(int);
327 offset
+= stringlen
+ skip
;
335 int db_enter(struct tree_context
* c
)
338 int newextra
= ((int*)c
->dircache
)[(c
->dircursor
+ c
->dirstart
)*2 + 1];
340 c
->dirpos
[c
->dirlevel
] = c
->dirstart
;
341 c
->cursorpos
[c
->dirlevel
] = c
->dircursor
;
342 c
->table_history
[c
->dirlevel
] = c
->currtable
;
343 c
->extra_history
[c
->dirlevel
] = c
->currextra
;
344 c
->pos_history
[c
->dirlevel
] = c
->firstpos
;
347 switch (c
->currtable
) {
349 c
->currtable
= newextra
;
350 c
->currextra
= newextra
;
354 c
->currtable
= albums4artist
;
355 c
->currextra
= newextra
;
360 c
->currtable
= songs4album
;
361 c
->currextra
= newextra
;
367 if (db_play_folder(c
) >= 0)
375 c
->dirstart
= c
->dircursor
= c
->firstpos
= 0;
380 void db_exit(struct tree_context
* c
)
383 c
->dirstart
= c
->dirpos
[c
->dirlevel
];
384 c
->dircursor
= c
->cursorpos
[c
->dirlevel
];
385 c
->currtable
= c
->table_history
[c
->dirlevel
];
386 c
->currextra
= c
->extra_history
[c
->dirlevel
];
387 c
->firstpos
= c
->pos_history
[c
->dirlevel
];
390 static int db_play_folder(struct tree_context
* c
)
394 int filenum
= c
->dircursor
+ c
->dirstart
;
396 if (playlist_create(NULL
, NULL
) < 0) {
397 DEBUGF("Failed creating playlist\n");
401 /* TODO: add support for very long tables */
403 for (i
=0; i
< c
->filesindir
; i
++) {
404 int pathoffset
= ((int*)c
->dircache
)[i
* c
->dentry_size
+ 2];
405 lseek(fd
, pathoffset
, SEEK_SET
);
406 rc
= read(fd
, buf
, sizeof(buf
));
408 DEBUGF("short path read(%d) = %d\n", sizeof(buf
), rc
);
412 playlist_insert_track(NULL
, buf
, PLAYLIST_INSERT
, false);
415 if (global_settings
.playlist_shuffle
)
416 filenum
= playlist_shuffle(current_tick
, filenum
);
417 if (!global_settings
.play_selected
)
420 playlist_start(filenum
,0);
425 #ifdef HAVE_LCD_BITMAP
426 const char* db_get_icon(struct tree_context
* c
)
430 switch (c
->currtable
)
442 return bitmap_icons_6x8
[icon
];
445 int db_get_icon(struct tree_context
* c
)
448 switch (c
->currtable
)