11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/fs/hfsplus/unicode.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2001 51da177e4SLinus Torvalds * Brad Boyer (flar@allandria.com) 61da177e4SLinus Torvalds * (C) 2003 Ardis Technologies <roman@ardistech.com> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Handler routines for unicode strings 91da177e4SLinus Torvalds */ 101da177e4SLinus Torvalds 111da177e4SLinus Torvalds #include <linux/types.h> 121da177e4SLinus Torvalds #include <linux/nls.h> 131da177e4SLinus Torvalds #include "hfsplus_fs.h" 141da177e4SLinus Torvalds #include "hfsplus_raw.h" 151da177e4SLinus Torvalds 161da177e4SLinus Torvalds /* Fold the case of a unicode char, given the 16 bit value */ 171da177e4SLinus Torvalds /* Returns folded char, or 0 if ignorable */ 181da177e4SLinus Torvalds static inline u16 case_fold(u16 c) 191da177e4SLinus Torvalds { 201da177e4SLinus Torvalds u16 tmp; 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds tmp = hfsplus_case_fold_table[c >> 8]; 231da177e4SLinus Torvalds if (tmp) 241da177e4SLinus Torvalds tmp = hfsplus_case_fold_table[tmp + (c & 0xff)]; 251da177e4SLinus Torvalds else 261da177e4SLinus Torvalds tmp = c; 271da177e4SLinus Torvalds return tmp; 281da177e4SLinus Torvalds } 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds /* Compare unicode strings, return values like normal strcmp */ 312179d372SDavid Elliott int hfsplus_strcasecmp(const struct hfsplus_unistr *s1, 322179d372SDavid Elliott const struct hfsplus_unistr *s2) 331da177e4SLinus Torvalds { 341da177e4SLinus Torvalds u16 len1, len2, c1, c2; 351da177e4SLinus Torvalds const hfsplus_unichr *p1, *p2; 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds len1 = be16_to_cpu(s1->length); 381da177e4SLinus Torvalds len2 = be16_to_cpu(s2->length); 391da177e4SLinus Torvalds p1 = s1->unicode; 401da177e4SLinus Torvalds p2 = s2->unicode; 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds while (1) { 431da177e4SLinus Torvalds c1 = c2 = 0; 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds while (len1 && !c1) { 461da177e4SLinus Torvalds c1 = case_fold(be16_to_cpu(*p1)); 471da177e4SLinus Torvalds p1++; 481da177e4SLinus Torvalds len1--; 491da177e4SLinus Torvalds } 501da177e4SLinus Torvalds while (len2 && !c2) { 511da177e4SLinus Torvalds c2 = case_fold(be16_to_cpu(*p2)); 521da177e4SLinus Torvalds p2++; 531da177e4SLinus Torvalds len2--; 541da177e4SLinus Torvalds } 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds if (c1 != c2) 571da177e4SLinus Torvalds return (c1 < c2) ? -1 : 1; 581da177e4SLinus Torvalds if (!c1 && !c2) 591da177e4SLinus Torvalds return 0; 601da177e4SLinus Torvalds } 611da177e4SLinus Torvalds } 621da177e4SLinus Torvalds 632179d372SDavid Elliott /* Compare names as a sequence of 16-bit unsigned integers */ 642179d372SDavid Elliott int hfsplus_strcmp(const struct hfsplus_unistr *s1, 652179d372SDavid Elliott const struct hfsplus_unistr *s2) 662179d372SDavid Elliott { 672179d372SDavid Elliott u16 len1, len2, c1, c2; 682179d372SDavid Elliott const hfsplus_unichr *p1, *p2; 692179d372SDavid Elliott int len; 702179d372SDavid Elliott 712179d372SDavid Elliott len1 = be16_to_cpu(s1->length); 722179d372SDavid Elliott len2 = be16_to_cpu(s2->length); 732179d372SDavid Elliott p1 = s1->unicode; 742179d372SDavid Elliott p2 = s2->unicode; 752179d372SDavid Elliott 762179d372SDavid Elliott for (len = min(len1, len2); len > 0; len--) { 772179d372SDavid Elliott c1 = be16_to_cpu(*p1); 782179d372SDavid Elliott c2 = be16_to_cpu(*p2); 792179d372SDavid Elliott if (c1 != c2) 802179d372SDavid Elliott return c1 < c2 ? -1 : 1; 812179d372SDavid Elliott p1++; 822179d372SDavid Elliott p2++; 832179d372SDavid Elliott } 842179d372SDavid Elliott 852179d372SDavid Elliott return len1 < len2 ? -1 : 862179d372SDavid Elliott len1 > len2 ? 1 : 0; 872179d372SDavid Elliott } 882179d372SDavid Elliott 892179d372SDavid Elliott 901da177e4SLinus Torvalds #define Hangul_SBase 0xac00 911da177e4SLinus Torvalds #define Hangul_LBase 0x1100 921da177e4SLinus Torvalds #define Hangul_VBase 0x1161 931da177e4SLinus Torvalds #define Hangul_TBase 0x11a7 941da177e4SLinus Torvalds #define Hangul_SCount 11172 951da177e4SLinus Torvalds #define Hangul_LCount 19 961da177e4SLinus Torvalds #define Hangul_VCount 21 971da177e4SLinus Torvalds #define Hangul_TCount 28 981da177e4SLinus Torvalds #define Hangul_NCount (Hangul_VCount * Hangul_TCount) 991da177e4SLinus Torvalds 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds static u16 *hfsplus_compose_lookup(u16 *p, u16 cc) 1021da177e4SLinus Torvalds { 1031da177e4SLinus Torvalds int i, s, e; 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds s = 1; 1061da177e4SLinus Torvalds e = p[1]; 1071da177e4SLinus Torvalds if (!e || cc < p[s * 2] || cc > p[e * 2]) 1081da177e4SLinus Torvalds return NULL; 1091da177e4SLinus Torvalds do { 1101da177e4SLinus Torvalds i = (s + e) / 2; 1111da177e4SLinus Torvalds if (cc > p[i * 2]) 1121da177e4SLinus Torvalds s = i + 1; 1131da177e4SLinus Torvalds else if (cc < p[i * 2]) 1141da177e4SLinus Torvalds e = i - 1; 1151da177e4SLinus Torvalds else 1161da177e4SLinus Torvalds return hfsplus_compose_table + p[i * 2 + 1]; 1171da177e4SLinus Torvalds } while (s <= e); 1181da177e4SLinus Torvalds return NULL; 1191da177e4SLinus Torvalds } 1201da177e4SLinus Torvalds 1212753cc28SAnton Salikhmetov int hfsplus_uni2asc(struct super_block *sb, 1222753cc28SAnton Salikhmetov const struct hfsplus_unistr *ustr, 1232753cc28SAnton Salikhmetov char *astr, int *len_p) 1241da177e4SLinus Torvalds { 1251da177e4SLinus Torvalds const hfsplus_unichr *ip; 126dd73a01aSChristoph Hellwig struct nls_table *nls = HFSPLUS_SB(sb)->nls; 1271da177e4SLinus Torvalds u8 *op; 1281da177e4SLinus Torvalds u16 cc, c0, c1; 1291da177e4SLinus Torvalds u16 *ce1, *ce2; 1301da177e4SLinus Torvalds int i, len, ustrlen, res, compose; 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds op = astr; 1331da177e4SLinus Torvalds ip = ustr->unicode; 1341da177e4SLinus Torvalds ustrlen = be16_to_cpu(ustr->length); 1351da177e4SLinus Torvalds len = *len_p; 1361da177e4SLinus Torvalds ce1 = NULL; 13784adede3SChristoph Hellwig compose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags); 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds while (ustrlen > 0) { 1401da177e4SLinus Torvalds c0 = be16_to_cpu(*ip++); 1411da177e4SLinus Torvalds ustrlen--; 1421da177e4SLinus Torvalds /* search for single decomposed char */ 1431da177e4SLinus Torvalds if (likely(compose)) 1441da177e4SLinus Torvalds ce1 = hfsplus_compose_lookup(hfsplus_compose_table, c0); 1452b4f9ca8SAnton Salikhmetov if (ce1) 1462b4f9ca8SAnton Salikhmetov cc = ce1[0]; 1472b4f9ca8SAnton Salikhmetov else 1482b4f9ca8SAnton Salikhmetov cc = 0; 1492b4f9ca8SAnton Salikhmetov if (cc) { 1501da177e4SLinus Torvalds /* start of a possibly decomposed Hangul char */ 1511da177e4SLinus Torvalds if (cc != 0xffff) 1521da177e4SLinus Torvalds goto done; 1531da177e4SLinus Torvalds if (!ustrlen) 1541da177e4SLinus Torvalds goto same; 1551da177e4SLinus Torvalds c1 = be16_to_cpu(*ip) - Hangul_VBase; 1561da177e4SLinus Torvalds if (c1 < Hangul_VCount) { 1571da177e4SLinus Torvalds /* compose the Hangul char */ 1581da177e4SLinus Torvalds cc = (c0 - Hangul_LBase) * Hangul_VCount; 1591da177e4SLinus Torvalds cc = (cc + c1) * Hangul_TCount; 1601da177e4SLinus Torvalds cc += Hangul_SBase; 1611da177e4SLinus Torvalds ip++; 1621da177e4SLinus Torvalds ustrlen--; 1631da177e4SLinus Torvalds if (!ustrlen) 1641da177e4SLinus Torvalds goto done; 1651da177e4SLinus Torvalds c1 = be16_to_cpu(*ip) - Hangul_TBase; 1661da177e4SLinus Torvalds if (c1 > 0 && c1 < Hangul_TCount) { 1671da177e4SLinus Torvalds cc += c1; 1681da177e4SLinus Torvalds ip++; 1691da177e4SLinus Torvalds ustrlen--; 1701da177e4SLinus Torvalds } 1711da177e4SLinus Torvalds goto done; 1721da177e4SLinus Torvalds } 1731da177e4SLinus Torvalds } 1741da177e4SLinus Torvalds while (1) { 1751da177e4SLinus Torvalds /* main loop for common case of not composed chars */ 1761da177e4SLinus Torvalds if (!ustrlen) 1771da177e4SLinus Torvalds goto same; 1781da177e4SLinus Torvalds c1 = be16_to_cpu(*ip); 1791da177e4SLinus Torvalds if (likely(compose)) 1802753cc28SAnton Salikhmetov ce1 = hfsplus_compose_lookup( 1812753cc28SAnton Salikhmetov hfsplus_compose_table, c1); 1821da177e4SLinus Torvalds if (ce1) 1831da177e4SLinus Torvalds break; 1841da177e4SLinus Torvalds switch (c0) { 1851da177e4SLinus Torvalds case 0: 1861da177e4SLinus Torvalds c0 = 0x2400; 1871da177e4SLinus Torvalds break; 1881da177e4SLinus Torvalds case '/': 1891da177e4SLinus Torvalds c0 = ':'; 1901da177e4SLinus Torvalds break; 1911da177e4SLinus Torvalds } 1921da177e4SLinus Torvalds res = nls->uni2char(c0, op, len); 1931da177e4SLinus Torvalds if (res < 0) { 1941da177e4SLinus Torvalds if (res == -ENAMETOOLONG) 1951da177e4SLinus Torvalds goto out; 1961da177e4SLinus Torvalds *op = '?'; 1971da177e4SLinus Torvalds res = 1; 1981da177e4SLinus Torvalds } 1991da177e4SLinus Torvalds op += res; 2001da177e4SLinus Torvalds len -= res; 2011da177e4SLinus Torvalds c0 = c1; 2021da177e4SLinus Torvalds ip++; 2031da177e4SLinus Torvalds ustrlen--; 2041da177e4SLinus Torvalds } 2051da177e4SLinus Torvalds ce2 = hfsplus_compose_lookup(ce1, c0); 2061da177e4SLinus Torvalds if (ce2) { 2071da177e4SLinus Torvalds i = 1; 2081da177e4SLinus Torvalds while (i < ustrlen) { 2092753cc28SAnton Salikhmetov ce1 = hfsplus_compose_lookup(ce2, 2102753cc28SAnton Salikhmetov be16_to_cpu(ip[i])); 2111da177e4SLinus Torvalds if (!ce1) 2121da177e4SLinus Torvalds break; 2131da177e4SLinus Torvalds i++; 2141da177e4SLinus Torvalds ce2 = ce1; 2151da177e4SLinus Torvalds } 2162b4f9ca8SAnton Salikhmetov cc = ce2[0]; 2172b4f9ca8SAnton Salikhmetov if (cc) { 2181da177e4SLinus Torvalds ip += i; 2191da177e4SLinus Torvalds ustrlen -= i; 2201da177e4SLinus Torvalds goto done; 2211da177e4SLinus Torvalds } 2221da177e4SLinus Torvalds } 2231da177e4SLinus Torvalds same: 2241da177e4SLinus Torvalds switch (c0) { 2251da177e4SLinus Torvalds case 0: 2261da177e4SLinus Torvalds cc = 0x2400; 2271da177e4SLinus Torvalds break; 2281da177e4SLinus Torvalds case '/': 2291da177e4SLinus Torvalds cc = ':'; 2301da177e4SLinus Torvalds break; 2311da177e4SLinus Torvalds default: 2321da177e4SLinus Torvalds cc = c0; 2331da177e4SLinus Torvalds } 2341da177e4SLinus Torvalds done: 2351da177e4SLinus Torvalds res = nls->uni2char(cc, op, len); 2361da177e4SLinus Torvalds if (res < 0) { 2371da177e4SLinus Torvalds if (res == -ENAMETOOLONG) 2381da177e4SLinus Torvalds goto out; 2391da177e4SLinus Torvalds *op = '?'; 2401da177e4SLinus Torvalds res = 1; 2411da177e4SLinus Torvalds } 2421da177e4SLinus Torvalds op += res; 2431da177e4SLinus Torvalds len -= res; 2441da177e4SLinus Torvalds } 2451da177e4SLinus Torvalds res = 0; 2461da177e4SLinus Torvalds out: 2471da177e4SLinus Torvalds *len_p = (char *)op - astr; 2481da177e4SLinus Torvalds return res; 2491da177e4SLinus Torvalds } 2501da177e4SLinus Torvalds 2511e96b7caSDuane Griffin /* 2521e96b7caSDuane Griffin * Convert one or more ASCII characters into a single unicode character. 2531e96b7caSDuane Griffin * Returns the number of ASCII characters corresponding to the unicode char. 2541e96b7caSDuane Griffin */ 2551e96b7caSDuane Griffin static inline int asc2unichar(struct super_block *sb, const char *astr, int len, 2561e96b7caSDuane Griffin wchar_t *uc) 2571da177e4SLinus Torvalds { 258dd73a01aSChristoph Hellwig int size = HFSPLUS_SB(sb)->nls->char2uni(astr, len, uc); 2591da177e4SLinus Torvalds if (size <= 0) { 2601e96b7caSDuane Griffin *uc = '?'; 2611da177e4SLinus Torvalds size = 1; 2621da177e4SLinus Torvalds } 2631e96b7caSDuane Griffin switch (*uc) { 2641da177e4SLinus Torvalds case 0x2400: 2651e96b7caSDuane Griffin *uc = 0; 2661da177e4SLinus Torvalds break; 2671da177e4SLinus Torvalds case ':': 2681e96b7caSDuane Griffin *uc = '/'; 2691da177e4SLinus Torvalds break; 2701da177e4SLinus Torvalds } 2711e96b7caSDuane Griffin return size; 2721da177e4SLinus Torvalds } 2731e96b7caSDuane Griffin 2741e96b7caSDuane Griffin /* Decomposes a single unicode character. */ 2751e96b7caSDuane Griffin static inline u16 *decompose_unichar(wchar_t uc, int *size) 2761e96b7caSDuane Griffin { 2771e96b7caSDuane Griffin int off; 2781e96b7caSDuane Griffin 2791e96b7caSDuane Griffin off = hfsplus_decompose_table[(uc >> 12) & 0xf]; 2801e96b7caSDuane Griffin if (off == 0 || off == 0xffff) 2811e96b7caSDuane Griffin return NULL; 2821e96b7caSDuane Griffin 2831e96b7caSDuane Griffin off = hfsplus_decompose_table[off + ((uc >> 8) & 0xf)]; 2841da177e4SLinus Torvalds if (!off) 2851e96b7caSDuane Griffin return NULL; 2861e96b7caSDuane Griffin 2871e96b7caSDuane Griffin off = hfsplus_decompose_table[off + ((uc >> 4) & 0xf)]; 2881da177e4SLinus Torvalds if (!off) 2891e96b7caSDuane Griffin return NULL; 2901e96b7caSDuane Griffin 2911e96b7caSDuane Griffin off = hfsplus_decompose_table[off + (uc & 0xf)]; 2921e96b7caSDuane Griffin *size = off & 3; 2931e96b7caSDuane Griffin if (*size == 0) 2941e96b7caSDuane Griffin return NULL; 2951e96b7caSDuane Griffin return hfsplus_decompose_table + (off / 4); 2961e96b7caSDuane Griffin } 2971e96b7caSDuane Griffin 298324ef39aSVyacheslav Dubeyko int hfsplus_asc2uni(struct super_block *sb, 299324ef39aSVyacheslav Dubeyko struct hfsplus_unistr *ustr, int max_unistr_len, 3001e96b7caSDuane Griffin const char *astr, int len) 3011e96b7caSDuane Griffin { 3021e96b7caSDuane Griffin int size, dsize, decompose; 3031e96b7caSDuane Griffin u16 *dstr, outlen = 0; 3041e96b7caSDuane Griffin wchar_t c; 3051e96b7caSDuane Griffin 30684adede3SChristoph Hellwig decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags); 307324ef39aSVyacheslav Dubeyko while (outlen < max_unistr_len && len > 0) { 3081e96b7caSDuane Griffin size = asc2unichar(sb, astr, len, &c); 3091e96b7caSDuane Griffin 3102b4f9ca8SAnton Salikhmetov if (decompose) 3112b4f9ca8SAnton Salikhmetov dstr = decompose_unichar(c, &dsize); 3122b4f9ca8SAnton Salikhmetov else 3132b4f9ca8SAnton Salikhmetov dstr = NULL; 3142b4f9ca8SAnton Salikhmetov if (dstr) { 315324ef39aSVyacheslav Dubeyko if (outlen + dsize > max_unistr_len) 3161da177e4SLinus Torvalds break; 3171da177e4SLinus Torvalds do { 3181e96b7caSDuane Griffin ustr->unicode[outlen++] = cpu_to_be16(*dstr++); 3191e96b7caSDuane Griffin } while (--dsize > 0); 3201e96b7caSDuane Griffin } else 3211da177e4SLinus Torvalds ustr->unicode[outlen++] = cpu_to_be16(c); 3221e96b7caSDuane Griffin 3231e96b7caSDuane Griffin astr += size; 3241e96b7caSDuane Griffin len -= size; 3251da177e4SLinus Torvalds } 3261da177e4SLinus Torvalds ustr->length = cpu_to_be16(outlen); 3271da177e4SLinus Torvalds if (len > 0) 3281da177e4SLinus Torvalds return -ENAMETOOLONG; 3291da177e4SLinus Torvalds return 0; 3301da177e4SLinus Torvalds } 331d45bce8fSDuane Griffin 332d45bce8fSDuane Griffin /* 333d45bce8fSDuane Griffin * Hash a string to an integer as appropriate for the HFS+ filesystem. 334d45bce8fSDuane Griffin * Composed unicode characters are decomposed and case-folding is performed 335d45bce8fSDuane Griffin * if the appropriate bits are (un)set on the superblock. 336d45bce8fSDuane Griffin */ 337b1e6a015SNick Piggin int hfsplus_hash_dentry(const struct dentry *dentry, const struct inode *inode, 338b1e6a015SNick Piggin struct qstr *str) 339d45bce8fSDuane Griffin { 340d45bce8fSDuane Griffin struct super_block *sb = dentry->d_sb; 341d45bce8fSDuane Griffin const char *astr; 342d45bce8fSDuane Griffin const u16 *dstr; 3438aa84ab9SAndrew Morton int casefold, decompose, size, len; 344d45bce8fSDuane Griffin unsigned long hash; 345d45bce8fSDuane Griffin wchar_t c; 346d45bce8fSDuane Griffin u16 c2; 347d45bce8fSDuane Griffin 34884adede3SChristoph Hellwig casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags); 34984adede3SChristoph Hellwig decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags); 350d45bce8fSDuane Griffin hash = init_name_hash(); 351d45bce8fSDuane Griffin astr = str->name; 352d45bce8fSDuane Griffin len = str->len; 353d45bce8fSDuane Griffin while (len > 0) { 3548aa84ab9SAndrew Morton int uninitialized_var(dsize); 355d45bce8fSDuane Griffin size = asc2unichar(sb, astr, len, &c); 356d45bce8fSDuane Griffin astr += size; 357d45bce8fSDuane Griffin len -= size; 358d45bce8fSDuane Griffin 3592b4f9ca8SAnton Salikhmetov if (decompose) 3602b4f9ca8SAnton Salikhmetov dstr = decompose_unichar(c, &dsize); 3612b4f9ca8SAnton Salikhmetov else 3622b4f9ca8SAnton Salikhmetov dstr = NULL; 3632b4f9ca8SAnton Salikhmetov if (dstr) { 364d45bce8fSDuane Griffin do { 365d45bce8fSDuane Griffin c2 = *dstr++; 3662b4f9ca8SAnton Salikhmetov if (casefold) 3672b4f9ca8SAnton Salikhmetov c2 = case_fold(c2); 3682b4f9ca8SAnton Salikhmetov if (!casefold || c2) 369d45bce8fSDuane Griffin hash = partial_name_hash(c2, hash); 370d45bce8fSDuane Griffin } while (--dsize > 0); 371d45bce8fSDuane Griffin } else { 372d45bce8fSDuane Griffin c2 = c; 3732b4f9ca8SAnton Salikhmetov if (casefold) 3742b4f9ca8SAnton Salikhmetov c2 = case_fold(c2); 3752b4f9ca8SAnton Salikhmetov if (!casefold || c2) 376d45bce8fSDuane Griffin hash = partial_name_hash(c2, hash); 377d45bce8fSDuane Griffin } 378d45bce8fSDuane Griffin } 379d45bce8fSDuane Griffin str->hash = end_name_hash(hash); 380d45bce8fSDuane Griffin 381d45bce8fSDuane Griffin return 0; 382d45bce8fSDuane Griffin } 383d45bce8fSDuane Griffin 384d45bce8fSDuane Griffin /* 385d45bce8fSDuane Griffin * Compare strings with HFS+ filename ordering. 386d45bce8fSDuane Griffin * Composed unicode characters are decomposed and case-folding is performed 387d45bce8fSDuane Griffin * if the appropriate bits are (un)set on the superblock. 388d45bce8fSDuane Griffin */ 389621e155aSNick Piggin int hfsplus_compare_dentry(const struct dentry *parent, 390621e155aSNick Piggin const struct inode *pinode, 391621e155aSNick Piggin const struct dentry *dentry, const struct inode *inode, 392621e155aSNick Piggin unsigned int len, const char *str, const struct qstr *name) 393d45bce8fSDuane Griffin { 394621e155aSNick Piggin struct super_block *sb = parent->d_sb; 395d45bce8fSDuane Griffin int casefold, decompose, size; 396d45bce8fSDuane Griffin int dsize1, dsize2, len1, len2; 397d45bce8fSDuane Griffin const u16 *dstr1, *dstr2; 398d45bce8fSDuane Griffin const char *astr1, *astr2; 399d45bce8fSDuane Griffin u16 c1, c2; 400d45bce8fSDuane Griffin wchar_t c; 401d45bce8fSDuane Griffin 40284adede3SChristoph Hellwig casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags); 40384adede3SChristoph Hellwig decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags); 404621e155aSNick Piggin astr1 = str; 405621e155aSNick Piggin len1 = len; 406621e155aSNick Piggin astr2 = name->name; 407621e155aSNick Piggin len2 = name->len; 408d45bce8fSDuane Griffin dsize1 = dsize2 = 0; 409d45bce8fSDuane Griffin dstr1 = dstr2 = NULL; 410d45bce8fSDuane Griffin 411d45bce8fSDuane Griffin while (len1 > 0 && len2 > 0) { 412d45bce8fSDuane Griffin if (!dsize1) { 413d45bce8fSDuane Griffin size = asc2unichar(sb, astr1, len1, &c); 414d45bce8fSDuane Griffin astr1 += size; 415d45bce8fSDuane Griffin len1 -= size; 416d45bce8fSDuane Griffin 4172753cc28SAnton Salikhmetov if (decompose) 4182753cc28SAnton Salikhmetov dstr1 = decompose_unichar(c, &dsize1); 4192753cc28SAnton Salikhmetov if (!decompose || !dstr1) { 420d45bce8fSDuane Griffin c1 = c; 421d45bce8fSDuane Griffin dstr1 = &c1; 422d45bce8fSDuane Griffin dsize1 = 1; 423d45bce8fSDuane Griffin } 424d45bce8fSDuane Griffin } 425d45bce8fSDuane Griffin 426d45bce8fSDuane Griffin if (!dsize2) { 427d45bce8fSDuane Griffin size = asc2unichar(sb, astr2, len2, &c); 428d45bce8fSDuane Griffin astr2 += size; 429d45bce8fSDuane Griffin len2 -= size; 430d45bce8fSDuane Griffin 4312753cc28SAnton Salikhmetov if (decompose) 4322753cc28SAnton Salikhmetov dstr2 = decompose_unichar(c, &dsize2); 4332753cc28SAnton Salikhmetov if (!decompose || !dstr2) { 434d45bce8fSDuane Griffin c2 = c; 435d45bce8fSDuane Griffin dstr2 = &c2; 436d45bce8fSDuane Griffin dsize2 = 1; 437d45bce8fSDuane Griffin } 438d45bce8fSDuane Griffin } 439d45bce8fSDuane Griffin 440d45bce8fSDuane Griffin c1 = *dstr1; 441d45bce8fSDuane Griffin c2 = *dstr2; 442d45bce8fSDuane Griffin if (casefold) { 4432b4f9ca8SAnton Salikhmetov c1 = case_fold(c1); 4442b4f9ca8SAnton Salikhmetov if (!c1) { 445d45bce8fSDuane Griffin dstr1++; 446d45bce8fSDuane Griffin dsize1--; 447d45bce8fSDuane Griffin continue; 448d45bce8fSDuane Griffin } 4492b4f9ca8SAnton Salikhmetov c2 = case_fold(c2); 4502b4f9ca8SAnton Salikhmetov if (!c2) { 451d45bce8fSDuane Griffin dstr2++; 452d45bce8fSDuane Griffin dsize2--; 453d45bce8fSDuane Griffin continue; 454d45bce8fSDuane Griffin } 455d45bce8fSDuane Griffin } 456d45bce8fSDuane Griffin if (c1 < c2) 457d45bce8fSDuane Griffin return -1; 458d45bce8fSDuane Griffin else if (c1 > c2) 459d45bce8fSDuane Griffin return 1; 460d45bce8fSDuane Griffin 461d45bce8fSDuane Griffin dstr1++; 462d45bce8fSDuane Griffin dsize1--; 463d45bce8fSDuane Griffin dstr2++; 464d45bce8fSDuane Griffin dsize2--; 465d45bce8fSDuane Griffin } 466d45bce8fSDuane Griffin 467d45bce8fSDuane Griffin if (len1 < len2) 468d45bce8fSDuane Griffin return -1; 469d45bce8fSDuane Griffin if (len1 > len2) 470d45bce8fSDuane Griffin return 1; 471d45bce8fSDuane Griffin return 0; 472d45bce8fSDuane Griffin } 473