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 ****************************************************************************/
34 #include "main_menu.h"
39 #include "filetypes.h"
40 #include "applimits.h"
47 static int db_play_folder(struct tree_context
* c
);
48 static int db_search(struct tree_context
* c
, char* string
);
50 static char searchstring
[32];
52 int db_load(struct tree_context
* c
)
55 int dcachesize
= global_settings
.max_files_in_dir
* sizeof(struct entry
);
56 int itemcount
, stringlen
, hits
=0;
57 unsigned long* nptr
= (void*) c
->name_buffer
;
58 unsigned long* dptr
= c
->dircache
;
59 unsigned long* safeplace
= NULL
;
62 int table
= c
->currtable
;
63 int extra
= c
->currextra
;
65 char* end_of_nbuf
= c
->name_buffer
+ c
->name_buffer_size
;
67 if (!tagdb_initialized
) {
68 DEBUGF("ID3 database is not initialized.\n");
76 DEBUGF("db_load() table: %d extra: 0x%x firstpos: %d\n", table
, extra
, c
->firstpos
);
85 static const int tables
[] = {allartists
, allalbums
, allsongs
,
87 char* nbuf
= (char*)nptr
;
88 char* labels
[] = { str(LANG_ID3DB_ARTISTS
),
89 str(LANG_ID3DB_ALBUMS
),
90 str(LANG_ID3DB_SONGS
),
91 str(LANG_ID3DB_SEARCH
)};
92 DEBUGF("dbload table root\n");
93 for (i
=0; i
< 4; i
++) {
94 strcpy(nbuf
, labels
[i
]);
95 dptr
[0] = (unsigned long)nbuf
;
97 nbuf
+= strlen(nbuf
) + 1;
100 c
->dirlength
= c
->filesindir
= i
;
105 static const int tables
[] = {searchartists
,
108 char* nbuf
= (char*)nptr
;
109 char* labels
[] = { str(LANG_ID3DB_SEARCH_ARTISTS
),
110 str(LANG_ID3DB_SEARCH_ALBUMS
),
111 str(LANG_ID3DB_SEARCH_SONGS
)};
112 DEBUGF("dbload table search\n");
113 for (i
=0; i
< 3; i
++) {
114 strcpy(nbuf
, labels
[i
]);
115 dptr
[0] = (unsigned long)nbuf
;
117 nbuf
+= strlen(nbuf
) + 1;
120 c
->dirlength
= c
->filesindir
= i
;
127 DEBUGF("dbload table searchsongs/searchartists/searchalbums\n");
128 i
= db_search(c
, searchstring
);
129 c
->dirlength
= c
->filesindir
= i
;
131 splash(HZ
, true, "%s %s",
132 str(LANG_SHOWDIR_ERROR_BUFFER
),
133 str(LANG_SHOWDIR_ERROR_FULL
));
137 splash(HZ
, true, str(LANG_ID3DB_MATCHES
), i
);
141 DEBUGF("dbload table allsongs\n");
142 offset
= tagdbheader
.songstart
+ c
->firstpos
* SONGENTRY_SIZE
;
143 itemcount
= tagdbheader
.songcount
;
144 stringlen
= tagdbheader
.songlen
;
148 DEBUGF("dbload table allalbums\n");
149 offset
= tagdbheader
.albumstart
+ c
->firstpos
* ALBUMENTRY_SIZE
;
150 itemcount
= tagdbheader
.albumcount
;
151 stringlen
= tagdbheader
.albumlen
;
155 DEBUGF("dbload table allartists\n");
156 offset
= tagdbheader
.artiststart
+ c
->firstpos
* ARTISTENTRY_SIZE
;
157 itemcount
= tagdbheader
.artistcount
;
158 stringlen
= tagdbheader
.artistlen
;
162 DEBUGF("dbload table albums4artist\n");
163 /* 'extra' is offset to the artist */
164 safeplacelen
= tagdbheader
.albumarraylen
* 4;
165 safeplace
= (void*)(end_of_nbuf
- safeplacelen
);
166 lseek(tagdb_fd
, extra
+ tagdbheader
.artistlen
, SEEK_SET
);
167 rc
= read(tagdb_fd
, safeplace
, safeplacelen
);
168 if (rc
< safeplacelen
)
171 #ifdef ROCKBOX_LITTLE_ENDIAN
172 for (i
=0; i
<tagdbheader
.albumarraylen
; i
++)
173 safeplace
[i
] = BE32(safeplace
[i
]);
175 offset
= safeplace
[0];
176 itemcount
= tagdbheader
.albumarraylen
;
177 stringlen
= tagdbheader
.albumlen
;
181 DEBUGF("dbload table songs4album\n");
182 /* 'extra' is offset to the album */
183 safeplacelen
= tagdbheader
.songarraylen
* 4;
184 safeplace
= (void*)(end_of_nbuf
- safeplacelen
);
185 lseek(tagdb_fd
, extra
+ tagdbheader
.albumlen
+ 4, SEEK_SET
);
186 rc
= read(tagdb_fd
, safeplace
, safeplacelen
);
187 if (rc
< safeplacelen
)
190 #ifdef ROCKBOX_LITTLE_ENDIAN
191 for (i
=0; i
<tagdbheader
.songarraylen
; i
++) {
192 safeplace
[i
] = BE32(safeplace
[i
]);
193 DEBUGF("db_load songs4album song %d: 0x%x\n",i
,safeplace
[i
]);
196 offset
= safeplace
[0];
197 itemcount
= tagdbheader
.songarraylen
;
198 stringlen
= tagdbheader
.songlen
;
202 DEBUGF("dbload table songs4artist\n");
203 /* 'extra' is offset to the artist, used as filter */
204 offset
= tagdbheader
.songstart
+ c
->firstpos
* SONGENTRY_SIZE
;
205 itemcount
= tagdbheader
.songcount
;
206 stringlen
= tagdbheader
.songlen
;
210 DEBUGF("Unsupported table %d\n", table
);
213 end_of_nbuf
-= safeplacelen
;
215 c
->dirlength
= itemcount
;
216 itemcount
-= c
->firstpos
;
219 lseek(tagdb_fd
, offset
, SEEK_SET
);
221 /* name_buffer (nptr) contains only names, null terminated.
222 the first word of dcache (dptr) is a pointer to the name,
223 the rest is table specific. see below. */
225 for ( i
=0; i
< itemcount
; i
++ ) {
234 lseek(tagdb_fd
, safeplace
[i
], SEEK_SET
);
235 offset
= safeplace
[i
];
239 rc
= read(tagdb_fd
, nptr
, stringlen
);
242 DEBUGF("%d read(%d) returned %d\n", i
, stringlen
, rc
);
250 rc
= read(tagdb_fd
, intbuf
, 12);
251 skip
= SONGENTRY_SIZE
-stringlen
-12; /* skip the rest of the song info */
253 DEBUGF("%d read(%d) returned %d\n", i
, 12, rc
);
256 /* continue to next song if wrong artist */
257 if (table
== songs4artist
&& (int)BE32(intbuf
[0]) != extra
) {
258 lseek(tagdb_fd
, skip
, SEEK_CUR
);
262 /* save offset of filename */
263 dptr
[1] = BE32(intbuf
[2]);
268 /* save offset of this album */
269 skip
= tagdbheader
.songarraylen
* 4 + 4;
274 /* save offset of this artist */
275 skip
= tagdbheader
.albumarraylen
* 4;
280 /* store name pointer in dir cache */
281 dptr
[0] = (unsigned long)nptr
;
284 lseek(tagdb_fd
, skip
, SEEK_CUR
);
288 if(table
==songs4artist
)
291 /* next name is stored immediately after this */
292 nptr
= (void*)nptr
+ strlen((char*)nptr
) + 1;
293 if ((void*)nptr
+ stringlen
> (void*)end_of_nbuf
) {
298 /* limit dir buffer */
299 dptr
= (void*)dptr
+ c
->dentry_size
* sizeof(int);
300 if ((void*)(dptr
+ c
->dentry_size
) >
301 (void*)(c
->dircache
+ dcachesize
))
308 offset
+= stringlen
+ skip
;
311 if (c
->currtable
== albums4artist
&& !c
->dirfull
) {
312 strcpy((char*)nptr
, str(LANG_ID3DB_ALL_SONGS
));
313 dptr
[0] = (unsigned long)nptr
;
314 dptr
[1] = extra
; /* offset to artist */
318 c
->filesindir
= hits
;
323 static int db_search(struct tree_context
* c
, char* string
)
325 int i
, count
, size
, hits
=0;
328 char* nptr
= c
->name_buffer
;
329 const char* end_of_nbuf
= nptr
+ c
->name_buffer_size
;
331 unsigned long* dptr
= c
->dircache
;
332 const long dcachesize
= global_settings
.max_files_in_dir
*
333 sizeof(struct entry
);
335 switch (c
->currtable
) {
337 start
= tagdbheader
.artiststart
;
338 count
= tagdbheader
.artistcount
;
339 size
= ARTISTENTRY_SIZE
;
343 start
= tagdbheader
.albumstart
;
344 count
= tagdbheader
.albumcount
;
345 size
= ALBUMENTRY_SIZE
;
349 start
= tagdbheader
.songstart
;
350 count
= tagdbheader
.songcount
;
351 size
= SONGENTRY_SIZE
;
355 DEBUGF("Invalid table %d\n", c
->currtable
);
359 lseek(tagdb_fd
, start
, SEEK_SET
);
361 for (i
=0; i
<count
; i
++) {
362 if (read(tagdb_fd
, nptr
, size
) < size
) {
363 DEBUGF("Short read(%d) in db_search()\n",size
);
366 if (strcasestr(nptr
, string
)) {
369 dptr
[0] = (unsigned long)nptr
;
370 if (c
->currtable
== searchsongs
) {
371 /* store offset of filename */
372 dptr
[1] = BE32(*((long*)(nptr
+ tagdbheader
.songlen
+ 8)));
375 /* store offset of database record */
376 dptr
[1] = start
+ i
* size
;
380 /* limit dir buffer */
381 if ((void*)(dptr
+ c
->dentry_size
) >
382 (void*)(c
->dircache
+ dcachesize
))
388 nptr
+= strlen(nptr
) + 1;
389 while ((unsigned long)nptr
& 3)
392 /* limit name buffer */
393 if ((void*)nptr
+ size
> (void*)end_of_nbuf
) {
403 int db_enter(struct tree_context
* c
)
406 int offset
= (c
->dircursor
+ c
->dirstart
) * c
->dentry_size
+ 1;
407 int newextra
= ((int*)c
->dircache
)[offset
];
409 if (c
->dirlevel
>= MAX_DIR_LEVELS
)
412 c
->dirpos
[c
->dirlevel
] = c
->dirstart
;
413 c
->cursorpos
[c
->dirlevel
] = c
->dircursor
;
414 c
->table_history
[c
->dirlevel
] = c
->currtable
;
415 c
->extra_history
[c
->dirlevel
] = c
->currextra
;
416 c
->pos_history
[c
->dirlevel
] = c
->firstpos
;
419 switch (c
->currtable
) {
421 c
->currtable
= newextra
;
422 c
->currextra
= newextra
;
427 c
->currtable
= albums4artist
;
428 c
->currextra
= newextra
;
434 /* virtual <all albums> entry points to the artist,
435 all normal entries point to the album */
436 if (newextra
< tagdbheader
.albumstart
)
437 c
->currtable
= songs4artist
;
439 c
->currtable
= songs4album
;
441 c
->currextra
= newextra
;
449 if (db_play_folder(c
) >= 0)
454 rc
= kbd_input(searchstring
, sizeof(searchstring
));
455 if (rc
== -1 || !searchstring
[0])
458 c
->currtable
= newextra
;
466 c
->dirstart
= c
->dircursor
= c
->firstpos
= 0;
471 void db_exit(struct tree_context
* c
)
474 c
->dirstart
= c
->dirpos
[c
->dirlevel
];
475 c
->dircursor
= c
->cursorpos
[c
->dirlevel
];
476 c
->currtable
= c
->table_history
[c
->dirlevel
];
477 c
->currextra
= c
->extra_history
[c
->dirlevel
];
478 c
->firstpos
= c
->pos_history
[c
->dirlevel
];
481 static int db_play_folder(struct tree_context
* c
)
485 int filenum
= c
->dircursor
+ c
->dirstart
;
487 if (playlist_create(NULL
, NULL
) < 0) {
488 DEBUGF("Failed creating playlist\n");
492 /* TODO: add support for very long tables */
494 for (i
=0; i
< c
->filesindir
; i
++) {
495 int pathoffset
= ((int*)c
->dircache
)[i
* c
->dentry_size
+ 1];
496 lseek(tagdb_fd
, pathoffset
, SEEK_SET
);
497 rc
= read(tagdb_fd
, buf
, sizeof(buf
));
498 if (rc
< tagdbheader
.songlen
) {
499 DEBUGF("short path read(%ld) = %d\n", sizeof(buf
), rc
);
503 playlist_insert_track(NULL
, buf
, PLAYLIST_INSERT
, false);
506 if (global_settings
.playlist_shuffle
)
507 filenum
= playlist_shuffle(current_tick
, filenum
);
508 if (!global_settings
.play_selected
)
511 playlist_start(filenum
,0);
516 #ifdef HAVE_LCD_BITMAP
517 const char* db_get_icon(struct tree_context
* c
)
519 int db_get_icon(struct tree_context
* c
)
524 switch (c
->currtable
)
538 #ifdef HAVE_LCD_BITMAP
539 return bitmap_icons_6x8
[icon
];