xref: /OK3568_Linux_fs/kernel/fs/hfsplus/unicode.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  linux/fs/hfsplus/unicode.c
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2001
6*4882a593Smuzhiyun  * Brad Boyer (flar@allandria.com)
7*4882a593Smuzhiyun  * (C) 2003 Ardis Technologies <roman@ardistech.com>
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Handler routines for unicode strings
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <linux/types.h>
13*4882a593Smuzhiyun #include <linux/nls.h>
14*4882a593Smuzhiyun #include "hfsplus_fs.h"
15*4882a593Smuzhiyun #include "hfsplus_raw.h"
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun /* Fold the case of a unicode char, given the 16 bit value */
18*4882a593Smuzhiyun /* Returns folded char, or 0 if ignorable */
case_fold(u16 c)19*4882a593Smuzhiyun static inline u16 case_fold(u16 c)
20*4882a593Smuzhiyun {
21*4882a593Smuzhiyun 	u16 tmp;
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun 	tmp = hfsplus_case_fold_table[c >> 8];
24*4882a593Smuzhiyun 	if (tmp)
25*4882a593Smuzhiyun 		tmp = hfsplus_case_fold_table[tmp + (c & 0xff)];
26*4882a593Smuzhiyun 	else
27*4882a593Smuzhiyun 		tmp = c;
28*4882a593Smuzhiyun 	return tmp;
29*4882a593Smuzhiyun }
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun /* Compare unicode strings, return values like normal strcmp */
hfsplus_strcasecmp(const struct hfsplus_unistr * s1,const struct hfsplus_unistr * s2)32*4882a593Smuzhiyun int hfsplus_strcasecmp(const struct hfsplus_unistr *s1,
33*4882a593Smuzhiyun 		       const struct hfsplus_unistr *s2)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun 	u16 len1, len2, c1, c2;
36*4882a593Smuzhiyun 	const hfsplus_unichr *p1, *p2;
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 	len1 = be16_to_cpu(s1->length);
39*4882a593Smuzhiyun 	len2 = be16_to_cpu(s2->length);
40*4882a593Smuzhiyun 	p1 = s1->unicode;
41*4882a593Smuzhiyun 	p2 = s2->unicode;
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	while (1) {
44*4882a593Smuzhiyun 		c1 = c2 = 0;
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 		while (len1 && !c1) {
47*4882a593Smuzhiyun 			c1 = case_fold(be16_to_cpu(*p1));
48*4882a593Smuzhiyun 			p1++;
49*4882a593Smuzhiyun 			len1--;
50*4882a593Smuzhiyun 		}
51*4882a593Smuzhiyun 		while (len2 && !c2) {
52*4882a593Smuzhiyun 			c2 = case_fold(be16_to_cpu(*p2));
53*4882a593Smuzhiyun 			p2++;
54*4882a593Smuzhiyun 			len2--;
55*4882a593Smuzhiyun 		}
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 		if (c1 != c2)
58*4882a593Smuzhiyun 			return (c1 < c2) ? -1 : 1;
59*4882a593Smuzhiyun 		if (!c1 && !c2)
60*4882a593Smuzhiyun 			return 0;
61*4882a593Smuzhiyun 	}
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun /* Compare names as a sequence of 16-bit unsigned integers */
hfsplus_strcmp(const struct hfsplus_unistr * s1,const struct hfsplus_unistr * s2)65*4882a593Smuzhiyun int hfsplus_strcmp(const struct hfsplus_unistr *s1,
66*4882a593Smuzhiyun 		   const struct hfsplus_unistr *s2)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun 	u16 len1, len2, c1, c2;
69*4882a593Smuzhiyun 	const hfsplus_unichr *p1, *p2;
70*4882a593Smuzhiyun 	int len;
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	len1 = be16_to_cpu(s1->length);
73*4882a593Smuzhiyun 	len2 = be16_to_cpu(s2->length);
74*4882a593Smuzhiyun 	p1 = s1->unicode;
75*4882a593Smuzhiyun 	p2 = s2->unicode;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	for (len = min(len1, len2); len > 0; len--) {
78*4882a593Smuzhiyun 		c1 = be16_to_cpu(*p1);
79*4882a593Smuzhiyun 		c2 = be16_to_cpu(*p2);
80*4882a593Smuzhiyun 		if (c1 != c2)
81*4882a593Smuzhiyun 			return c1 < c2 ? -1 : 1;
82*4882a593Smuzhiyun 		p1++;
83*4882a593Smuzhiyun 		p2++;
84*4882a593Smuzhiyun 	}
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	return len1 < len2 ? -1 :
87*4882a593Smuzhiyun 	       len1 > len2 ? 1 : 0;
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun #define Hangul_SBase	0xac00
92*4882a593Smuzhiyun #define Hangul_LBase	0x1100
93*4882a593Smuzhiyun #define Hangul_VBase	0x1161
94*4882a593Smuzhiyun #define Hangul_TBase	0x11a7
95*4882a593Smuzhiyun #define Hangul_SCount	11172
96*4882a593Smuzhiyun #define Hangul_LCount	19
97*4882a593Smuzhiyun #define Hangul_VCount	21
98*4882a593Smuzhiyun #define Hangul_TCount	28
99*4882a593Smuzhiyun #define Hangul_NCount	(Hangul_VCount * Hangul_TCount)
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 
hfsplus_compose_lookup(u16 * p,u16 cc)102*4882a593Smuzhiyun static u16 *hfsplus_compose_lookup(u16 *p, u16 cc)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun 	int i, s, e;
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	s = 1;
107*4882a593Smuzhiyun 	e = p[1];
108*4882a593Smuzhiyun 	if (!e || cc < p[s * 2] || cc > p[e * 2])
109*4882a593Smuzhiyun 		return NULL;
110*4882a593Smuzhiyun 	do {
111*4882a593Smuzhiyun 		i = (s + e) / 2;
112*4882a593Smuzhiyun 		if (cc > p[i * 2])
113*4882a593Smuzhiyun 			s = i + 1;
114*4882a593Smuzhiyun 		else if (cc < p[i * 2])
115*4882a593Smuzhiyun 			e = i - 1;
116*4882a593Smuzhiyun 		else
117*4882a593Smuzhiyun 			return hfsplus_compose_table + p[i * 2 + 1];
118*4882a593Smuzhiyun 	} while (s <= e);
119*4882a593Smuzhiyun 	return NULL;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun 
hfsplus_uni2asc(struct super_block * sb,const struct hfsplus_unistr * ustr,char * astr,int * len_p)122*4882a593Smuzhiyun int hfsplus_uni2asc(struct super_block *sb,
123*4882a593Smuzhiyun 		const struct hfsplus_unistr *ustr,
124*4882a593Smuzhiyun 		char *astr, int *len_p)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun 	const hfsplus_unichr *ip;
127*4882a593Smuzhiyun 	struct nls_table *nls = HFSPLUS_SB(sb)->nls;
128*4882a593Smuzhiyun 	u8 *op;
129*4882a593Smuzhiyun 	u16 cc, c0, c1;
130*4882a593Smuzhiyun 	u16 *ce1, *ce2;
131*4882a593Smuzhiyun 	int i, len, ustrlen, res, compose;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	op = astr;
134*4882a593Smuzhiyun 	ip = ustr->unicode;
135*4882a593Smuzhiyun 	ustrlen = be16_to_cpu(ustr->length);
136*4882a593Smuzhiyun 	len = *len_p;
137*4882a593Smuzhiyun 	ce1 = NULL;
138*4882a593Smuzhiyun 	compose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	while (ustrlen > 0) {
141*4882a593Smuzhiyun 		c0 = be16_to_cpu(*ip++);
142*4882a593Smuzhiyun 		ustrlen--;
143*4882a593Smuzhiyun 		/* search for single decomposed char */
144*4882a593Smuzhiyun 		if (likely(compose))
145*4882a593Smuzhiyun 			ce1 = hfsplus_compose_lookup(hfsplus_compose_table, c0);
146*4882a593Smuzhiyun 		if (ce1)
147*4882a593Smuzhiyun 			cc = ce1[0];
148*4882a593Smuzhiyun 		else
149*4882a593Smuzhiyun 			cc = 0;
150*4882a593Smuzhiyun 		if (cc) {
151*4882a593Smuzhiyun 			/* start of a possibly decomposed Hangul char */
152*4882a593Smuzhiyun 			if (cc != 0xffff)
153*4882a593Smuzhiyun 				goto done;
154*4882a593Smuzhiyun 			if (!ustrlen)
155*4882a593Smuzhiyun 				goto same;
156*4882a593Smuzhiyun 			c1 = be16_to_cpu(*ip) - Hangul_VBase;
157*4882a593Smuzhiyun 			if (c1 < Hangul_VCount) {
158*4882a593Smuzhiyun 				/* compose the Hangul char */
159*4882a593Smuzhiyun 				cc = (c0 - Hangul_LBase) * Hangul_VCount;
160*4882a593Smuzhiyun 				cc = (cc + c1) * Hangul_TCount;
161*4882a593Smuzhiyun 				cc += Hangul_SBase;
162*4882a593Smuzhiyun 				ip++;
163*4882a593Smuzhiyun 				ustrlen--;
164*4882a593Smuzhiyun 				if (!ustrlen)
165*4882a593Smuzhiyun 					goto done;
166*4882a593Smuzhiyun 				c1 = be16_to_cpu(*ip) - Hangul_TBase;
167*4882a593Smuzhiyun 				if (c1 > 0 && c1 < Hangul_TCount) {
168*4882a593Smuzhiyun 					cc += c1;
169*4882a593Smuzhiyun 					ip++;
170*4882a593Smuzhiyun 					ustrlen--;
171*4882a593Smuzhiyun 				}
172*4882a593Smuzhiyun 				goto done;
173*4882a593Smuzhiyun 			}
174*4882a593Smuzhiyun 		}
175*4882a593Smuzhiyun 		while (1) {
176*4882a593Smuzhiyun 			/* main loop for common case of not composed chars */
177*4882a593Smuzhiyun 			if (!ustrlen)
178*4882a593Smuzhiyun 				goto same;
179*4882a593Smuzhiyun 			c1 = be16_to_cpu(*ip);
180*4882a593Smuzhiyun 			if (likely(compose))
181*4882a593Smuzhiyun 				ce1 = hfsplus_compose_lookup(
182*4882a593Smuzhiyun 					hfsplus_compose_table, c1);
183*4882a593Smuzhiyun 			if (ce1)
184*4882a593Smuzhiyun 				break;
185*4882a593Smuzhiyun 			switch (c0) {
186*4882a593Smuzhiyun 			case 0:
187*4882a593Smuzhiyun 				c0 = 0x2400;
188*4882a593Smuzhiyun 				break;
189*4882a593Smuzhiyun 			case '/':
190*4882a593Smuzhiyun 				c0 = ':';
191*4882a593Smuzhiyun 				break;
192*4882a593Smuzhiyun 			}
193*4882a593Smuzhiyun 			res = nls->uni2char(c0, op, len);
194*4882a593Smuzhiyun 			if (res < 0) {
195*4882a593Smuzhiyun 				if (res == -ENAMETOOLONG)
196*4882a593Smuzhiyun 					goto out;
197*4882a593Smuzhiyun 				*op = '?';
198*4882a593Smuzhiyun 				res = 1;
199*4882a593Smuzhiyun 			}
200*4882a593Smuzhiyun 			op += res;
201*4882a593Smuzhiyun 			len -= res;
202*4882a593Smuzhiyun 			c0 = c1;
203*4882a593Smuzhiyun 			ip++;
204*4882a593Smuzhiyun 			ustrlen--;
205*4882a593Smuzhiyun 		}
206*4882a593Smuzhiyun 		ce2 = hfsplus_compose_lookup(ce1, c0);
207*4882a593Smuzhiyun 		if (ce2) {
208*4882a593Smuzhiyun 			i = 1;
209*4882a593Smuzhiyun 			while (i < ustrlen) {
210*4882a593Smuzhiyun 				ce1 = hfsplus_compose_lookup(ce2,
211*4882a593Smuzhiyun 					be16_to_cpu(ip[i]));
212*4882a593Smuzhiyun 				if (!ce1)
213*4882a593Smuzhiyun 					break;
214*4882a593Smuzhiyun 				i++;
215*4882a593Smuzhiyun 				ce2 = ce1;
216*4882a593Smuzhiyun 			}
217*4882a593Smuzhiyun 			cc = ce2[0];
218*4882a593Smuzhiyun 			if (cc) {
219*4882a593Smuzhiyun 				ip += i;
220*4882a593Smuzhiyun 				ustrlen -= i;
221*4882a593Smuzhiyun 				goto done;
222*4882a593Smuzhiyun 			}
223*4882a593Smuzhiyun 		}
224*4882a593Smuzhiyun same:
225*4882a593Smuzhiyun 		switch (c0) {
226*4882a593Smuzhiyun 		case 0:
227*4882a593Smuzhiyun 			cc = 0x2400;
228*4882a593Smuzhiyun 			break;
229*4882a593Smuzhiyun 		case '/':
230*4882a593Smuzhiyun 			cc = ':';
231*4882a593Smuzhiyun 			break;
232*4882a593Smuzhiyun 		default:
233*4882a593Smuzhiyun 			cc = c0;
234*4882a593Smuzhiyun 		}
235*4882a593Smuzhiyun done:
236*4882a593Smuzhiyun 		res = nls->uni2char(cc, op, len);
237*4882a593Smuzhiyun 		if (res < 0) {
238*4882a593Smuzhiyun 			if (res == -ENAMETOOLONG)
239*4882a593Smuzhiyun 				goto out;
240*4882a593Smuzhiyun 			*op = '?';
241*4882a593Smuzhiyun 			res = 1;
242*4882a593Smuzhiyun 		}
243*4882a593Smuzhiyun 		op += res;
244*4882a593Smuzhiyun 		len -= res;
245*4882a593Smuzhiyun 	}
246*4882a593Smuzhiyun 	res = 0;
247*4882a593Smuzhiyun out:
248*4882a593Smuzhiyun 	*len_p = (char *)op - astr;
249*4882a593Smuzhiyun 	return res;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun /*
253*4882a593Smuzhiyun  * Convert one or more ASCII characters into a single unicode character.
254*4882a593Smuzhiyun  * Returns the number of ASCII characters corresponding to the unicode char.
255*4882a593Smuzhiyun  */
asc2unichar(struct super_block * sb,const char * astr,int len,wchar_t * uc)256*4882a593Smuzhiyun static inline int asc2unichar(struct super_block *sb, const char *astr, int len,
257*4882a593Smuzhiyun 			      wchar_t *uc)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun 	int size = HFSPLUS_SB(sb)->nls->char2uni(astr, len, uc);
260*4882a593Smuzhiyun 	if (size <= 0) {
261*4882a593Smuzhiyun 		*uc = '?';
262*4882a593Smuzhiyun 		size = 1;
263*4882a593Smuzhiyun 	}
264*4882a593Smuzhiyun 	switch (*uc) {
265*4882a593Smuzhiyun 	case 0x2400:
266*4882a593Smuzhiyun 		*uc = 0;
267*4882a593Smuzhiyun 		break;
268*4882a593Smuzhiyun 	case ':':
269*4882a593Smuzhiyun 		*uc = '/';
270*4882a593Smuzhiyun 		break;
271*4882a593Smuzhiyun 	}
272*4882a593Smuzhiyun 	return size;
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun /* Decomposes a non-Hangul unicode character. */
hfsplus_decompose_nonhangul(wchar_t uc,int * size)276*4882a593Smuzhiyun static u16 *hfsplus_decompose_nonhangul(wchar_t uc, int *size)
277*4882a593Smuzhiyun {
278*4882a593Smuzhiyun 	int off;
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	off = hfsplus_decompose_table[(uc >> 12) & 0xf];
281*4882a593Smuzhiyun 	if (off == 0 || off == 0xffff)
282*4882a593Smuzhiyun 		return NULL;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	off = hfsplus_decompose_table[off + ((uc >> 8) & 0xf)];
285*4882a593Smuzhiyun 	if (!off)
286*4882a593Smuzhiyun 		return NULL;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	off = hfsplus_decompose_table[off + ((uc >> 4) & 0xf)];
289*4882a593Smuzhiyun 	if (!off)
290*4882a593Smuzhiyun 		return NULL;
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	off = hfsplus_decompose_table[off + (uc & 0xf)];
293*4882a593Smuzhiyun 	*size = off & 3;
294*4882a593Smuzhiyun 	if (*size == 0)
295*4882a593Smuzhiyun 		return NULL;
296*4882a593Smuzhiyun 	return hfsplus_decompose_table + (off / 4);
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun /*
300*4882a593Smuzhiyun  * Try to decompose a unicode character as Hangul. Return 0 if @uc is not
301*4882a593Smuzhiyun  * precomposed Hangul, otherwise return the length of the decomposition.
302*4882a593Smuzhiyun  *
303*4882a593Smuzhiyun  * This function was adapted from sample code from the Unicode Standard
304*4882a593Smuzhiyun  * Annex #15: Unicode Normalization Forms, version 3.2.0.
305*4882a593Smuzhiyun  *
306*4882a593Smuzhiyun  * Copyright (C) 1991-2018 Unicode, Inc.  All rights reserved.  Distributed
307*4882a593Smuzhiyun  * under the Terms of Use in http://www.unicode.org/copyright.html.
308*4882a593Smuzhiyun  */
hfsplus_try_decompose_hangul(wchar_t uc,u16 * result)309*4882a593Smuzhiyun static int hfsplus_try_decompose_hangul(wchar_t uc, u16 *result)
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun 	int index;
312*4882a593Smuzhiyun 	int l, v, t;
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	index = uc - Hangul_SBase;
315*4882a593Smuzhiyun 	if (index < 0 || index >= Hangul_SCount)
316*4882a593Smuzhiyun 		return 0;
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	l = Hangul_LBase + index / Hangul_NCount;
319*4882a593Smuzhiyun 	v = Hangul_VBase + (index % Hangul_NCount) / Hangul_TCount;
320*4882a593Smuzhiyun 	t = Hangul_TBase + index % Hangul_TCount;
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	result[0] = l;
323*4882a593Smuzhiyun 	result[1] = v;
324*4882a593Smuzhiyun 	if (t != Hangul_TBase) {
325*4882a593Smuzhiyun 		result[2] = t;
326*4882a593Smuzhiyun 		return 3;
327*4882a593Smuzhiyun 	}
328*4882a593Smuzhiyun 	return 2;
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun /* Decomposes a single unicode character. */
decompose_unichar(wchar_t uc,int * size,u16 * hangul_buffer)332*4882a593Smuzhiyun static u16 *decompose_unichar(wchar_t uc, int *size, u16 *hangul_buffer)
333*4882a593Smuzhiyun {
334*4882a593Smuzhiyun 	u16 *result;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	/* Hangul is handled separately */
337*4882a593Smuzhiyun 	result = hangul_buffer;
338*4882a593Smuzhiyun 	*size = hfsplus_try_decompose_hangul(uc, result);
339*4882a593Smuzhiyun 	if (*size == 0)
340*4882a593Smuzhiyun 		result = hfsplus_decompose_nonhangul(uc, size);
341*4882a593Smuzhiyun 	return result;
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun 
hfsplus_asc2uni(struct super_block * sb,struct hfsplus_unistr * ustr,int max_unistr_len,const char * astr,int len)344*4882a593Smuzhiyun int hfsplus_asc2uni(struct super_block *sb,
345*4882a593Smuzhiyun 		    struct hfsplus_unistr *ustr, int max_unistr_len,
346*4882a593Smuzhiyun 		    const char *astr, int len)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun 	int size, dsize, decompose;
349*4882a593Smuzhiyun 	u16 *dstr, outlen = 0;
350*4882a593Smuzhiyun 	wchar_t c;
351*4882a593Smuzhiyun 	u16 dhangul[3];
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
354*4882a593Smuzhiyun 	while (outlen < max_unistr_len && len > 0) {
355*4882a593Smuzhiyun 		size = asc2unichar(sb, astr, len, &c);
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 		if (decompose)
358*4882a593Smuzhiyun 			dstr = decompose_unichar(c, &dsize, dhangul);
359*4882a593Smuzhiyun 		else
360*4882a593Smuzhiyun 			dstr = NULL;
361*4882a593Smuzhiyun 		if (dstr) {
362*4882a593Smuzhiyun 			if (outlen + dsize > max_unistr_len)
363*4882a593Smuzhiyun 				break;
364*4882a593Smuzhiyun 			do {
365*4882a593Smuzhiyun 				ustr->unicode[outlen++] = cpu_to_be16(*dstr++);
366*4882a593Smuzhiyun 			} while (--dsize > 0);
367*4882a593Smuzhiyun 		} else
368*4882a593Smuzhiyun 			ustr->unicode[outlen++] = cpu_to_be16(c);
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 		astr += size;
371*4882a593Smuzhiyun 		len -= size;
372*4882a593Smuzhiyun 	}
373*4882a593Smuzhiyun 	ustr->length = cpu_to_be16(outlen);
374*4882a593Smuzhiyun 	if (len > 0)
375*4882a593Smuzhiyun 		return -ENAMETOOLONG;
376*4882a593Smuzhiyun 	return 0;
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun /*
380*4882a593Smuzhiyun  * Hash a string to an integer as appropriate for the HFS+ filesystem.
381*4882a593Smuzhiyun  * Composed unicode characters are decomposed and case-folding is performed
382*4882a593Smuzhiyun  * if the appropriate bits are (un)set on the superblock.
383*4882a593Smuzhiyun  */
hfsplus_hash_dentry(const struct dentry * dentry,struct qstr * str)384*4882a593Smuzhiyun int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str)
385*4882a593Smuzhiyun {
386*4882a593Smuzhiyun 	struct super_block *sb = dentry->d_sb;
387*4882a593Smuzhiyun 	const char *astr;
388*4882a593Smuzhiyun 	const u16 *dstr;
389*4882a593Smuzhiyun 	int casefold, decompose, size, len;
390*4882a593Smuzhiyun 	unsigned long hash;
391*4882a593Smuzhiyun 	wchar_t c;
392*4882a593Smuzhiyun 	u16 c2;
393*4882a593Smuzhiyun 	u16 dhangul[3];
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
396*4882a593Smuzhiyun 	decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
397*4882a593Smuzhiyun 	hash = init_name_hash(dentry);
398*4882a593Smuzhiyun 	astr = str->name;
399*4882a593Smuzhiyun 	len = str->len;
400*4882a593Smuzhiyun 	while (len > 0) {
401*4882a593Smuzhiyun 		int dsize;
402*4882a593Smuzhiyun 		size = asc2unichar(sb, astr, len, &c);
403*4882a593Smuzhiyun 		astr += size;
404*4882a593Smuzhiyun 		len -= size;
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 		if (decompose)
407*4882a593Smuzhiyun 			dstr = decompose_unichar(c, &dsize, dhangul);
408*4882a593Smuzhiyun 		else
409*4882a593Smuzhiyun 			dstr = NULL;
410*4882a593Smuzhiyun 		if (dstr) {
411*4882a593Smuzhiyun 			do {
412*4882a593Smuzhiyun 				c2 = *dstr++;
413*4882a593Smuzhiyun 				if (casefold)
414*4882a593Smuzhiyun 					c2 = case_fold(c2);
415*4882a593Smuzhiyun 				if (!casefold || c2)
416*4882a593Smuzhiyun 					hash = partial_name_hash(c2, hash);
417*4882a593Smuzhiyun 			} while (--dsize > 0);
418*4882a593Smuzhiyun 		} else {
419*4882a593Smuzhiyun 			c2 = c;
420*4882a593Smuzhiyun 			if (casefold)
421*4882a593Smuzhiyun 				c2 = case_fold(c2);
422*4882a593Smuzhiyun 			if (!casefold || c2)
423*4882a593Smuzhiyun 				hash = partial_name_hash(c2, hash);
424*4882a593Smuzhiyun 		}
425*4882a593Smuzhiyun 	}
426*4882a593Smuzhiyun 	str->hash = end_name_hash(hash);
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	return 0;
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun /*
432*4882a593Smuzhiyun  * Compare strings with HFS+ filename ordering.
433*4882a593Smuzhiyun  * Composed unicode characters are decomposed and case-folding is performed
434*4882a593Smuzhiyun  * if the appropriate bits are (un)set on the superblock.
435*4882a593Smuzhiyun  */
hfsplus_compare_dentry(const struct dentry * dentry,unsigned int len,const char * str,const struct qstr * name)436*4882a593Smuzhiyun int hfsplus_compare_dentry(const struct dentry *dentry,
437*4882a593Smuzhiyun 		unsigned int len, const char *str, const struct qstr *name)
438*4882a593Smuzhiyun {
439*4882a593Smuzhiyun 	struct super_block *sb = dentry->d_sb;
440*4882a593Smuzhiyun 	int casefold, decompose, size;
441*4882a593Smuzhiyun 	int dsize1, dsize2, len1, len2;
442*4882a593Smuzhiyun 	const u16 *dstr1, *dstr2;
443*4882a593Smuzhiyun 	const char *astr1, *astr2;
444*4882a593Smuzhiyun 	u16 c1, c2;
445*4882a593Smuzhiyun 	wchar_t c;
446*4882a593Smuzhiyun 	u16 dhangul_1[3], dhangul_2[3];
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
449*4882a593Smuzhiyun 	decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
450*4882a593Smuzhiyun 	astr1 = str;
451*4882a593Smuzhiyun 	len1 = len;
452*4882a593Smuzhiyun 	astr2 = name->name;
453*4882a593Smuzhiyun 	len2 = name->len;
454*4882a593Smuzhiyun 	dsize1 = dsize2 = 0;
455*4882a593Smuzhiyun 	dstr1 = dstr2 = NULL;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	while (len1 > 0 && len2 > 0) {
458*4882a593Smuzhiyun 		if (!dsize1) {
459*4882a593Smuzhiyun 			size = asc2unichar(sb, astr1, len1, &c);
460*4882a593Smuzhiyun 			astr1 += size;
461*4882a593Smuzhiyun 			len1 -= size;
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 			if (decompose)
464*4882a593Smuzhiyun 				dstr1 = decompose_unichar(c, &dsize1,
465*4882a593Smuzhiyun 							  dhangul_1);
466*4882a593Smuzhiyun 			if (!decompose || !dstr1) {
467*4882a593Smuzhiyun 				c1 = c;
468*4882a593Smuzhiyun 				dstr1 = &c1;
469*4882a593Smuzhiyun 				dsize1 = 1;
470*4882a593Smuzhiyun 			}
471*4882a593Smuzhiyun 		}
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 		if (!dsize2) {
474*4882a593Smuzhiyun 			size = asc2unichar(sb, astr2, len2, &c);
475*4882a593Smuzhiyun 			astr2 += size;
476*4882a593Smuzhiyun 			len2 -= size;
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 			if (decompose)
479*4882a593Smuzhiyun 				dstr2 = decompose_unichar(c, &dsize2,
480*4882a593Smuzhiyun 							  dhangul_2);
481*4882a593Smuzhiyun 			if (!decompose || !dstr2) {
482*4882a593Smuzhiyun 				c2 = c;
483*4882a593Smuzhiyun 				dstr2 = &c2;
484*4882a593Smuzhiyun 				dsize2 = 1;
485*4882a593Smuzhiyun 			}
486*4882a593Smuzhiyun 		}
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 		c1 = *dstr1;
489*4882a593Smuzhiyun 		c2 = *dstr2;
490*4882a593Smuzhiyun 		if (casefold) {
491*4882a593Smuzhiyun 			c1 = case_fold(c1);
492*4882a593Smuzhiyun 			if (!c1) {
493*4882a593Smuzhiyun 				dstr1++;
494*4882a593Smuzhiyun 				dsize1--;
495*4882a593Smuzhiyun 				continue;
496*4882a593Smuzhiyun 			}
497*4882a593Smuzhiyun 			c2 = case_fold(c2);
498*4882a593Smuzhiyun 			if (!c2) {
499*4882a593Smuzhiyun 				dstr2++;
500*4882a593Smuzhiyun 				dsize2--;
501*4882a593Smuzhiyun 				continue;
502*4882a593Smuzhiyun 			}
503*4882a593Smuzhiyun 		}
504*4882a593Smuzhiyun 		if (c1 < c2)
505*4882a593Smuzhiyun 			return -1;
506*4882a593Smuzhiyun 		else if (c1 > c2)
507*4882a593Smuzhiyun 			return 1;
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 		dstr1++;
510*4882a593Smuzhiyun 		dsize1--;
511*4882a593Smuzhiyun 		dstr2++;
512*4882a593Smuzhiyun 		dsize2--;
513*4882a593Smuzhiyun 	}
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 	if (len1 < len2)
516*4882a593Smuzhiyun 		return -1;
517*4882a593Smuzhiyun 	if (len1 > len2)
518*4882a593Smuzhiyun 		return 1;
519*4882a593Smuzhiyun 	return 0;
520*4882a593Smuzhiyun }
521