Linux-libre 5.4.49-gnu
[librecmc/linux-libre.git] / fs / cifs / cifs_unicode.h
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * cifs_unicode:  Unicode kernel case support
4  *
5  * Function:
6  *     Convert a unicode character to upper or lower case using
7  *     compressed tables.
8  *
9  *   Copyright (c) International Business Machines  Corp., 2000,2009
10  *
11  * Notes:
12  *     These APIs are based on the C library functions.  The semantics
13  *     should match the C functions but with expanded size operands.
14  *
15  *     The upper/lower functions are based on a table created by mkupr.
16  *     This is a compressed table of upper and lower case conversion.
17  */
18 #ifndef _CIFS_UNICODE_H
19 #define _CIFS_UNICODE_H
20
21 #include <asm/byteorder.h>
22 #include <linux/types.h>
23 #include <linux/nls.h>
24
25 #define  UNIUPR_NOLOWER         /* Example to not expand lower case tables */
26
27 /*
28  * Windows maps these to the user defined 16 bit Unicode range since they are
29  * reserved symbols (along with \ and /), otherwise illegal to store
30  * in filenames in NTFS
31  */
32 #define UNI_ASTERISK    (__u16) ('*' + 0xF000)
33 #define UNI_QUESTION    (__u16) ('?' + 0xF000)
34 #define UNI_COLON       (__u16) (':' + 0xF000)
35 #define UNI_GRTRTHAN    (__u16) ('>' + 0xF000)
36 #define UNI_LESSTHAN    (__u16) ('<' + 0xF000)
37 #define UNI_PIPE        (__u16) ('|' + 0xF000)
38 #define UNI_SLASH       (__u16) ('\\' + 0xF000)
39
40 /*
41  * Macs use an older "SFM" mapping of the symbols above. Fortunately it does
42  * not conflict (although almost does) with the mapping above.
43  */
44
45 #define SFM_DOUBLEQUOTE ((__u16) 0xF020)
46 #define SFM_ASTERISK    ((__u16) 0xF021)
47 #define SFM_QUESTION    ((__u16) 0xF025)
48 #define SFM_COLON       ((__u16) 0xF022)
49 #define SFM_GRTRTHAN    ((__u16) 0xF024)
50 #define SFM_LESSTHAN    ((__u16) 0xF023)
51 #define SFM_PIPE        ((__u16) 0xF027)
52 #define SFM_SLASH       ((__u16) 0xF026)
53 #define SFM_SPACE       ((__u16) 0xF028)
54 #define SFM_PERIOD      ((__u16) 0xF029)
55
56 /*
57  * Mapping mechanism to use when one of the seven reserved characters is
58  * encountered.  We can only map using one of the mechanisms at a time
59  * since otherwise readdir could return directory entries which we would
60  * not be able to open
61  *
62  * NO_MAP_UNI_RSVD  = do not perform any remapping of the character
63  * SFM_MAP_UNI_RSVD = map reserved characters using SFM scheme (MAC compatible)
64  * SFU_MAP_UNI_RSVD = map reserved characters ala SFU ("mapchars" option)
65  *
66  */
67 #define NO_MAP_UNI_RSVD         0
68 #define SFM_MAP_UNI_RSVD        1
69 #define SFU_MAP_UNI_RSVD        2
70
71 /* Just define what we want from uniupr.h.  We don't want to define the tables
72  * in each source file.
73  */
74 #ifndef UNICASERANGE_DEFINED
75 struct UniCaseRange {
76         wchar_t start;
77         wchar_t end;
78         signed char *table;
79 };
80 #endif                          /* UNICASERANGE_DEFINED */
81
82 #ifndef UNIUPR_NOUPPER
83 extern signed char CifsUniUpperTable[512];
84 extern const struct UniCaseRange CifsUniUpperRange[];
85 #endif                          /* UNIUPR_NOUPPER */
86
87 #ifndef UNIUPR_NOLOWER
88 extern signed char CifsUniLowerTable[512];
89 extern const struct UniCaseRange CifsUniLowerRange[];
90 #endif                          /* UNIUPR_NOLOWER */
91
92 #ifdef __KERNEL__
93 int cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
94                     const struct nls_table *cp, int map_type);
95 int cifs_utf16_bytes(const __le16 *from, int maxbytes,
96                      const struct nls_table *codepage);
97 int cifs_strtoUTF16(__le16 *, const char *, int, const struct nls_table *);
98 char *cifs_strndup_from_utf16(const char *src, const int maxlen,
99                               const bool is_unicode,
100                               const struct nls_table *codepage);
101 extern int cifsConvertToUTF16(__le16 *target, const char *source, int maxlen,
102                               const struct nls_table *cp, int mapChars);
103 extern int cifs_remap(struct cifs_sb_info *cifs_sb);
104 extern __le16 *cifs_strndup_to_utf16(const char *src, const int maxlen,
105                                      int *utf16_len, const struct nls_table *cp,
106                                      int remap);
107 #endif
108
109 wchar_t cifs_toupper(wchar_t in);
110
111 /*
112  * UniStrcat:  Concatenate the second string to the first
113  *
114  * Returns:
115  *     Address of the first string
116  */
117 static inline __le16 *
118 UniStrcat(__le16 *ucs1, const __le16 *ucs2)
119 {
120         __le16 *anchor = ucs1;  /* save a pointer to start of ucs1 */
121
122         while (*ucs1++) ;       /* To end of first string */
123         ucs1--;                 /* Return to the null */
124         while ((*ucs1++ = *ucs2++)) ;   /* copy string 2 over */
125         return anchor;
126 }
127
128 /*
129  * UniStrchr:  Find a character in a string
130  *
131  * Returns:
132  *     Address of first occurrence of character in string
133  *     or NULL if the character is not in the string
134  */
135 static inline wchar_t *
136 UniStrchr(const wchar_t *ucs, wchar_t uc)
137 {
138         while ((*ucs != uc) && *ucs)
139                 ucs++;
140
141         if (*ucs == uc)
142                 return (wchar_t *) ucs;
143         return NULL;
144 }
145
146 /*
147  * UniStrcmp:  Compare two strings
148  *
149  * Returns:
150  *     < 0:  First string is less than second
151  *     = 0:  Strings are equal
152  *     > 0:  First string is greater than second
153  */
154 static inline int
155 UniStrcmp(const wchar_t *ucs1, const wchar_t *ucs2)
156 {
157         while ((*ucs1 == *ucs2) && *ucs1) {
158                 ucs1++;
159                 ucs2++;
160         }
161         return (int) *ucs1 - (int) *ucs2;
162 }
163
164 /*
165  * UniStrcpy:  Copy a string
166  */
167 static inline wchar_t *
168 UniStrcpy(wchar_t *ucs1, const wchar_t *ucs2)
169 {
170         wchar_t *anchor = ucs1; /* save the start of result string */
171
172         while ((*ucs1++ = *ucs2++)) ;
173         return anchor;
174 }
175
176 /*
177  * UniStrlen:  Return the length of a string (in 16 bit Unicode chars not bytes)
178  */
179 static inline size_t
180 UniStrlen(const wchar_t *ucs1)
181 {
182         int i = 0;
183
184         while (*ucs1++)
185                 i++;
186         return i;
187 }
188
189 /*
190  * UniStrnlen:  Return the length (in 16 bit Unicode chars not bytes) of a
191  *              string (length limited)
192  */
193 static inline size_t
194 UniStrnlen(const wchar_t *ucs1, int maxlen)
195 {
196         int i = 0;
197
198         while (*ucs1++) {
199                 i++;
200                 if (i >= maxlen)
201                         break;
202         }
203         return i;
204 }
205
206 /*
207  * UniStrncat:  Concatenate length limited string
208  */
209 static inline wchar_t *
210 UniStrncat(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
211 {
212         wchar_t *anchor = ucs1; /* save pointer to string 1 */
213
214         while (*ucs1++) ;
215         ucs1--;                 /* point to null terminator of s1 */
216         while (n-- && (*ucs1 = *ucs2)) {        /* copy s2 after s1 */
217                 ucs1++;
218                 ucs2++;
219         }
220         *ucs1 = 0;              /* Null terminate the result */
221         return (anchor);
222 }
223
224 /*
225  * UniStrncmp:  Compare length limited string
226  */
227 static inline int
228 UniStrncmp(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
229 {
230         if (!n)
231                 return 0;       /* Null strings are equal */
232         while ((*ucs1 == *ucs2) && *ucs1 && --n) {
233                 ucs1++;
234                 ucs2++;
235         }
236         return (int) *ucs1 - (int) *ucs2;
237 }
238
239 /*
240  * UniStrncmp_le:  Compare length limited string - native to little-endian
241  */
242 static inline int
243 UniStrncmp_le(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
244 {
245         if (!n)
246                 return 0;       /* Null strings are equal */
247         while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) {
248                 ucs1++;
249                 ucs2++;
250         }
251         return (int) *ucs1 - (int) __le16_to_cpu(*ucs2);
252 }
253
254 /*
255  * UniStrncpy:  Copy length limited string with pad
256  */
257 static inline wchar_t *
258 UniStrncpy(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
259 {
260         wchar_t *anchor = ucs1;
261
262         while (n-- && *ucs2)    /* Copy the strings */
263                 *ucs1++ = *ucs2++;
264
265         n++;
266         while (n--)             /* Pad with nulls */
267                 *ucs1++ = 0;
268         return anchor;
269 }
270
271 /*
272  * UniStrncpy_le:  Copy length limited string with pad to little-endian
273  */
274 static inline wchar_t *
275 UniStrncpy_le(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
276 {
277         wchar_t *anchor = ucs1;
278
279         while (n-- && *ucs2)    /* Copy the strings */
280                 *ucs1++ = __le16_to_cpu(*ucs2++);
281
282         n++;
283         while (n--)             /* Pad with nulls */
284                 *ucs1++ = 0;
285         return anchor;
286 }
287
288 /*
289  * UniStrstr:  Find a string in a string
290  *
291  * Returns:
292  *     Address of first match found
293  *     NULL if no matching string is found
294  */
295 static inline wchar_t *
296 UniStrstr(const wchar_t *ucs1, const wchar_t *ucs2)
297 {
298         const wchar_t *anchor1 = ucs1;
299         const wchar_t *anchor2 = ucs2;
300
301         while (*ucs1) {
302                 if (*ucs1 == *ucs2) {
303                         /* Partial match found */
304                         ucs1++;
305                         ucs2++;
306                 } else {
307                         if (!*ucs2)     /* Match found */
308                                 return (wchar_t *) anchor1;
309                         ucs1 = ++anchor1;       /* No match */
310                         ucs2 = anchor2;
311                 }
312         }
313
314         if (!*ucs2)             /* Both end together */
315                 return (wchar_t *) anchor1;     /* Match found */
316         return NULL;            /* No match */
317 }
318
319 #ifndef UNIUPR_NOUPPER
320 /*
321  * UniToupper:  Convert a unicode character to upper case
322  */
323 static inline wchar_t
324 UniToupper(register wchar_t uc)
325 {
326         register const struct UniCaseRange *rp;
327
328         if (uc < sizeof(CifsUniUpperTable)) {
329                 /* Latin characters */
330                 return uc + CifsUniUpperTable[uc];      /* Use base tables */
331         } else {
332                 rp = CifsUniUpperRange; /* Use range tables */
333                 while (rp->start) {
334                         if (uc < rp->start)     /* Before start of range */
335                                 return uc;      /* Uppercase = input */
336                         if (uc <= rp->end)      /* In range */
337                                 return uc + rp->table[uc - rp->start];
338                         rp++;   /* Try next range */
339                 }
340         }
341         return uc;              /* Past last range */
342 }
343
344 /*
345  * UniStrupr:  Upper case a unicode string
346  */
347 static inline __le16 *
348 UniStrupr(register __le16 *upin)
349 {
350         register __le16 *up;
351
352         up = upin;
353         while (*up) {           /* For all characters */
354                 *up = cpu_to_le16(UniToupper(le16_to_cpu(*up)));
355                 up++;
356         }
357         return upin;            /* Return input pointer */
358 }
359 #endif                          /* UNIUPR_NOUPPER */
360
361 #ifndef UNIUPR_NOLOWER
362 /*
363  * UniTolower:  Convert a unicode character to lower case
364  */
365 static inline wchar_t
366 UniTolower(register wchar_t uc)
367 {
368         register const struct UniCaseRange *rp;
369
370         if (uc < sizeof(CifsUniLowerTable)) {
371                 /* Latin characters */
372                 return uc + CifsUniLowerTable[uc];      /* Use base tables */
373         } else {
374                 rp = CifsUniLowerRange; /* Use range tables */
375                 while (rp->start) {
376                         if (uc < rp->start)     /* Before start of range */
377                                 return uc;      /* Uppercase = input */
378                         if (uc <= rp->end)      /* In range */
379                                 return uc + rp->table[uc - rp->start];
380                         rp++;   /* Try next range */
381                 }
382         }
383         return uc;              /* Past last range */
384 }
385
386 /*
387  * UniStrlwr:  Lower case a unicode string
388  */
389 static inline wchar_t *
390 UniStrlwr(register wchar_t *upin)
391 {
392         register wchar_t *up;
393
394         up = upin;
395         while (*up) {           /* For all characters */
396                 *up = UniTolower(*up);
397                 up++;
398         }
399         return upin;            /* Return input pointer */
400 }
401
402 #endif
403
404 #endif /* _CIFS_UNICODE_H */