diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/dbtree.c | 196 | ||||
-rw-r--r-- | apps/dbtree.h | 3 | ||||
-rw-r--r-- | apps/lang/english.lang | 30 |
3 files changed, 186 insertions, 43 deletions
diff --git a/apps/dbtree.c b/apps/dbtree.c index 6925fd3f29..5b30863f39 100644 --- a/apps/dbtree.c +++ b/apps/dbtree.c | |||
@@ -16,6 +16,7 @@ | |||
16 | * KIND, either express or implied. | 16 | * KIND, either express or implied. |
17 | * | 17 | * |
18 | ****************************************************************************/ | 18 | ****************************************************************************/ |
19 | #define _GNU_SOURCE | ||
19 | #include <stdio.h> | 20 | #include <stdio.h> |
20 | #include <string.h> | 21 | #include <string.h> |
21 | #include "file.h" | 22 | #include "file.h" |
@@ -40,6 +41,7 @@ | |||
40 | #include "dbtree.h" | 41 | #include "dbtree.h" |
41 | #include "icons.h" | 42 | #include "icons.h" |
42 | #include "lang.h" | 43 | #include "lang.h" |
44 | #include "keyboard.h" | ||
43 | 45 | ||
44 | #ifdef LITTLE_ENDIAN | 46 | #ifdef LITTLE_ENDIAN |
45 | #include <netinet/in.h> | 47 | #include <netinet/in.h> |
@@ -60,6 +62,9 @@ static int | |||
60 | artistlen, initialized = 0; | 62 | artistlen, initialized = 0; |
61 | 63 | ||
62 | static int db_play_folder(struct tree_context* c); | 64 | static int db_play_folder(struct tree_context* c); |
65 | static int db_search(struct tree_context* c, char* string); | ||
66 | |||
67 | static char searchstring[32]; | ||
63 | 68 | ||
64 | int db_init(void) | 69 | int db_init(void) |
65 | { | 70 | { |
@@ -78,45 +83,35 @@ int db_init(void) | |||
78 | ptr[1] != 'D' || | 83 | ptr[1] != 'D' || |
79 | ptr[2] != 'B') | 84 | ptr[2] != 'B') |
80 | { | 85 | { |
81 | DEBUGF("File is not a rockbox id3 database, aborting\n"); | 86 | splash(HZ,true,"Not a rockbox ID3 database!"); |
82 | return -1; | 87 | return -1; |
83 | } | 88 | } |
84 | 89 | ||
85 | version = BE32(buf[0]) & 0xff; | 90 | version = BE32(buf[0]) & 0xff; |
86 | if (version != ID3DB_VERSION) | 91 | if (version != ID3DB_VERSION) |
87 | { | 92 | { |
88 | DEBUGF("Unsupported database version %d, aborting.\n"); | 93 | splash(HZ,true,"Unsupported database version %d!", version); |
89 | return -1; | 94 | return -1; |
90 | } | 95 | } |
91 | DEBUGF("Version: RDB%d\n", version); | ||
92 | 96 | ||
93 | songstart = BE32(buf[1]); | 97 | songstart = BE32(buf[1]); |
94 | songcount = BE32(buf[2]); | 98 | songcount = BE32(buf[2]); |
95 | songlen = BE32(buf[3]); | 99 | songlen = BE32(buf[3]); |
96 | DEBUGF("Number of songs: %d\n", songcount); | ||
97 | DEBUGF("Songstart: %x\n", songstart); | ||
98 | DEBUGF("Songlen: %d\n", songlen); | ||
99 | 100 | ||
100 | albumstart = BE32(buf[4]); | 101 | albumstart = BE32(buf[4]); |
101 | albumcount = BE32(buf[5]); | 102 | albumcount = BE32(buf[5]); |
102 | albumlen = BE32(buf[6]); | 103 | albumlen = BE32(buf[6]); |
103 | songarraylen = BE32(buf[7]); | 104 | songarraylen = BE32(buf[7]); |
104 | DEBUGF("Number of albums: %d\n", albumcount); | ||
105 | DEBUGF("Albumstart: %x\n", albumstart); | ||
106 | DEBUGF("Albumlen: %d\n", albumlen); | ||
107 | 105 | ||
108 | artiststart = BE32(buf[8]); | 106 | artiststart = BE32(buf[8]); |
109 | artistcount = BE32(buf[9]); | 107 | artistcount = BE32(buf[9]); |
110 | artistlen = BE32(buf[10]); | 108 | artistlen = BE32(buf[10]); |
111 | albumarraylen = BE32(buf[11]); | 109 | albumarraylen = BE32(buf[11]); |
112 | DEBUGF("Number of artists: %d\n", artistcount); | ||
113 | DEBUGF("Artiststart: %x\n", artiststart); | ||
114 | DEBUGF("Artistlen: %d\n", artistlen); | ||
115 | 110 | ||
116 | if (songstart > albumstart || | 111 | if (songstart > albumstart || |
117 | albumstart > artiststart) | 112 | albumstart > artiststart) |
118 | { | 113 | { |
119 | DEBUGF("Corrupt id3db database, aborting.\n"); | 114 | splash(HZ,true,"Corrupt ID3 database!"); |
120 | return -1; | 115 | return -1; |
121 | } | 116 | } |
122 | 117 | ||
@@ -157,11 +152,33 @@ int db_load(struct tree_context* c) | |||
157 | 152 | ||
158 | switch (table) { | 153 | switch (table) { |
159 | case root: { | 154 | case root: { |
160 | static const int tables[] = {allartists, allalbums, allsongs}; | 155 | static const int tables[] = {allartists, allalbums, allsongs, |
156 | search }; | ||
161 | char* nbuf = (char*)nptr; | 157 | char* nbuf = (char*)nptr; |
162 | char* labels[] = { str(LANG_ID3DB_ARTISTS), | 158 | char* labels[] = { str(LANG_ID3DB_ARTISTS), |
163 | str(LANG_ID3DB_ALBUMS), | 159 | str(LANG_ID3DB_ALBUMS), |
164 | str(LANG_ID3DB_SONGS)}; | 160 | str(LANG_ID3DB_SONGS), |
161 | str(LANG_ID3DB_SEARCH)}; | ||
162 | |||
163 | for (i=0; i < 4; i++) { | ||
164 | strcpy(nbuf, labels[i]); | ||
165 | dptr[0] = (unsigned int)nbuf; | ||
166 | dptr[1] = tables[i]; | ||
167 | nbuf += strlen(nbuf) + 1; | ||
168 | dptr += 2; | ||
169 | } | ||
170 | c->dirlength = c->filesindir = i; | ||
171 | return i; | ||
172 | } | ||
173 | |||
174 | case search: { | ||
175 | static const int tables[] = {searchartists, | ||
176 | searchalbums, | ||
177 | searchsongs}; | ||
178 | char* nbuf = (char*)nptr; | ||
179 | char* labels[] = { str(LANG_ID3DB_SEARCH_ARTISTS), | ||
180 | str(LANG_ID3DB_SEARCH_ALBUMS), | ||
181 | str(LANG_ID3DB_SEARCH_SONGS)}; | ||
165 | 182 | ||
166 | for (i=0; i < 3; i++) { | 183 | for (i=0; i < 3; i++) { |
167 | strcpy(nbuf, labels[i]); | 184 | strcpy(nbuf, labels[i]); |
@@ -173,12 +190,26 @@ int db_load(struct tree_context* c) | |||
173 | c->dirlength = c->filesindir = i; | 190 | c->dirlength = c->filesindir = i; |
174 | return i; | 191 | return i; |
175 | } | 192 | } |
176 | 193 | ||
194 | case searchartists: | ||
195 | case searchalbums: | ||
196 | case searchsongs: | ||
197 | i = db_search(c, searchstring); | ||
198 | c->dirlength = c->filesindir = i; | ||
199 | if (c->dirfull) { | ||
200 | splash(HZ, true, "%s %s", | ||
201 | str(LANG_SHOWDIR_ERROR_BUFFER), | ||
202 | str(LANG_SHOWDIR_ERROR_FULL)); | ||
203 | c->dirfull = false; | ||
204 | } | ||
205 | else | ||
206 | splash(HZ, true, str(LANG_ID3DB_MATCHES), i); | ||
207 | return i; | ||
208 | |||
177 | case allsongs: | 209 | case allsongs: |
178 | offset = songstart + c->firstpos * (songlen + 12); | 210 | offset = songstart + c->firstpos * (songlen + 12); |
179 | itemcount = songcount; | 211 | itemcount = songcount; |
180 | stringlen = songlen; | 212 | stringlen = songlen; |
181 | c->dentry_size = 3; | ||
182 | break; | 213 | break; |
183 | 214 | ||
184 | case allalbums: | 215 | case allalbums: |
@@ -229,7 +260,6 @@ int db_load(struct tree_context* c) | |||
229 | offset = safeplace[0]; | 260 | offset = safeplace[0]; |
230 | itemcount = songarraylen; | 261 | itemcount = songarraylen; |
231 | stringlen = songlen; | 262 | stringlen = songlen; |
232 | c->dentry_size = 3; | ||
233 | break; | 263 | break; |
234 | 264 | ||
235 | default: | 265 | default: |
@@ -257,7 +287,7 @@ int db_load(struct tree_context* c) | |||
257 | if (max_items > itemcount) { | 287 | if (max_items > itemcount) { |
258 | max_items = itemcount; | 288 | max_items = itemcount; |
259 | } | 289 | } |
260 | 290 | ||
261 | for ( i=0; i < max_items; i++ ) { | 291 | for ( i=0; i < max_items; i++ ) { |
262 | int rc, skip=0; | 292 | int rc, skip=0; |
263 | int intbuf[4]; | 293 | int intbuf[4]; |
@@ -267,7 +297,6 @@ int db_load(struct tree_context* c) | |||
267 | c->dirlength = i; | 297 | c->dirlength = i; |
268 | break; | 298 | break; |
269 | } | 299 | } |
270 | //DEBUGF("Seeking to %x\n", safeplace[i]); | ||
271 | lseek(fd, safeplace[i], SEEK_SET); | 300 | lseek(fd, safeplace[i], SEEK_SET); |
272 | offset = safeplace[i]; | 301 | offset = safeplace[i]; |
273 | } | 302 | } |
@@ -286,16 +315,13 @@ int db_load(struct tree_context* c) | |||
286 | switch (table) { | 315 | switch (table) { |
287 | case allsongs: | 316 | case allsongs: |
288 | case songs4album: | 317 | case songs4album: |
289 | /* save offset of this song */ | ||
290 | dptr[1] = offset; | ||
291 | |||
292 | rc = read(fd, intbuf, 12); | 318 | rc = read(fd, intbuf, 12); |
293 | if (rc < 12) { | 319 | if (rc < 12) { |
294 | DEBUGF("%d read(%d) returned %d\n", i, 12, rc); | 320 | DEBUGF("%d read(%d) returned %d\n", i, 12, rc); |
295 | return -1; | 321 | return -1; |
296 | } | 322 | } |
297 | /* save offset of filename */ | 323 | /* save offset of filename */ |
298 | dptr[2] = BE32(intbuf[2]); | 324 | dptr[1] = BE32(intbuf[2]); |
299 | break; | 325 | break; |
300 | 326 | ||
301 | case allalbums: | 327 | case allalbums: |
@@ -332,11 +358,95 @@ int db_load(struct tree_context* c) | |||
332 | return i; | 358 | return i; |
333 | } | 359 | } |
334 | 360 | ||
361 | static int db_search(struct tree_context* c, char* string) | ||
362 | { | ||
363 | int i, count, size, hits=0; | ||
364 | long start; | ||
365 | |||
366 | char* nptr = c->name_buffer; | ||
367 | const char* end_of_nbuf = nptr + c->name_buffer_size; | ||
368 | |||
369 | unsigned long* dptr = c->dircache; | ||
370 | const long dcachesize = global_settings.max_files_in_dir * | ||
371 | sizeof(struct entry); | ||
372 | |||
373 | switch (c->currtable) { | ||
374 | case searchartists: | ||
375 | start = artiststart; | ||
376 | count = artistcount; | ||
377 | size = artistlen + albumarraylen * 4; | ||
378 | break; | ||
379 | |||
380 | case searchalbums: | ||
381 | start = albumstart; | ||
382 | count = albumcount; | ||
383 | size = albumlen + 4 + songarraylen * 4; | ||
384 | break; | ||
385 | |||
386 | case searchsongs: | ||
387 | start = songstart; | ||
388 | count = songcount; | ||
389 | size = songlen + 12; | ||
390 | break; | ||
391 | |||
392 | default: | ||
393 | DEBUGF("Invalid table %d\n", c->currtable); | ||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | lseek(fd, start, SEEK_SET); | ||
398 | |||
399 | for (i=0; i<count; i++) { | ||
400 | if (read(fd, nptr, size) < size) { | ||
401 | DEBUGF("Short read(%d) in db_search()\n",size); | ||
402 | break; | ||
403 | } | ||
404 | if (strcasestr(nptr, string)) { | ||
405 | hits++; | ||
406 | |||
407 | dptr[0] = (unsigned long)nptr; | ||
408 | if (c->currtable == searchsongs) { | ||
409 | /* store offset of filename */ | ||
410 | dptr[1] = BE32(*((long*)(nptr + songlen + 8))); | ||
411 | } | ||
412 | else | ||
413 | /* store offset of database record */ | ||
414 | dptr[1] = start + i * size; | ||
415 | |||
416 | dptr += 2; | ||
417 | |||
418 | /* limit dir buffer */ | ||
419 | if ((void*)(dptr + c->dentry_size) > | ||
420 | (void*)(c->dircache + dcachesize)) | ||
421 | { | ||
422 | c->dirfull = true; | ||
423 | break; | ||
424 | } | ||
425 | |||
426 | nptr += strlen(nptr) + 1; | ||
427 | while ((unsigned long)nptr & 3) | ||
428 | nptr++; | ||
429 | |||
430 | /* limit name buffer */ | ||
431 | if ((void*)nptr + size > (void*)end_of_nbuf) { | ||
432 | c->dirfull = true; | ||
433 | break; | ||
434 | } | ||
435 | } | ||
436 | } | ||
437 | |||
438 | return hits; | ||
439 | } | ||
440 | |||
335 | int db_enter(struct tree_context* c) | 441 | int db_enter(struct tree_context* c) |
336 | { | 442 | { |
337 | int rc = 0; | 443 | int rc = 0; |
338 | int newextra = ((int*)c->dircache)[(c->dircursor + c->dirstart)*2 + 1]; | 444 | int offset = (c->dircursor + c->dirstart) * c->dentry_size + 1; |
445 | int newextra = ((int*)c->dircache)[offset]; | ||
339 | 446 | ||
447 | if (c->dirlevel >= MAX_DIR_LEVELS) | ||
448 | return 0; | ||
449 | |||
340 | c->dirpos[c->dirlevel] = c->dirstart; | 450 | c->dirpos[c->dirlevel] = c->dirstart; |
341 | c->cursorpos[c->dirlevel] = c->dircursor; | 451 | c->cursorpos[c->dirlevel] = c->dircursor; |
342 | c->table_history[c->dirlevel] = c->currtable; | 452 | c->table_history[c->dirlevel] = c->currtable; |
@@ -351,24 +461,36 @@ int db_enter(struct tree_context* c) | |||
351 | break; | 461 | break; |
352 | 462 | ||
353 | case allartists: | 463 | case allartists: |
464 | case searchartists: | ||
354 | c->currtable = albums4artist; | 465 | c->currtable = albums4artist; |
355 | c->currextra = newextra; | 466 | c->currextra = newextra; |
356 | break; | 467 | break; |
357 | 468 | ||
358 | case allalbums: | 469 | case allalbums: |
359 | case albums4artist: | 470 | case albums4artist: |
471 | case searchalbums: | ||
360 | c->currtable = songs4album; | 472 | c->currtable = songs4album; |
361 | c->currextra = newextra; | 473 | c->currextra = newextra; |
362 | break; | 474 | break; |
363 | 475 | ||
364 | case allsongs: | 476 | case allsongs: |
365 | case songs4album: | 477 | case songs4album: |
478 | case searchsongs: | ||
366 | c->dirlevel--; | 479 | c->dirlevel--; |
367 | if (db_play_folder(c) >= 0) | 480 | if (db_play_folder(c) >= 0) |
368 | rc = 3; | 481 | rc = 3; |
369 | break; | 482 | break; |
483 | |||
484 | case search: | ||
485 | rc = kbd_input(searchstring, sizeof(searchstring)); | ||
486 | if (rc == -1 || !searchstring[0]) | ||
487 | c->dirlevel--; | ||
488 | else | ||
489 | c->currtable = newextra; | ||
490 | break; | ||
370 | 491 | ||
371 | default: | 492 | default: |
493 | c->dirlevel--; | ||
372 | break; | 494 | break; |
373 | } | 495 | } |
374 | 496 | ||
@@ -401,7 +523,7 @@ static int db_play_folder(struct tree_context* c) | |||
401 | /* TODO: add support for very long tables */ | 523 | /* TODO: add support for very long tables */ |
402 | 524 | ||
403 | for (i=0; i < c->filesindir; i++) { | 525 | for (i=0; i < c->filesindir; i++) { |
404 | int pathoffset = ((int*)c->dircache)[i * c->dentry_size + 2]; | 526 | int pathoffset = ((int*)c->dircache)[i * c->dentry_size + 1]; |
405 | lseek(fd, pathoffset, SEEK_SET); | 527 | lseek(fd, pathoffset, SEEK_SET); |
406 | rc = read(fd, buf, sizeof(buf)); | 528 | rc = read(fd, buf, sizeof(buf)); |
407 | if (rc < songlen) { | 529 | if (rc < songlen) { |
@@ -424,6 +546,9 @@ static int db_play_folder(struct tree_context* c) | |||
424 | 546 | ||
425 | #ifdef HAVE_LCD_BITMAP | 547 | #ifdef HAVE_LCD_BITMAP |
426 | const char* db_get_icon(struct tree_context* c) | 548 | const char* db_get_icon(struct tree_context* c) |
549 | #else | ||
550 | int db_get_icon(struct tree_context* c) | ||
551 | #endif | ||
427 | { | 552 | { |
428 | int icon; | 553 | int icon; |
429 | 554 | ||
@@ -431,6 +556,7 @@ const char* db_get_icon(struct tree_context* c) | |||
431 | { | 556 | { |
432 | case allsongs: | 557 | case allsongs: |
433 | case songs4album: | 558 | case songs4album: |
559 | case searchsongs: | ||
434 | icon = File; | 560 | icon = File; |
435 | break; | 561 | break; |
436 | 562 | ||
@@ -439,23 +565,9 @@ const char* db_get_icon(struct tree_context* c) | |||
439 | break; | 565 | break; |
440 | } | 566 | } |
441 | 567 | ||
568 | #ifdef HAVE_LCD_BITMAP | ||
442 | return bitmap_icons_6x8[icon]; | 569 | return bitmap_icons_6x8[icon]; |
443 | } | ||
444 | #else | 570 | #else |
445 | int db_get_icon(struct tree_context* c) | ||
446 | { | ||
447 | int icon; | ||
448 | switch (c->currtable) | ||
449 | { | ||
450 | case allsongs: | ||
451 | case songs4album: | ||
452 | icon = File; | ||
453 | break; | ||
454 | |||
455 | default: | ||
456 | icon = Folder; | ||
457 | break; | ||
458 | } | ||
459 | return icon; | 571 | return icon; |
460 | } | ||
461 | #endif | 572 | #endif |
573 | } | ||
diff --git a/apps/dbtree.h b/apps/dbtree.h index b0c726881f..5cf2e4feed 100644 --- a/apps/dbtree.h +++ b/apps/dbtree.h | |||
@@ -22,7 +22,8 @@ | |||
22 | #include "tree.h" | 22 | #include "tree.h" |
23 | 23 | ||
24 | enum table { invalid, root, allsongs, allalbums, allartists, | 24 | enum table { invalid, root, allsongs, allalbums, allartists, |
25 | albums4artist, songs4album }; | 25 | albums4artist, songs4album, |
26 | search, searchartists, searchalbums, searchsongs }; | ||
26 | 27 | ||
27 | int db_init(void); | 28 | int db_init(void); |
28 | int db_enter(struct tree_context* c); | 29 | int db_enter(struct tree_context* c); |
diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 05903601db..795bde69f8 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang | |||
@@ -2895,3 +2895,33 @@ desc: ID3 virtual folder name | |||
2895 | eng: "Songs" | 2895 | eng: "Songs" |
2896 | voice: "" | 2896 | voice: "" |
2897 | new: | 2897 | new: |
2898 | |||
2899 | id: LANG_ID3DB_SEARCH | ||
2900 | desc: ID3 virtual folder name | ||
2901 | eng: "Search" | ||
2902 | voice: "" | ||
2903 | new: | ||
2904 | |||
2905 | id: LANG_ID3DB_SEARCH_ARTISTS | ||
2906 | desc: ID3 virtual folder name | ||
2907 | eng: "Search Artists" | ||
2908 | voice: "" | ||
2909 | new: | ||
2910 | |||
2911 | id: LANG_ID3DB_SEARCH_ALBUMS | ||
2912 | desc: ID3 virtual folder name | ||
2913 | eng: "Search Albums" | ||
2914 | voice: "" | ||
2915 | new: | ||
2916 | |||
2917 | id: LANG_ID3DB_SEARCH_SONGS | ||
2918 | desc: ID3 virtual folder name | ||
2919 | eng: "Search Songs" | ||
2920 | voice: "" | ||
2921 | new: | ||
2922 | |||
2923 | id: LANG_ID3DB_MATCHES | ||
2924 | desc: ID3 virtual folder name | ||
2925 | eng: "Found %d matches" | ||
2926 | voice: "" | ||
2927 | new: | ||