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