1/*
2 * cifs_unicode:  Unicode kernel case support
3 *
4 * Function:
5 *     Convert a unicode character to upper or lower case using
6 *     compressed tables.
7 *
8 *   Copyright (c) International Business Machines  Corp., 2000,2009
9 *
10 *   This program is free software;  you can redistribute it and/or modify
11 *   it under the terms of the GNU General Public License as published by
12 *   the Free Software Foundation; either version 2 of the License, or
13 *   (at your option) any later version.
14 *
15 *   This program is distributed in the hope that it will be useful,
16 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
17 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
18 *   the GNU General Public License for more details.
19 *
20 *   You should have received a copy of the GNU General Public License
21 *   along with this program;  if not, write to the Free Software
22 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 *
25 * Notes:
26 *     These APIs are based on the C library functions.  The semantics
27 *     should match the C functions but with expanded size operands.
28 *
29 *     The upper/lower functions are based on a table created by mkupr.
30 *     This is a compressed table of upper and lower case conversion.
31 *
32 */
33#ifndef _CIFS_UNICODE_H
34#define _CIFS_UNICODE_H
35
36#include <asm/byteorder.h>
37#include <linux/types.h>
38#include <linux/nls.h>
39
40#define  UNIUPR_NOLOWER		/* Example to not expand lower case tables */
41
42/*
43 * Windows maps these to the user defined 16 bit Unicode range since they are
44 * reserved symbols (along with \ and /), otherwise illegal to store
45 * in filenames in NTFS
46 */
47#define UNI_ASTERIK     (__u16) ('*' + 0xF000)
48#define UNI_QUESTION    (__u16) ('?' + 0xF000)
49#define UNI_COLON       (__u16) (':' + 0xF000)
50#define UNI_GRTRTHAN    (__u16) ('>' + 0xF000)
51#define UNI_LESSTHAN    (__u16) ('<' + 0xF000)
52#define UNI_PIPE        (__u16) ('|' + 0xF000)
53#define UNI_SLASH       (__u16) ('\\' + 0xF000)
54
55/* Just define what we want from uniupr.h.  We don't want to define the tables
56 * in each source file.
57 */
58#ifndef	UNICASERANGE_DEFINED
59struct UniCaseRange {
60	wchar_t start;
61	wchar_t end;
62	signed char *table;
63};
64#endif				/* UNICASERANGE_DEFINED */
65
66#ifndef UNIUPR_NOUPPER
67extern signed char CifsUniUpperTable[512];
68extern const struct UniCaseRange CifsUniUpperRange[];
69#endif				/* UNIUPR_NOUPPER */
70
71#ifndef UNIUPR_NOLOWER
72extern signed char CifsUniLowerTable[512];
73extern const struct UniCaseRange CifsUniLowerRange[];
74#endif				/* UNIUPR_NOLOWER */
75
76#ifdef __KERNEL__
77int cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen,
78		   const struct nls_table *codepage, bool mapchar);
79int cifs_ucs2_bytes(const __le16 *from, int maxbytes,
80		    const struct nls_table *codepage);
81int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *);
82char *cifs_strndup_from_ucs(const char *src, const int maxlen,
83			    const bool is_unicode,
84			    const struct nls_table *codepage);
85#endif
86
87/*
88 * UniStrcat:  Concatenate the second string to the first
89 *
90 * Returns:
91 *     Address of the first string
92 */
93static inline wchar_t *
94UniStrcat(wchar_t *ucs1, const wchar_t *ucs2)
95{
96	wchar_t *anchor = ucs1;	/* save a pointer to start of ucs1 */
97
98	while (*ucs1++) ;	/* To end of first string */
99	ucs1--;			/* Return to the null */
100	while ((*ucs1++ = *ucs2++)) ;	/* copy string 2 over */
101	return anchor;
102}
103
104/*
105 * UniStrchr:  Find a character in a string
106 *
107 * Returns:
108 *     Address of first occurrence of character in string
109 *     or NULL if the character is not in the string
110 */
111static inline wchar_t *
112UniStrchr(const wchar_t *ucs, wchar_t uc)
113{
114	while ((*ucs != uc) && *ucs)
115		ucs++;
116
117	if (*ucs == uc)
118		return (wchar_t *) ucs;
119	return NULL;
120}
121
122/*
123 * UniStrcmp:  Compare two strings
124 *
125 * Returns:
126 *     < 0:  First string is less than second
127 *     = 0:  Strings are equal
128 *     > 0:  First string is greater than second
129 */
130static inline int
131UniStrcmp(const wchar_t *ucs1, const wchar_t *ucs2)
132{
133	while ((*ucs1 == *ucs2) && *ucs1) {
134		ucs1++;
135		ucs2++;
136	}
137	return (int) *ucs1 - (int) *ucs2;
138}
139
140/*
141 * UniStrcpy:  Copy a string
142 */
143static inline wchar_t *
144UniStrcpy(wchar_t *ucs1, const wchar_t *ucs2)
145{
146	wchar_t *anchor = ucs1;	/* save the start of result string */
147
148	while ((*ucs1++ = *ucs2++)) ;
149	return anchor;
150}
151
152/*
153 * UniStrlen:  Return the length of a string (in 16 bit Unicode chars not bytes)
154 */
155static inline size_t
156UniStrlen(const wchar_t *ucs1)
157{
158	int i = 0;
159
160	while (*ucs1++)
161		i++;
162	return i;
163}
164
165/*
166 * UniStrnlen:  Return the length (in 16 bit Unicode chars not bytes) of a
167 *		string (length limited)
168 */
169static inline size_t
170UniStrnlen(const wchar_t *ucs1, int maxlen)
171{
172	int i = 0;
173
174	while (*ucs1++) {
175		i++;
176		if (i >= maxlen)
177			break;
178	}
179	return i;
180}
181
182/*
183 * UniStrncat:  Concatenate length limited string
184 */
185static inline wchar_t *
186UniStrncat(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
187{
188	wchar_t *anchor = ucs1;	/* save pointer to string 1 */
189
190	while (*ucs1++) ;
191	ucs1--;			/* point to null terminator of s1 */
192	while (n-- && (*ucs1 = *ucs2)) {	/* copy s2 after s1 */
193		ucs1++;
194		ucs2++;
195	}
196	*ucs1 = 0;		/* Null terminate the result */
197	return (anchor);
198}
199
200/*
201 * UniStrncmp:  Compare length limited string
202 */
203static inline int
204UniStrncmp(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
205{
206	if (!n)
207		return 0;	/* Null strings are equal */
208	while ((*ucs1 == *ucs2) && *ucs1 && --n) {
209		ucs1++;
210		ucs2++;
211	}
212	return (int) *ucs1 - (int) *ucs2;
213}
214
215/*
216 * UniStrncmp_le:  Compare length limited string - native to little-endian
217 */
218static inline int
219UniStrncmp_le(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
220{
221	if (!n)
222		return 0;	/* Null strings are equal */
223	while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) {
224		ucs1++;
225		ucs2++;
226	}
227	return (int) *ucs1 - (int) __le16_to_cpu(*ucs2);
228}
229
230/*
231 * UniStrncpy:  Copy length limited string with pad
232 */
233static inline wchar_t *
234UniStrncpy(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
235{
236	wchar_t *anchor = ucs1;
237
238	while (n-- && *ucs2)	/* Copy the strings */
239		*ucs1++ = *ucs2++;
240
241	n++;
242	while (n--)		/* Pad with nulls */
243		*ucs1++ = 0;
244	return anchor;
245}
246
247/*
248 * UniStrncpy_le:  Copy length limited string with pad to little-endian
249 */
250static inline wchar_t *
251UniStrncpy_le(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
252{
253	wchar_t *anchor = ucs1;
254
255	while (n-- && *ucs2)	/* Copy the strings */
256		*ucs1++ = __le16_to_cpu(*ucs2++);
257
258	n++;
259	while (n--)		/* Pad with nulls */
260		*ucs1++ = 0;
261	return anchor;
262}
263
264/*
265 * UniStrstr:  Find a string in a string
266 *
267 * Returns:
268 *     Address of first match found
269 *     NULL if no matching string is found
270 */
271static inline wchar_t *
272UniStrstr(const wchar_t *ucs1, const wchar_t *ucs2)
273{
274	const wchar_t *anchor1 = ucs1;
275	const wchar_t *anchor2 = ucs2;
276
277	while (*ucs1) {
278		if (*ucs1 == *ucs2) {
279			/* Partial match found */
280			ucs1++;
281			ucs2++;
282		} else {
283			if (!*ucs2)	/* Match found */
284				return (wchar_t *) anchor1;
285			ucs1 = ++anchor1;	/* No match */
286			ucs2 = anchor2;
287		}
288	}
289
290	if (!*ucs2)		/* Both end together */
291		return (wchar_t *) anchor1;	/* Match found */
292	return NULL;		/* No match */
293}
294
295#ifndef UNIUPR_NOUPPER
296/*
297 * UniToupper:  Convert a unicode character to upper case
298 */
299static inline wchar_t
300UniToupper(register wchar_t uc)
301{
302	register const struct UniCaseRange *rp;
303
304	if (uc < sizeof(CifsUniUpperTable)) {
305		/* Latin characters */
306		return uc + CifsUniUpperTable[uc];	/* Use base tables */
307	} else {
308		rp = CifsUniUpperRange;	/* Use range tables */
309		while (rp->start) {
310			if (uc < rp->start)	/* Before start of range */
311				return uc;	/* Uppercase = input */
312			if (uc <= rp->end)	/* In range */
313				return uc + rp->table[uc - rp->start];
314			rp++;	/* Try next range */
315		}
316	}
317	return uc;		/* Past last range */
318}
319
320/*
321 * UniStrupr:  Upper case a unicode string
322 */
323static inline wchar_t *
324UniStrupr(register wchar_t *upin)
325{
326	register wchar_t *up;
327
328	up = upin;
329	while (*up) {		/* For all characters */
330		*up = UniToupper(*up);
331		up++;
332	}
333	return upin;		/* Return input pointer */
334}
335#endif				/* UNIUPR_NOUPPER */
336
337#ifndef UNIUPR_NOLOWER
338/*
339 * UniTolower:  Convert a unicode character to lower case
340 */
341static inline wchar_t
342UniTolower(register wchar_t uc)
343{
344	register const struct UniCaseRange *rp;
345
346	if (uc < sizeof(CifsUniLowerTable)) {
347		/* Latin characters */
348		return uc + CifsUniLowerTable[uc];	/* Use base tables */
349	} else {
350		rp = CifsUniLowerRange;	/* Use range tables */
351		while (rp->start) {
352			if (uc < rp->start)	/* Before start of range */
353				return uc;	/* Uppercase = input */
354			if (uc <= rp->end)	/* In range */
355				return uc + rp->table[uc - rp->start];
356			rp++;	/* Try next range */
357		}
358	}
359	return uc;		/* Past last range */
360}
361
362/*
363 * UniStrlwr:  Lower case a unicode string
364 */
365static inline wchar_t *
366UniStrlwr(register wchar_t *upin)
367{
368	register wchar_t *up;
369
370	up = upin;
371	while (*up) {		/* For all characters */
372		*up = UniTolower(*up);
373		up++;
374	}
375	return upin;		/* Return input pointer */
376}
377
378#endif
379
380#endif /* _CIFS_UNICODE_H */
381