summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorBjörn Stenberg <bjorn@haxx.se>2005-01-18 22:45:00 +0000
committerBjörn Stenberg <bjorn@haxx.se>2005-01-18 22:45:00 +0000
commit84c7d8802106266c94d0a30827dff418a2fcac6d (patch)
tree17a4d8a7f5375584783925dd3b44203245413755 /apps
parentf9c06226d6c3f756437dc45d573d23f14699e728 (diff)
downloadrockbox-84c7d8802106266c94d0a30827dff418a2fcac6d.tar.gz
rockbox-84c7d8802106266c94d0a30827dff418a2fcac6d.zip
Added support for very large tables in ID3 database.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@5595 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
-rw-r--r--apps/dbtree.c81
-rw-r--r--apps/dbtree.h6
-rw-r--r--apps/filetree.c15
-rw-r--r--apps/filetree.h2
-rw-r--r--apps/playlist.c4
-rw-r--r--apps/tree.c202
-rw-r--r--apps/tree.h5
7 files changed, 194 insertions, 121 deletions
diff --git a/apps/dbtree.c b/apps/dbtree.c
index 68a211a836..abe8aed647 100644
--- a/apps/dbtree.c
+++ b/apps/dbtree.c
@@ -121,18 +121,21 @@ int db_init(void)
121 return 0; 121 return 0;
122} 122}
123 123
124int db_load(struct tree_context* c, bool* dir_buffer_full) 124int db_load(struct tree_context* c)
125{ 125{
126 int i, offset, len, rc; 126 int i, offset, rc;
127 int dcachesize = global_settings.max_files_in_dir * sizeof(struct entry); 127 int dcachesize = global_settings.max_files_in_dir * sizeof(struct entry);
128 int max_items, itemcount, stringlen; 128 int max_items, itemcount, stringlen;
129 unsigned int* nptr = (void*) c->name_buffer; 129 unsigned int* nptr = (void*) c->name_buffer;
130 unsigned int* dptr = c->dircache; 130 unsigned int* dptr = c->dircache;
131 unsigned int* safeplace = NULL; 131 unsigned int* safeplace = NULL;
132 int safeplacelen = 0;
132 133
133 int table = c->currtable; 134 int table = c->currtable;
134 int extra = c->currextra; 135 int extra = c->currextra;
135 136
137 char* end_of_nbuf = c->name_buffer + c->name_buffer_size;
138
136 if (!initialized) { 139 if (!initialized) {
137 DEBUGF("ID3 database is not initialized.\n"); 140 DEBUGF("ID3 database is not initialized.\n");
138 c->filesindir = 0; 141 c->filesindir = 0;
@@ -140,8 +143,9 @@ int db_load(struct tree_context* c, bool* dir_buffer_full)
140 } 143 }
141 144
142 c->dentry_size = 2 * sizeof(int); 145 c->dentry_size = 2 * sizeof(int);
143 146 c->dirfull = false;
144 DEBUGF("db_load(%d, %x)\n", table, extra); 147
148 DEBUGF("db_load(%d, %x, %d)\n", table, extra, c->firstpos);
145 149
146 if (!table) { 150 if (!table) {
147 table = allartists; 151 table = allartists;
@@ -150,51 +154,50 @@ int db_load(struct tree_context* c, bool* dir_buffer_full)
150 154
151 switch (table) { 155 switch (table) {
152 case allsongs: 156 case allsongs:
153 offset = songstart; 157 offset = songstart + c->firstpos * (songlen + 12);
154 itemcount = songcount; 158 itemcount = songcount;
155 stringlen = songlen; 159 stringlen = songlen;
156 break; 160 break;
157 161
158 case allalbums: 162 case allalbums:
159 offset = albumstart; 163 offset = albumstart +
164 c->firstpos * (albumlen + 4 + songarraylen * 4);
160 itemcount = albumcount; 165 itemcount = albumcount;
161 stringlen = albumlen; 166 stringlen = albumlen;
162 break; 167 break;
163 168
164 case allartists: 169 case allartists:
165 offset = artiststart; 170 offset = artiststart +
171 c->firstpos * (artistlen + albumarraylen * 4);
166 itemcount = artistcount; 172 itemcount = artistcount;
167 stringlen = artistlen; 173 stringlen = artistlen;
168 break; 174 break;
169 175
170 case albums: 176 case albums4artist:
171 /* 'extra' is offset to the artist */ 177 /* 'extra' is offset to the artist */
172 len = albumarraylen * 4; 178 safeplacelen = albumarraylen * 4;
173 safeplace = (void*)(c->name_buffer + c->name_buffer_size - len); 179 safeplace = (void*)(end_of_nbuf - safeplacelen);
174 //DEBUGF("Seeking to %x\n", extra + artistlen);
175 lseek(fd, extra + artistlen, SEEK_SET); 180 lseek(fd, extra + artistlen, SEEK_SET);
176 rc = read(fd, safeplace, len); 181 rc = read(fd, safeplace, safeplacelen);
177 if (rc < len) 182 if (rc < safeplacelen)
178 return -1; 183 return -1;
179 184
180#ifdef LITTLE_ENDIAN 185#ifdef LITTLE_ENDIAN
181 for (i=0; i<albumarraylen; i++) 186 for (i=0; i<albumarraylen; i++)
182 safeplace[i] = BE32(safeplace[i]); 187 safeplace[i] = BE32(safeplace[i]);
183#endif 188#endif
184
185 offset = safeplace[0]; 189 offset = safeplace[0];
186 itemcount = albumarraylen; 190 itemcount = albumarraylen;
187 stringlen = albumlen; 191 stringlen = albumlen;
188 break; 192 break;
189 193
190 case songs: 194 case songs4album:
191 /* 'extra' is offset to the album */ 195 /* 'extra' is offset to the album */
192 len = songarraylen * 4; 196 safeplacelen = songarraylen * 4;
193 safeplace = (void*)(c->name_buffer + c->name_buffer_size - len); 197 safeplace = (void*)(end_of_nbuf - safeplacelen);
194 //DEBUGF("Seeking to %x\n", extra + albumlen + 4);
195 lseek(fd, extra + albumlen + 4, SEEK_SET); 198 lseek(fd, extra + albumlen + 4, SEEK_SET);
196 rc = read(fd, safeplace, len); 199 rc = read(fd, safeplace, safeplacelen);
197 if (rc < len) 200 if (rc < safeplacelen)
198 return -1; 201 return -1;
199 202
200#ifdef LITTLE_ENDIAN 203#ifdef LITTLE_ENDIAN
@@ -211,6 +214,10 @@ int db_load(struct tree_context* c, bool* dir_buffer_full)
211 return -1; 214 return -1;
212 } 215 }
213 max_items = dcachesize / c->dentry_size; 216 max_items = dcachesize / c->dentry_size;
217 end_of_nbuf -= safeplacelen;
218
219 c->dirlength = itemcount;
220 itemcount -= c->firstpos;
214 221
215 if (!safeplace) { 222 if (!safeplace) {
216 //DEBUGF("Seeking to %x\n", offset); 223 //DEBUGF("Seeking to %x\n", offset);
@@ -222,8 +229,7 @@ int db_load(struct tree_context* c, bool* dir_buffer_full)
222 the rest is table specific. see below. */ 229 the rest is table specific. see below. */
223 230
224 if (itemcount > max_items) 231 if (itemcount > max_items)
225 if (dir_buffer_full) 232 c->dirfull = true;
226 *dir_buffer_full = true;
227 233
228 if (max_items > itemcount) { 234 if (max_items > itemcount) {
229 max_items = itemcount; 235 max_items = itemcount;
@@ -233,8 +239,10 @@ int db_load(struct tree_context* c, bool* dir_buffer_full)
233 int rc, skip=0; 239 int rc, skip=0;
234 240
235 if (safeplace) { 241 if (safeplace) {
236 if (!safeplace[i]) 242 if (!safeplace[i]) {
243 c->dirlength = i;
237 break; 244 break;
245 }
238 //DEBUGF("Seeking to %x\n", safeplace[i]); 246 //DEBUGF("Seeking to %x\n", safeplace[i]);
239 lseek(fd, safeplace[i], SEEK_SET); 247 lseek(fd, safeplace[i], SEEK_SET);
240 offset = safeplace[i]; 248 offset = safeplace[i];
@@ -252,15 +260,15 @@ int db_load(struct tree_context* c, bool* dir_buffer_full)
252 dptr[0] = (unsigned int)nptr; 260 dptr[0] = (unsigned int)nptr;
253 261
254 switch (table) { 262 switch (table) {
255 case songs:
256 case allsongs: 263 case allsongs:
264 case songs4album:
257 /* save offset of this song */ 265 /* save offset of this song */
258 skip = 12; 266 skip = 12;
259 dptr[1] = offset; 267 dptr[1] = offset;
260 break; 268 break;
261 269
262 case allalbums: 270 case allalbums:
263 case albums: 271 case albums4artist:
264 /* save offset of this album */ 272 /* save offset of this album */
265 skip = songarraylen * 4 + 4; 273 skip = songarraylen * 4 + 4;
266 dptr[1] = offset; 274 dptr[1] = offset;
@@ -273,15 +281,14 @@ int db_load(struct tree_context* c, bool* dir_buffer_full)
273 break; 281 break;
274 } 282 }
275 283
276 //DEBUGF("%x: %s\n", dptr[1], dptr[0]);
277
278 if (skip) 284 if (skip)
279 lseek(fd, skip, SEEK_CUR); 285 lseek(fd, skip, SEEK_CUR);
280 286
281 /* next name is stored immediately after this */ 287 /* next name is stored immediately after this */
282 nptr = (void*)nptr + strlen((char*)nptr) + 1; 288 nptr = (void*)nptr + strlen((char*)nptr) + 1;
283 if ((void*)nptr > (void*)c->name_buffer + c->name_buffer_size) { 289 if ((void*)nptr > (void*)end_of_nbuf) {
284 DEBUGF("Name buffer overflow (%d)\n",i); 290 DEBUGF("Name buffer overflow (%d)\n",i);
291 c->dirfull = true;
285 break; 292 break;
286 } 293 }
287 dptr = (void*)dptr + c->dentry_size; 294 dptr = (void*)dptr + c->dentry_size;
@@ -299,11 +306,12 @@ void db_enter(struct tree_context* c)
299{ 306{
300 switch (c->currtable) { 307 switch (c->currtable) {
301 case allartists: 308 case allartists:
302 case albums: 309 case albums4artist:
303 c->dirpos[c->dirlevel] = c->dirstart; 310 c->dirpos[c->dirlevel] = c->dirstart;
304 c->cursorpos[c->dirlevel] = c->dircursor; 311 c->cursorpos[c->dirlevel] = c->dircursor;
305 c->table_history[c->dirlevel] = c->currtable; 312 c->table_history[c->dirlevel] = c->currtable;
306 c->extra_history[c->dirlevel] = c->currextra; 313 c->extra_history[c->dirlevel] = c->currextra;
314 c->pos_history[c->dirlevel] = c->firstpos;
307 c->dirlevel++; 315 c->dirlevel++;
308 break; 316 break;
309 317
@@ -313,16 +321,16 @@ void db_enter(struct tree_context* c)
313 321
314 switch (c->currtable) { 322 switch (c->currtable) {
315 case allartists: 323 case allartists:
316 c->currtable = albums; 324 c->currtable = albums4artist;
317 c->currextra = ((int*)c->dircache)[(c->dircursor + c->dirstart)*2 + 1]; 325 c->currextra = ((int*)c->dircache)[(c->dircursor + c->dirstart)*2 + 1];
318 break; 326 break;
319 327
320 case albums: 328 case albums4artist:
321 c->currtable = songs; 329 c->currtable = songs4album;
322 c->currextra = ((int*)c->dircache)[(c->dircursor + c->dirstart)*2 + 1]; 330 c->currextra = ((int*)c->dircache)[(c->dircursor + c->dirstart)*2 + 1];
323 break; 331 break;
324 332
325 case songs: 333 case songs4album:
326 splash(HZ,true,"No playing implemented yet"); 334 splash(HZ,true,"No playing implemented yet");
327#if 0 335#if 0
328 /* find filenames, build playlist, play */ 336 /* find filenames, build playlist, play */
@@ -334,7 +342,7 @@ void db_enter(struct tree_context* c)
334 break; 342 break;
335 } 343 }
336 344
337 c->dirstart = c->dircursor = 0; 345 c->dirstart = c->dircursor = c->firstpos = 0;
338} 346}
339 347
340void db_exit(struct tree_context* c) 348void db_exit(struct tree_context* c)
@@ -344,6 +352,7 @@ void db_exit(struct tree_context* c)
344 c->dircursor = c->cursorpos[c->dirlevel]; 352 c->dircursor = c->cursorpos[c->dirlevel];
345 c->currtable = c->table_history[c->dirlevel]; 353 c->currtable = c->table_history[c->dirlevel];
346 c->currextra = c->extra_history[c->dirlevel]; 354 c->currextra = c->extra_history[c->dirlevel];
355 c->firstpos = c->pos_history[c->dirlevel];
347} 356}
348 357
349#ifdef HAVE_LCD_BITMAP 358#ifdef HAVE_LCD_BITMAP
@@ -354,7 +363,7 @@ const char* db_get_icon(struct tree_context* c)
354 switch (c->currtable) 363 switch (c->currtable)
355 { 364 {
356 case allsongs: 365 case allsongs:
357 case songs: 366 case songs4album:
358 icon = File; 367 icon = File;
359 break; 368 break;
360 369
@@ -372,7 +381,7 @@ int db_get_icon(struct tree_context* c)
372 switch (c->currtable) 381 switch (c->currtable)
373 { 382 {
374 case allsongs: 383 case allsongs:
375 case songs: 384 case songs4album:
376 icon = File; 385 icon = File;
377 break; 386 break;
378 387
diff --git a/apps/dbtree.h b/apps/dbtree.h
index 414aa6f19f..5fa09b0eaf 100644
--- a/apps/dbtree.h
+++ b/apps/dbtree.h
@@ -21,13 +21,13 @@
21 21
22#include "tree.h" 22#include "tree.h"
23 23
24enum table { invalid, allsongs, allalbums, allartists, albums, songs }; 24enum table { invalid, allsongs, allalbums, allartists,
25 albums4artist, songs4album };
25 26
26int db_init(void); 27int db_init(void);
27void db_enter(struct tree_context* c); 28void db_enter(struct tree_context* c);
28void db_exit(struct tree_context* c); 29void db_exit(struct tree_context* c);
29int db_load(struct tree_context* c, 30int db_load(struct tree_context* c);
30 bool* dir_buffer_full);
31#ifdef HAVE_LCD_BITMAP 31#ifdef HAVE_LCD_BITMAP
32const char* db_get_icon(struct tree_context* c); 32const char* db_get_icon(struct tree_context* c);
33#else 33#else
diff --git a/apps/filetree.c b/apps/filetree.c
index 09c2a2dcc0..a46ffbb2bc 100644
--- a/apps/filetree.c
+++ b/apps/filetree.c
@@ -184,9 +184,8 @@ static int compare(const void* p1, const void* p2)
184} 184}
185 185
186/* load and sort directory into dircache. returns NULL on failure. */ 186/* load and sort directory into dircache. returns NULL on failure. */
187int ft_load(struct tree_context* c, bool *buffer_full) 187int ft_load(struct tree_context* c)
188{ 188{
189 extern char lastdir[]; /* from tree.c */
190 int i; 189 int i;
191 int name_buffer_used = 0; 190 int name_buffer_used = 0;
192 DIR *dir = opendir(c->currdir); 191 DIR *dir = opendir(c->currdir);
@@ -194,13 +193,13 @@ int ft_load(struct tree_context* c, bool *buffer_full)
194 return -1; /* not a directory */ 193 return -1; /* not a directory */
195 194
196 c->dirsindir = 0; 195 c->dirsindir = 0;
197 if (buffer_full) 196 c->dirfull = false;
198 *buffer_full = false;
199 197
200 for ( i=0; i < global_settings.max_files_in_dir; i++ ) { 198 for ( i=0; i < global_settings.max_files_in_dir; i++ ) {
201 int len; 199 int len;
202 struct dirent *entry = readdir(dir); 200 struct dirent *entry = readdir(dir);
203 struct entry* dptr = (struct entry*)(c->dircache + i * sizeof(struct entry)); 201 struct entry* dptr =
202 (struct entry*)(c->dircache + i * sizeof(struct entry));
204 if (!entry) 203 if (!entry)
205 break; 204 break;
206 205
@@ -268,8 +267,7 @@ int ft_load(struct tree_context* c, bool *buffer_full)
268 267
269 if (len > c->name_buffer_size - name_buffer_used - 1) { 268 if (len > c->name_buffer_size - name_buffer_used - 1) {
270 /* Tell the world that we ran out of buffer space */ 269 /* Tell the world that we ran out of buffer space */
271 if (buffer_full) 270 c->dirfull = true;
272 *buffer_full = true;
273 break; 271 break;
274 } 272 }
275 dptr->name = &c->name_buffer[name_buffer_used]; 273 dptr->name = &c->name_buffer[name_buffer_used];
@@ -281,10 +279,9 @@ int ft_load(struct tree_context* c, bool *buffer_full)
281 c->dirsindir++; 279 c->dirsindir++;
282 } 280 }
283 c->filesindir = i; 281 c->filesindir = i;
282 c->dirlength = i;
284 closedir(dir); 283 closedir(dir);
285 284
286 strcpy(lastdir, c->currdir);
287
288 qsort(c->dircache,i,sizeof(struct entry),compare); 285 qsort(c->dircache,i,sizeof(struct entry),compare);
289 286
290 /* If thumbnail talking is enabled, make an extra run to mark files with 287 /* If thumbnail talking is enabled, make an extra run to mark files with
diff --git a/apps/filetree.h b/apps/filetree.h
index fcf8b64af2..143b75ad66 100644
--- a/apps/filetree.h
+++ b/apps/filetree.h
@@ -20,7 +20,7 @@
20#define FILETREE_H 20#define FILETREE_H
21#include "tree.h" 21#include "tree.h"
22 22
23int ft_load(struct tree_context* c, bool *buffer_full); 23int ft_load(struct tree_context* c);
24int ft_play_filenumber(int pos, int attr); 24int ft_play_filenumber(int pos, int attr);
25int ft_play_dirname(int start_index); 25int ft_play_dirname(int start_index);
26void ft_play_filename(char *dir, char *file); 26void ft_play_filename(char *dir, char *file);
diff --git a/apps/playlist.c b/apps/playlist.c
index aa8415a86f..4506ec5f54 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -545,7 +545,7 @@ static int add_directory_to_playlist(struct playlist_info* playlist,
545 /* use the tree browser dircache to load files */ 545 /* use the tree browser dircache to load files */
546 global_settings.dirfilter = SHOW_ALL; 546 global_settings.dirfilter = SHOW_ALL;
547 strncpy(tc->currdir, dirname, sizeof(tc->currdir)); 547 strncpy(tc->currdir, dirname, sizeof(tc->currdir));
548 num_files = ft_load(tc, NULL); 548 num_files = ft_load(tc);
549 files = (struct entry*) tc->dircache; 549 files = (struct entry*) tc->dircache;
550 550
551 if(!num_files) 551 if(!num_files)
@@ -585,7 +585,7 @@ static int add_directory_to_playlist(struct playlist_info* playlist,
585 585
586 /* we now need to reload our current directory */ 586 /* we now need to reload our current directory */
587 strncpy(tc->currdir, dirname, sizeof(tc->currdir)); 587 strncpy(tc->currdir, dirname, sizeof(tc->currdir));
588 num_files = ft_load(tc, NULL); 588 num_files = ft_load(tc);
589 files = (struct entry*) tc->dircache; 589 files = (struct entry*) tc->dircache;
590 if (!num_files) 590 if (!num_files)
591 { 591 {
diff --git a/apps/tree.c b/apps/tree.c
index b844060322..2ba4585047 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -92,7 +92,9 @@ static struct tree_context tc;
92bool boot_changed = false; 92bool boot_changed = false;
93 93
94char lastfile[MAX_PATH]; 94char lastfile[MAX_PATH];
95char lastdir[MAX_PATH]; 95static char lastdir[MAX_PATH];
96static int lasttable, lastextra, lastfirstpos;
97static int max_files = 0;
96 98
97static bool reload_dir = false; 99static bool reload_dir = false;
98 100
@@ -245,10 +247,9 @@ static int showdir(void)
245 struct entry *dircache = tc.dircache; 247 struct entry *dircache = tc.dircache;
246 int i; 248 int i;
247 int tree_max_on_screen; 249 int tree_max_on_screen;
248 bool dir_buffer_full = false;
249 int start = tc.dirstart; 250 int start = tc.dirstart;
250 bool id3db = global_settings.dirfilter == SHOW_ID3DB; 251 bool id3db = global_settings.dirfilter == SHOW_ID3DB;
251 252 bool newdir = false;
252#ifdef HAVE_LCD_BITMAP 253#ifdef HAVE_LCD_BITMAP
253 const char* icon; 254 const char* icon;
254 int line_height; 255 int line_height;
@@ -264,17 +265,30 @@ static int showdir(void)
264 265
265 /* new file dir? load it */ 266 /* new file dir? load it */
266 if (id3db) { 267 if (id3db) {
267 if (db_load(&tc, &dir_buffer_full) < 0) 268 if (tc.currtable != lasttable ||
268 return -1; 269 tc.currextra != lastextra ||
270 tc.firstpos != lastfirstpos)
271 {
272 if (db_load(&tc) < 0)
273 return -1;
274 lasttable = tc.currtable;
275 lastextra = tc.currextra;
276 lastfirstpos = tc.firstpos;
277 newdir = true;
278 }
269 } 279 }
270 else { 280 else {
271 if (strncmp(tc.currdir, lastdir, sizeof(lastdir)) || reload_dir) { 281 if (strncmp(tc.currdir, lastdir, sizeof(lastdir)) || reload_dir) {
272 if (ft_load(&tc, &dir_buffer_full) < 0) 282 if (ft_load(&tc) < 0)
273 return -1; 283 return -1;
284 strcpy(lastdir, tc.currdir);
285 newdir = true;
274 } 286 }
275 } 287 }
276 288
277 if ( dir_buffer_full || tc.filesindir == global_settings.max_files_in_dir ) { 289 if (newdir && !id3db &&
290 (tc.dirfull || tc.filesindir == global_settings.max_files_in_dir) )
291 {
278#ifdef HAVE_LCD_CHARCELLS 292#ifdef HAVE_LCD_CHARCELLS
279 lcd_double_height(false); 293 lcd_double_height(false);
280#endif 294#endif
@@ -383,10 +397,11 @@ static int showdir(void)
383 } 397 }
384 398
385#ifdef HAVE_LCD_BITMAP 399#ifdef HAVE_LCD_BITMAP
386 if (global_settings.scrollbar && (tc.filesindir > tree_max_on_screen)) 400 if (global_settings.scrollbar && (tc.dirlength > tree_max_on_screen))
387 scrollbar(SCROLLBAR_X, SCROLLBAR_Y, SCROLLBAR_WIDTH - 1, 401 scrollbar(SCROLLBAR_X, SCROLLBAR_Y, SCROLLBAR_WIDTH - 1,
388 tree_max_on_screen * line_height, tc.filesindir, start, 402 tree_max_on_screen * line_height, tc.dirlength,
389 start + tree_max_on_screen, VERTICAL); 403 start + tc.firstpos,
404 start + tc.firstpos + tree_max_on_screen, VERTICAL);
390 405
391#if CONFIG_KEYPAD == RECORDER_PAD 406#if CONFIG_KEYPAD == RECORDER_PAD
392 if(global_settings.buttonbar) { 407 if(global_settings.buttonbar) {
@@ -483,10 +498,8 @@ static bool ask_resume(bool ask_once)
483/* load tracks from specified directory to resume play */ 498/* load tracks from specified directory to resume play */
484void resume_directory(const char *dir) 499void resume_directory(const char *dir)
485{ 500{
486 bool buffer_full;
487
488 strcpy(tc.currdir, dir); 501 strcpy(tc.currdir, dir);
489 if (!ft_load(&tc, &buffer_full)) 502 if (!ft_load(&tc))
490 return; 503 return;
491 lastdir[0] = 0; 504 lastdir[0] = 0;
492 505
@@ -586,10 +599,10 @@ static bool check_changed_id3mode(bool currmode)
586 if (currmode != (global_settings.dirfilter == SHOW_ID3DB)) { 599 if (currmode != (global_settings.dirfilter == SHOW_ID3DB)) {
587 currmode = global_settings.dirfilter == SHOW_ID3DB; 600 currmode = global_settings.dirfilter == SHOW_ID3DB;
588 if (currmode) { 601 if (currmode) {
589 db_load(&tc, NULL); 602 db_load(&tc);
590 } 603 }
591 else 604 else
592 ft_load(&tc, NULL); 605 ft_load(&tc);
593 } 606 }
594 return currmode; 607 return currmode;
595} 608}
@@ -624,6 +637,10 @@ static bool dirbrowse(void)
624 tc.dircursor=0; 637 tc.dircursor=0;
625 tc.dirstart=0; 638 tc.dirstart=0;
626 tc.dirlevel=0; 639 tc.dirlevel=0;
640 tc.firstpos=0;
641 lasttable = -1;
642 lastextra = -1;
643 lastfirstpos = 0;
627 644
628 if (*tc.dirfilter < NUM_FILTER_MODES) 645 if (*tc.dirfilter < NUM_FILTER_MODES)
629 start_resume(true); 646 start_resume(true);
@@ -778,39 +795,59 @@ static bool dirbrowse(void)
778 case TREE_RC_PREV: 795 case TREE_RC_PREV:
779 case TREE_RC_PREV | BUTTON_REPEAT: 796 case TREE_RC_PREV | BUTTON_REPEAT:
780#endif 797#endif
781 if(tc.filesindir) { 798 if (!tc.filesindir)
782 if(tc.dircursor) { 799 break;
783 put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, false); 800
784 tc.dircursor--; 801 if (tc.dircursor) {
785 put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); 802 put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, false);
786 } 803 tc.dircursor--;
787 else { 804 put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true);
788 if (tc.dirstart) { 805 }
806 else {
807 if (tc.dirstart || tc.firstpos) {
808 if (tc.dirstart)
789 tc.dirstart--; 809 tc.dirstart--;
790 numentries = showdir();
791 update_all=true;
792 put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true);
793 }
794 else { 810 else {
795 if (numentries < tree_max_on_screen) { 811 if (tc.firstpos > max_files/2) {
796 put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, 812 tc.firstpos -= max_files/2;
797 false); 813 tc.dirstart += max_files/2;
798 tc.dircursor = numentries - 1; 814 tc.dirstart--;
799 put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor,
800 true);
801 } 815 }
802 else { 816 else {
803 tc.dirstart = numentries - tree_max_on_screen; 817 tc.dirstart = tc.firstpos - 1;
804 tc.dircursor = tree_max_on_screen - 1; 818 tc.firstpos = 0;
805 numentries = showdir();
806 update_all = true;
807 put_cursorxy(CURSOR_X, CURSOR_Y +
808 tree_max_on_screen - 1, true);
809 } 819 }
810 } 820 }
821 restore = true;
822 }
823 else {
824 if (numentries < tree_max_on_screen) {
825 put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor,
826 false);
827 tc.dircursor = numentries - 1;
828 put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor,
829 true);
830 }
831 else if (id3db && tc.dirfull) {
832 /* load last dir segment */
833 /* use max_files/2 in case names are longer than
834 AVERAGE_FILE_LENGTH */
835 tc.firstpos = tc.dirlength - max_files/2;
836 tc.dirstart = tc.firstpos;
837 tc.dircursor = tree_max_on_screen - 1;
838 numentries = showdir();
839 update_all = true;
840 put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor,
841 true);
842 }
843 else {
844 tc.dirstart = numentries - tree_max_on_screen;
845 tc.dircursor = tree_max_on_screen - 1;
846 restore = true;
847 }
811 } 848 }
812 need_update = true;
813 } 849 }
850 need_update = true;
814 break; 851 break;
815 852
816 case TREE_NEXT: 853 case TREE_NEXT:
@@ -819,46 +856,67 @@ static bool dirbrowse(void)
819 case TREE_RC_NEXT: 856 case TREE_RC_NEXT:
820 case TREE_RC_NEXT | BUTTON_REPEAT: 857 case TREE_RC_NEXT | BUTTON_REPEAT:
821#endif 858#endif
822 if(tc.filesindir) 859 if (!tc.filesindir)
823 { 860 break;
824 if (tc.dircursor + tc.dirstart + 1 < numentries ) { 861
825 if(tc.dircursor+1 < tree_max_on_screen) { 862 if (tc.dircursor + tc.dirstart + 1 < numentries ) {
826 put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, false); 863 if(tc.dircursor+1 < tree_max_on_screen) {
827 tc.dircursor++; 864 put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, false);
828 put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); 865 tc.dircursor++;
829 } 866 put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true);
830 else {
831 tc.dirstart++;
832 numentries = showdir();
833 update_all = true;
834 put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true);
835 }
836 } 867 }
837 else { 868 else {
838 if(numentries < tree_max_on_screen) { 869 tc.dirstart++;
839 put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, false); 870 restore = true;
840 tc.dirstart = tc.dircursor = 0;
841 put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true);
842 }
843 else {
844 tc.dirstart = tc.dircursor = 0;
845 numentries = showdir();
846 update_all=true;
847 put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true);
848 }
849 } 871 }
850 need_update = true;
851 } 872 }
873 else if (id3db && (tc.firstpos || tc.dirfull)) {
874 if (tc.dircursor + tc.dirstart + tc.firstpos + 1 >= tc.dirlength) {
875 /* wrap and load first dir segment */
876 tc.firstpos = tc.dirstart = tc.dircursor = 0;
877 }
878 else {
879 /* load next dir segment */
880 tc.firstpos += tc.dirstart;
881 tc.dirstart = 0;
882 }
883 restore = true;
884 }
885 else {
886 if(numentries < tree_max_on_screen) {
887 put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, false);
888 tc.dirstart = tc.dircursor = 0;
889 put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true);
890 }
891 else {
892 tc.dirstart = tc.dircursor = 0;
893 numentries = showdir();
894 update_all=true;
895 put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true);
896 }
897 }
898 need_update = true;
852 break; 899 break;
853 900
854#ifdef TREE_PGUP 901#ifdef TREE_PGUP
855 case TREE_PGUP: 902 case TREE_PGUP:
856 case TREE_PGUP | BUTTON_REPEAT: 903 case TREE_PGUP | BUTTON_REPEAT:
857 if ( tc.dirstart ) { 904 if (tc.dirstart) {
858 tc.dirstart -= tree_max_on_screen; 905 tc.dirstart -= tree_max_on_screen;
859 if ( tc.dirstart < 0 ) 906 if ( tc.dirstart < 0 )
860 tc.dirstart = 0; 907 tc.dirstart = 0;
861 } 908 }
909 else if (tc.firstpos) {
910 if (tc.firstpos > max_files/2) {
911 tc.firstpos -= max_files/2;
912 tc.dirstart += max_files/2;
913 tc.dirstart -= tree_max_on_screen;
914 }
915 else {
916 tc.dirstart = tc.firstpos - tree_max_on_screen;
917 tc.firstpos = 0;
918 }
919 }
862 else 920 else
863 tc.dircursor = 0; 921 tc.dircursor = 0;
864 restore = true; 922 restore = true;
@@ -868,10 +926,14 @@ static bool dirbrowse(void)
868 case TREE_PGDN | BUTTON_REPEAT: 926 case TREE_PGDN | BUTTON_REPEAT:
869 if ( tc.dirstart < numentries - tree_max_on_screen ) { 927 if ( tc.dirstart < numentries - tree_max_on_screen ) {
870 tc.dirstart += tree_max_on_screen; 928 tc.dirstart += tree_max_on_screen;
871 if ( tc.dirstart > 929 if ( tc.dirstart > numentries - tree_max_on_screen )
872 numentries - tree_max_on_screen )
873 tc.dirstart = numentries - tree_max_on_screen; 930 tc.dirstart = numentries - tree_max_on_screen;
874 } 931 }
932 else if (id3db && tc.dirfull) {
933 /* load next dir segment */
934 tc.firstpos += tc.dirstart;
935 tc.dirstart = 0;
936 }
875 else 937 else
876 tc.dircursor = numentries - tc.dirstart - 1; 938 tc.dircursor = numentries - tc.dirstart - 1;
877 restore = true; 939 restore = true;
@@ -1334,7 +1396,7 @@ void tree_init(void)
1334{ 1396{
1335 /* We copy the settings value in case it is changed by the user. We can't 1397 /* We copy the settings value in case it is changed by the user. We can't
1336 use it until the next reboot. */ 1398 use it until the next reboot. */
1337 int max_files = global_settings.max_files_in_dir; 1399 max_files = global_settings.max_files_in_dir;
1338 1400
1339 /* initialize tree context struct */ 1401 /* initialize tree context struct */
1340 memset(&tc, 0, sizeof(tc)); 1402 memset(&tc, 0, sizeof(tc));
diff --git a/apps/tree.h b/apps/tree.h
index 87e0361e50..87364bfd5a 100644
--- a/apps/tree.h
+++ b/apps/tree.h
@@ -121,12 +121,16 @@ struct tree_context {
121 int dirlevel; 121 int dirlevel;
122 int dircursor; 122 int dircursor;
123 int dirstart; 123 int dirstart;
124 int firstpos; /* which dir entry is on first
125 position in dir buffer */
126 int pos_history[MAX_DIR_LEVELS];
124 int dirpos[MAX_DIR_LEVELS]; 127 int dirpos[MAX_DIR_LEVELS];
125 int cursorpos[MAX_DIR_LEVELS]; 128 int cursorpos[MAX_DIR_LEVELS];
126 char currdir[MAX_PATH]; /* file use */ 129 char currdir[MAX_PATH]; /* file use */
127 int *dirfilter; /* file use */ 130 int *dirfilter; /* file use */
128 int filesindir; 131 int filesindir;
129 int dirsindir; /* file use */ 132 int dirsindir; /* file use */
133 int dirlength; /* total number of entries in dir, incl. those not loaded */
130 int table_history[MAX_DIR_LEVELS]; /* db use */ 134 int table_history[MAX_DIR_LEVELS]; /* db use */
131 int extra_history[MAX_DIR_LEVELS]; /* db use */ 135 int extra_history[MAX_DIR_LEVELS]; /* db use */
132 int currtable; /* db use */ 136 int currtable; /* db use */
@@ -137,6 +141,7 @@ struct tree_context {
137 char* name_buffer; 141 char* name_buffer;
138 int name_buffer_size; 142 int name_buffer_size;
139 int dentry_size; 143 int dentry_size;
144 bool dirfull;
140}; 145};
141 146
142/* using attribute bits not used by FAT (FAT uses lower 7) */ 147/* using attribute bits not used by FAT (FAT uses lower 7) */