diff options
| author | Michiel Van Der Kolk <not.valid@email.address> | 2005-07-01 17:29:44 +0000 |
|---|---|---|
| committer | Michiel Van Der Kolk <not.valid@email.address> | 2005-07-01 17:29:44 +0000 |
| commit | c735ed79142a0260fc05d58cb0672e5d1720a26a (patch) | |
| tree | 3fd67eb9fb598e9b8bc0c3003ec3bf037379ebb4 /apps/database.c | |
| parent | 4ec80704d5f34a167d45db7539f47b12cc23c59e (diff) | |
| download | rockbox-c735ed79142a0260fc05d58cb0672e5d1720a26a.zip rockbox-c735ed79142a0260fc05d58cb0672e5d1720a26a.tar.gz rockbox-c735ed79142a0260fc05d58cb0672e5d1720a26a.tar.bz2 rockbox-c735ed79142a0260fc05d58cb0672e5d1720a26a.tar.xz | |
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
Diffstat (limited to 'apps/database.c')
| -rw-r--r-- | apps/database.c | 217 |
1 files changed, 193 insertions, 24 deletions
diff --git a/apps/database.c b/apps/database.c index c753362..06bac4a 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<end;i++) { + for(i=start;i<end;i++) { getfentrybyrecord(i); if(fe.songentry!=-1) { int p; @@ -187,7 +206,7 @@ int update_fentryoffsets(int start, int end) { } } if(fe.rundbentry!=-1) { - splash(HZ*2, "o.o.. found a rundbentry? o.o; didn't update it, update the code o.o;"); + splash(HZ*2,true, "o.o.. found a rundbentry? o.o; didn't update it, update the code o.o;"); } } } @@ -195,18 +214,18 @@ int update_fentryoffsets(int start, int end) { int tagdb_shiftdown(int targetoffset, int startingoffset, int bytes) { int amount; if(targetoffset>=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;min<rundbheader.entrycount;min++) { + getrundbentrybyrecord(min); + if(hash==rundbentry.hash) + return 1; + } + memset(&rundbentry,0,sizeof(struct rundb_entry)); + return 0; +} + +void writerundbentry(void) { + if(rundbentry.hash==0) // 0 = invalid rundb info. + return; + lseek(rundb_fd,currentreoffset,SEEK_SET); + write(rundb_fd,&rundbentry,20); + fsync(rundb_fd); +} + +void loadruntimeinfo(char *filename) { + memset(&rundbentry,0,sizeof(struct rundb_entry)); + valid_file=0; + if(!getfentrybyfilename(filename)) + return; /* file is not in tagdatabase, could not load. */ + valid_file=1; + if(fe.rundbentry!=-1&&fe.rundbentry<rundbsize) { + logf("load rundbentry: 0x%x",fe.rundbentry); + getrundbentrybyoffset(fe.rundbentry); + if(fe.hash!=rundbentry.hash) { + logf("Rundb: Hash mismatch. trying to repair entry.",fe.hash,rundbentry.hash); + addrundbentry(); + } + } + else // add new rundb entry. + addrundbentry(); +} + +void addrundbentry() { + // first search for an entry with an equal hash. + if(getrundbentrybyhash(fe.hash)) { + logf("Found existing rundb entry: 0x%x",currentreoffset); + fe.rundbentry=currentreoffset; + writefentry(); + return; + } + rundbheader.entrycount++; + writerundbheader(); + fe.rundbentry=currentreoffset=lseek(rundb_fd,0,SEEK_END); + logf("Add rundb entry: 0x%x hash: 0x%x",fe.rundbentry,fe.hash); + rundbentry.hash=fe.hash; + rundbentry.fileentry=currentfeoffset; + writefentry(); + writerundbentry(); + rundbsize=lseek(rundb_fd,0,SEEK_END); +} + +void increaseplaycount(void) { + if(rundbentry.hash==0) // 0 = invalid rundb info. + return; + rundbentry.playcount++; + writerundbentry(); +} + +void setrating(int rating) { + if(rundbentry.hash==0) // 0 = invalid rundb info. + return; + rundbentry.rating=rating; + writerundbentry(); +} + +/*** end RuntimeDatabase code ***/ |