summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjörn Stenberg <bjorn@haxx.se>2005-01-27 22:21:08 +0000
committerBjörn Stenberg <bjorn@haxx.se>2005-01-27 22:21:08 +0000
commit6660f8e91060593cfd6a50c5acf58a653bd284e0 (patch)
tree494ac07fe5b3737d29d1567093f98024b6a73104
parentd719abce64c51a40bf01b613d26b63e57e2abcc2 (diff)
downloadrockbox-6660f8e91060593cfd6a50c5acf58a653bd284e0.tar.gz
rockbox-6660f8e91060593cfd6a50c5acf58a653bd284e0.zip
Added ID3 searching
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@5683 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/dbtree.c196
-rw-r--r--apps/dbtree.h3
-rw-r--r--apps/lang/english.lang30
-rw-r--r--firmware/SOURCES1
-rw-r--r--firmware/common/strcasestr.c122
-rw-r--r--firmware/include/string.h1
6 files changed, 310 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
62static int db_play_folder(struct tree_context* c); 64static int db_play_folder(struct tree_context* c);
65static int db_search(struct tree_context* c, char* string);
66
67static char searchstring[32];
63 68
64int db_init(void) 69int 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
361static 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
335int db_enter(struct tree_context* c) 441int 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
426const char* db_get_icon(struct tree_context* c) 548const char* db_get_icon(struct tree_context* c)
549#else
550int 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
445int 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
24enum table { invalid, root, allsongs, allalbums, allartists, 24enum table { invalid, root, allsongs, allalbums, allartists,
25 albums4artist, songs4album }; 25 albums4artist, songs4album,
26 search, searchartists, searchalbums, searchsongs };
26 27
27int db_init(void); 28int db_init(void);
28int db_enter(struct tree_context* c); 29int 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
2895eng: "Songs" 2895eng: "Songs"
2896voice: "" 2896voice: ""
2897new: 2897new:
2898
2899id: LANG_ID3DB_SEARCH
2900desc: ID3 virtual folder name
2901eng: "Search"
2902voice: ""
2903new:
2904
2905id: LANG_ID3DB_SEARCH_ARTISTS
2906desc: ID3 virtual folder name
2907eng: "Search Artists"
2908voice: ""
2909new:
2910
2911id: LANG_ID3DB_SEARCH_ALBUMS
2912desc: ID3 virtual folder name
2913eng: "Search Albums"
2914voice: ""
2915new:
2916
2917id: LANG_ID3DB_SEARCH_SONGS
2918desc: ID3 virtual folder name
2919eng: "Search Songs"
2920voice: ""
2921new:
2922
2923id: LANG_ID3DB_MATCHES
2924desc: ID3 virtual folder name
2925eng: "Found %d matches"
2926voice: ""
2927new:
diff --git a/firmware/SOURCES b/firmware/SOURCES
index c3db4e163b..92ba69d179 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -17,6 +17,7 @@ common/qsort.c
17common/random.c 17common/random.c
18common/sprintf.c 18common/sprintf.c
19common/strcasecmp.c 19common/strcasecmp.c
20common/strcasestr.c
20common/strcat.c 21common/strcat.c
21common/strchr.c 22common/strchr.c
22common/strcmp.c 23common/strcmp.c
diff --git a/firmware/common/strcasestr.c b/firmware/common/strcasestr.c
new file mode 100644
index 0000000000..095eebdd66
--- /dev/null
+++ b/firmware/common/strcasestr.c
@@ -0,0 +1,122 @@
1/* Return the offset of one string within another.
2 Copyright (C) 1994,1996,1997,1998,1999,2000 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
19
20/*
21 * My personal strstr() implementation that beats most other algorithms.
22 * Until someone tells me otherwise, I assume that this is the
23 * fastest implementation of strstr() in C.
24 * I deliberately chose not to comment it. You should have at least
25 * as much fun trying to understand it, as I had to write it :-).
26 *
27 * Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de*/
28
29/* Faster looping by precalculating bl, bu, cl, cu before looping.
30 * 2004 Apr 08 Jose Da Silva, digital@joescat@com */
31
32#include <string.h>
33#include <ctype.h>
34
35typedef unsigned chartype;
36
37char* strcasestr (const char* phaystack, const char* pneedle)
38{
39 const unsigned char *haystack, *needle;
40 chartype bl, bu, cl, cu;
41
42 haystack = (const unsigned char *) phaystack;
43 needle = (const unsigned char *) pneedle;
44
45 bl = tolower (*needle);
46 if (bl != '\0')
47 {
48 bu = toupper (bl);
49 haystack--;/* possible ANSI violation */
50 do
51 {
52 cl = *++haystack;
53 if (cl == '\0')
54 goto ret0;
55 }
56 while ((cl != bl) && (cl != bu));
57
58 cl = tolower (*++needle);
59 if (cl == '\0')
60 goto foundneedle;
61 cu = toupper (cl);
62 ++needle;
63 goto jin;
64
65 for (;;)
66 {
67 chartype a;
68 const unsigned char *rhaystack, *rneedle;
69
70 do
71 {
72 a = *++haystack;
73 if (a == '\0')
74 goto ret0;
75 if ((a == bl) || (a == bu))
76 break;
77 a = *++haystack;
78 if (a == '\0')
79 goto ret0;
80 shloop:
81 ;
82 }
83 while ((a != bl) && (a != bu));
84
85 jin: a = *++haystack;
86 if (a == '\0')
87 goto ret0;
88
89 if ((a != cl) && (a != cu))
90 goto shloop;
91
92 rhaystack = haystack-- + 1;
93 rneedle = needle;
94 a = tolower (*rneedle);
95
96 if (tolower (*rhaystack) == (int) a)
97 do
98 {
99 if (a == '\0')
100 goto foundneedle;
101 ++rhaystack;
102 a = tolower (*++needle);
103 if (tolower (*rhaystack) != (int) a)
104 break;
105 if (a == '\0')
106 goto foundneedle;
107 ++rhaystack;
108 a = tolower (*++needle);
109 }
110 while (tolower (*rhaystack) == (int) a);
111
112 needle = rneedle;/* took the register-poor approach */
113
114 if (a == '\0')
115 break;
116 }
117 }
118 foundneedle:
119 return (char*) haystack;
120 ret0:
121 return 0;
122}
diff --git a/firmware/include/string.h b/firmware/include/string.h
index e9aa24c530..713a875698 100644
--- a/firmware/include/string.h
+++ b/firmware/include/string.h
@@ -40,6 +40,7 @@ char *_EXFUN(strpbrk,(const char *, const char *));
40char *_EXFUN(strrchr,(const char *, int)); 40char *_EXFUN(strrchr,(const char *, int));
41size_t _EXFUN(strspn,(const char *, const char *)); 41size_t _EXFUN(strspn,(const char *, const char *));
42char *_EXFUN(strstr,(const char *, const char *)); 42char *_EXFUN(strstr,(const char *, const char *));
43char *_EXFUN(strcasestr,(const char *, const char *));
43 44
44#ifndef _REENT_ONLY 45#ifndef _REENT_ONLY
45char *_EXFUN(strtok,(char *, const char *)); 46char *_EXFUN(strtok,(char *, const char *));