@@ -53,25 +53,22 @@ void SingleFileDrive::onUnplug(void (*cb)(uint32_t), uint32_t cbData) {
5353 _cbUnplugData = cbData;
5454}
5555
56- bool SingleFileDrive::begin (const char *localFile, const char *FILENAME, const char *EXT ) {
56+ bool SingleFileDrive::begin (const char *localFile, const char *dosFile ) {
5757 if (_started) {
5858 return false ;
5959 }
6060 _localFile = strdup (localFile);
61- _FILENAME = strdup (FILENAME);
62- _EXT = strdup (EXT);
61+ _dosFile = strdup (dosFile);
6362 _started = true ;
6463 return true ;
6564}
6665
6766void SingleFileDrive::end () {
6867 _started = false ;
6968 free (_localFile);
70- free (_FILENAME);
71- free (_EXT);
69+ free (_dosFile);
7270 _localFile = nullptr ;
73- _FILENAME = nullptr ;
74- _EXT = nullptr ;
71+ _dosFile = nullptr ;
7572}
7673
7774void SingleFileDrive::bootSector (char buff[512 ]) {
@@ -94,30 +91,85 @@ void SingleFileDrive::bootSector(char buff[512]) {
9491 buff[0x1ff ] = 0xff ;
9592}
9693
94+ static char _toLegalFATChar (char c) {
95+ const char *odds = " !#$%&'()-@^_`{}~" ;
96+ c = toupper (c);
97+ if (((c >= ' 0' ) && (c <= ' 9' )) || ((c >= ' A' ) && (c <= ' Z' )) || strchr (odds, c)) {
98+ return c;
99+ } else {
100+ return ' ~' ;
101+ }
102+ }
103+
97104void SingleFileDrive::directorySector (char buff[512 ]) {
98105 const uint8_t lbl[] = {
99106 0x50 , 0x49 , 0x43 , 0x4f , 0x44 , 0x49 , 0x53 , 0x4b , 0x20 , 0x20 , 0x20 , 0x08 , 0x00 , 0x00 , 0xac , 0x56 ,
100107 0x82 , 0x55 , 0x82 , 0x55 , 0x00 , 0x00 , 0xac , 0x56 , 0x82 , 0x55
101108 }; // , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
102109 memset (buff, 0 , 512 );
103110 memcpy (buff, lbl, sizeof (lbl));
104- // space-pad
105- memset (buff + 32 , ' ' , 8 + 3 );
106- for (int i = 0 ; i < 8 && _FILENAME[i]; i++) {
107- buff[32 + i] = toupper (_FILENAME[i]);
111+ buff += 32 ; // Skip the just-set label
112+
113+ // Create a legal 11-char UPPERCASE FILENAME WITH 0x20 PAD
114+ char SFN[11 ];
115+ memset (SFN, ' ' , 11 );
116+ for (int i = 0 ; (i < 8 ) && _dosFile[i] && (_dosFile[i] != ' .' ); i++) {
117+ SFN[i] = _toLegalFATChar (_dosFile[i]);
118+ }
119+ char *dot = _dosFile + strlen (_dosFile) - 1 ;
120+ while ((dot >= _dosFile) && (*dot != ' .' )) {
121+ dot--;
122+ }
123+ if (*dot == ' .' ) {
124+ dot++;
125+ for (int i = 0 ; (i < 3 ) && dot[i]; i++) {
126+ SFN[8 +i] = _toLegalFATChar (dot[i]);
127+ }
128+ }
129+ uint8_t chksum = 0 ; // for LFN
130+ for (int i = 0 ; i < 11 ; i++) {
131+ chksum = (chksum >> 1 ) + (chksum << 7 ) + SFN[i];
132+ }
133+
134+ // Create LFN structure
135+ int entries = (strlen (_dosFile) + 12 ) / 13 ; // round up
136+ for (int i = 0 ; i < entries; i++) {
137+ *buff++ = (entries - i) | (i == 0 ? 0x40 : 0 );
138+ const char *partname = _dosFile + 13 * (entries - i - 1 );
139+ for (int j=0 ; j<13 ; j++) {
140+ uint16_t u;
141+ if (j > (int )strlen (partname)) {
142+ u = 0xffff ;
143+ } else {
144+ u = partname[j] & 0xff ;
145+ }
146+ *buff++ = u & 0xff ;
147+ *buff++ = (u >> 8 ) & 0xff ;
148+ if (j == 4 ) {
149+ *buff++ = 0x0f ; // LFN ATTR
150+ *buff++ = 0 ;
151+ *buff++ = chksum;
152+ } else if (j == 10 ) {
153+ *buff++ = 0 ;
154+ *buff++ = 0 ;
155+ }
156+ }
108157 }
109- for (int i = 0 ; i < 3 && _EXT[i]; i++) {
110- buff[32 + 8 + i] = toupper (_EXT[i]);
158+
159+ // Create SFN
160+ memset (buff, 0 , 32 );
161+ for (int i = 0 ; i < 11 ; i++) {
162+ buff[i] = SFN[i];
111163 }
112- buff[32 + 0x0b ] = 0x20 ; // ATTR = Archive
164+ buff[0x0b ] = 0x20 ; // ATTR = Archive
113165 // Ignore creation data/time, etc.
114- buff[32 + 0x1a ] = 0x03 ; // Starting cluster 3
166+ buff[0x1a ] = 0x03 ; // Starting cluster 3
115167 File f = LittleFS.open (_localFile, " r" );
116168 int size = f.size ();
117169 f.close ();
118- buff[32 + 0x1c ] = size & 255 ;
119- buff[32 + 0x1d ] = (size >> 8 ) & 255 ;
120- buff[32 + 0x1e ] = (size >> 16 ) & 255 ; // 16MB or smaller
170+ buff[0x1c ] = size & 255 ;
171+ buff[0x1d ] = (size >> 8 ) & 255 ;
172+ buff[0x1e ] = (size >> 16 ) & 255 ; // 16MB or smaller
121173}
122174
123175void SingleFileDrive::fatSector (char fat[512 ]) {
0 commit comments