summaryrefslogtreecommitdiff
path: root/firmware/drivers/fat.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/fat.c')
-rw-r--r--firmware/drivers/fat.c108
1 files changed, 59 insertions, 49 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}