From 8a5de5fec96171e739442b0601047d93079e3179 Mon Sep 17 00:00:00 2001 From: Björn Stenberg Date: Mon, 17 Jan 2005 11:39:46 +0000 Subject: Added ID3 database support. Still very early. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@5575 a1c6a512-1295-4272-9138-f99709370657 --- apps/dbtree.c | 343 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 343 insertions(+) create mode 100644 apps/dbtree.c (limited to 'apps/dbtree.c') diff --git a/apps/dbtree.c b/apps/dbtree.c new file mode 100644 index 0000000000..f9bd950057 --- /dev/null +++ b/apps/dbtree.c @@ -0,0 +1,343 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Björn Stenberg + * + * 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. + * + ****************************************************************************/ +#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 "dbtree.h" +#include "icons.h" + +#ifdef LITTLE_ENDIAN +#include +#define BE32(_x_) htonl(_x_) +#else +#define BE32(_x_) _x_ +#endif + +static int fd; + +static int + songstart, albumstart, artiststart, + songcount, albumcount, artistcount, + songlen, songarraylen, + albumlen, albumarraylen, + artistlen; + +int db_init(void) +{ + unsigned int version; + unsigned int buf[12]; + + fd = open(ROCKBOX_DIR "/rockbox.id3db", O_RDONLY); + if (fd < 0) { + DEBUGF("Failed opening database\n"); + return -1; + } + read(fd, buf, 48); + + version = BE32(buf[0]) & 0xff; + DEBUGF("Version: RDB%d\n", version); + + songstart = BE32(buf[1]); + songcount = BE32(buf[2]); + songlen = BE32(buf[3]); + DEBUGF("Number of songs: %d\n", songcount); + DEBUGF("Songstart: %x\n", songstart); + DEBUGF("Songlen: %d\n", songlen); + + albumstart = BE32(buf[4]); + albumcount = BE32(buf[5]); + albumlen = BE32(buf[6]); + songarraylen = BE32(buf[7]); + DEBUGF("Number of albums: %d\n", albumcount); + DEBUGF("Albumstart: %x\n", albumstart); + DEBUGF("Albumlen: %d\n", albumlen); + + artiststart = BE32(buf[8]); + artistcount = BE32(buf[9]); + artistlen = BE32(buf[10]); + albumarraylen = BE32(buf[11]); + DEBUGF("Number of artists: %d\n", artistcount); + DEBUGF("Artiststart: %x\n", artiststart); + DEBUGF("Artistlen: %d\n", artistlen); + + return 0; +} + +int db_load(struct tree_context* c, bool* dir_buffer_full) +{ + int i, offset, len, rc; + int dcachesize = global_settings.max_files_in_dir * sizeof(struct entry); + int max_items, itemcount, stringlen; + unsigned int* nptr = (void*) c->name_buffer; + unsigned int* dptr = c->dircache; + unsigned int* safeplace = NULL; + + int table = c->currtable; + int extra = c->currextra; + c->dentry_size = 2 * sizeof(int); + + DEBUGF("db_load(%d, %x)\n", table, extra); + + if (!table) { + table = allartists; + c->currtable = table; + } + + switch (table) { + case allsongs: + offset = songstart; + itemcount = songcount; + stringlen = songlen; + break; + + case allalbums: + offset = albumstart; + itemcount = albumcount; + stringlen = albumlen; + break; + + case allartists: + offset = artiststart; + itemcount = artistcount; + stringlen = artistlen; + break; + + case albums: + /* 'extra' is offset to the artist */ + len = albumarraylen * 4; + safeplace = (void*)(c->name_buffer + c->name_buffer_size - len); + //DEBUGF("Seeking to %x\n", extra + artistlen); + lseek(fd, extra + artistlen, SEEK_SET); + rc = read(fd, safeplace, len); + if (rc < len) + return -1; + +#ifdef LITTLE_ENDIAN + for (i=0; iname_buffer + c->name_buffer_size - len); + //DEBUGF("Seeking to %x\n", extra + albumlen + 4); + lseek(fd, extra + albumlen + 4, SEEK_SET); + rc = read(fd, safeplace, len); + if (rc < len) + return -1; + +#ifdef LITTLE_ENDIAN + for (i=0; identry_size; + + if (!safeplace) { + //DEBUGF("Seeking to %x\n", offset); + lseek(fd, offset, SEEK_SET); + } + + /* name_buffer (nptr) contains only names, null terminated. + the first word of dcache (dptr) is a pointer to the name, + the rest is table specific. see below. */ + + if (itemcount > max_items) + if (dir_buffer_full) + *dir_buffer_full = true; + + if (max_items > itemcount) { + max_items = itemcount; + } + + for ( i=0; i < max_items; i++ ) { + int rc, skip=0; + + if (safeplace) { + if (!safeplace[i]) + break; + //DEBUGF("Seeking to %x\n", safeplace[i]); + lseek(fd, safeplace[i], SEEK_SET); + offset = safeplace[i]; + } + + /* read name */ + rc = read(fd, nptr, stringlen); + if (rc < stringlen) + { + DEBUGF("%d read(%d) returned %d\n", i, stringlen, rc); + return -1; + } + + /* store name pointer in dir cache */ + dptr[0] = (unsigned int)nptr; + + switch (table) { + case songs: + case allsongs: + /* save offset of this song */ + skip = 12; + dptr[1] = offset; + break; + + case allalbums: + case albums: + /* save offset of this album */ + skip = songarraylen * 4 + 4; + dptr[1] = offset; + break; + + case allartists: + /* save offset of this artist */ + skip = albumarraylen * 4; + dptr[1] = offset; + break; + } + + //DEBUGF("%x: %s\n", dptr[1], dptr[0]); + + if (skip) + lseek(fd, skip, SEEK_CUR); + + /* next name is stored immediately after this */ + nptr = (void*)nptr + strlen((char*)nptr) + 1; + if ((void*)nptr > (void*)c->name_buffer + c->name_buffer_size) { + DEBUGF("Name buffer overflow (%d)\n",i); + break; + } + dptr = (void*)dptr + c->dentry_size; + + if (!safeplace) + offset += stringlen + skip; + } + + c->filesindir = i; + + return i; +} + +void db_enter(struct tree_context* c) +{ + switch (c->currtable) { + case allartists: + case albums: + c->dirpos[c->dirlevel] = c->dirstart; + c->cursorpos[c->dirlevel] = c->dircursor; + c->table_history[c->dirlevel] = c->currtable; + c->extra_history[c->dirlevel] = c->currextra; + c->dirlevel++; + break; + + default: + break; + } + + switch (c->currtable) { + case allartists: + c->currtable = albums; + c->currextra = ((int*)c->dircache)[(c->dircursor + c->dirstart)*2 + 1]; + break; + + case albums: + c->currtable = songs; + c->currextra = ((int*)c->dircache)[(c->dircursor + c->dirstart)*2 + 1]; + break; + + case songs: + splash(HZ,true,"No playing implemented yet"); +#if 0 + /* find filenames, build playlist, play */ + playlist_create(NULL,NULL); +#endif + break; + + default: + break; + } + + c->dirstart = c->dircursor = 0; +} + +void db_exit(struct tree_context* c) +{ + c->dirlevel--; + c->dirstart = c->dirpos[c->dirlevel]; + c->dircursor = c->cursorpos[c->dirlevel]; + c->currtable = c->table_history[c->dirlevel]; + c->currextra = c->extra_history[c->dirlevel]; +} + +#ifdef HAVE_LCD_BITMAP +const char* db_get_icon(struct tree_context* c) +{ + int icon; + + switch (c->currtable) + { + case allsongs: + case songs: + icon = File; + break; + + default: + icon = Folder; + break; + } + + return bitmap_icons_6x8[icon]; +} +#else +int db_get_icon(struct tree_context* c) +{ + (void)c; + return Folder; +} +#endif -- cgit v1.2.3