1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * linux/fs/hfsplus/unicode.c
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Copyright (C) 2001
61da177e4SLinus Torvalds * Brad Boyer (flar@allandria.com)
71da177e4SLinus Torvalds * (C) 2003 Ardis Technologies <roman@ardistech.com>
81da177e4SLinus Torvalds *
91da177e4SLinus Torvalds * Handler routines for unicode strings
101da177e4SLinus Torvalds */
111da177e4SLinus Torvalds
121da177e4SLinus Torvalds #include <linux/types.h>
131da177e4SLinus Torvalds #include <linux/nls.h>
141da177e4SLinus Torvalds #include "hfsplus_fs.h"
151da177e4SLinus Torvalds #include "hfsplus_raw.h"
161da177e4SLinus Torvalds
171da177e4SLinus Torvalds /* Fold the case of a unicode char, given the 16 bit value */
181da177e4SLinus Torvalds /* Returns folded char, or 0 if ignorable */
case_fold(u16 c)191da177e4SLinus Torvalds static inline u16 case_fold(u16 c)
201da177e4SLinus Torvalds {
211da177e4SLinus Torvalds u16 tmp;
221da177e4SLinus Torvalds
231da177e4SLinus Torvalds tmp = hfsplus_case_fold_table[c >> 8];
241da177e4SLinus Torvalds if (tmp)
251da177e4SLinus Torvalds tmp = hfsplus_case_fold_table[tmp + (c & 0xff)];
261da177e4SLinus Torvalds else
271da177e4SLinus Torvalds tmp = c;
281da177e4SLinus Torvalds return tmp;
291da177e4SLinus Torvalds }
301da177e4SLinus Torvalds
311da177e4SLinus Torvalds /* Compare unicode strings, return values like normal strcmp */
hfsplus_strcasecmp(const struct hfsplus_unistr * s1,const struct hfsplus_unistr * s2)322179d372SDavid Elliott int hfsplus_strcasecmp(const struct hfsplus_unistr *s1,
332179d372SDavid Elliott const struct hfsplus_unistr *s2)
341da177e4SLinus Torvalds {
351da177e4SLinus Torvalds u16 len1, len2, c1, c2;
361da177e4SLinus Torvalds const hfsplus_unichr *p1, *p2;
371da177e4SLinus Torvalds
381da177e4SLinus Torvalds len1 = be16_to_cpu(s1->length);
391da177e4SLinus Torvalds len2 = be16_to_cpu(s2->length);
401da177e4SLinus Torvalds p1 = s1->unicode;
411da177e4SLinus Torvalds p2 = s2->unicode;
421da177e4SLinus Torvalds
431da177e4SLinus Torvalds while (1) {
441da177e4SLinus Torvalds c1 = c2 = 0;
451da177e4SLinus Torvalds
461da177e4SLinus Torvalds while (len1 && !c1) {
471da177e4SLinus Torvalds c1 = case_fold(be16_to_cpu(*p1));
481da177e4SLinus Torvalds p1++;
491da177e4SLinus Torvalds len1--;
501da177e4SLinus Torvalds }
511da177e4SLinus Torvalds while (len2 && !c2) {
521da177e4SLinus Torvalds c2 = case_fold(be16_to_cpu(*p2));
531da177e4SLinus Torvalds p2++;
541da177e4SLinus Torvalds len2--;
551da177e4SLinus Torvalds }
561da177e4SLinus Torvalds
571da177e4SLinus Torvalds if (c1 != c2)
581da177e4SLinus Torvalds return (c1 < c2) ? -1 : 1;
591da177e4SLinus Torvalds if (!c1 && !c2)
601da177e4SLinus Torvalds return 0;
611da177e4SLinus Torvalds }
621da177e4SLinus Torvalds }
631da177e4SLinus Torvalds
642179d372SDavid Elliott /* Compare names as a sequence of 16-bit unsigned integers */
hfsplus_strcmp(const struct hfsplus_unistr * s1,const struct hfsplus_unistr * s2)652179d372SDavid Elliott int hfsplus_strcmp(const struct hfsplus_unistr *s1,
662179d372SDavid Elliott const struct hfsplus_unistr *s2)
672179d372SDavid Elliott {
682179d372SDavid Elliott u16 len1, len2, c1, c2;
692179d372SDavid Elliott const hfsplus_unichr *p1, *p2;
702179d372SDavid Elliott int len;
712179d372SDavid Elliott
722179d372SDavid Elliott len1 = be16_to_cpu(s1->length);
732179d372SDavid Elliott len2 = be16_to_cpu(s2->length);
742179d372SDavid Elliott p1 = s1->unicode;
752179d372SDavid Elliott p2 = s2->unicode;
762179d372SDavid Elliott
772179d372SDavid Elliott for (len = min(len1, len2); len > 0; len--) {
782179d372SDavid Elliott c1 = be16_to_cpu(*p1);
792179d372SDavid Elliott c2 = be16_to_cpu(*p2);
802179d372SDavid Elliott if (c1 != c2)
812179d372SDavid Elliott return c1 < c2 ? -1 : 1;
822179d372SDavid Elliott p1++;
832179d372SDavid Elliott p2++;
842179d372SDavid Elliott }
852179d372SDavid Elliott
862179d372SDavid Elliott return len1 < len2 ? -1 :
872179d372SDavid Elliott len1 > len2 ? 1 : 0;
882179d372SDavid Elliott }
892179d372SDavid Elliott
902179d372SDavid Elliott
911da177e4SLinus Torvalds #define Hangul_SBase 0xac00
921da177e4SLinus Torvalds #define Hangul_LBase 0x1100
931da177e4SLinus Torvalds #define Hangul_VBase 0x1161
941da177e4SLinus Torvalds #define Hangul_TBase 0x11a7
951da177e4SLinus Torvalds #define Hangul_SCount 11172
961da177e4SLinus Torvalds #define Hangul_LCount 19
971da177e4SLinus Torvalds #define Hangul_VCount 21
981da177e4SLinus Torvalds #define Hangul_TCount 28
991da177e4SLinus Torvalds #define Hangul_NCount (Hangul_VCount * Hangul_TCount)
1001da177e4SLinus Torvalds
1011da177e4SLinus Torvalds
hfsplus_compose_lookup(u16 * p,u16 cc)1021da177e4SLinus Torvalds static u16 *hfsplus_compose_lookup(u16 *p, u16 cc)
1031da177e4SLinus Torvalds {
1041da177e4SLinus Torvalds int i, s, e;
1051da177e4SLinus Torvalds
1061da177e4SLinus Torvalds s = 1;
1071da177e4SLinus Torvalds e = p[1];
1081da177e4SLinus Torvalds if (!e || cc < p[s * 2] || cc > p[e * 2])
1091da177e4SLinus Torvalds return NULL;
1101da177e4SLinus Torvalds do {
1111da177e4SLinus Torvalds i = (s + e) / 2;
1121da177e4SLinus Torvalds if (cc > p[i * 2])
1131da177e4SLinus Torvalds s = i + 1;
1141da177e4SLinus Torvalds else if (cc < p[i * 2])
1151da177e4SLinus Torvalds e = i - 1;
1161da177e4SLinus Torvalds else
1171da177e4SLinus Torvalds return hfsplus_compose_table + p[i * 2 + 1];
1181da177e4SLinus Torvalds } while (s <= e);
1191da177e4SLinus Torvalds return NULL;
1201da177e4SLinus Torvalds }
1211da177e4SLinus Torvalds
hfsplus_uni2asc(struct super_block * sb,const struct hfsplus_unistr * ustr,char * astr,int * len_p)1222753cc28SAnton Salikhmetov int hfsplus_uni2asc(struct super_block *sb,
1232753cc28SAnton Salikhmetov const struct hfsplus_unistr *ustr,
1242753cc28SAnton Salikhmetov char *astr, int *len_p)
1251da177e4SLinus Torvalds {
1261da177e4SLinus Torvalds const hfsplus_unichr *ip;
127dd73a01aSChristoph Hellwig struct nls_table *nls = HFSPLUS_SB(sb)->nls;
1281da177e4SLinus Torvalds u8 *op;
1291da177e4SLinus Torvalds u16 cc, c0, c1;
1301da177e4SLinus Torvalds u16 *ce1, *ce2;
1311da177e4SLinus Torvalds int i, len, ustrlen, res, compose;
1321da177e4SLinus Torvalds
1331da177e4SLinus Torvalds op = astr;
1341da177e4SLinus Torvalds ip = ustr->unicode;
1351da177e4SLinus Torvalds ustrlen = be16_to_cpu(ustr->length);
1361da177e4SLinus Torvalds len = *len_p;
1371da177e4SLinus Torvalds ce1 = NULL;
13884adede3SChristoph Hellwig compose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
1391da177e4SLinus Torvalds
1401da177e4SLinus Torvalds while (ustrlen > 0) {
1411da177e4SLinus Torvalds c0 = be16_to_cpu(*ip++);
1421da177e4SLinus Torvalds ustrlen--;
1431da177e4SLinus Torvalds /* search for single decomposed char */
1441da177e4SLinus Torvalds if (likely(compose))
1451da177e4SLinus Torvalds ce1 = hfsplus_compose_lookup(hfsplus_compose_table, c0);
1462b4f9ca8SAnton Salikhmetov if (ce1)
1472b4f9ca8SAnton Salikhmetov cc = ce1[0];
1482b4f9ca8SAnton Salikhmetov else
1492b4f9ca8SAnton Salikhmetov cc = 0;
1502b4f9ca8SAnton Salikhmetov if (cc) {
1511da177e4SLinus Torvalds /* start of a possibly decomposed Hangul char */
1521da177e4SLinus Torvalds if (cc != 0xffff)
1531da177e4SLinus Torvalds goto done;
1541da177e4SLinus Torvalds if (!ustrlen)
1551da177e4SLinus Torvalds goto same;
1561da177e4SLinus Torvalds c1 = be16_to_cpu(*ip) - Hangul_VBase;
1571da177e4SLinus Torvalds if (c1 < Hangul_VCount) {
1581da177e4SLinus Torvalds /* compose the Hangul char */
1591da177e4SLinus Torvalds cc = (c0 - Hangul_LBase) * Hangul_VCount;
1601da177e4SLinus Torvalds cc = (cc + c1) * Hangul_TCount;
1611da177e4SLinus Torvalds cc += Hangul_SBase;
1621da177e4SLinus Torvalds ip++;
1631da177e4SLinus Torvalds ustrlen--;
1641da177e4SLinus Torvalds if (!ustrlen)
1651da177e4SLinus Torvalds goto done;
1661da177e4SLinus Torvalds c1 = be16_to_cpu(*ip) - Hangul_TBase;
1671da177e4SLinus Torvalds if (c1 > 0 && c1 < Hangul_TCount) {
1681da177e4SLinus Torvalds cc += c1;
1691da177e4SLinus Torvalds ip++;
1701da177e4SLinus Torvalds ustrlen--;
1711da177e4SLinus Torvalds }
1721da177e4SLinus Torvalds goto done;
1731da177e4SLinus Torvalds }
1741da177e4SLinus Torvalds }
1751da177e4SLinus Torvalds while (1) {
1761da177e4SLinus Torvalds /* main loop for common case of not composed chars */
1771da177e4SLinus Torvalds if (!ustrlen)
1781da177e4SLinus Torvalds goto same;
1791da177e4SLinus Torvalds c1 = be16_to_cpu(*ip);
1801da177e4SLinus Torvalds if (likely(compose))
1812753cc28SAnton Salikhmetov ce1 = hfsplus_compose_lookup(
1822753cc28SAnton Salikhmetov hfsplus_compose_table, c1);
1831da177e4SLinus Torvalds if (ce1)
1841da177e4SLinus Torvalds break;
1851da177e4SLinus Torvalds switch (c0) {
1861da177e4SLinus Torvalds case 0:
1871da177e4SLinus Torvalds c0 = 0x2400;
1881da177e4SLinus Torvalds break;
1891da177e4SLinus Torvalds case '/':
1901da177e4SLinus Torvalds c0 = ':';
1911da177e4SLinus Torvalds break;
1921da177e4SLinus Torvalds }
1931da177e4SLinus Torvalds res = nls->uni2char(c0, op, len);
1941da177e4SLinus Torvalds if (res < 0) {
1951da177e4SLinus Torvalds if (res == -ENAMETOOLONG)
1961da177e4SLinus Torvalds goto out;
1971da177e4SLinus Torvalds *op = '?';
1981da177e4SLinus Torvalds res = 1;
1991da177e4SLinus Torvalds }
2001da177e4SLinus Torvalds op += res;
2011da177e4SLinus Torvalds len -= res;
2021da177e4SLinus Torvalds c0 = c1;
2031da177e4SLinus Torvalds ip++;
2041da177e4SLinus Torvalds ustrlen--;
2051da177e4SLinus Torvalds }
2061da177e4SLinus Torvalds ce2 = hfsplus_compose_lookup(ce1, c0);
2071da177e4SLinus Torvalds if (ce2) {
2081da177e4SLinus Torvalds i = 1;
2091da177e4SLinus Torvalds while (i < ustrlen) {
2102753cc28SAnton Salikhmetov ce1 = hfsplus_compose_lookup(ce2,
2112753cc28SAnton Salikhmetov be16_to_cpu(ip[i]));
2121da177e4SLinus Torvalds if (!ce1)
2131da177e4SLinus Torvalds break;
2141da177e4SLinus Torvalds i++;
2151da177e4SLinus Torvalds ce2 = ce1;
2161da177e4SLinus Torvalds }
2172b4f9ca8SAnton Salikhmetov cc = ce2[0];
2182b4f9ca8SAnton Salikhmetov if (cc) {
2191da177e4SLinus Torvalds ip += i;
2201da177e4SLinus Torvalds ustrlen -= i;
2211da177e4SLinus Torvalds goto done;
2221da177e4SLinus Torvalds }
2231da177e4SLinus Torvalds }
2241da177e4SLinus Torvalds same:
2251da177e4SLinus Torvalds switch (c0) {
2261da177e4SLinus Torvalds case 0:
2271da177e4SLinus Torvalds cc = 0x2400;
2281da177e4SLinus Torvalds break;
2291da177e4SLinus Torvalds case '/':
2301da177e4SLinus Torvalds cc = ':';
2311da177e4SLinus Torvalds break;
2321da177e4SLinus Torvalds default:
2331da177e4SLinus Torvalds cc = c0;
2341da177e4SLinus Torvalds }
2351da177e4SLinus Torvalds done:
2361da177e4SLinus Torvalds res = nls->uni2char(cc, op, len);
2371da177e4SLinus Torvalds if (res < 0) {
2381da177e4SLinus Torvalds if (res == -ENAMETOOLONG)
2391da177e4SLinus Torvalds goto out;
2401da177e4SLinus Torvalds *op = '?';
2411da177e4SLinus Torvalds res = 1;
2421da177e4SLinus Torvalds }
2431da177e4SLinus Torvalds op += res;
2441da177e4SLinus Torvalds len -= res;
2451da177e4SLinus Torvalds }
2461da177e4SLinus Torvalds res = 0;
2471da177e4SLinus Torvalds out:
2481da177e4SLinus Torvalds *len_p = (char *)op - astr;
2491da177e4SLinus Torvalds return res;
2501da177e4SLinus Torvalds }
2511da177e4SLinus Torvalds
2521e96b7caSDuane Griffin /*
2531e96b7caSDuane Griffin * Convert one or more ASCII characters into a single unicode character.
2541e96b7caSDuane Griffin * Returns the number of ASCII characters corresponding to the unicode char.
2551e96b7caSDuane Griffin */
asc2unichar(struct super_block * sb,const char * astr,int len,wchar_t * uc)2561e96b7caSDuane Griffin static inline int asc2unichar(struct super_block *sb, const char *astr, int len,
2571e96b7caSDuane Griffin wchar_t *uc)
2581da177e4SLinus Torvalds {
259dd73a01aSChristoph Hellwig int size = HFSPLUS_SB(sb)->nls->char2uni(astr, len, uc);
2601da177e4SLinus Torvalds if (size <= 0) {
2611e96b7caSDuane Griffin *uc = '?';
2621da177e4SLinus Torvalds size = 1;
2631da177e4SLinus Torvalds }
2641e96b7caSDuane Griffin switch (*uc) {
2651da177e4SLinus Torvalds case 0x2400:
2661e96b7caSDuane Griffin *uc = 0;
2671da177e4SLinus Torvalds break;
2681da177e4SLinus Torvalds case ':':
2691e96b7caSDuane Griffin *uc = '/';
2701da177e4SLinus Torvalds break;
2711da177e4SLinus Torvalds }
2721e96b7caSDuane Griffin return size;
2731da177e4SLinus Torvalds }
2741e96b7caSDuane Griffin
275afd6c9e1SErnesto A. Fernández /* Decomposes a non-Hangul unicode character. */
hfsplus_decompose_nonhangul(wchar_t uc,int * size)276afd6c9e1SErnesto A. Fernández static u16 *hfsplus_decompose_nonhangul(wchar_t uc, int *size)
2771e96b7caSDuane Griffin {
2781e96b7caSDuane Griffin int off;
2791e96b7caSDuane Griffin
2801e96b7caSDuane Griffin off = hfsplus_decompose_table[(uc >> 12) & 0xf];
2811e96b7caSDuane Griffin if (off == 0 || off == 0xffff)
2821e96b7caSDuane Griffin return NULL;
2831e96b7caSDuane Griffin
2841e96b7caSDuane Griffin off = hfsplus_decompose_table[off + ((uc >> 8) & 0xf)];
2851da177e4SLinus Torvalds if (!off)
2861e96b7caSDuane Griffin return NULL;
2871e96b7caSDuane Griffin
2881e96b7caSDuane Griffin off = hfsplus_decompose_table[off + ((uc >> 4) & 0xf)];
2891da177e4SLinus Torvalds if (!off)
2901e96b7caSDuane Griffin return NULL;
2911e96b7caSDuane Griffin
2921e96b7caSDuane Griffin off = hfsplus_decompose_table[off + (uc & 0xf)];
2931e96b7caSDuane Griffin *size = off & 3;
2941e96b7caSDuane Griffin if (*size == 0)
2951e96b7caSDuane Griffin return NULL;
2961e96b7caSDuane Griffin return hfsplus_decompose_table + (off / 4);
2971e96b7caSDuane Griffin }
2981e96b7caSDuane Griffin
299afd6c9e1SErnesto A. Fernández /*
300afd6c9e1SErnesto A. Fernández * Try to decompose a unicode character as Hangul. Return 0 if @uc is not
301afd6c9e1SErnesto A. Fernández * precomposed Hangul, otherwise return the length of the decomposition.
302afd6c9e1SErnesto A. Fernández *
303afd6c9e1SErnesto A. Fernández * This function was adapted from sample code from the Unicode Standard
304afd6c9e1SErnesto A. Fernández * Annex #15: Unicode Normalization Forms, version 3.2.0.
305afd6c9e1SErnesto A. Fernández *
306afd6c9e1SErnesto A. Fernández * Copyright (C) 1991-2018 Unicode, Inc. All rights reserved. Distributed
307afd6c9e1SErnesto A. Fernández * under the Terms of Use in http://www.unicode.org/copyright.html.
308afd6c9e1SErnesto A. Fernández */
hfsplus_try_decompose_hangul(wchar_t uc,u16 * result)309afd6c9e1SErnesto A. Fernández static int hfsplus_try_decompose_hangul(wchar_t uc, u16 *result)
310afd6c9e1SErnesto A. Fernández {
311afd6c9e1SErnesto A. Fernández int index;
312afd6c9e1SErnesto A. Fernández int l, v, t;
313afd6c9e1SErnesto A. Fernández
314afd6c9e1SErnesto A. Fernández index = uc - Hangul_SBase;
315afd6c9e1SErnesto A. Fernández if (index < 0 || index >= Hangul_SCount)
316afd6c9e1SErnesto A. Fernández return 0;
317afd6c9e1SErnesto A. Fernández
318afd6c9e1SErnesto A. Fernández l = Hangul_LBase + index / Hangul_NCount;
319afd6c9e1SErnesto A. Fernández v = Hangul_VBase + (index % Hangul_NCount) / Hangul_TCount;
320afd6c9e1SErnesto A. Fernández t = Hangul_TBase + index % Hangul_TCount;
321afd6c9e1SErnesto A. Fernández
322afd6c9e1SErnesto A. Fernández result[0] = l;
323afd6c9e1SErnesto A. Fernández result[1] = v;
324afd6c9e1SErnesto A. Fernández if (t != Hangul_TBase) {
325afd6c9e1SErnesto A. Fernández result[2] = t;
326afd6c9e1SErnesto A. Fernández return 3;
327afd6c9e1SErnesto A. Fernández }
328afd6c9e1SErnesto A. Fernández return 2;
329afd6c9e1SErnesto A. Fernández }
330afd6c9e1SErnesto A. Fernández
331afd6c9e1SErnesto A. Fernández /* Decomposes a single unicode character. */
decompose_unichar(wchar_t uc,int * size,u16 * hangul_buffer)332afd6c9e1SErnesto A. Fernández static u16 *decompose_unichar(wchar_t uc, int *size, u16 *hangul_buffer)
333afd6c9e1SErnesto A. Fernández {
334afd6c9e1SErnesto A. Fernández u16 *result;
335afd6c9e1SErnesto A. Fernández
336afd6c9e1SErnesto A. Fernández /* Hangul is handled separately */
337afd6c9e1SErnesto A. Fernández result = hangul_buffer;
338afd6c9e1SErnesto A. Fernández *size = hfsplus_try_decompose_hangul(uc, result);
339afd6c9e1SErnesto A. Fernández if (*size == 0)
340afd6c9e1SErnesto A. Fernández result = hfsplus_decompose_nonhangul(uc, size);
341afd6c9e1SErnesto A. Fernández return result;
342afd6c9e1SErnesto A. Fernández }
343afd6c9e1SErnesto A. Fernández
hfsplus_asc2uni(struct super_block * sb,struct hfsplus_unistr * ustr,int max_unistr_len,const char * astr,int len)344324ef39aSVyacheslav Dubeyko int hfsplus_asc2uni(struct super_block *sb,
345324ef39aSVyacheslav Dubeyko struct hfsplus_unistr *ustr, int max_unistr_len,
3461e96b7caSDuane Griffin const char *astr, int len)
3471e96b7caSDuane Griffin {
3481e96b7caSDuane Griffin int size, dsize, decompose;
3491e96b7caSDuane Griffin u16 *dstr, outlen = 0;
3501e96b7caSDuane Griffin wchar_t c;
351afd6c9e1SErnesto A. Fernández u16 dhangul[3];
3521e96b7caSDuane Griffin
35384adede3SChristoph Hellwig decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
354324ef39aSVyacheslav Dubeyko while (outlen < max_unistr_len && len > 0) {
3551e96b7caSDuane Griffin size = asc2unichar(sb, astr, len, &c);
3561e96b7caSDuane Griffin
3572b4f9ca8SAnton Salikhmetov if (decompose)
358afd6c9e1SErnesto A. Fernández dstr = decompose_unichar(c, &dsize, dhangul);
3592b4f9ca8SAnton Salikhmetov else
3602b4f9ca8SAnton Salikhmetov dstr = NULL;
3612b4f9ca8SAnton Salikhmetov if (dstr) {
362324ef39aSVyacheslav Dubeyko if (outlen + dsize > max_unistr_len)
3631da177e4SLinus Torvalds break;
3641da177e4SLinus Torvalds do {
3651e96b7caSDuane Griffin ustr->unicode[outlen++] = cpu_to_be16(*dstr++);
3661e96b7caSDuane Griffin } while (--dsize > 0);
3671e96b7caSDuane Griffin } else
3681da177e4SLinus Torvalds ustr->unicode[outlen++] = cpu_to_be16(c);
3691e96b7caSDuane Griffin
3701e96b7caSDuane Griffin astr += size;
3711e96b7caSDuane Griffin len -= size;
3721da177e4SLinus Torvalds }
3731da177e4SLinus Torvalds ustr->length = cpu_to_be16(outlen);
3741da177e4SLinus Torvalds if (len > 0)
3751da177e4SLinus Torvalds return -ENAMETOOLONG;
3761da177e4SLinus Torvalds return 0;
3771da177e4SLinus Torvalds }
378d45bce8fSDuane Griffin
379d45bce8fSDuane Griffin /*
380d45bce8fSDuane Griffin * Hash a string to an integer as appropriate for the HFS+ filesystem.
381d45bce8fSDuane Griffin * Composed unicode characters are decomposed and case-folding is performed
382d45bce8fSDuane Griffin * if the appropriate bits are (un)set on the superblock.
383d45bce8fSDuane Griffin */
hfsplus_hash_dentry(const struct dentry * dentry,struct qstr * str)384da53be12SLinus Torvalds int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str)
385d45bce8fSDuane Griffin {
386d45bce8fSDuane Griffin struct super_block *sb = dentry->d_sb;
387d45bce8fSDuane Griffin const char *astr;
388d45bce8fSDuane Griffin const u16 *dstr;
3898aa84ab9SAndrew Morton int casefold, decompose, size, len;
390d45bce8fSDuane Griffin unsigned long hash;
391d45bce8fSDuane Griffin wchar_t c;
392d45bce8fSDuane Griffin u16 c2;
393afd6c9e1SErnesto A. Fernández u16 dhangul[3];
394d45bce8fSDuane Griffin
39584adede3SChristoph Hellwig casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
39684adede3SChristoph Hellwig decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
3978387ff25SLinus Torvalds hash = init_name_hash(dentry);
398d45bce8fSDuane Griffin astr = str->name;
399d45bce8fSDuane Griffin len = str->len;
400d45bce8fSDuane Griffin while (len > 0) {
401*3f649ab7SKees Cook int dsize;
402d45bce8fSDuane Griffin size = asc2unichar(sb, astr, len, &c);
403d45bce8fSDuane Griffin astr += size;
404d45bce8fSDuane Griffin len -= size;
405d45bce8fSDuane Griffin
4062b4f9ca8SAnton Salikhmetov if (decompose)
407afd6c9e1SErnesto A. Fernández dstr = decompose_unichar(c, &dsize, dhangul);
4082b4f9ca8SAnton Salikhmetov else
4092b4f9ca8SAnton Salikhmetov dstr = NULL;
4102b4f9ca8SAnton Salikhmetov if (dstr) {
411d45bce8fSDuane Griffin do {
412d45bce8fSDuane Griffin c2 = *dstr++;
4132b4f9ca8SAnton Salikhmetov if (casefold)
4142b4f9ca8SAnton Salikhmetov c2 = case_fold(c2);
4152b4f9ca8SAnton Salikhmetov if (!casefold || c2)
416d45bce8fSDuane Griffin hash = partial_name_hash(c2, hash);
417d45bce8fSDuane Griffin } while (--dsize > 0);
418d45bce8fSDuane Griffin } else {
419d45bce8fSDuane Griffin c2 = c;
4202b4f9ca8SAnton Salikhmetov if (casefold)
4212b4f9ca8SAnton Salikhmetov c2 = case_fold(c2);
4222b4f9ca8SAnton Salikhmetov if (!casefold || c2)
423d45bce8fSDuane Griffin hash = partial_name_hash(c2, hash);
424d45bce8fSDuane Griffin }
425d45bce8fSDuane Griffin }
426d45bce8fSDuane Griffin str->hash = end_name_hash(hash);
427d45bce8fSDuane Griffin
428d45bce8fSDuane Griffin return 0;
429d45bce8fSDuane Griffin }
430d45bce8fSDuane Griffin
431d45bce8fSDuane Griffin /*
432d45bce8fSDuane Griffin * Compare strings with HFS+ filename ordering.
433d45bce8fSDuane Griffin * Composed unicode characters are decomposed and case-folding is performed
434d45bce8fSDuane Griffin * if the appropriate bits are (un)set on the superblock.
435d45bce8fSDuane Griffin */
hfsplus_compare_dentry(const struct dentry * dentry,unsigned int len,const char * str,const struct qstr * name)4366fa67e70SAl Viro int hfsplus_compare_dentry(const struct dentry *dentry,
437621e155aSNick Piggin unsigned int len, const char *str, const struct qstr *name)
438d45bce8fSDuane Griffin {
439d3fe1985SAl Viro struct super_block *sb = dentry->d_sb;
440d45bce8fSDuane Griffin int casefold, decompose, size;
441d45bce8fSDuane Griffin int dsize1, dsize2, len1, len2;
442d45bce8fSDuane Griffin const u16 *dstr1, *dstr2;
443d45bce8fSDuane Griffin const char *astr1, *astr2;
444d45bce8fSDuane Griffin u16 c1, c2;
445d45bce8fSDuane Griffin wchar_t c;
446afd6c9e1SErnesto A. Fernández u16 dhangul_1[3], dhangul_2[3];
447d45bce8fSDuane Griffin
44884adede3SChristoph Hellwig casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
44984adede3SChristoph Hellwig decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
450621e155aSNick Piggin astr1 = str;
451621e155aSNick Piggin len1 = len;
452621e155aSNick Piggin astr2 = name->name;
453621e155aSNick Piggin len2 = name->len;
454d45bce8fSDuane Griffin dsize1 = dsize2 = 0;
455d45bce8fSDuane Griffin dstr1 = dstr2 = NULL;
456d45bce8fSDuane Griffin
457d45bce8fSDuane Griffin while (len1 > 0 && len2 > 0) {
458d45bce8fSDuane Griffin if (!dsize1) {
459d45bce8fSDuane Griffin size = asc2unichar(sb, astr1, len1, &c);
460d45bce8fSDuane Griffin astr1 += size;
461d45bce8fSDuane Griffin len1 -= size;
462d45bce8fSDuane Griffin
4632753cc28SAnton Salikhmetov if (decompose)
464afd6c9e1SErnesto A. Fernández dstr1 = decompose_unichar(c, &dsize1,
465afd6c9e1SErnesto A. Fernández dhangul_1);
4662753cc28SAnton Salikhmetov if (!decompose || !dstr1) {
467d45bce8fSDuane Griffin c1 = c;
468d45bce8fSDuane Griffin dstr1 = &c1;
469d45bce8fSDuane Griffin dsize1 = 1;
470d45bce8fSDuane Griffin }
471d45bce8fSDuane Griffin }
472d45bce8fSDuane Griffin
473d45bce8fSDuane Griffin if (!dsize2) {
474d45bce8fSDuane Griffin size = asc2unichar(sb, astr2, len2, &c);
475d45bce8fSDuane Griffin astr2 += size;
476d45bce8fSDuane Griffin len2 -= size;
477d45bce8fSDuane Griffin
4782753cc28SAnton Salikhmetov if (decompose)
479afd6c9e1SErnesto A. Fernández dstr2 = decompose_unichar(c, &dsize2,
480afd6c9e1SErnesto A. Fernández dhangul_2);
4812753cc28SAnton Salikhmetov if (!decompose || !dstr2) {
482d45bce8fSDuane Griffin c2 = c;
483d45bce8fSDuane Griffin dstr2 = &c2;
484d45bce8fSDuane Griffin dsize2 = 1;
485d45bce8fSDuane Griffin }
486d45bce8fSDuane Griffin }
487d45bce8fSDuane Griffin
488d45bce8fSDuane Griffin c1 = *dstr1;
489d45bce8fSDuane Griffin c2 = *dstr2;
490d45bce8fSDuane Griffin if (casefold) {
4912b4f9ca8SAnton Salikhmetov c1 = case_fold(c1);
4922b4f9ca8SAnton Salikhmetov if (!c1) {
493d45bce8fSDuane Griffin dstr1++;
494d45bce8fSDuane Griffin dsize1--;
495d45bce8fSDuane Griffin continue;
496d45bce8fSDuane Griffin }
4972b4f9ca8SAnton Salikhmetov c2 = case_fold(c2);
4982b4f9ca8SAnton Salikhmetov if (!c2) {
499d45bce8fSDuane Griffin dstr2++;
500d45bce8fSDuane Griffin dsize2--;
501d45bce8fSDuane Griffin continue;
502d45bce8fSDuane Griffin }
503d45bce8fSDuane Griffin }
504d45bce8fSDuane Griffin if (c1 < c2)
505d45bce8fSDuane Griffin return -1;
506d45bce8fSDuane Griffin else if (c1 > c2)
507d45bce8fSDuane Griffin return 1;
508d45bce8fSDuane Griffin
509d45bce8fSDuane Griffin dstr1++;
510d45bce8fSDuane Griffin dsize1--;
511d45bce8fSDuane Griffin dstr2++;
512d45bce8fSDuane Griffin dsize2--;
513d45bce8fSDuane Griffin }
514d45bce8fSDuane Griffin
515d45bce8fSDuane Griffin if (len1 < len2)
516d45bce8fSDuane Griffin return -1;
517d45bce8fSDuane Griffin if (len1 > len2)
518d45bce8fSDuane Griffin return 1;
519d45bce8fSDuane Griffin return 0;
520d45bce8fSDuane Griffin }
521