diff options
-rw-r--r-- | fs/hfsplus/unicode.c | 107 |
1 files changed, 62 insertions, 45 deletions
diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c index 689c8bd721fb..5df0052b2775 100644 --- a/fs/hfsplus/unicode.c +++ b/fs/hfsplus/unicode.c | |||
@@ -239,58 +239,75 @@ out: | |||
239 | return res; | 239 | return res; |
240 | } | 240 | } |
241 | 241 | ||
242 | int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, const char *astr, int len) | 242 | /* |
243 | * Convert one or more ASCII characters into a single unicode character. | ||
244 | * Returns the number of ASCII characters corresponding to the unicode char. | ||
245 | */ | ||
246 | static inline int asc2unichar(struct super_block *sb, const char *astr, int len, | ||
247 | wchar_t *uc) | ||
243 | { | 248 | { |
244 | struct nls_table *nls = HFSPLUS_SB(sb).nls; | 249 | int size = HFSPLUS_SB(sb).nls->char2uni(astr, len, uc); |
245 | int size, off, decompose; | 250 | if (size <= 0) { |
251 | *uc = '?'; | ||
252 | size = 1; | ||
253 | } | ||
254 | switch (*uc) { | ||
255 | case 0x2400: | ||
256 | *uc = 0; | ||
257 | break; | ||
258 | case ':': | ||
259 | *uc = '/'; | ||
260 | break; | ||
261 | } | ||
262 | return size; | ||
263 | } | ||
264 | |||
265 | /* Decomposes a single unicode character. */ | ||
266 | static inline u16 *decompose_unichar(wchar_t uc, int *size) | ||
267 | { | ||
268 | int off; | ||
269 | |||
270 | off = hfsplus_decompose_table[(uc >> 12) & 0xf]; | ||
271 | if (off == 0 || off == 0xffff) | ||
272 | return NULL; | ||
273 | |||
274 | off = hfsplus_decompose_table[off + ((uc >> 8) & 0xf)]; | ||
275 | if (!off) | ||
276 | return NULL; | ||
277 | |||
278 | off = hfsplus_decompose_table[off + ((uc >> 4) & 0xf)]; | ||
279 | if (!off) | ||
280 | return NULL; | ||
281 | |||
282 | off = hfsplus_decompose_table[off + (uc & 0xf)]; | ||
283 | *size = off & 3; | ||
284 | if (*size == 0) | ||
285 | return NULL; | ||
286 | return hfsplus_decompose_table + (off / 4); | ||
287 | } | ||
288 | |||
289 | int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, | ||
290 | const char *astr, int len) | ||
291 | { | ||
292 | int size, dsize, decompose; | ||
293 | u16 *dstr, outlen = 0; | ||
246 | wchar_t c; | 294 | wchar_t c; |
247 | u16 outlen = 0; | ||
248 | 295 | ||
249 | decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE); | 296 | decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE); |
250 | |||
251 | while (outlen < HFSPLUS_MAX_STRLEN && len > 0) { | 297 | while (outlen < HFSPLUS_MAX_STRLEN && len > 0) { |
252 | size = nls->char2uni(astr, len, &c); | 298 | size = asc2unichar(sb, astr, len, &c); |
253 | if (size <= 0) { | 299 | |
254 | c = '?'; | 300 | if (decompose && (dstr = decompose_unichar(c, &dsize))) { |
255 | size = 1; | 301 | if (outlen + dsize > HFSPLUS_MAX_STRLEN) |
256 | } | ||
257 | astr += size; | ||
258 | len -= size; | ||
259 | switch (c) { | ||
260 | case 0x2400: | ||
261 | c = 0; | ||
262 | break; | ||
263 | case ':': | ||
264 | c = '/'; | ||
265 | break; | ||
266 | } | ||
267 | if (c >= 0xc0 && decompose) { | ||
268 | off = hfsplus_decompose_table[(c >> 12) & 0xf]; | ||
269 | if (!off) | ||
270 | goto done; | ||
271 | if (off == 0xffff) { | ||
272 | goto done; | ||
273 | } | ||
274 | off = hfsplus_decompose_table[off + ((c >> 8) & 0xf)]; | ||
275 | if (!off) | ||
276 | goto done; | ||
277 | off = hfsplus_decompose_table[off + ((c >> 4) & 0xf)]; | ||
278 | if (!off) | ||
279 | goto done; | ||
280 | off = hfsplus_decompose_table[off + (c & 0xf)]; | ||
281 | size = off & 3; | ||
282 | if (!size) | ||
283 | goto done; | ||
284 | off /= 4; | ||
285 | if (outlen + size > HFSPLUS_MAX_STRLEN) | ||
286 | break; | 302 | break; |
287 | do { | 303 | do { |
288 | ustr->unicode[outlen++] = cpu_to_be16(hfsplus_decompose_table[off++]); | 304 | ustr->unicode[outlen++] = cpu_to_be16(*dstr++); |
289 | } while (--size > 0); | 305 | } while (--dsize > 0); |
290 | continue; | 306 | } else |
291 | } | 307 | ustr->unicode[outlen++] = cpu_to_be16(c); |
292 | done: | 308 | |
293 | ustr->unicode[outlen++] = cpu_to_be16(c); | 309 | astr += size; |
310 | len -= size; | ||
294 | } | 311 | } |
295 | ustr->length = cpu_to_be16(outlen); | 312 | ustr->length = cpu_to_be16(outlen); |
296 | if (len > 0) | 313 | if (len > 0) |