/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id * * Copyright (C) 2005 by Michiel van der Kolk * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #define _GNU_SOURCE #include #include #include "file.h" #include "screens.h" #include "kernel.h" #include "tree.h" #include "lcd.h" #include "font.h" #include "settings.h" #include "icons.h" #include "status.h" #include "debug.h" #include "button.h" #include "menu.h" #include "main_menu.h" #include "mpeg.h" #include "misc.h" #include "ata.h" #include "wps.h" #include "filetypes.h" #include "applimits.h" #include "icons.h" #include "lang.h" #include "keyboard.h" #include "database.h" #include "autoconf.h" #include "playback.h" #include "logf.h" /* 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; int tagdb_fd = -1; int tagdb_initialized = 0; struct tagdb_header tagdbheader; int tagdb_init(void) { unsigned char* ptr = (char*)&tagdbheader.version; #ifdef ROCKBOX_LITTLE_ENDIAN int i, *p; #endif tagdb_fd = open(ROCKBOX_DIR "/rockbox.tagdb", O_RDWR); if (tagdb_fd < 0) { DEBUGF("Failed opening database\n"); return -1; } read(tagdb_fd, &tagdbheader, 68); if (ptr[0] != 'R' || ptr[1] != 'D' || ptr[2] != 'B') { splash(HZ,true,"Not a rockbox ID3 database!"); return -1; } #ifdef ROCKBOX_LITTLE_ENDIAN p=(int *)&tagdbheader; for(i=0;i<17;i++) { *p=BE32(*p); p++; } #endif if ( (tagdbheader.version&0xFF) != TAGDB_VERSION) { splash(HZ,true,"Unsupported database version %d!", tagdbheader.version&0xFF); return -1; } if (tagdbheader.songstart > tagdbheader.filestart || tagdbheader.albumstart > tagdbheader.songstart || tagdbheader.artiststart > tagdbheader.albumstart) { splash(HZ,true,"Corrupt ID3 database!"); return -1; } tagdb_initialized = 1; return 0; } void tagdb_shutdown(void) { if (tagdb_fd >= 0) close(tagdb_fd); tagdb_initialized = 0; } /* NOTE: All these functions below are yet untested. */ /*** TagDatabase code ***/ 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); read(tagdb_fd,sbuf,tagdbheader.filelen); read(tagdb_fd,&fe.hash,12); fe.name=sbuf; currentfeoffset=offset; currentferecord=(offset-tagdbheader.filestart)/FILEENTRY_SIZE; } #define getfentrybyrecord(_x_) getfentrybyoffset(FILERECORD2OFFSET(_x_)) int getfentrybyfilename(char *fname) { int min=0; int max=tagdbheader.filecount; while(min=startingoffset) { 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))) { int written; startingoffset+=amount; lseek(tagdb_fd,targetoffset,SEEK_SET); written=write(tagdb_fd,sbuf,amount); targetoffset+=written; if(amount!=written) { splash(HZ*2,true,"Something went very wrong. expect database corruption. (tagdb_shiftdown)"); return 0; } lseek(tagdb_fd,startingoffset,SEEK_SET); bytes-=amount; } return 1; } int tagdb_shiftup(int targetoffset, int startingoffset, int bytes) { int amount,amount2; int readpos,writepos,filelen; if(targetoffset<=startingoffset) { splash(HZ*2,true,"Um. no. (tagdb_shiftup)"); return 0; } filelen=lseek(tagdb_fd,0,SEEK_END); readpos=startingoffset+bytes; do { amount=bytes>1024 ? 1024 : bytes; readpos-=amount; writepos=readpos+targetoffset-startingoffset; lseek(tagdb_fd,readpos,SEEK_SET); amount2=read(tagdb_fd,sbuf,amount); if(amount2!=amount) { 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,true,"Something went very wrong. expect database corruption. (tagdb_shiftup)"); return 0; } bytes-=amount; } while (amount>0); if(bytes==0) return 1; else { 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 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