diff options
Diffstat (limited to 'apps/dbtree.c')
-rw-r--r-- | apps/dbtree.c | 343 |
1 files changed, 343 insertions, 0 deletions
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 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 by Björn Stenberg | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #include <stdio.h> | ||
20 | #include <string.h> | ||
21 | #include "file.h" | ||
22 | #include "screens.h" | ||
23 | #include "kernel.h" | ||
24 | #include "tree.h" | ||
25 | #include "lcd.h" | ||
26 | #include "font.h" | ||
27 | #include "settings.h" | ||
28 | #include "icons.h" | ||
29 | #include "status.h" | ||
30 | #include "debug.h" | ||
31 | #include "button.h" | ||
32 | #include "menu.h" | ||
33 | #include "main_menu.h" | ||
34 | #include "mpeg.h" | ||
35 | #include "misc.h" | ||
36 | #include "ata.h" | ||
37 | #include "wps.h" | ||
38 | #include "filetypes.h" | ||
39 | #include "applimits.h" | ||
40 | #include "dbtree.h" | ||
41 | #include "icons.h" | ||
42 | |||
43 | #ifdef LITTLE_ENDIAN | ||
44 | #include <netinet/in.h> | ||
45 | #define BE32(_x_) htonl(_x_) | ||
46 | #else | ||
47 | #define BE32(_x_) _x_ | ||
48 | #endif | ||
49 | |||
50 | static int fd; | ||
51 | |||
52 | static int | ||
53 | songstart, albumstart, artiststart, | ||
54 | songcount, albumcount, artistcount, | ||
55 | songlen, songarraylen, | ||
56 | albumlen, albumarraylen, | ||
57 | artistlen; | ||
58 | |||
59 | int db_init(void) | ||
60 | { | ||
61 | unsigned int version; | ||
62 | unsigned int buf[12]; | ||
63 | |||
64 | fd = open(ROCKBOX_DIR "/rockbox.id3db", O_RDONLY); | ||
65 | if (fd < 0) { | ||
66 | DEBUGF("Failed opening database\n"); | ||
67 | return -1; | ||
68 | } | ||
69 | read(fd, buf, 48); | ||
70 | |||
71 | version = BE32(buf[0]) & 0xff; | ||
72 | DEBUGF("Version: RDB%d\n", version); | ||
73 | |||
74 | songstart = BE32(buf[1]); | ||
75 | songcount = BE32(buf[2]); | ||
76 | songlen = BE32(buf[3]); | ||
77 | DEBUGF("Number of songs: %d\n", songcount); | ||
78 | DEBUGF("Songstart: %x\n", songstart); | ||
79 | DEBUGF("Songlen: %d\n", songlen); | ||
80 | |||
81 | albumstart = BE32(buf[4]); | ||
82 | albumcount = BE32(buf[5]); | ||
83 | albumlen = BE32(buf[6]); | ||
84 | songarraylen = BE32(buf[7]); | ||
85 | DEBUGF("Number of albums: %d\n", albumcount); | ||
86 | DEBUGF("Albumstart: %x\n", albumstart); | ||
87 | DEBUGF("Albumlen: %d\n", albumlen); | ||
88 | |||
89 | artiststart = BE32(buf[8]); | ||
90 | artistcount = BE32(buf[9]); | ||
91 | artistlen = BE32(buf[10]); | ||
92 | albumarraylen = BE32(buf[11]); | ||
93 | DEBUGF("Number of artists: %d\n", artistcount); | ||
94 | DEBUGF("Artiststart: %x\n", artiststart); | ||
95 | DEBUGF("Artistlen: %d\n", artistlen); | ||
96 | |||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | int db_load(struct tree_context* c, bool* dir_buffer_full) | ||
101 | { | ||
102 | int i, offset, len, rc; | ||
103 | int dcachesize = global_settings.max_files_in_dir * sizeof(struct entry); | ||
104 | int max_items, itemcount, stringlen; | ||
105 | unsigned int* nptr = (void*) c->name_buffer; | ||
106 | unsigned int* dptr = c->dircache; | ||
107 | unsigned int* safeplace = NULL; | ||
108 | |||
109 | int table = c->currtable; | ||
110 | int extra = c->currextra; | ||
111 | c->dentry_size = 2 * sizeof(int); | ||
112 | |||
113 | DEBUGF("db_load(%d, %x)\n", table, extra); | ||
114 | |||
115 | if (!table) { | ||
116 | table = allartists; | ||
117 | c->currtable = table; | ||
118 | } | ||
119 | |||
120 | switch (table) { | ||
121 | case allsongs: | ||
122 | offset = songstart; | ||
123 | itemcount = songcount; | ||
124 | stringlen = songlen; | ||
125 | break; | ||
126 | |||
127 | case allalbums: | ||
128 | offset = albumstart; | ||
129 | itemcount = albumcount; | ||
130 | stringlen = albumlen; | ||
131 | break; | ||
132 | |||
133 | case allartists: | ||
134 | offset = artiststart; | ||
135 | itemcount = artistcount; | ||
136 | stringlen = artistlen; | ||
137 | break; | ||
138 | |||
139 | case albums: | ||
140 | /* 'extra' is offset to the artist */ | ||
141 | len = albumarraylen * 4; | ||
142 | safeplace = (void*)(c->name_buffer + c->name_buffer_size - len); | ||
143 | //DEBUGF("Seeking to %x\n", extra + artistlen); | ||
144 | lseek(fd, extra + artistlen, SEEK_SET); | ||
145 | rc = read(fd, safeplace, len); | ||
146 | if (rc < len) | ||
147 | return -1; | ||
148 | |||
149 | #ifdef LITTLE_ENDIAN | ||
150 | for (i=0; i<albumarraylen; i++) | ||
151 | safeplace[i] = BE32(safeplace[i]); | ||
152 | #endif | ||
153 | |||
154 | offset = safeplace[0]; | ||
155 | itemcount = albumarraylen; | ||
156 | stringlen = albumlen; | ||
157 | break; | ||
158 | |||
159 | case songs: | ||
160 | /* 'extra' is offset to the album */ | ||
161 | len = songarraylen * 4; | ||
162 | safeplace = (void*)(c->name_buffer + c->name_buffer_size - len); | ||
163 | //DEBUGF("Seeking to %x\n", extra + albumlen + 4); | ||
164 | lseek(fd, extra + albumlen + 4, SEEK_SET); | ||
165 | rc = read(fd, safeplace, len); | ||
166 | if (rc < len) | ||
167 | return -1; | ||
168 | |||
169 | #ifdef LITTLE_ENDIAN | ||
170 | for (i=0; i<songarraylen; i++) | ||
171 | safeplace[i] = BE32(safeplace[i]); | ||
172 | #endif | ||
173 | offset = safeplace[0]; | ||
174 | itemcount = songarraylen; | ||
175 | stringlen = songlen; | ||
176 | break; | ||
177 | |||
178 | default: | ||
179 | DEBUGF("Unsupported table %d\n", table); | ||
180 | return -1; | ||
181 | } | ||
182 | max_items = dcachesize / c->dentry_size; | ||
183 | |||
184 | if (!safeplace) { | ||
185 | //DEBUGF("Seeking to %x\n", offset); | ||
186 | lseek(fd, offset, SEEK_SET); | ||
187 | } | ||
188 | |||
189 | /* name_buffer (nptr) contains only names, null terminated. | ||
190 | the first word of dcache (dptr) is a pointer to the name, | ||
191 | the rest is table specific. see below. */ | ||
192 | |||
193 | if (itemcount > max_items) | ||
194 | if (dir_buffer_full) | ||
195 | *dir_buffer_full = true; | ||
196 | |||
197 | if (max_items > itemcount) { | ||
198 | max_items = itemcount; | ||
199 | } | ||
200 | |||
201 | for ( i=0; i < max_items; i++ ) { | ||
202 | int rc, skip=0; | ||
203 | |||
204 | if (safeplace) { | ||
205 | if (!safeplace[i]) | ||
206 | break; | ||
207 | //DEBUGF("Seeking to %x\n", safeplace[i]); | ||
208 | lseek(fd, safeplace[i], SEEK_SET); | ||
209 | offset = safeplace[i]; | ||
210 | } | ||
211 | |||
212 | /* read name */ | ||
213 | rc = read(fd, nptr, stringlen); | ||
214 | if (rc < stringlen) | ||
215 | { | ||
216 | DEBUGF("%d read(%d) returned %d\n", i, stringlen, rc); | ||
217 | return -1; | ||
218 | } | ||
219 | |||
220 | /* store name pointer in dir cache */ | ||
221 | dptr[0] = (unsigned int)nptr; | ||
222 | |||
223 | switch (table) { | ||
224 | case songs: | ||
225 | case allsongs: | ||
226 | /* save offset of this song */ | ||
227 | skip = 12; | ||
228 | dptr[1] = offset; | ||
229 | break; | ||
230 | |||
231 | case allalbums: | ||
232 | case albums: | ||
233 | /* save offset of this album */ | ||
234 | skip = songarraylen * 4 + 4; | ||
235 | dptr[1] = offset; | ||
236 | break; | ||
237 | |||
238 | case allartists: | ||
239 | /* save offset of this artist */ | ||
240 | skip = albumarraylen * 4; | ||
241 | dptr[1] = offset; | ||
242 | break; | ||
243 | } | ||
244 | |||
245 | //DEBUGF("%x: %s\n", dptr[1], dptr[0]); | ||
246 | |||
247 | if (skip) | ||
248 | lseek(fd, skip, SEEK_CUR); | ||
249 | |||
250 | /* next name is stored immediately after this */ | ||
251 | nptr = (void*)nptr + strlen((char*)nptr) + 1; | ||
252 | if ((void*)nptr > (void*)c->name_buffer + c->name_buffer_size) { | ||
253 | DEBUGF("Name buffer overflow (%d)\n",i); | ||
254 | break; | ||
255 | } | ||
256 | dptr = (void*)dptr + c->dentry_size; | ||
257 | |||
258 | if (!safeplace) | ||
259 | offset += stringlen + skip; | ||
260 | } | ||
261 | |||
262 | c->filesindir = i; | ||
263 | |||
264 | return i; | ||
265 | } | ||
266 | |||
267 | void db_enter(struct tree_context* c) | ||
268 | { | ||
269 | switch (c->currtable) { | ||
270 | case allartists: | ||
271 | case albums: | ||
272 | c->dirpos[c->dirlevel] = c->dirstart; | ||
273 | c->cursorpos[c->dirlevel] = c->dircursor; | ||
274 | c->table_history[c->dirlevel] = c->currtable; | ||
275 | c->extra_history[c->dirlevel] = c->currextra; | ||
276 | c->dirlevel++; | ||
277 | break; | ||
278 | |||
279 | default: | ||
280 | break; | ||
281 | } | ||
282 | |||
283 | switch (c->currtable) { | ||
284 | case allartists: | ||
285 | c->currtable = albums; | ||
286 | c->currextra = ((int*)c->dircache)[(c->dircursor + c->dirstart)*2 + 1]; | ||
287 | break; | ||
288 | |||
289 | case albums: | ||
290 | c->currtable = songs; | ||
291 | c->currextra = ((int*)c->dircache)[(c->dircursor + c->dirstart)*2 + 1]; | ||
292 | break; | ||
293 | |||
294 | case songs: | ||
295 | splash(HZ,true,"No playing implemented yet"); | ||
296 | #if 0 | ||
297 | /* find filenames, build playlist, play */ | ||
298 | playlist_create(NULL,NULL); | ||
299 | #endif | ||
300 | break; | ||
301 | |||
302 | default: | ||
303 | break; | ||
304 | } | ||
305 | |||
306 | c->dirstart = c->dircursor = 0; | ||
307 | } | ||
308 | |||
309 | void db_exit(struct tree_context* c) | ||
310 | { | ||
311 | c->dirlevel--; | ||
312 | c->dirstart = c->dirpos[c->dirlevel]; | ||
313 | c->dircursor = c->cursorpos[c->dirlevel]; | ||
314 | c->currtable = c->table_history[c->dirlevel]; | ||
315 | c->currextra = c->extra_history[c->dirlevel]; | ||
316 | } | ||
317 | |||
318 | #ifdef HAVE_LCD_BITMAP | ||
319 | const char* db_get_icon(struct tree_context* c) | ||
320 | { | ||
321 | int icon; | ||
322 | |||
323 | switch (c->currtable) | ||
324 | { | ||
325 | case allsongs: | ||
326 | case songs: | ||
327 | icon = File; | ||
328 | break; | ||
329 | |||
330 | default: | ||
331 | icon = Folder; | ||
332 | break; | ||
333 | } | ||
334 | |||
335 | return bitmap_icons_6x8[icon]; | ||
336 | } | ||
337 | #else | ||
338 | int db_get_icon(struct tree_context* c) | ||
339 | { | ||
340 | (void)c; | ||
341 | return Folder; | ||
342 | } | ||
343 | #endif | ||