@@ -703,14 +703,18 @@ bool SdBaseFile::open(SdBaseFile *dirFile, const uint8_t dname[11]
703
703
// Get VFat dir entry
704
704
pvFat = (vfat_t *) p;
705
705
// Get checksum from the last entry of the sequence
706
- if (pvFat->sequenceNumber & 0x40 ) lfnChecksum = pvFat->checksum ;
706
+ if (pvFat->sequenceNumber & 0x40 ) {
707
+ lfnChecksum = pvFat->checksum ;
708
+ ZERO (lfnName);
709
+ }
707
710
// Get LFN sequence number
708
711
lfnSequenceNumber = pvFat->sequenceNumber & 0x1F ;
709
712
if WITHIN (lfnSequenceNumber, 1 , reqEntriesNum) {
710
713
// Check checksum for all other entries with the starting checksum fetched before
711
714
if (lfnChecksum == pvFat->checksum ) {
712
715
// Set chunk of LFN from VFAT entry into lfnName
713
716
getLFNName (pvFat, (char *)lfnName, lfnSequenceNumber);
717
+ TERN_ (UTF_FILENAME_SUPPORT, convertUtf16ToUtf8 ((char *)lfnName));
714
718
// LFN found?
715
719
if (!strncasecmp ((char *)dlname, (char *)lfnName, lfnNameLength)) lfnFileFound = true ;
716
720
}
@@ -1132,13 +1136,13 @@ bool SdBaseFile::openNext(SdBaseFile *dirFile, uint8_t oflag) {
1132
1136
* Get the LFN filename block from a dir. Get the block in lname at startOffset
1133
1137
*/
1134
1138
void SdBaseFile::getLFNName (vfat_t *pFatDir, char *lname, uint8_t sequenceNumber) {
1135
- uint8_t startOffset = (sequenceNumber - 1 ) * FILENAME_LENGTH;
1139
+ const uint8_t startOffset = (sequenceNumber - 1 ) * FILENAME_LENGTH;
1136
1140
LOOP_L_N (i, FILENAME_LENGTH) {
1137
1141
const uint16_t utf16_ch = (i >= 11 ) ? pFatDir->name3 [i - 11 ] : (i >= 5 ) ? pFatDir->name2 [i - 5 ] : pFatDir->name1 [i];
1138
1142
#if ENABLED(UTF_FILENAME_SUPPORT)
1139
1143
// We can't reconvert to UTF-8 here as UTF-8 is variable-size encoding, but joining LFN blocks
1140
1144
// needs static bytes addressing. So here just store full UTF-16LE words to re-convert later.
1141
- uint16_t idx = (startOffset + i) * 2 ; // This is fixed as FAT LFN always contain UTF-16LE encoding
1145
+ const uint16_t idx = (startOffset + i) * 2 ; // This is fixed as FAT LFN always contain UTF-16LE encoding
1142
1146
lname[idx] = utf16_ch & 0xFF ;
1143
1147
lname[idx + 1 ] = (utf16_ch >> 8 ) & 0xFF ;
1144
1148
#else
@@ -1152,8 +1156,8 @@ bool SdBaseFile::openNext(SdBaseFile *dirFile, uint8_t oflag) {
1152
1156
* Set the LFN filename block lname to a dir. Put the block based on sequence number
1153
1157
*/
1154
1158
void SdBaseFile::setLFNName (vfat_t *pFatDir, char *lname, uint8_t sequenceNumber) {
1155
- uint8_t startOffset = (sequenceNumber - 1 ) * FILENAME_LENGTH;
1156
- uint8_t nameLength = strlen (lname);
1159
+ const uint8_t startOffset = (sequenceNumber - 1 ) * FILENAME_LENGTH,
1160
+ nameLength = strlen (lname);
1157
1161
LOOP_L_N (i, FILENAME_LENGTH) {
1158
1162
uint16_t ch = 0 ;
1159
1163
if ((startOffset + i) < nameLength)
@@ -1424,7 +1428,7 @@ int16_t SdBaseFile::read(void *buf, uint16_t nbyte) {
1424
1428
* readDir() called before a directory has been opened, this is not
1425
1429
* a directory file or an I/O error occurred.
1426
1430
*/
1427
- int8_t SdBaseFile::readDir (dir_t *dir, char *longFilename) {
1431
+ int8_t SdBaseFile::readDir (dir_t *dir, char * const longFilename) {
1428
1432
int16_t n;
1429
1433
// if not a directory file or miss-positioned return an error
1430
1434
if (!isDir () || (0x1F & curPosition_)) return -1 ;
@@ -1506,44 +1510,55 @@ int8_t SdBaseFile::readDir(dir_t *dir, char *longFilename) {
1506
1510
// Post-process normal file or subdirectory longname, if any
1507
1511
if (DIR_IS_FILE_OR_SUBDIR (dir)) {
1508
1512
#if ENABLED(UTF_FILENAME_SUPPORT)
1509
- #if LONG_FILENAME_CHARSIZE > 2
1510
- // Add warning for developers for unsupported 3-byte cases.
1511
- // (Converting 2-byte codepoints to 3-byte in-place would break the rest of filename.)
1512
- #error "Currently filename re-encoding is done in-place. It may break the remaining chars to use 3-byte codepoints."
1513
- #endif
1514
-
1515
1513
// Is there a long filename to decode?
1516
1514
if (longFilename) {
1517
- // Reset n to the start of the long name
1518
- n = 0 ;
1519
- for (uint16_t idx = 0 ; idx < (LONG_FILENAME_LENGTH); idx += 2 ) { // idx is fixed since FAT LFN always contains UTF-16LE encoding
1520
- const uint16_t utf16_ch = longFilename[idx] | (longFilename[idx + 1 ] << 8 );
1521
- if (0xD800 == (utf16_ch & 0xF800 )) // Surrogate pair - encode as '_'
1522
- longFilename[n++] = ' _' ;
1523
- else if (0 == (utf16_ch & 0xFF80 )) // Encode as 1-byte UTF-8 char
1524
- longFilename[n++] = utf16_ch & 0x007F ;
1525
- else if (0 == (utf16_ch & 0xF800 )) { // Encode as 2-byte UTF-8 char
1526
- longFilename[n++] = 0xC0 | ((utf16_ch >> 6 ) & 0x1F );
1527
- longFilename[n++] = 0x80 | ( utf16_ch & 0x3F );
1528
- }
1529
- else {
1530
- #if LONG_FILENAME_CHARSIZE > 2 // Encode as 3-byte UTF-8 char
1531
- longFilename[n++] = 0xE0 | ((utf16_ch >> 12 ) & 0x0F );
1532
- longFilename[n++] = 0xC0 | ((utf16_ch >> 6 ) & 0x3F );
1533
- longFilename[n++] = 0xC0 | ( utf16_ch & 0x3F );
1534
- #else // Encode as '_'
1535
- longFilename[n++] = ' _' ;
1536
- #endif
1537
- }
1538
- if (0 == utf16_ch) break ; // End of filename
1539
- } // idx
1540
- } // longFilename
1515
+ n = convertUtf16ToUtf8 (longFilename);
1516
+ }
1541
1517
#endif
1542
1518
return n;
1543
1519
} // DIR_IS_FILE_OR_SUBDIR
1544
1520
}
1545
1521
}
1546
1522
1523
+ #if ENABLED(UTF_FILENAME_SUPPORT)
1524
+
1525
+ uint8_t SdBaseFile::convertUtf16ToUtf8 (char * const longFilename) {
1526
+ #if LONG_FILENAME_CHARSIZE > 2
1527
+ // Add warning for developers for unsupported 3-byte cases.
1528
+ // (Converting 2-byte codepoints to 3-byte in-place would break the rest of filename.)
1529
+ #error "Currently filename re-encoding is done in-place. It may break the remaining chars to use 3-byte codepoints."
1530
+ #endif
1531
+
1532
+ int16_t n;
1533
+ // Reset n to the start of the long name
1534
+ n = 0 ;
1535
+ for (uint16_t idx = 0 ; idx < (LONG_FILENAME_LENGTH); idx += 2 ) { // idx is fixed since FAT LFN always contains UTF-16LE encoding
1536
+ const uint16_t utf16_ch = longFilename[idx] | (longFilename[idx + 1 ] << 8 );
1537
+ if (0xD800 == (utf16_ch & 0xF800 )) // Surrogate pair - encode as '_'
1538
+ longFilename[n++] = ' _' ;
1539
+ else if (0 == (utf16_ch & 0xFF80 )) // Encode as 1-byte UTF-8 char
1540
+ longFilename[n++] = utf16_ch & 0x007F ;
1541
+ else if (0 == (utf16_ch & 0xF800 )) { // Encode as 2-byte UTF-8 char
1542
+ longFilename[n++] = 0xC0 | ((utf16_ch >> 6 ) & 0x1F );
1543
+ longFilename[n++] = 0x80 | ( utf16_ch & 0x3F );
1544
+ }
1545
+ else {
1546
+ #if LONG_FILENAME_CHARSIZE > 2 // Encode as 3-byte UTF-8 char
1547
+ longFilename[n++] = 0xE0 | ((utf16_ch >> 12 ) & 0x0F );
1548
+ longFilename[n++] = 0xC0 | ((utf16_ch >> 6 ) & 0x3F );
1549
+ longFilename[n++] = 0xC0 | ( utf16_ch & 0x3F );
1550
+ #else // Encode as '_'
1551
+ longFilename[n++] = ' _' ;
1552
+ #endif
1553
+ }
1554
+ if (0 == utf16_ch) break ; // End of filename
1555
+ } // idx
1556
+
1557
+ return n;
1558
+ }
1559
+
1560
+ #endif // UTF_FILENAME_SUPPORT
1561
+
1547
1562
// Read next directory entry into the cache
1548
1563
// Assumes file is correctly positioned
1549
1564
dir_t * SdBaseFile::readDirCache () {
0 commit comments