1 /*
2  *  linux/fs/hfsplus/unicode.c
3  *
4  * Copyright (C) 2001
5  * Brad Boyer (flar@allandria.com)
6  * (C) 2003 Ardis Technologies <roman@ardistech.com>
7  *
8  * Handler routines for unicode strings
9  */
10 
11 #include <linux/types.h>
12 #include <linux/nls.h>
13 #include "hfsplus_fs.h"
14 #include "hfsplus_raw.h"
15 
16 /* Fold the case of a unicode char, given the 16 bit value */
17 /* Returns folded char, or 0 if ignorable */
case_fold(u16 c)18 static inline u16 case_fold(u16 c)
19 {
20         u16 tmp;
21 
22         tmp = case_fold_table[(c>>8)];
23         if (tmp)
24                 tmp = case_fold_table[tmp + (c & 0xFF)];
25         else
26                 tmp = c;
27         return tmp;
28 }
29 
30 /* Compare unicode strings, return values like normal strcmp */
hfsplus_unistrcmp(const hfsplus_unistr * s1,const hfsplus_unistr * s2)31 int hfsplus_unistrcmp(const hfsplus_unistr *s1, const hfsplus_unistr *s2)
32 {
33 	u16 len1, len2, c1, c2;
34 	const hfsplus_unichr *p1, *p2;
35 
36 	len1 = be16_to_cpu(s1->length);
37 	len2 = be16_to_cpu(s2->length);
38 	p1 = s1->unicode;
39 	p2 = s2->unicode;
40 
41 	while (1) {
42 		c1 = c2 = 0;
43 
44 		while (len1 && !c1) {
45 			c1 = case_fold(be16_to_cpu(*p1));
46 			p1++;
47 			len1--;
48 		}
49 		while (len2 && !c2) {
50 			c2 = case_fold(be16_to_cpu(*p2));
51 			p2++;
52 			len2--;
53 		}
54 
55 		if (c1 != c2)
56 			return (c1 < c2) ? -1 : 1;
57 		if (!c1 && !c2)
58 			return 0;
59 	}
60 }
61 
hfsplus_uni2asc(const hfsplus_unistr * ustr,char * astr,int * len)62 int hfsplus_uni2asc(const hfsplus_unistr *ustr, char *astr, int *len)
63 {
64 	const hfsplus_unichr *ip;
65 	u8 *op;
66 	u16 ustrlen, cc;
67 	int size, tmp;
68 
69 	op = astr;
70 	ip = ustr->unicode;
71 	ustrlen = be16_to_cpu(ustr->length);
72 	tmp = *len;
73 	while (ustrlen > 0 && tmp > 0) {
74 		cc = be16_to_cpu(*ip);
75 		if (!cc || cc > 0x7f) {
76 			size = utf8_wctomb(op, cc ? cc : 0x2400, tmp);
77 			if (size == -1) {
78 				/* ignore */
79 			} else {
80 				op += size;
81 				tmp -= size;
82 			}
83 		} else {
84 			*op++ = (u8) cc;
85 			tmp--;
86 		}
87 		ip++;
88 		ustrlen--;
89 	}
90 	*len = (char *)op - astr;
91 	if (ustrlen)
92 		return -ENAMETOOLONG;
93 	return 0;
94 }
95 
hfsplus_asc2uni(hfsplus_unistr * ustr,const char * astr,int len)96 int hfsplus_asc2uni(hfsplus_unistr *ustr, const char *astr, int len)
97 {
98 	int tmp;
99 	wchar_t c;
100 	u16 outlen = 0;
101 
102 	while (outlen <= HFSPLUS_MAX_STRLEN && len > 0) {
103 		if (*astr & 0x80) {
104 			tmp = utf8_mbtowc(&c, astr, len);
105 			if (tmp < 0) {
106 				astr++;
107 				len--;
108 				continue;
109 			} else {
110 				astr += tmp;
111 				len -= tmp;
112 			}
113 			if (c == 0x2400)
114 				c = 0;
115 		} else {
116 			c = *astr++;
117 			len--;
118 		}
119 		ustr->unicode[outlen] = cpu_to_be16(c);
120 		outlen++;
121 	}
122 	ustr->length = cpu_to_be16(outlen);
123 	if (len > 0)
124 		return -ENAMETOOLONG;
125 	return 0;
126 }
127