aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/hfsplus/unicode.c107
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
242int 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 */
246static 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. */
266static 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
289int 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)