diff options
Diffstat (limited to 'firmware/drivers/fat.c')
-rw-r--r-- | firmware/drivers/fat.c | 165 |
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 */ | ||
119 | static 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 | |||
186 | struct fsinfo { | 119 | struct 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 */ | ||
2230 | static 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 | |||
2281 | int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) | 2168 | int 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; |