diff options
author | Michiel Van Der Kolk <not.valid@email.address> | 2005-04-26 21:37:44 +0000 |
---|---|---|
committer | Michiel Van Der Kolk <not.valid@email.address> | 2005-04-26 21:37:44 +0000 |
commit | 929e7837cd8433d2e265d982e31b6ddd765cf5d1 (patch) | |
tree | b7cf326db1f6f019c96263e8a312793786c232f3 | |
parent | 04ed408de9ea576a3b22ee44bac9483ca27124c6 (diff) |
Restructurizing database code, seperating database code from dbtree code,
wrote the first basic functions to manipulate fileentries.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6359 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | apps/SOURCES | 1 | ||||
-rw-r--r-- | apps/database.c | 195 | ||||
-rw-r--r-- | apps/database.h | 98 | ||||
-rw-r--r-- | apps/dbtree.c | 202 | ||||
-rw-r--r-- | apps/dbtree.h | 4 | ||||
-rw-r--r-- | apps/tree.c | 6 |
6 files changed, 352 insertions, 154 deletions
diff --git a/apps/SOURCES b/apps/SOURCES index 33a6ded691..10a04da6ea 100644 --- a/apps/SOURCES +++ b/apps/SOURCES @@ -24,6 +24,7 @@ talk.c #endif tree.c dbtree.c +database.c filetree.c wps-display.c wps.c diff --git a/apps/database.c b/apps/database.c new file mode 100644 index 0000000000..1258b94c30 --- /dev/null +++ b/apps/database.c @@ -0,0 +1,195 @@ +/*************************************************************************** + * __________ __ ___. + * 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 <stdio.h> +#include <string.h> +#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" + +#undef NEW_DB_CODE + +#ifdef NEW_DB_CODE +static char sbuf[1024]; +static struct file_entry fe; +static int currentferecord; +#endif + +int tagdb_fd = -1; +int tagdb_initialized = 0; +struct tagdb_header tagdbheader; + +int tagdb_init(void) +{ + unsigned char* ptr = (char*)&tagdbheader.version; +#ifdef LITTLE_ENDIAN + int i, *p; +#endif + + tagdb_fd = open(ROCKBOX_DIR "/rockbox.id3db", O_RDONLY); + 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 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. */ + +#ifdef NEW_DB_CODE +void writetagdbheader() { + lseek(tagdb_fd,0,SEEK_SET); + write(tagdb_fd, &tagdbheader, 68); +} + +void getfentrybyoffset(int offset) { + lseek(tagdb_fd,offset,SEEK_SET); + fread(tagdb_fd,sbuf,tagdbheader.filelen); + fread(tagdb_fd,&fe+sizeof(char *),12); + fe.name=sbuf; + currentferecord=(offset-tagdbheader.filestart)/FILEENTRY_SIZE; +} + +void getfentrybyrecord(int record) { + getfentrybyoffset(FILERECORD2OFFSET(record)); +} + +int getfentrybyfilename(char *fname) { + int min=0; + int max=tagdbheader.filecount; + while(min<max) { + int mid=(min+max)/2; + int compare; + getfentrybyrecord(mid); + compare=strcasecmp(fname,fe.name)); + if(compare==0) + return 1; + else if(compare<0) + max=mid; + else + min=mid+1; + } + return 0; +} + +int shiftdown(int targetoffset, int startingoffset) { + int amount; + if(targetoffset>=startingoffset) { + splash(HZ*2,"Woah. no beeping way. (shiftdown)"); + return 0; + } + lseek(tagdb_fd,startingoffset,SEEK_SET); + while(amount=read(tagdb_fd,sbuf,1024)) { + 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."); + return 0; + } + lseek(tagdb_fd,startingoffset,SEEK_SET); + } + ftruncate(tagdb_fd,lseek(tagdb_fd,0,SEEK_END) - (startingoffset-targetoffset)); + return 1; +} + +int deletefentry(char *fname) { + if(!getfentrybyfilename(fname)) + return 0; + int restrecord = currentferecord+1; + if(currentferecord==tagdbheader.filecount) /* file is last entry */ + ftruncate(tagdb_fd,lseek(tagdb_fd,0,SEEK_END)-FILEENTRY_SIZE); + else + shiftdown(FILERECORD2OFFSET(currentferecord),FILERECORD2OFFSET(restrecord)); + tagdbheader.filecount--; + writetagdbheader(); + return 1; +} + +int getfentrybyhash(int hash) { + int min=0; + for(min=0;min<tagdbheader.filecount;min++) { + getfentrybyrecord(min); + if(hash==fe.hash) + return 1; + } + return 0; +} + +#endif diff --git a/apps/database.h b/apps/database.h new file mode 100644 index 0000000000..cdbd4d44e5 --- /dev/null +++ b/apps/database.h @@ -0,0 +1,98 @@ +/*************************************************************************** + * __________ __ ___. + * 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. + * + ****************************************************************************/ +#ifndef DATABASE_H +#define DATABASE_H + +/* workaround for cygwin not defining endian macros */ +#if !defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN) && defined(_X86_) +#define LITTLE_ENDIAN +#endif + +#ifdef LITTLE_ENDIAN +#define BE32(_x_) (((_x_ & 0xff000000) >> 24) | \ + ((_x_ & 0x00ff0000) >> 8) | \ + ((_x_ & 0x0000ff00) << 8) | \ + ((_x_ & 0x000000ff) << 24)) +#else +#define BE32(_x_) _x_ +#endif + +#define SONGENTRY_SIZE (tagdbheader.songlen+12+tagdbheader.genrelen+4) +#define FILEENTRY_SIZE (tagdbheader.filelen+12) +#define ALBUMENTRY_SIZE (tagdbheader.albumlen+4+tagdbheader.songarraylen*4) +#define ARTISTENTRY_SIZE (tagdbheader.artistlen+tagdbheader.albumarraylen*4) + +#define FILERECORD2OFFSET(_x_) (tagdbheader.filestart + _x_ * FILEENTRY_SIZE) + +extern int tagdb_initialized; + +struct tagdb_header { + int version; + int artiststart; + int albumstart; + int songstart; + int filestart; + int artistcount; + int albumcount; + int songcount; + int filecount; + int artistlen; + int albumlen; + int songlen; + int genrelen; + int filelen; + int songarraylen; + int albumarraylen; + int rundbdirty; +}; + +struct file_entry { + char *name; + int hash; + int tagentry; + int rundbentry; +}; + +extern struct tagdb_header tagdbheader; +extern int tagdb_fd; + +int tagdb_init(void); +void tagdb_shutdown(void); + +#define TAGDB_VERSION 2 + +struct rundb_header { + int version; + int entrycount; +}; + +struct rundb_entry { + int fileentry; + int hash; + short rating; + short voladjust; + int playcount; + int lastplayed; +}; + +extern struct rundb_header rundbheader; + +#define RUNDB_VERSION 1 + +#endif diff --git a/apps/dbtree.c b/apps/dbtree.c index 5b0d325213..187cb618c1 100644 --- a/apps/dbtree.c +++ b/apps/dbtree.c @@ -43,107 +43,11 @@ #include "lang.h" #include "keyboard.h" -/* workaround for cygwin not defining endian macros */ -#if !defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN) && defined(_X86_) -#define LITTLE_ENDIAN -#endif - -#ifdef LITTLE_ENDIAN -#define BE32(_x_) (((_x_ & 0xff000000) >> 24) | \ - ((_x_ & 0x00ff0000) >> 8) | \ - ((_x_ & 0x0000ff00) << 8) | \ - ((_x_ & 0x000000ff) << 24)) -#else -#define BE32(_x_) _x_ -#endif - -#define SONGENTRY_SIZE (songlen+12+genrelen+4) -#define FILEENTRY_SIZE (filelen+12) -#define ALBUMENTRY_SIZE (albumlen+4+songarraylen*4) -#define ARTISTENTRY_SIZE (artistlen+albumarraylen*4) - -#define ID3DB_VERSION 2 - -static int fd = -1; - -static int - songstart, albumstart, artiststart, filestart, - songcount, albumcount, artistcount, filecount, - songlen, songarraylen, genrelen, filelen, - albumlen, albumarraylen, - artistlen, rundbdirty, initialized = 0; - static int db_play_folder(struct tree_context* c); static int db_search(struct tree_context* c, char* string); static char searchstring[32]; -int db_init(void) -{ - unsigned int version; - unsigned int buf[17]; - unsigned char* ptr = (char*)buf; - - fd = open(ROCKBOX_DIR "/rockbox.id3db", O_RDONLY); - if (fd < 0) { - DEBUGF("Failed opening database\n"); - return -1; - } - read(fd, buf, 68); - - if (ptr[0] != 'R' || - ptr[1] != 'D' || - ptr[2] != 'B') - { - splash(HZ,true,"Not a rockbox ID3 database!"); - return -1; - } - - version = BE32(buf[0])&0xFF; - if (version != ID3DB_VERSION) - { - splash(HZ,true,"Unsupported database version %d!", version); - return -1; - } - - artiststart = BE32(buf[1]); - albumstart = BE32(buf[2]); - songstart = BE32(buf[3]); - filestart = BE32(buf[4]); - - artistcount = BE32(buf[5]); - albumcount = BE32(buf[6]); - songcount = BE32(buf[7]); - filecount = BE32(buf[8]); - - artistlen = BE32(buf[9]); - albumlen = BE32(buf[10]); - songlen = BE32(buf[11]); - genrelen = BE32(buf[12]); - filelen = BE32(buf[13]); - songarraylen = BE32(buf[14]); - albumarraylen = BE32(buf[15]); - rundbdirty = BE32(buf[16]); - - if (songstart > filestart || - albumstart > songstart || - artiststart > albumstart) - { - splash(HZ,true,"Corrupt ID3 database!"); - return -1; - } - - initialized = 1; - return 0; -} - -void db_shutdown(void) -{ - if (fd >= 0) - close(fd); - initialized = 0; -} - int db_load(struct tree_context* c) { int i, offset, rc; @@ -159,7 +63,7 @@ int db_load(struct tree_context* c) char* end_of_nbuf = c->name_buffer + c->name_buffer_size; - if (!initialized) { + if (!tagdb_initialized) { DEBUGF("ID3 database is not initialized.\n"); c->filesindir = 0; return 0; @@ -233,33 +137,33 @@ int db_load(struct tree_context* c) return i; case allsongs: - DEBUGF("dbload table allsongs\n"); - offset = songstart + c->firstpos * SONGENTRY_SIZE; - itemcount = songcount; - stringlen = songlen; + DEBUGF("dbload table allsongs\n"); + offset = tagdbheader.songstart + c->firstpos * SONGENTRY_SIZE; + itemcount = tagdbheader.songcount; + stringlen = tagdbheader.songlen; break; case allalbums: - DEBUGF("dbload table allalbums\n"); - offset = albumstart + c->firstpos * ALBUMENTRY_SIZE; - itemcount = albumcount; - stringlen = albumlen; + DEBUGF("dbload table allalbums\n"); + offset = tagdbheader.albumstart + c->firstpos * ALBUMENTRY_SIZE; + itemcount = tagdbheader.albumcount; + stringlen = tagdbheader.albumlen; break; case allartists: - DEBUGF("dbload table allartists\n"); - offset = artiststart + c->firstpos * ARTISTENTRY_SIZE; - itemcount = artistcount; - stringlen = artistlen; + DEBUGF("dbload table allartists\n"); + offset = tagdbheader.artiststart + c->firstpos * ARTISTENTRY_SIZE; + itemcount = tagdbheader.artistcount; + stringlen = tagdbheader.artistlen; break; case albums4artist: - DEBUGF("dbload table albums4artist\n"); + DEBUGF("dbload table albums4artist\n"); /* 'extra' is offset to the artist */ - safeplacelen = albumarraylen * 4; + safeplacelen = tagdbheader.albumarraylen * 4; safeplace = (void*)(end_of_nbuf - safeplacelen); - lseek(fd, extra + artistlen, SEEK_SET); - rc = read(fd, safeplace, safeplacelen); + lseek(tagdb_fd, extra + tagdbheader.artistlen, SEEK_SET); + rc = read(tagdb_fd, safeplace, safeplacelen); if (rc < safeplacelen) return -1; @@ -268,17 +172,17 @@ int db_load(struct tree_context* c) safeplace[i] = BE32(safeplace[i]); #endif offset = safeplace[0]; - itemcount = albumarraylen; - stringlen = albumlen; + itemcount = tagdbheader.albumarraylen; + stringlen = tagdbheader.albumlen; break; case songs4album: DEBUGF("dbload table songs4album\n"); /* 'extra' is offset to the album */ - safeplacelen = songarraylen * 4; + safeplacelen = tagdbheader.songarraylen * 4; safeplace = (void*)(end_of_nbuf - safeplacelen); - lseek(fd, extra + albumlen + 4, SEEK_SET); - rc = read(fd, safeplace, safeplacelen); + lseek(tagdb_fd, extra + tagdbheader.albumlen + 4, SEEK_SET); + rc = read(tagdb_fd, safeplace, safeplacelen); if (rc < safeplacelen) return -1; @@ -289,16 +193,16 @@ int db_load(struct tree_context* c) } #endif offset = safeplace[0]; - itemcount = songarraylen; - stringlen = songlen; + itemcount = tagdbheader.songarraylen; + stringlen = tagdbheader.songlen; break; case songs4artist: - DEBUGF("dbload table songs4artist\n"); + DEBUGF("dbload table songs4artist\n"); /* 'extra' is offset to the artist, used as filter */ - offset = songstart + c->firstpos * SONGENTRY_SIZE; - itemcount = songcount; - stringlen = songlen; + offset = tagdbheader.songstart + c->firstpos * SONGENTRY_SIZE; + itemcount = tagdbheader.songcount; + stringlen = tagdbheader.songlen; break; default: @@ -311,7 +215,7 @@ int db_load(struct tree_context* c) itemcount -= c->firstpos; if (!safeplace) - lseek(fd, offset, SEEK_SET); + lseek(tagdb_fd, offset, SEEK_SET); /* name_buffer (nptr) contains only names, null terminated. the first word of dcache (dptr) is a pointer to the name, @@ -326,12 +230,12 @@ int db_load(struct tree_context* c) c->dirlength = i; break; } - lseek(fd, safeplace[i], SEEK_SET); + lseek(tagdb_fd, safeplace[i], SEEK_SET); offset = safeplace[i]; } /* read name */ - rc = read(fd, nptr, stringlen); + rc = read(tagdb_fd, nptr, stringlen); if (rc < stringlen) { DEBUGF("%d read(%d) returned %d\n", i, stringlen, rc); @@ -342,17 +246,17 @@ int db_load(struct tree_context* c) case allsongs: case songs4album: case songs4artist: - rc = read(fd, intbuf, 12); - skip = SONGENTRY_SIZE-stringlen-12; /* skip the rest of the song info */ + rc = read(tagdb_fd, intbuf, 12); + skip = SONGENTRY_SIZE-stringlen-12; /* skip the rest of the song info */ if (rc < 12) { DEBUGF("%d read(%d) returned %d\n", i, 12, rc); return -1; } /* continue to next song if wrong artist */ if (table == songs4artist && (int)BE32(intbuf[0]) != extra) { - lseek(fd, skip, SEEK_CUR); + lseek(tagdb_fd, skip, SEEK_CUR); continue; - } + } /* save offset of filename */ dptr[1] = BE32(intbuf[2]); @@ -361,13 +265,13 @@ int db_load(struct tree_context* c) case allalbums: case albums4artist: /* save offset of this album */ - skip = songarraylen * 4 + 4; + skip = tagdbheader.songarraylen * 4 + 4; dptr[1] = offset; break; case allartists: /* save offset of this artist */ - skip = albumarraylen * 4; + skip = tagdbheader.albumarraylen * 4; dptr[1] = offset; break; } @@ -376,12 +280,12 @@ int db_load(struct tree_context* c) dptr[0] = (unsigned long)nptr; if (skip) - lseek(fd, skip, SEEK_CUR); + lseek(tagdb_fd, skip, SEEK_CUR); hits++; - if(table==songs4artist) - c->dirlength=hits; + if(table==songs4artist) + c->dirlength=hits; /* next name is stored immediately after this */ nptr = (void*)nptr + strlen((char*)nptr) + 1; @@ -429,20 +333,20 @@ static int db_search(struct tree_context* c, char* string) switch (c->currtable) { case searchartists: - start = artiststart; - count = artistcount; + start = tagdbheader.artiststart; + count = tagdbheader.artistcount; size = ARTISTENTRY_SIZE; break; case searchalbums: - start = albumstart; - count = albumcount; + start = tagdbheader.albumstart; + count = tagdbheader.albumcount; size = ALBUMENTRY_SIZE; break; case searchsongs: - start = songstart; - count = songcount; + start = tagdbheader.songstart; + count = tagdbheader.songcount; size = SONGENTRY_SIZE; break; @@ -451,10 +355,10 @@ static int db_search(struct tree_context* c, char* string) return 0; } - lseek(fd, start, SEEK_SET); + lseek(tagdb_fd, start, SEEK_SET); for (i=0; i<count; i++) { - if (read(fd, nptr, size) < size) { + if (read(tagdb_fd, nptr, size) < size) { DEBUGF("Short read(%d) in db_search()\n",size); break; } @@ -464,7 +368,7 @@ static int db_search(struct tree_context* c, char* string) dptr[0] = (unsigned long)nptr; if (c->currtable == searchsongs) { /* store offset of filename */ - dptr[1] = BE32(*((long*)(nptr + songlen + 8))); + dptr[1] = BE32(*((long*)(nptr + tagdbheader.songlen + 8))); } else /* store offset of database record */ @@ -528,7 +432,7 @@ int db_enter(struct tree_context* c) case searchalbums: /* virtual <all albums> entry points to the artist, all normal entries point to the album */ - if (newextra < albumstart) + if (newextra < tagdbheader.albumstart) c->currtable = songs4artist; else c->currtable = songs4album; @@ -588,9 +492,9 @@ static int db_play_folder(struct tree_context* c) for (i=0; i < c->filesindir; i++) { int pathoffset = ((int*)c->dircache)[i * c->dentry_size + 1]; - lseek(fd, pathoffset, SEEK_SET); - rc = read(fd, buf, sizeof(buf)); - if (rc < songlen) { + lseek(tagdb_fd, pathoffset, SEEK_SET); + rc = read(tagdb_fd, buf, sizeof(buf)); + if (rc < tagdbheader.songlen) { DEBUGF("short path read(%ld) = %d\n", sizeof(buf), rc); return -2; } diff --git a/apps/dbtree.h b/apps/dbtree.h index 94453c59af..1e26f5d521 100644 --- a/apps/dbtree.h +++ b/apps/dbtree.h @@ -20,13 +20,12 @@ #define DBTREE_H #include "tree.h" +#include "database.h" enum table { invalid, root, allsongs, allalbums, allartists, albums4artist, songs4album, songs4artist, search, searchartists, searchalbums, searchsongs }; -int db_init(void); -void db_shutdown(void); int db_enter(struct tree_context* c); void db_exit(struct tree_context* c); int db_load(struct tree_context* c); @@ -37,5 +36,6 @@ int db_get_icon(struct tree_context* c); #endif + #endif diff --git a/apps/tree.c b/apps/tree.c index bcb96a8995..c226f254b6 100644 --- a/apps/tree.c +++ b/apps/tree.c @@ -628,7 +628,7 @@ static bool check_changed_id3mode(bool currmode) static void tree_prepare_usb(void *parameter) { (void) parameter; - db_shutdown(); + tagdb_shutdown(); } static bool dirbrowse(void) @@ -1130,7 +1130,7 @@ static bool dirbrowse(void) if (default_event_handler_ex(button, tree_prepare_usb, NULL) == SYS_USB_CONNECTED) { - db_init(); /* re-init database */ + tagdb_init(); /* re-init database */ if(*tc.dirfilter > NUM_FILTER_MODES) /* leave sub-browsers after usb, doing otherwise might be confusing to the user */ @@ -1455,7 +1455,7 @@ void tree_init(void) memset(&tc, 0, sizeof(tc)); tc.dirfilter = &global_settings.dirfilter; - db_init(); + tagdb_init(); tc.name_buffer_size = AVERAGE_FILENAME_LENGTH * max_files; tc.name_buffer = buffer_alloc(tc.name_buffer_size); |