From c735ed79142a0260fc05d58cb0672e5d1720a26a Mon Sep 17 00:00:00 2001 From: Michiel Van Der Kolk Date: Fri, 1 Jul 2005 17:29:44 +0000 Subject: First runtime database support, self repairing, only playcount works for now, which is still rather crude; playcount gets increased even if the song started playback but was skipped... track rating should be trivial to add, autorating also works since its based on playcount. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6969 a1c6a512-1295-4272-9138-f99709370657 --- apps/database.c | 217 ++++++++++++++++++++++++++++---- apps/database.h | 8 ++ apps/main.c | 1 + apps/plugin.c | 3 + apps/plugin.h | 5 +- apps/plugins/databox/edittoken.h | 2 +- apps/plugins/searchengine/dbinterface.c | 15 ++- apps/plugins/searchengine/dbinterface.h | 8 +- apps/plugins/searchengine/token.h | 9 +- tools/songdb.pl | 4 +- tools/testdbv2.c | 13 +- 11 files changed, 241 insertions(+), 44 deletions(-) diff --git a/apps/database.c b/apps/database.c index c753362cd1..06bac4a10c 100644 --- a/apps/database.c +++ b/apps/database.c @@ -43,14 +43,26 @@ #include "keyboard.h" #include "database.h" #include "autoconf.h" +#include "playback.h" +#include "logf.h" -#undef NEW_DB_CODE - -#ifdef NEW_DB_CODE +/* internal functions */ +void writetagdbheader(void); +void writefentry(void); +void getfentrybyoffset(int offset); +void update_fentryoffsets(int start, int end); +void writerundbheader(void); +void getrundbentrybyoffset(int offset); +void writerundbentry(void); +int getfentrybyfilename(char *fname); +int getfentrybyhash(int hash); +int deletefentry(char *fname); +int tagdb_shiftdown(int targetoffset, int startingoffset, int bytes); +int tagdb_shiftup(int targetoffset, int startingoffset, int bytes); + static char sbuf[1024]; static struct file_entry fe; static int currentfeoffset, currentferecord; -#endif int tagdb_fd = -1; int tagdb_initialized = 0; @@ -63,7 +75,7 @@ int tagdb_init(void) int i, *p; #endif - tagdb_fd = open(ROCKBOX_DIR "/rockbox.id3db", O_RDONLY); + tagdb_fd = open(ROCKBOX_DIR "/rockbox.tagdb", O_RDWR); if (tagdb_fd < 0) { DEBUGF("Failed opening database\n"); return -1; @@ -111,19 +123,26 @@ void tagdb_shutdown(void) /* NOTE: All these functions below are yet untested. */ -#ifdef NEW_DB_CODE - /*** TagDatabase code ***/ -void writetagdbheader() { +void writetagdbheader(void) { lseek(tagdb_fd,0,SEEK_SET); write(tagdb_fd, &tagdbheader, 68); + fsync(tagdb_fd); +} + +void writefentry(void) { + lseek(tagdb_fd,currentfeoffset,SEEK_SET); + write(tagdb_fd,sbuf,tagdbheader.filelen); + write(tagdb_fd,&fe.hash,12); + fsync(tagdb_fd); } void getfentrybyoffset(int offset) { + memset(&fe,0,sizeof(struct file_entry)); lseek(tagdb_fd,offset,SEEK_SET); - fread(tagdb_fd,sbuf,tagdbheader.filelen); - fread(tagdb_fd,&fe+sizeof(char *),12); + read(tagdb_fd,sbuf,tagdbheader.filelen); + read(tagdb_fd,&fe.hash,12); fe.name=sbuf; currentfeoffset=offset; currentferecord=(offset-tagdbheader.filestart)/FILEENTRY_SIZE; @@ -138,7 +157,7 @@ int getfentrybyfilename(char *fname) { int mid=(min+max)/2; int compare; getfentrybyrecord(mid); - compare=strcasecmp(fname,fe.name)); + compare=strcasecmp(fname,fe.name); if(compare==0) return 1; else if(compare<0) @@ -164,7 +183,7 @@ int deletefentry(char *fname) { return 0; int restrecord = currentferecord+1; if(currentferecord!=tagdbheader.filecount) /* file is not last entry */ - shiftdown(FILERECORD2OFFSET(currentferecord),FILERECORD2OFFSET(restrecord),(tagdbheader.filecount-restrecord)*FILEENTRY_SIZE); + tagdb_shiftdown(FILERECORD2OFFSET(currentferecord),FILERECORD2OFFSET(restrecord),(tagdbheader.filecount-restrecord)*FILEENTRY_SIZE); ftruncate(tagdb_fd,lseek(tagdb_fd,0,SEEK_END)-FILEENTRY_SIZE); tagdbheader.filecount--; update_fentryoffsets(restrecord,tagdbheader.filecount); @@ -172,9 +191,9 @@ int deletefentry(char *fname) { return 1; } -int update_fentryoffsets(int start, int end) { +void update_fentryoffsets(int start, int end) { int i; - for(int i=start;i=startingoffset) { - splash(HZ*2,"Woah. no beeping way. (tagdb_shiftdown)"); + splash(HZ*2,true,"Woah. no beeping way. (tagdb_shiftdown)"); return 0; } lseek(tagdb_fd,startingoffset,SEEK_SET); - while(amount=read(tagdb_fd,sbuf,bytes > 1024 ? 1024 : bytes)) { + while((amount=read(tagdb_fd,sbuf,(bytes > 1024) ? 1024 : bytes))) { int written; startingoffset+=amount; lseek(tagdb_fd,targetoffset,SEEK_SET); written=write(tagdb_fd,sbuf,amount); targetoffset+=written; if(amount!=written) { - splash(HZ*2,"Something went very wrong. expect database corruption. (tagdb_shiftdown)"); + splash(HZ*2,true,"Something went very wrong. expect database corruption. (tagdb_shiftdown)"); return 0; } lseek(tagdb_fd,startingoffset,SEEK_SET); @@ -218,9 +237,8 @@ int tagdb_shiftdown(int targetoffset, int startingoffset, int bytes) { int tagdb_shiftup(int targetoffset, int startingoffset, int bytes) { int amount,amount2; int readpos,writepos,filelen; - int ok; if(targetoffset<=startingoffset) { - splash(HZ*2,"Um. no. (tagdb_shiftup)"); + splash(HZ*2,true,"Um. no. (tagdb_shiftup)"); return 0; } filelen=lseek(tagdb_fd,0,SEEK_END); @@ -232,13 +250,13 @@ int tagdb_shiftup(int targetoffset, int startingoffset, int bytes) { lseek(tagdb_fd,readpos,SEEK_SET); amount2=read(tagdb_fd,sbuf,amount); if(amount2!=amount) { - splash(HZ*2,"Something went very wrong. expect database corruption. (tagdb_shiftup)"); + splash(HZ*2,true,"Something went very wrong. expect database corruption. (tagdb_shiftup)"); return 0; } lseek(tagdb_fd,writepos,SEEK_SET); amount=write(tagdb_fd,sbuf,amount2); if(amount2!=amount) { - splash(HZ*2,"Something went very wrong. expect database corruption. (tagdb_shiftup)"); + splash(HZ*2,true,"Something went very wrong. expect database corruption. (tagdb_shiftup)"); return 0; } bytes-=amount; @@ -246,17 +264,168 @@ int tagdb_shiftup(int targetoffset, int startingoffset, int bytes) { if(bytes==0) return 1; else { - splash(HZ*2,"Something went wrong, >.>;; (tagdb_shiftup)"); + splash(HZ*2,true,"Something went wrong, >.>;; (tagdb_shiftup)"); return 0; } } /*** end TagDatabase code ***/ +int rundb_fd = -1; +int rundb_initialized = 0; +struct rundb_header rundbheader; + +static int valid_file, currentreoffset,rundbsize; +static struct rundb_entry rundbentry; + /*** RuntimeDatabase code ***/ +void rundb_track_changed(struct track_info *ti) { + increaseplaycount(); + logf("rundb new track: %s", ti->id3.path); + loadruntimeinfo(ti->id3.path); +} +int rundb_init(void) +{ + unsigned char* ptr = (char*)&rundbheader.version; +#ifdef ROCKBOX_LITTLE_ENDIAN + int i, *p; +#endif -/*** end RuntimeDatabase code ***/ + if(!tagdb_initialized) /* forget it.*/ + return -1; + + rundb_fd = open(ROCKBOX_DIR "/rockbox.rundb", O_CREAT|O_RDWR); + if (rundb_fd < 0) { + DEBUGF("Failed opening database\n"); + return -1; + } + if(read(rundb_fd, &rundbheader, 8)!=8) { + ptr[0]=ptr[1]='R'; + ptr[2]='D'; + ptr[3]=0x1; + rundbheader.entrycount=0; + writerundbheader(); + } + + if (ptr[0] != 'R' || + ptr[1] != 'R' || + ptr[2] != 'D') + { + splash(HZ,true,"Not a rockbox runtime database!"); + return -1; + } +#ifdef ROCKBOX_LITTLE_ENDIAN + p=(int *)&rundbheader; + for(i=0;i<2;i++) { + *p=BE32(*p); + p++; + } +#endif + if ( (rundbheader.version&0xFF) != RUNDB_VERSION) + { + splash(HZ,true,"Unsupported runtime database version %d!", rundbheader.version&0xFF); + return -1; + } + + rundb_initialized = 1; + audio_set_track_changed_event(&rundb_track_changed); + memset(&rundbentry,0,sizeof(struct rundb_entry)); + rundbsize=lseek(rundb_fd,0,SEEK_END); + return 0; +} +void writerundbheader(void) { + lseek(rundb_fd,0,SEEK_SET); + write(rundb_fd, &rundbheader, 8); + fsync(rundb_fd); +} + +#define getrundbentrybyrecord(_x_) getrundbentrybyoffset(8+_x_*20) + +void getrundbentrybyoffset(int offset) { + lseek(rundb_fd,offset,SEEK_SET); + read(rundb_fd,&rundbentry,20); + currentreoffset=offset; +#ifdef ROCKBOX_LITTLE_ENDIAN + rundbentry.fileentry=BE32(rundbentry.fileentry); + rundbentry.hash=BE32(rundbentry.hash); + rundbentry.rating=BE16(rundbentry.rating); + rundbentry.voladjust=BE16(rundbentry.voladjust); + rundbentry.playcount=BE32(rundbentry.playcount); + rundbentry.lastplayed=BE32(rundbentry.lastplayed); #endif +} + +int getrundbentrybyhash(int hash) { + int min=0; + for(min=0;mintagdbheader->filelen+12) #define ALBUMENTRY_SIZE (rb->tagdbheader->albumlen+4+rb->tagdbheader->songarraylen*4) #define ARTISTENTRY_SIZE (rb->tagdbheader->artistlen+rb->tagdbheader->albumarraylen*4) +#define RUNDBENTRY_SIZE 20 #define FILERECORD2OFFSET(_x_) (rb->tagdbheader->filestart + _x_ * FILEENTRY_SIZE) @@ -45,7 +46,7 @@ int database_init() { // zero all entries. for(i=0;itagdbheader->filecount;i++) *(p++)=0; - if(*rb->tagdb_initialized!=1) { + if(!*rb->tagdb_initialized) { if(!rb->tagdb_init()) { // failed loading db return -1; @@ -110,8 +111,18 @@ void loadsongdata() { } void loadrundbdata() { - // we don't do this yet. currententry->loadedrundbdata=1; + if(!*rb->rundb_initialized) + return; + if(currententry->rundbentry==-1) + return; + rb->lseek(*rb->rundb_fd,currententry->rundbentry,SEEK_SET); + currententry->rundbfe=readlong(*rb->rundb_fd); + currententry->rundbhash=readlong(*rb->rundb_fd); + currententry->rating=readshort(*rb->rundb_fd); + currententry->voladj=readshort(*rb->rundb_fd); + currententry->playcount=readlong(*rb->rundb_fd); + currententry->lastplayed=readlong(*rb->rundb_fd); } void loadartistname() { diff --git a/apps/plugins/searchengine/dbinterface.h b/apps/plugins/searchengine/dbinterface.h index 98596aed2f..b168456b85 100644 --- a/apps/plugins/searchengine/dbinterface.h +++ b/apps/plugins/searchengine/dbinterface.h @@ -30,13 +30,15 @@ struct entry { loadedalbumname, loadedartistname; char *filename; - long hash; - long songentry; + long hash,rundbhash; + long songentry,rundbfe; long rundbentry; short year; short bitrate; - long rating; + short rating; long playcount; + long lastplayed; + short voladj; char *title; char *genre; long artistoffset; diff --git a/apps/plugins/searchengine/token.h b/apps/plugins/searchengine/token.h index cd337690bb..6deecd81a5 100644 --- a/apps/plugins/searchengine/token.h +++ b/apps/plugins/searchengine/token.h @@ -54,13 +54,12 @@ #define INTVALUE_GENRE 17 #define INTVALUE_FILENAME 18 -/* static char *spelling[] = { "not", "and", "or",">",">=","<", "<=","==","!=", - "contains","(",")" }; */ +#define SPELLING_LENGTH 100 struct token { - unsigned char kind; - char spelling[255]; // 255 should make it aligned again.. - long intvalue; + char kind; + char spelling[SPELLING_LENGTH + 3]; + long intvalue; }; char *getstring(struct token *token); diff --git a/tools/songdb.pl b/tools/songdb.pl index 9ed0c541bf..202ab06401 100755 --- a/tools/songdb.pl +++ b/tools/songdb.pl @@ -9,7 +9,7 @@ use vorbiscomm; -my $db = "rockbox.id3db"; +my $db = "rockbox.tagdb"; my $dir; my $strip; my $add; @@ -626,7 +626,7 @@ if ($db) { my $str = $f."\x00" x ($maxfilelen- length($f)); my $id3 = $entries{$f}; print DB $str; - dumpint(0); + dumpint(0); # TODO: add hashing; 0 for now. dumpint($id3->{'songoffset'}); dumpint(-1); } diff --git a/tools/testdbv2.c b/tools/testdbv2.c index 60cdcc77f5..c80043763c 100644 --- a/tools/testdbv2.c +++ b/tools/testdbv2.c @@ -128,12 +128,13 @@ void showartist(int offset) { void showrundb(int offset) { fseek(fp2,offset,SEEK_SET); fread(&RundbEntry,sizeof(struct RundbEntry),1,fp2); - RundbEntry.hash=BE32(RundbEntry.hash); - RundbEntry.playcount=BE32(RundbEntry.playcount); - RundbEntry.lastplayed=BE32(RundbEntry.lastplayed); - RundbEntry.rating=BE16(RundbEntry.rating); - RundbEntry.voladj=BE16(RundbEntry.voladj); - printf("Offset: 0x%x\nHash: 0x%x\nRating: %d\nVoladj: 0x%x\n",offset,RundbEntry.hash,RundbEntry.rating,RundbEntry.voladj); + RundbEntry.file=BE32(RundbEntry.file); + RundbEntry.hash=BE32(RundbEntry.hash); + RundbEntry.playcount=BE32(RundbEntry.playcount); + RundbEntry.lastplayed=BE32(RundbEntry.lastplayed); + RundbEntry.rating=BE16(RundbEntry.rating); + RundbEntry.voladj=BE16(RundbEntry.voladj); + printf("Offset: 0x%x\nFileEntry: 0x%x\nHash: 0x%x\nRating: %d\nVoladj: 0x%x\n",offset,RundbEntry.file,RundbEntry.hash,RundbEntry.rating,RundbEntry.voladj); printf("Playcount: 0x%x\nLastplayed: %d\n",RundbEntry.playcount,RundbEntry.lastplayed); } -- cgit v1.2.3