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,2005555555555555555555555555555555555555555555555555555555 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 34#include <asm/byteorder.h> 35#include <linux/types.h> 36#include <linux/nls.h> 37 38#define UNIUPR_NOLOWER /* Example to not expand lower case tables */ 39 40/* Just define what we want from uniupr.h. We don't want to define the tables 41 * in each source file. 42 */ 43#ifndef UNICASERANGE_DEFINED 44struct UniCaseRange { 45 wchar_t start; 46 wchar_t end; 47 signed char *table; 48}; 49#endif /* UNICASERANGE_DEFINED */ 50 51#ifndef UNIUPR_NOUPPER 52extern signed char CifsUniUpperTable[512]; 53extern const struct UniCaseRange CifsUniUpperRange[]; 54#endif /* UNIUPR_NOUPPER */ 55 56#ifndef UNIUPR_NOLOWER 57extern signed char UniLowerTable[512]; 58extern struct UniCaseRange UniLowerRange[]; 59#endif /* UNIUPR_NOLOWER */ 60 61#ifdef __KERNEL__ 62int cifs_strfromUCS_le(char *, const __le16 *, int, const struct nls_table *); 63int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *); 64#endif 65 66/* 67 * UniStrcat: Concatenate the second string to the first 68 * 69 * Returns: 70 * Address of the first string 71 */ 72static inline wchar_t * 73UniStrcat(wchar_t * ucs1, const wchar_t * ucs2) 74{ 75 wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */ 76 77 while (*ucs1++) ; /* To end of first string */ 78 ucs1--; /* Return to the null */ 79 while ((*ucs1++ = *ucs2++)) ; /* copy string 2 over */ 80 return anchor; 81} 82 83/* 84 * UniStrchr: Find a character in a string 85 * 86 * Returns: 87 * Address of first occurrence of character in string 88 * or NULL if the character is not in the string 89 */ 90static inline wchar_t * 91UniStrchr(const wchar_t * ucs, wchar_t uc) 92{ 93 while ((*ucs != uc) && *ucs) 94 ucs++; 95 96 if (*ucs == uc) 97 return (wchar_t *) ucs; 98 return NULL; 99} 100 101/* 102 * UniStrcmp: Compare two strings 103 * 104 * Returns: 105 * < 0: First string is less than second 106 * = 0: Strings are equal 107 * > 0: First string is greater than second 108 */ 109static inline int 110UniStrcmp(const wchar_t * ucs1, const wchar_t * ucs2) 111{ 112 while ((*ucs1 == *ucs2) && *ucs1) { 113 ucs1++; 114 ucs2++; 115 } 116 return (int) *ucs1 - (int) *ucs2; 117} 118 119/* 120 * UniStrcpy: Copy a string 121 */ 122static inline wchar_t * 123UniStrcpy(wchar_t * ucs1, const wchar_t * ucs2) 124{ 125 wchar_t *anchor = ucs1; /* save the start of result string */ 126 127 while ((*ucs1++ = *ucs2++)) ; 128 return anchor; 129} 130 131/* 132 * UniStrlen: Return the length of a string (in 16 bit Unicode chars not bytes) 133 */ 134static inline size_t 135UniStrlen(const wchar_t * ucs1) 136{ 137 int i = 0; 138 139 while (*ucs1++) 140 i++; 141 return i; 142} 143 144/* 145 * UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a string (length limited) 146 */ 147static inline size_t 148UniStrnlen(const wchar_t * ucs1, int maxlen) 149{ 150 int i = 0; 151 152 while (*ucs1++) { 153 i++; 154 if (i >= maxlen) 155 break; 156 } 157 return i; 158} 159 160/* 161 * UniStrncat: Concatenate length limited string 162 */ 163static inline wchar_t * 164UniStrncat(wchar_t * ucs1, const wchar_t * ucs2, size_t n) 165{ 166 wchar_t *anchor = ucs1; /* save pointer to string 1 */ 167 168 while (*ucs1++) ; 169 ucs1--; /* point to null terminator of s1 */ 170 while (n-- && (*ucs1 = *ucs2)) { /* copy s2 after s1 */ 171 ucs1++; 172 ucs2++; 173 } 174 *ucs1 = 0; /* Null terminate the result */ 175 return (anchor); 176} 177 178/* 179 * UniStrncmp: Compare length limited string 180 */ 181static inline int 182UniStrncmp(const wchar_t * ucs1, const wchar_t * ucs2, size_t n) 183{ 184 if (!n) 185 return 0; /* Null strings are equal */ 186 while ((*ucs1 == *ucs2) && *ucs1 && --n) { 187 ucs1++; 188 ucs2++; 189 } 190 return (int) *ucs1 - (int) *ucs2; 191} 192 193/* 194 * UniStrncmp_le: Compare length limited string - native to little-endian 195 */ 196static inline int 197UniStrncmp_le(const wchar_t * ucs1, const wchar_t * ucs2, size_t n) 198{ 199 if (!n) 200 return 0; /* Null strings are equal */ 201 while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) { 202 ucs1++; 203 ucs2++; 204 } 205 return (int) *ucs1 - (int) __le16_to_cpu(*ucs2); 206} 207 208/* 209 * UniStrncpy: Copy length limited string with pad 210 */ 211static inline wchar_t * 212UniStrncpy(wchar_t * ucs1, const wchar_t * ucs2, size_t n) 213{ 214 wchar_t *anchor = ucs1; 215 216 while (n-- && *ucs2) /* Copy the strings */ 217 *ucs1++ = *ucs2++; 218 219 n++; 220 while (n--) /* Pad with nulls */ 221 *ucs1++ = 0; 222 return anchor; 223} 224 225/* 226 * UniStrncpy_le: Copy length limited string with pad to little-endian 227 */ 228static inline wchar_t * 229UniStrncpy_le(wchar_t * ucs1, const wchar_t * ucs2, size_t n) 230{ 231 wchar_t *anchor = ucs1; 232 233 while (n-- && *ucs2) /* Copy the strings */ 234 *ucs1++ = __le16_to_cpu(*ucs2++); 235 236 n++; 237 while (n--) /* Pad with nulls */ 238 *ucs1++ = 0; 239 return anchor; 240} 241 242/* 243 * UniStrstr: Find a string in a string 244 * 245 * Returns: 246 * Address of first match found 247 * NULL if no matching string is found 248 */ 249static inline wchar_t * 250UniStrstr(const wchar_t * ucs1, const wchar_t * ucs2) 251{ 252 const wchar_t *anchor1 = ucs1; 253 const wchar_t *anchor2 = ucs2; 254 255 while (*ucs1) { 256 if (*ucs1 == *ucs2) { /* Partial match found */ 257 ucs1++; 258 ucs2++; 259 } else { 260 if (!*ucs2) /* Match found */ 261 return (wchar_t *) anchor1; 262 ucs1 = ++anchor1; /* No match */ 263 ucs2 = anchor2; 264 } 265 } 266 267 if (!*ucs2) /* Both end together */ 268 return (wchar_t *) anchor1; /* Match found */ 269 return NULL; /* No match */ 270} 271 272#ifndef UNIUPR_NOUPPER 273/* 274 * UniToupper: Convert a unicode character to upper case 275 */ 276static inline wchar_t 277UniToupper(register wchar_t uc) 278{ 279 register const struct UniCaseRange *rp; 280 281 if (uc < sizeof (CifsUniUpperTable)) { /* Latin characters */ 282 return uc + CifsUniUpperTable[uc]; /* Use base tables */ 283 } else { 284 rp = CifsUniUpperRange; /* Use range tables */ 285 while (rp->start) { 286 if (uc < rp->start) /* Before start of range */ 287 return uc; /* Uppercase = input */ 288 if (uc <= rp->end) /* In range */ 289 return uc + rp->table[uc - rp->start]; 290 rp++; /* Try next range */ 291 } 292 } 293 return uc; /* Past last range */ 294} 295 296/* 297 * UniStrupr: Upper case a unicode string 298 */ 299static inline wchar_t * 300UniStrupr(register wchar_t * upin) 301{ 302 register wchar_t *up; 303 304 up = upin; 305 while (*up) { /* For all characters */ 306 *up = UniToupper(*up); 307 up++; 308 } 309 return upin; /* Return input pointer */ 310} 311#endif /* UNIUPR_NOUPPER */ 312 313#ifndef UNIUPR_NOLOWER 314/* 315 * UniTolower: Convert a unicode character to lower case 316 */ 317static inline wchar_t 318UniTolower(wchar_t uc) 319{ 320 register struct UniCaseRange *rp; 321 322 if (uc < sizeof (UniLowerTable)) { /* Latin characters */ 323 return uc + UniLowerTable[uc]; /* Use base tables */ 324 } else { 325 rp = UniLowerRange; /* Use range tables */ 326 while (rp->start) { 327 if (uc < rp->start) /* Before start of range */ 328 return uc; /* Uppercase = input */ 329 if (uc <= rp->end) /* In range */ 330 return uc + rp->table[uc - rp->start]; 331 rp++; /* Try next range */ 332 } 333 } 334 return uc; /* Past last range */ 335} 336 337/* 338 * UniStrlwr: Lower case a unicode string 339 */ 340static inline wchar_t * 341UniStrlwr(register wchar_t * upin) 342{ 343 register wchar_t *up; 344 345 up = upin; 346 while (*up) { /* For all characters */ 347 *up = UniTolower(*up); 348 up++; 349 } 350 return upin; /* Return input pointer */ 351} 352 353#endif 354