diff options
Diffstat (limited to 'apps/database.c')
-rw-r--r-- | apps/database.c | 239 |
1 files changed, 142 insertions, 97 deletions
diff --git a/apps/database.c b/apps/database.c index ad97b55ee7..50f8b80ac9 100644 --- a/apps/database.c +++ b/apps/database.c | |||
@@ -48,21 +48,23 @@ | |||
48 | 48 | ||
49 | /* internal functions */ | 49 | /* internal functions */ |
50 | void writetagdbheader(void); | 50 | void writetagdbheader(void); |
51 | void writefentry(void); | 51 | void writefentry(struct mp3entry *id); |
52 | void getfentrybyoffset(int offset); | 52 | void getfentrybyoffset(struct mp3entry *id,int offset); |
53 | void update_fentryoffsets(int start, int end); | 53 | void update_fentryoffsets(int start, int end); |
54 | void writerundbheader(void); | 54 | void writerundbheader(void); |
55 | void getrundbentrybyoffset(int offset); | 55 | void getrundbentrybyoffset(struct mp3entry *id,int offset); |
56 | void writerundbentry(void); | 56 | void writerundbentry(struct mp3entry *id); |
57 | int getfentrybyfilename(char *fname); | 57 | int getfentrybyfilename(struct mp3entry *id); |
58 | void clearfileentryinfo(struct mp3entry *id); | ||
59 | void clearruntimeinfo(struct mp3entry *id); | ||
60 | int findrundbentry(struct mp3entry *id); | ||
61 | |||
58 | int getfentrybyhash(int hash); | 62 | int getfentrybyhash(int hash); |
59 | int deletefentry(char *fname); | 63 | int deletefentry(char *fname); |
60 | int tagdb_shiftdown(int targetoffset, int startingoffset, int bytes); | 64 | int tagdb_shiftdown(int targetoffset, int startingoffset, int bytes); |
61 | int tagdb_shiftup(int targetoffset, int startingoffset, int bytes); | 65 | int tagdb_shiftup(int targetoffset, int startingoffset, int bytes); |
62 | 66 | ||
63 | static char sbuf[1024]; | 67 | static char sbuf[MAX_PATH]; |
64 | static struct file_entry fe; | ||
65 | static long currentfeoffset, currentferecord; | ||
66 | 68 | ||
67 | int tagdb_fd = -1; | 69 | int tagdb_fd = -1; |
68 | int tagdb_initialized = 0; | 70 | int tagdb_initialized = 0; |
@@ -133,36 +135,42 @@ void writetagdbheader(void) | |||
133 | fsync(tagdb_fd); | 135 | fsync(tagdb_fd); |
134 | } | 136 | } |
135 | 137 | ||
136 | void writefentry(void) | 138 | void writefentry(struct mp3entry *id) |
137 | { | 139 | { long temp; |
138 | lseek(tagdb_fd,currentfeoffset,SEEK_SET); | 140 | if(!id->fileentryoffset) |
139 | write(tagdb_fd,sbuf,tagdbheader.filelen); | 141 | return; |
140 | write(tagdb_fd,&fe.hash,12); | 142 | lseek(tagdb_fd,id->fileentryoffset,SEEK_SET); |
141 | fsync(tagdb_fd); | 143 | write(tagdb_fd,id->path,tagdbheader.filelen); |
144 | temp=id->filehash; | ||
145 | write(tagdb_fd,&temp,4); | ||
146 | temp=id->songentryoffset; | ||
147 | write(tagdb_fd,&temp,4); | ||
148 | temp=id->rundbentryoffset; | ||
149 | write(tagdb_fd,&temp,4); | ||
142 | } | 150 | } |
143 | 151 | ||
144 | void getfentrybyoffset(int offset) | 152 | void getfentrybyoffset(struct mp3entry *id,int offset) |
145 | { | 153 | { |
146 | memset(&fe,0,sizeof(struct file_entry)); | 154 | clearfileentryinfo(id); |
147 | lseek(tagdb_fd,offset,SEEK_SET); | 155 | lseek(tagdb_fd,offset,SEEK_SET); |
148 | read(tagdb_fd,sbuf,tagdbheader.filelen); | 156 | read(tagdb_fd,sbuf,tagdbheader.filelen); |
149 | read(tagdb_fd,&fe.hash,12); | 157 | id->fileentryoffset=offset; |
150 | fe.name=sbuf; | 158 | read(tagdb_fd,&id->filehash,4); |
151 | currentfeoffset=offset; | 159 | read(tagdb_fd,&id->songentryoffset,4); |
152 | currentferecord=(offset-tagdbheader.filestart)/FILEENTRY_SIZE; | 160 | read(tagdb_fd,&id->rundbentryoffset,4); |
153 | } | 161 | } |
154 | 162 | ||
155 | #define getfentrybyrecord(_x_) getfentrybyoffset(FILERECORD2OFFSET(_x_)) | 163 | #define getfentrybyrecord(_y_,_x_) getfentrybyoffset(_y_,FILERECORD2OFFSET(_x_)) |
156 | 164 | ||
157 | int getfentrybyfilename(char *fname) | 165 | int getfentrybyfilename(struct mp3entry *id) |
158 | { | 166 | { |
159 | int min=0; | 167 | int min=0; |
160 | int max=tagdbheader.filecount; | 168 | int max=tagdbheader.filecount; |
161 | while(min<max) { | 169 | while(min<max) { |
162 | int mid=(min+max)/2; | 170 | int mid=(min+max)/2; |
163 | int compare; | 171 | int compare; |
164 | getfentrybyrecord(mid); | 172 | getfentrybyrecord(id,mid); |
165 | compare=strcasecmp(fname,fe.name); | 173 | compare=strcasecmp(id->path,sbuf); |
166 | if(compare==0) | 174 | if(compare==0) |
167 | return 1; | 175 | return 1; |
168 | else if(compare<0) | 176 | else if(compare<0) |
@@ -170,8 +178,10 @@ int getfentrybyfilename(char *fname) | |||
170 | else | 178 | else |
171 | min=mid+1; | 179 | min=mid+1; |
172 | } | 180 | } |
181 | clearfileentryinfo(id); | ||
173 | return 0; | 182 | return 0; |
174 | } | 183 | } |
184 | |||
175 | #if 0 | 185 | #if 0 |
176 | int getfentrybyhash(int hash) | 186 | int getfentrybyhash(int hash) |
177 | { | 187 | { |
@@ -292,16 +302,28 @@ int rundb_fd = -1; | |||
292 | int rundb_initialized = 0; | 302 | int rundb_initialized = 0; |
293 | struct rundb_header rundbheader; | 303 | struct rundb_header rundbheader; |
294 | 304 | ||
295 | static long valid_file, currentreoffset,rundbsize; | 305 | static long rundbsize; |
296 | static struct rundb_entry rundbentry; | ||
297 | 306 | ||
298 | /*** RuntimeDatabase code ***/ | 307 | /*** RuntimeDatabase code ***/ |
299 | 308 | ||
300 | void rundb_track_changed(struct track_info *ti) | 309 | void rundb_unbuffer_track(struct mp3entry *id, bool last_track) { |
301 | { | 310 | writeruntimeinfo(id); |
302 | increaseplaycount(); | 311 | if(last_track) { |
303 | logf("rundb new track: %s", ti->id3.path); | 312 | fsync(rundb_fd); |
304 | loadruntimeinfo(ti->id3.path); | 313 | fsync(tagdb_fd); |
314 | } | ||
315 | } | ||
316 | |||
317 | void rundb_track_change(struct track_info *ti) { | ||
318 | ti->id3.playcount++; | ||
319 | } | ||
320 | |||
321 | void rundb_buffer_track(struct mp3entry *id, bool last_track) { | ||
322 | loadruntimeinfo(id); | ||
323 | if(last_track) { | ||
324 | fsync(rundb_fd); | ||
325 | fsync(tagdb_fd); | ||
326 | } | ||
305 | } | 327 | } |
306 | 328 | ||
307 | int rundb_init(void) | 329 | int rundb_init(void) |
@@ -354,8 +376,9 @@ int rundb_init(void) | |||
354 | } | 376 | } |
355 | 377 | ||
356 | rundb_initialized = 1; | 378 | rundb_initialized = 1; |
357 | audio_set_track_changed_event(&rundb_track_changed); | 379 | audio_set_track_buffer_event(&rundb_buffer_track); |
358 | memset(&rundbentry,0,sizeof(struct rundb_entry)); | 380 | audio_set_track_changed_event(&rundb_track_change); |
381 | audio_set_track_unbuffer_event(&rundb_unbuffer_track); | ||
359 | rundbsize=lseek(rundb_fd,0,SEEK_END); | 382 | rundbsize=lseek(rundb_fd,0,SEEK_END); |
360 | return 0; | 383 | return 0; |
361 | #endif | 384 | #endif |
@@ -366,106 +389,128 @@ void rundb_shutdown(void) | |||
366 | if (rundb_fd >= 0) | 389 | if (rundb_fd >= 0) |
367 | close(rundb_fd); | 390 | close(rundb_fd); |
368 | rundb_initialized = 0; | 391 | rundb_initialized = 0; |
392 | audio_set_track_buffer_event(NULL); | ||
393 | audio_set_track_unbuffer_event(NULL); | ||
369 | } | 394 | } |
370 | 395 | ||
371 | void writerundbheader(void) | 396 | void writerundbheader(void) |
372 | { | 397 | { |
373 | lseek(rundb_fd,0,SEEK_SET); | 398 | lseek(rundb_fd,0,SEEK_SET); |
374 | write(rundb_fd, &rundbheader, 8); | 399 | write(rundb_fd, &rundbheader, 8); |
375 | fsync(rundb_fd); | ||
376 | } | 400 | } |
377 | 401 | ||
378 | #define getrundbentrybyrecord(_x_) getrundbentrybyoffset(8+_x_*20) | 402 | #define getrundbentrybyrecord(_y_,_x_) getrundbentrybyoffset(_y_,8+_x_*20) |
379 | 403 | ||
380 | void getrundbentrybyoffset(int offset) { | 404 | void getrundbentrybyoffset(struct mp3entry *id,int offset) { |
381 | lseek(rundb_fd,offset,SEEK_SET); | 405 | lseek(rundb_fd,offset+4,SEEK_SET); // skip fileentry offset |
382 | read(rundb_fd,&rundbentry,20); | 406 | id->rundbentryoffset=offset; |
383 | currentreoffset=offset; | 407 | read(rundb_fd,&id->rundbhash,4); |
408 | read(rundb_fd,&id->rating,2); | ||
409 | read(rundb_fd,&id->voladjust,2); | ||
410 | read(rundb_fd,&id->playcount,4); | ||
411 | read(rundb_fd,&id->lastplayed,4); | ||
384 | #ifdef ROCKBOX_LITTLE_ENDIAN | 412 | #ifdef ROCKBOX_LITTLE_ENDIAN |
385 | rundbentry.fileentry=BE32(rundbentry.fileentry); | 413 | id->rundbhash=BE32(id->rundbhash); |
386 | rundbentry.hash=BE32(rundbentry.hash); | 414 | id->rating=BE16(id->rating); |
387 | rundbentry.rating=BE16(rundbentry.rating); | 415 | id->voladjust=BE16(id->voladjust); |
388 | rundbentry.voladjust=BE16(rundbentry.voladjust); | 416 | id->playcount=BE32(id->playcount); |
389 | rundbentry.playcount=BE32(rundbentry.playcount); | 417 | id->lastplayed=BE32(id->lastplayed); |
390 | rundbentry.lastplayed=BE32(rundbentry.lastplayed); | ||
391 | #endif | 418 | #endif |
392 | } | 419 | } |
393 | 420 | ||
394 | int getrundbentrybyhash(int hash) | 421 | int getrundbentrybyhash(struct mp3entry *id) |
395 | { | 422 | { |
396 | int min=0; | 423 | int min=0; |
397 | for(min=0;min<rundbheader.entrycount;min++) { | 424 | for(min=0;min<rundbheader.entrycount;min++) { |
398 | getrundbentrybyrecord(min); | 425 | getrundbentrybyrecord(id,min); |
399 | if(hash==rundbentry.hash) | 426 | if(id->filehash==id->rundbhash) |
400 | return 1; | 427 | return 1; |
401 | } | 428 | } |
402 | memset(&rundbentry,0,sizeof(struct rundb_entry)); | 429 | clearruntimeinfo(id); |
403 | return 0; | 430 | return 0; |
404 | } | 431 | } |
405 | 432 | ||
406 | void writerundbentry(void) | 433 | void writerundbentry(struct mp3entry *id) |
407 | { | 434 | { |
408 | if(rundbentry.hash==0) /* 0 = invalid rundb info. */ | 435 | if(id->rundbhash==0) /* 0 = invalid rundb info. */ |
409 | return; | 436 | return; |
410 | lseek(rundb_fd,currentreoffset,SEEK_SET); | 437 | lseek(rundb_fd,id->rundbentryoffset,SEEK_SET); |
411 | write(rundb_fd,&rundbentry,20); | 438 | write(rundb_fd,&id->fileentryoffset,4); |
412 | fsync(rundb_fd); | 439 | write(rundb_fd,&id->rundbhash,4); |
440 | write(rundb_fd,&id->rating,2); | ||
441 | write(rundb_fd,&id->voladjust,2); | ||
442 | write(rundb_fd,&id->playcount,4); | ||
443 | write(rundb_fd,&id->lastplayed,4); | ||
444 | } | ||
445 | |||
446 | void writeruntimeinfo(struct mp3entry *id) { | ||
447 | if(!id->rundbhash) | ||
448 | addrundbentry(id); | ||
449 | else | ||
450 | writerundbentry(id); | ||
451 | } | ||
452 | |||
453 | void clearfileentryinfo(struct mp3entry *id) { | ||
454 | id->fileentryoffset=0; | ||
455 | id->filehash=0; | ||
456 | id->songentryoffset=0; | ||
457 | id->rundbentryoffset=0; | ||
458 | } | ||
459 | |||
460 | void clearruntimeinfo(struct mp3entry *id) { | ||
461 | id->rundbhash=0; | ||
462 | id->rating=0; | ||
463 | id->voladjust=0; | ||
464 | id->playcount=0; | ||
465 | id->lastplayed=0; | ||
413 | } | 466 | } |
414 | 467 | ||
415 | void loadruntimeinfo(char *filename) | 468 | void loadruntimeinfo(struct mp3entry *id) |
416 | { | 469 | { |
417 | memset(&rundbentry,0,sizeof(struct rundb_entry)); | 470 | clearruntimeinfo(id); |
418 | valid_file=0; | 471 | clearfileentryinfo(id); |
419 | if(!getfentrybyfilename(filename)) | 472 | if(!getfentrybyfilename(id)) { |
473 | logf("tagdb fail: %s",id->path); | ||
420 | return; /* file is not in tagdatabase, could not load. */ | 474 | return; /* file is not in tagdatabase, could not load. */ |
421 | valid_file=1; | 475 | } |
422 | if(fe.rundbentry!=-1&&fe.rundbentry<rundbsize) { | 476 | if(id->rundbentryoffset!=-1&&id->rundbentryoffset<rundbsize) { |
423 | logf("load rundbentry: 0x%x",fe.rundbentry); | 477 | logf("load rundbentry: 0x%x",id->rundbentryoffset); |
424 | getrundbentrybyoffset(fe.rundbentry); | 478 | getrundbentrybyoffset(id,id->rundbentryoffset); |
425 | if(fe.hash!=rundbentry.hash) { | 479 | if(id->filehash!=id->rundbhash) { |
426 | logf("Rundb: Hash mismatch. trying to repair entry.", | 480 | logf("Rundb: Hash mismatch. trying to repair entry.", |
427 | fe.hash,rundbentry.hash); | 481 | id->filehash,id->rundbhash); |
428 | addrundbentry(); | 482 | findrundbentry(id); |
429 | } | 483 | } |
430 | } | 484 | } |
431 | else /* add new rundb entry. */ | 485 | else { |
432 | addrundbentry(); | 486 | if(!findrundbentry(id)) |
487 | logf("rundb:no entry and not found."); | ||
488 | } | ||
433 | } | 489 | } |
434 | 490 | ||
435 | void addrundbentry() | 491 | int findrundbentry(struct mp3entry *id) { |
492 | if(getrundbentrybyhash(id)) { | ||
493 | logf("Found existing rundb entry: 0x%x",id->rundbentryoffset); | ||
494 | writefentry(id); | ||
495 | return 1; | ||
496 | } | ||
497 | clearruntimeinfo(id); | ||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | void addrundbentry(struct mp3entry *id) | ||
436 | { | 502 | { |
437 | /* first search for an entry with an equal hash. */ | 503 | /* first search for an entry with an equal hash. */ |
438 | if(getrundbentrybyhash(fe.hash)) { | 504 | /* if(findrundbentry(id)) |
439 | logf("Found existing rundb entry: 0x%x",currentreoffset); | 505 | return; disabled cause this SHOULD have been checked at the buffer event.. */ |
440 | fe.rundbentry=currentreoffset; | ||
441 | writefentry(); | ||
442 | return; | ||
443 | } | ||
444 | rundbheader.entrycount++; | 506 | rundbheader.entrycount++; |
445 | writerundbheader(); | 507 | writerundbheader(); |
446 | fe.rundbentry=currentreoffset=lseek(rundb_fd,0,SEEK_END); | 508 | id->rundbentryoffset=lseek(rundb_fd,0,SEEK_END); |
447 | logf("Add rundb entry: 0x%x hash: 0x%x",fe.rundbentry,fe.hash); | 509 | logf("Add rundb entry: 0x%x hash: 0x%x",id->rundbentryoffset,id->filehash); |
448 | rundbentry.hash=fe.hash; | 510 | id->rundbhash=id->filehash; |
449 | rundbentry.fileentry=currentfeoffset; | 511 | writefentry(id); |
450 | writefentry(); | 512 | writerundbentry(id); |
451 | writerundbentry(); | ||
452 | rundbsize=lseek(rundb_fd,0,SEEK_END); | 513 | rundbsize=lseek(rundb_fd,0,SEEK_END); |
453 | } | 514 | } |
454 | 515 | ||
455 | void increaseplaycount(void) | ||
456 | { | ||
457 | if(rundbentry.hash==0) /* 0 = invalid rundb info. */ | ||
458 | return; | ||
459 | rundbentry.playcount++; | ||
460 | writerundbentry(); | ||
461 | } | ||
462 | |||
463 | void setrating(int rating) | ||
464 | { | ||
465 | if(rundbentry.hash==0) /* 0 = invalid rundb info. */ | ||
466 | return; | ||
467 | rundbentry.rating=rating; | ||
468 | writerundbentry(); | ||
469 | } | ||
470 | |||
471 | /*** end RuntimeDatabase code ***/ | 516 | /*** end RuntimeDatabase code ***/ |