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.c165
1 files changed, 24 insertions, 141 deletions
diff --git a/firmware/drivers/fat.c b/firmware/drivers/fat.c
index fd09bff0da..559d00b2b9 100644
--- a/firmware/drivers/fat.c
+++ b/firmware/drivers/fat.c
@@ -28,6 +28,7 @@
28#include "system.h" 28#include "system.h"
29#include "timefuncs.h" 29#include "timefuncs.h"
30#include "kernel.h" 30#include "kernel.h"
31#include "rbunicode.h"
31 32
32#define BYTES2INT16(array,pos) \ 33#define BYTES2INT16(array,pos) \
33 (array[pos] | (array[pos+1] << 8 )) 34 (array[pos] | (array[pos+1] << 8 ))
@@ -115,74 +116,6 @@
115#define FAT_BAD_MARK 0x0ffffff7 116#define FAT_BAD_MARK 0x0ffffff7
116#define FAT_EOF_MARK 0x0ffffff8 117#define FAT_EOF_MARK 0x0ffffff8
117 118
118/* filename charset conversion table */
119static const unsigned char unicode2iso8859_2[] = {
120 0x00, 0x00, 0xc3, 0xe3, 0xa1, 0xb1, 0xc6, 0xe6, /* 0x0100 */
121 0x00, 0x00, 0x00, 0x00, 0xc8, 0xe8, 0xcf, 0xef, /* 0x0108 */
122 0xd0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0110 */
123 0xca, 0xea, 0xcc, 0xec, 0x00, 0x00, 0x00, 0x00, /* 0x0118 */
124 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0120 */
125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0128 */
126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0130 */
127 0x00, 0xc5, 0xe5, 0x00, 0x00, 0xa5, 0xb5, 0x00, /* 0x0138 */
128 0x00, 0xa3, 0xb3, 0xd1, 0xf1, 0x00, 0x00, 0xd2, /* 0x0140 */
129 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0148 */
130 0xd5, 0xf5, 0x00, 0x00, 0xc0, 0xe0, 0x00, 0x00, /* 0x0150 */
131 0xd8, 0xf8, 0xa6, 0xb6, 0x00, 0x00, 0xaa, 0xba, /* 0x0158 */
132 0xa9, 0xb9, 0xde, 0xfe, 0xab, 0xbb, 0x00, 0x00, /* 0x0160 */
133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0xf9, /* 0x0168 */
134 0xdb, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0170 */
135 0x00, 0xac, 0xbc, 0xaf, 0xbf, 0xae, 0xbe, 0x00, /* 0x0178 */
136 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0180 */
137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0188 */
138 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0190 */
139 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0198 */
140 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01a0 */
141 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01a8 */
142 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01b0 */
143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01b8 */
144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01c0 */
145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01c8 */
146 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01d0 */
147 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01d8 */
148 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01e0 */
149 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01e8 */
150 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01f0 */
151 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01f8 */
152 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0200 */
153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0208 */
154 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0210 */
155 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0218 */
156 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0220 */
157 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0228 */
158 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0230 */
159 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0238 */
160 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0240 */
161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0248 */
162 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0250 */
163 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0258 */
164 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0260 */
165 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0268 */
166 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0270 */
167 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0278 */
168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0280 */
169 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0288 */
170 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0290 */
171 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0298 */
172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02a0 */
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02a8 */
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02b0 */
175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02b8 */
176 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, /* 0x02c0 */
177 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02c8 */
178 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02d0 */
179 0xa2, 0xff, 0x00, 0xb2, 0x00, 0xbd, 0x00, 0x00, /* 0x02d8 */
180 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02e0 */
181 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02e8 */
182 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02f0 */
183 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* 0x02f8 */
184};
185
186struct fsinfo { 119struct fsinfo {
187 unsigned long freecount; /* last known free cluster count */ 120 unsigned long freecount; /* last known free cluster count */
188 unsigned long nextfree; /* first cluster to start looking for free 121 unsigned long nextfree; /* first cluster to start looking for free
@@ -1106,10 +1039,11 @@ static int write_long_name(struct fat_file* file,
1106 unsigned char* entry; 1039 unsigned char* entry;
1107 unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR; 1040 unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
1108 unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR; 1041 unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1109 unsigned int i, j=0;
1110 unsigned char chksum = 0; 1042 unsigned char chksum = 0;
1111 int nameidx=0, namelen = strlen(name); 1043 unsigned int i, j=0;
1044 unsigned int nameidx=0, namelen = utf8length(name);
1112 int rc; 1045 int rc;
1046 unsigned short name_utf16[namelen + 1];
1113 1047
1114 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n", 1048 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
1115 file->firstcluster, firstentry, numentries, name); 1049 file->firstcluster, firstentry, numentries, name);
@@ -1132,6 +1066,11 @@ static int write_long_name(struct fat_file* file,
1132 nameidx < (namelen - NAME_BYTES_PER_ENTRY); 1066 nameidx < (namelen - NAME_BYTES_PER_ENTRY);
1133 nameidx += NAME_BYTES_PER_ENTRY); 1067 nameidx += NAME_BYTES_PER_ENTRY);
1134 1068
1069 /* we need to convert the name first */
1070 /* since it is written in reverse order */
1071 for (i = 0; i <= namelen; i++)
1072 name = utf8decode(name, &name_utf16[i]);
1073
1135 for (i=0; i < numentries; i++) { 1074 for (i=0; i < numentries; i++) {
1136 /* new sector? */ 1075 /* new sector? */
1137 if ( idx >= DIR_ENTRIES_PER_SECTOR ) { 1076 if ( idx >= DIR_ENTRIES_PER_SECTOR ) {
@@ -1170,7 +1109,7 @@ static int write_long_name(struct fat_file* file,
1170 memset(entry, 0, DIR_ENTRY_SIZE); 1109 memset(entry, 0, DIR_ENTRY_SIZE);
1171 if ( i+1 < numentries ) { 1110 if ( i+1 < numentries ) {
1172 /* longname entry */ 1111 /* longname entry */
1173 int k, l = nameidx; 1112 unsigned int k, l = nameidx;
1174 1113
1175 entry[FATLONG_ORDER] = numentries-i-1; 1114 entry[FATLONG_ORDER] = numentries-i-1;
1176 if (i==0) { 1115 if (i==0) {
@@ -1178,22 +1117,22 @@ static int write_long_name(struct fat_file* file,
1178 entry[FATLONG_ORDER] |= 0x40; 1117 entry[FATLONG_ORDER] |= 0x40;
1179 1118
1180 /* pad name with 0xffff */ 1119 /* pad name with 0xffff */
1181 for (k=1; k<12; k++) entry[k] = 0xff; 1120 for (k=1; k<11; k++) entry[k] = 0xff;
1182 for (k=14; k<26; k++) entry[k] = 0xff; 1121 for (k=14; k<26; k++) entry[k] = 0xff;
1183 for (k=28; k<32; k++) entry[k] = 0xff; 1122 for (k=28; k<32; k++) entry[k] = 0xff;
1184 }; 1123 };
1185 /* set name */ 1124 /* set name */
1186 for (k=0; k<5 && l <= namelen; k++) { 1125 for (k=0; k<5 && l <= namelen; k++) {
1187 entry[k*2 + 1] = name[l++]; 1126 entry[k*2 + 1] = (unsigned char)(name_utf16[l] & 0xff);
1188 entry[k*2 + 2] = 0; 1127 entry[k*2 + 2] = (unsigned char)(name_utf16[l++] >> 8);
1189 } 1128 }
1190 for (k=0; k<6 && l <= namelen; k++) { 1129 for (k=0; k<6 && l <= namelen; k++) {
1191 entry[k*2 + 14] = name[l++]; 1130 entry[k*2 + 14] = (unsigned char)(name_utf16[l] & 0xff);
1192 entry[k*2 + 15] = 0; 1131 entry[k*2 + 15] = (unsigned char)(name_utf16[l++] >> 8);
1193 } 1132 }
1194 for (k=0; k<2 && l <= namelen; k++) { 1133 for (k=0; k<2 && l <= namelen; k++) {
1195 entry[k*2 + 28] = name[l++]; 1134 entry[k*2 + 28] = (unsigned char)(name_utf16[l] & 0xff);
1196 entry[k*2 + 29] = 0; 1135 entry[k*2 + 29] = (unsigned char)(name_utf16[l++] >> 8);
1197 } 1136 }
1198 1137
1199 entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME; 1138 entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME;
@@ -1291,7 +1230,7 @@ static int add_dir_entry(struct fat_dir* dir,
1291 1230
1292 /* one dir entry needed for every 13 bytes of filename, 1231 /* one dir entry needed for every 13 bytes of filename,
1293 plus one entry for the short name */ 1232 plus one entry for the short name */
1294 entries_needed = (strlen(name) + (NAME_BYTES_PER_ENTRY-1)) 1233 entries_needed = (utf8length(name) + (NAME_BYTES_PER_ENTRY-1))
1295 / NAME_BYTES_PER_ENTRY + 1; 1234 / NAME_BYTES_PER_ENTRY + 1;
1296 } 1235 }
1297 1236
@@ -2226,58 +2165,6 @@ int fat_opendir(IF_MV2(int volume,)
2226 return 0; 2165 return 0;
2227} 2166}
2228 2167
2229/* convert from unicode to a single-byte charset */
2230static void unicode2iso(const unsigned char* unicode, unsigned char* iso,
2231 int count)
2232{
2233 int i;
2234
2235 for (i=0; i<count; i++) {
2236 int x = i*2;
2237 switch (unicode[x+1]) {
2238 case 0x01: /* latin extended. convert to ISO 8859-2 */
2239 case 0x02:
2240 iso[i] = unicode2iso8859_2[unicode[x]];
2241 break;
2242
2243 case 0x03: /* greek, convert to ISO 8859-7 */
2244 iso[i] = unicode[x] + 0x30;
2245 break;
2246
2247 /* Sergei says most russians use Win1251, so we will too.
2248 Win1251 differs from ISO 8859-5 by an offset of 0x10. */
2249 case 0x04: /* cyrillic, convert to Win1251 */
2250 switch (unicode[x]) {
2251 case 1:
2252 iso[i] = 168;
2253 break;
2254
2255 case 81:
2256 iso[i] = 184;
2257 break;
2258
2259 default:
2260 iso[i] = unicode[x] + 0xb0; /* 0xa0 for ISO 8859-5 */
2261 break;
2262 }
2263 break;
2264
2265 case 0x05: /* hebrew, convert to ISO 8859-8 */
2266 iso[i] = unicode[x] + 0x10;
2267 break;
2268
2269 case 0x06: /* arabic, convert to ISO 8859-6 */
2270 case 0x0e: /* thai, convert to ISO 8859-11 */
2271 iso[i] = unicode[x] + 0xa0;
2272 break;
2273
2274 default:
2275 iso[i] = unicode[x];
2276 break;
2277 }
2278 }
2279}
2280
2281int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) 2168int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2282{ 2169{
2283 bool done = false; 2170 bool done = false;
@@ -2348,7 +2235,8 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2348 2235
2349 /* replace shortname with longname? */ 2236 /* replace shortname with longname? */
2350 if ( longs ) { 2237 if ( longs ) {
2351 int j,l=0; 2238 int j;
2239 unsigned char* utf8 = entry->name;
2352 /* iterate backwards through the dir entries */ 2240 /* iterate backwards through the dir entries */
2353 for (j=longs-1; j>=0; j--) { 2241 for (j=longs-1; j>=0; j--) {
2354 unsigned char* ptr = cached_buf; 2242 unsigned char* ptr = cached_buf;
@@ -2370,16 +2258,11 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2370 index &= SECTOR_SIZE-1; 2258 index &= SECTOR_SIZE-1;
2371 } 2259 }
2372 2260
2373 /* names are stored in unicode, but we 2261 utf8 = utf16LEdecode(ptr + index + 1, utf8, 5);
2374 only grab the low byte (iso8859-1). */ 2262 utf8 = utf16LEdecode(ptr + index + 14, utf8, 6);
2375 unicode2iso(ptr + index + 1, entry->name + l, 5); 2263 utf8 = utf16LEdecode(ptr + index + 28, utf8, 2);
2376 l+= 5;
2377 unicode2iso(ptr + index + 14, entry->name + l, 6);
2378 l+= 6;
2379 unicode2iso(ptr + index + 28, entry->name + l, 2);
2380 l+= 2;
2381 } 2264 }
2382 entry->name[l]=0; 2265 *utf8 = 0;
2383 } 2266 }
2384 done = true; 2267 done = true;
2385 sectoridx = 0; 2268 sectoridx = 0;