diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/drivers/fat.c | 108 | ||||
-rw-r--r-- | firmware/export/fat.h | 8 |
2 files changed, 66 insertions, 50 deletions
diff --git a/firmware/drivers/fat.c b/firmware/drivers/fat.c index f9d116eba8..e6383787ca 100644 --- a/firmware/drivers/fat.c +++ b/firmware/drivers/fat.c | |||
@@ -16,6 +16,7 @@ | |||
16 | * KIND, either express or implied. | 16 | * KIND, either express or implied. |
17 | * | 17 | * |
18 | ****************************************************************************/ | 18 | ****************************************************************************/ |
19 | #include "config.h" | ||
19 | #include <stdio.h> | 20 | #include <stdio.h> |
20 | #include <string.h> | 21 | #include <string.h> |
21 | #include <stdlib.h> | 22 | #include <stdlib.h> |
@@ -2158,6 +2159,7 @@ int fat_opendir(IF_MV2(int volume,) | |||
2158 | 2159 | ||
2159 | dir->entry = 0; | 2160 | dir->entry = 0; |
2160 | dir->sector = 0; | 2161 | dir->sector = 0; |
2162 | dir->bufindex = 0; | ||
2161 | 2163 | ||
2162 | if (startcluster == 0) | 2164 | if (startcluster == 0) |
2163 | startcluster = fat_bpb->bpb_rootclus; | 2165 | startcluster = fat_bpb->bpb_rootclus; |
@@ -2213,15 +2215,19 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) | |||
2213 | int longarray[20]; | 2215 | int longarray[20]; |
2214 | int longs=0; | 2216 | int longs=0; |
2215 | int sectoridx=0; | 2217 | int sectoridx=0; |
2216 | unsigned char* cached_buf = dir->sectorcache[0]; | 2218 | /* Set the cache pointer to the sector buffer we are currently using */ |
2219 | unsigned char* cached_buf = dir->sectorcache[dir->bufindex]; | ||
2217 | 2220 | ||
2218 | dir->entrycount = 0; | 2221 | dir->entrycount = 0; |
2219 | 2222 | ||
2220 | while(!done) | 2223 | while(!done) |
2221 | { | 2224 | { |
2222 | if ( !(dir->entry % DIR_ENTRIES_PER_SECTOR) || !dir->sector ) | 2225 | if ( !(dir->entry % (DIR_ENTRIES_PER_SECTOR*FAT_DIR_BUFSECTORS)) || |
2226 | !dir->sector ) | ||
2223 | { | 2227 | { |
2224 | rc = fat_readwrite(&dir->file, 1, cached_buf, false); | 2228 | /* Always read 2 sectors at a time */ |
2229 | rc = fat_readwrite(&dir->file, FAT_DIR_BUFSECTORS, cached_buf, | ||
2230 | false); | ||
2225 | if (rc == 0) { | 2231 | if (rc == 0) { |
2226 | /* eof */ | 2232 | /* eof */ |
2227 | entry->name[0] = 0; | 2233 | entry->name[0] = 0; |
@@ -2235,8 +2241,8 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) | |||
2235 | dir->sector = dir->file.lastsector; | 2241 | dir->sector = dir->file.lastsector; |
2236 | } | 2242 | } |
2237 | 2243 | ||
2238 | for (i = dir->entry % DIR_ENTRIES_PER_SECTOR; | 2244 | for (i = dir->entry % (DIR_ENTRIES_PER_SECTOR*FAT_DIR_BUFSECTORS); |
2239 | i < DIR_ENTRIES_PER_SECTOR; i++) | 2245 | i < (DIR_ENTRIES_PER_SECTOR*FAT_DIR_BUFSECTORS); i++) |
2240 | { | 2246 | { |
2241 | unsigned int entrypos = i * DIR_ENTRY_SIZE; | 2247 | unsigned int entrypos = i * DIR_ENTRY_SIZE; |
2242 | 2248 | ||
@@ -2277,40 +2283,44 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) | |||
2277 | /* replace shortname with longname? */ | 2283 | /* replace shortname with longname? */ |
2278 | if ( longs ) { | 2284 | if ( longs ) { |
2279 | int j; | 2285 | int j; |
2280 | /* This should be enough to hold any name segment utf8-encoded */ | 2286 | /* This should be enough to hold any name segment |
2287 | utf8-encoded */ | ||
2281 | unsigned char shortname[13]; /* 8+3+dot+\0 */ | 2288 | unsigned char shortname[13]; /* 8+3+dot+\0 */ |
2282 | unsigned char longname_utf8segm[6*4 + 1]; /* Add 1 for trailing \0 */ | 2289 | /* Add 1 for trailing \0 */ |
2290 | unsigned char longname_utf8segm[6*4 + 1]; | ||
2283 | int longname_utf8len = 0; | 2291 | int longname_utf8len = 0; |
2284 | 2292 | ||
2285 | strcpy(shortname, entry->name); /* Temporarily store it */ | 2293 | /* Store it temporarily */ |
2294 | strcpy(shortname, entry->name); | ||
2286 | entry->name[0] = 0; | 2295 | entry->name[0] = 0; |
2287 | 2296 | ||
2288 | /* iterate backwards through the dir entries */ | 2297 | /* iterate backwards through the dir entries */ |
2289 | for (j=longs-1; j>=0; j--) { | 2298 | for (j=longs-1; j>=0; j--) { |
2290 | unsigned char* ptr = cached_buf; | ||
2291 | int index = longarray[j]; | 2299 | int index = longarray[j]; |
2292 | /* current or cached sector? */ | 2300 | unsigned char* ptr; |
2293 | if ( sectoridx >= SECTOR_SIZE ) { | 2301 | |
2294 | if ( sectoridx >= SECTOR_SIZE*2 ) { | 2302 | /* If we have spanned over 3 sectors, the current |
2295 | if ( ( index >= SECTOR_SIZE ) && | 2303 | buffer holds the last part and the other one |
2296 | ( index < SECTOR_SIZE*2 )) | 2304 | the first part. */ |
2297 | ptr = dir->sectorcache[1]; | 2305 | if(sectoridx >= FAT_DIR_BUFSIZE) { |
2298 | else | 2306 | if(index / FAT_DIR_BUFSIZE > 0) |
2299 | ptr = dir->sectorcache[2]; | 2307 | ptr = dir->sectorcache[dir->bufindex]; |
2300 | } | 2308 | else |
2301 | else { | 2309 | ptr = dir->sectorcache[1 - dir->bufindex]; |
2302 | if ( index < SECTOR_SIZE ) | 2310 | } else { |
2303 | ptr = dir->sectorcache[1]; | 2311 | ptr = dir->sectorcache[dir->bufindex]; |
2304 | } | ||
2305 | |||
2306 | index &= SECTOR_SIZE-1; | ||
2307 | } | 2312 | } |
2308 | 2313 | ||
2309 | /* Try to append each segment of the long name. Check if we'd | 2314 | /* Let the index point into the selected |
2310 | exceed the buffer. Also check for FAT padding characters 0xFFFF. */ | 2315 | buffer */ |
2316 | index &= FAT_DIR_BUFSIZE-1; | ||
2317 | |||
2318 | /* Try to append each segment of the long name. | ||
2319 | Check if we'd exceed the buffer. Also check for | ||
2320 | FAT padding characters 0xFFFF. */ | ||
2311 | if (fat_copy_long_name_segment(ptr + index + 1, 5, | 2321 | if (fat_copy_long_name_segment(ptr + index + 1, 5, |
2312 | longname_utf8segm) == 0) break; | 2322 | longname_utf8segm) == 0) |
2313 | // logf("SG: %s, EN: %s", longname_utf8segm, entry->name); | 2323 | break; |
2314 | longname_utf8len += strlen(longname_utf8segm); | 2324 | longname_utf8len += strlen(longname_utf8segm); |
2315 | if (longname_utf8len < FAT_FILENAME_BYTES) | 2325 | if (longname_utf8len < FAT_FILENAME_BYTES) |
2316 | strcat(entry->name, longname_utf8segm); | 2326 | strcat(entry->name, longname_utf8segm); |
@@ -2318,8 +2328,8 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) | |||
2318 | break; | 2328 | break; |
2319 | 2329 | ||
2320 | if (fat_copy_long_name_segment(ptr + index + 14, 6, | 2330 | if (fat_copy_long_name_segment(ptr + index + 14, 6, |
2321 | longname_utf8segm) == 0) break; | 2331 | longname_utf8segm) == 0) |
2322 | // logf("SG: %s, EN: %s", longname_utf8segm, entry->name); | 2332 | break; |
2323 | longname_utf8len += strlen(longname_utf8segm); | 2333 | longname_utf8len += strlen(longname_utf8segm); |
2324 | if (longname_utf8len < FAT_FILENAME_BYTES) | 2334 | if (longname_utf8len < FAT_FILENAME_BYTES) |
2325 | strcat(entry->name, longname_utf8segm); | 2335 | strcat(entry->name, longname_utf8segm); |
@@ -2327,8 +2337,8 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) | |||
2327 | break; | 2337 | break; |
2328 | 2338 | ||
2329 | if (fat_copy_long_name_segment(ptr + index + 28, 2, | 2339 | if (fat_copy_long_name_segment(ptr + index + 28, 2, |
2330 | longname_utf8segm) == 0) break; | 2340 | longname_utf8segm) == 0) |
2331 | // logf("SG: %s, EN: %s", longname_utf8segm, entry->name); | 2341 | break; |
2332 | longname_utf8len += strlen(longname_utf8segm); | 2342 | longname_utf8len += strlen(longname_utf8segm); |
2333 | if (longname_utf8len < FAT_FILENAME_BYTES) | 2343 | if (longname_utf8len < FAT_FILENAME_BYTES) |
2334 | strcat(entry->name, longname_utf8segm); | 2344 | strcat(entry->name, longname_utf8segm); |
@@ -2338,19 +2348,18 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) | |||
2338 | 2348 | ||
2339 | /* Does the utf8-encoded name fit into the entry? */ | 2349 | /* Does the utf8-encoded name fit into the entry? */ |
2340 | if (longname_utf8len >= FAT_FILENAME_BYTES) { | 2350 | if (longname_utf8len >= FAT_FILENAME_BYTES) { |
2341 | /* Take the short DOS name. Need to utf8-encode it since | 2351 | /* Take the short DOS name. Need to utf8-encode it |
2342 | it may contain chars from the upper half of the OEM | 2352 | since it may contain chars from the upper half |
2343 | code page which wouldn't be a valid utf8. Beware: this | 2353 | of the OEM code page which wouldn't be a valid |
2344 | file will be shown with strange glyphs in file browser | 2354 | utf8. Beware: this file will be shown with |
2345 | since unicode 0x80 to 0x9F are control characters. */ | 2355 | strange glyphs in file browser since unicode |
2356 | 0x80 to 0x9F are control characters. */ | ||
2346 | logf("SN-DOS: %s", shortname); | 2357 | logf("SN-DOS: %s", shortname); |
2347 | unsigned char *utf8; | 2358 | unsigned char *utf8; |
2348 | utf8 = iso_decode(shortname, entry->name, -1, strlen(shortname)); | 2359 | utf8 = iso_decode(shortname, entry->name, -1, |
2349 | *utf8 = 0; | 2360 | strlen(shortname)); |
2361 | *utf8 = 0; | ||
2350 | logf("SN: %s", entry->name); | 2362 | logf("SN: %s", entry->name); |
2351 | } else { | ||
2352 | // logf("LN: %s", entry->name); | ||
2353 | // logf("LNLen: %d (%c)", longname_utf8len, entry->name[0]); | ||
2354 | } | 2363 | } |
2355 | } | 2364 | } |
2356 | done = true; | 2365 | done = true; |
@@ -2361,13 +2370,14 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) | |||
2361 | } | 2370 | } |
2362 | } | 2371 | } |
2363 | 2372 | ||
2364 | /* save this sector, for longname use */ | 2373 | /* Did the name span across a buffer boundary? |
2365 | if ( sectoridx ) | 2374 | Then we need to fill the second buffer as well and continue. */ |
2366 | memcpy( dir->sectorcache[2], dir->sectorcache[0], SECTOR_SIZE ); | 2375 | if(!done) { |
2367 | else | 2376 | sectoridx += FAT_DIR_BUFSIZE; |
2368 | memcpy( dir->sectorcache[1], dir->sectorcache[0], SECTOR_SIZE ); | ||
2369 | sectoridx += SECTOR_SIZE; | ||
2370 | 2377 | ||
2378 | dir->bufindex = 1 - dir->bufindex; | ||
2379 | cached_buf = dir->sectorcache[dir->bufindex]; | ||
2380 | } | ||
2371 | } | 2381 | } |
2372 | return 0; | 2382 | return 0; |
2373 | } | 2383 | } |
diff --git a/firmware/export/fat.h b/firmware/export/fat.h index 2680fdf751..93b60e6dc0 100644 --- a/firmware/export/fat.h +++ b/firmware/export/fat.h | |||
@@ -73,13 +73,19 @@ struct fat_file | |||
73 | #endif | 73 | #endif |
74 | }; | 74 | }; |
75 | 75 | ||
76 | #define FAT_DIR_BUFSECTORS 2 /* Needs to be an even number, at least 2 */ | ||
77 | #define FAT_DIR_BUFSIZE (SECTOR_SIZE*FAT_DIR_BUFSECTORS) | ||
78 | |||
76 | struct fat_dir | 79 | struct fat_dir |
77 | { | 80 | { |
78 | unsigned int entry; | 81 | unsigned int entry; |
79 | unsigned int entrycount; | 82 | unsigned int entrycount; |
80 | long sector; | 83 | long sector; |
81 | struct fat_file file; | 84 | struct fat_file file; |
82 | unsigned char sectorcache[3][SECTOR_SIZE]; | 85 | /* The buffer needs to be at least 3 sectors, so we make it 2*2 and |
86 | alternate between them */ | ||
87 | unsigned char sectorcache[2][FAT_DIR_BUFSIZE]; | ||
88 | unsigned int bufindex; /* Which buffer to be loaded next */ | ||
83 | }; | 89 | }; |
84 | 90 | ||
85 | 91 | ||