1/* SPDX-License-Identifier: GPL-2.0-or-later */ 2/* 3 * Some of the source code in this file came from fs/cifs/cifs_unicode.c 4 * and then via server/unicode.c 5 * cifs_unicode: Unicode kernel case support 6 * 7 * Function: 8 * Convert a unicode character to upper or lower case using 9 * compressed tables. 10 * 11 * Copyright (c) International Business Machines Corp., 2000,2009 12 * 13 * 14 * Notes: 15 * These APIs are based on the C library functions. The semantics 16 * should match the C functions but with expanded size operands. 17 * 18 * The upper/lower functions are based on a table created by mkupr. 19 * This is a compressed table of upper and lower case conversion. 20 * 21 */ 22#ifndef _NLS_UCS2_UTILS_H 23#define _NLS_UCS2_UTILS_H 24 25#include <asm/byteorder.h> 26#include <linux/types.h> 27#include <linux/nls.h> 28#include <linux/unicode.h> 29#include "nls_ucs2_data.h" 30 31/* 32 * Windows maps these to the user defined 16 bit Unicode range since they are 33 * reserved symbols (along with \ and /), otherwise illegal to store 34 * in filenames in NTFS 35 */ 36#define UNI_ASTERISK ((__u16)('*' + 0xF000)) 37#define UNI_QUESTION ((__u16)('?' + 0xF000)) 38#define UNI_COLON ((__u16)(':' + 0xF000)) 39#define UNI_GRTRTHAN ((__u16)('>' + 0xF000)) 40#define UNI_LESSTHAN ((__u16)('<' + 0xF000)) 41#define UNI_PIPE ((__u16)('|' + 0xF000)) 42#define UNI_SLASH ((__u16)('\\' + 0xF000)) 43 44/* 45 * UniStrcat: Concatenate the second string to the first 46 * 47 * Returns: 48 * Address of the first string 49 */ 50static inline wchar_t *UniStrcat(wchar_t *ucs1, const wchar_t *ucs2) 51{ 52 wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */ 53 54 while (*ucs1++) 55 /*NULL*/; /* To end of first string */ 56 ucs1--; /* Return to the null */ 57 while ((*ucs1++ = *ucs2++)) 58 /*NULL*/; /* copy string 2 over */ 59 return anchor; 60} 61 62/* 63 * UniStrchr: Find a character in a string 64 * 65 * Returns: 66 * Address of first occurrence of character in string 67 * or NULL if the character is not in the string 68 */ 69static inline wchar_t *UniStrchr(const wchar_t *ucs, wchar_t uc) 70{ 71 while ((*ucs != uc) && *ucs) 72 ucs++; 73 74 if (*ucs == uc) 75 return (wchar_t *)ucs; 76 return NULL; 77} 78 79/* 80 * UniStrcmp: Compare two strings 81 * 82 * Returns: 83 * < 0: First string is less than second 84 * = 0: Strings are equal 85 * > 0: First string is greater than second 86 */ 87static inline int UniStrcmp(const wchar_t *ucs1, const wchar_t *ucs2) 88{ 89 while ((*ucs1 == *ucs2) && *ucs1) { 90 ucs1++; 91 ucs2++; 92 } 93 return (int)*ucs1 - (int)*ucs2; 94} 95 96/* 97 * UniStrcpy: Copy a string 98 */ 99static inline wchar_t *UniStrcpy(wchar_t *ucs1, const wchar_t *ucs2) 100{ 101 wchar_t *anchor = ucs1; /* save the start of result string */ 102 103 while ((*ucs1++ = *ucs2++)) 104 /*NULL*/; 105 return anchor; 106} 107 108/* 109 * UniStrlen: Return the length of a string (in 16 bit Unicode chars not bytes) 110 */ 111static inline size_t UniStrlen(const wchar_t *ucs1) 112{ 113 int i = 0; 114 115 while (*ucs1++) 116 i++; 117 return i; 118} 119 120/* 121 * UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a 122 * string (length limited) 123 */ 124static inline size_t UniStrnlen(const wchar_t *ucs1, int maxlen) 125{ 126 int i = 0; 127 128 while (*ucs1++) { 129 i++; 130 if (i >= maxlen) 131 break; 132 } 133 return i; 134} 135 136/* 137 * UniStrncat: Concatenate length limited string 138 */ 139static inline wchar_t *UniStrncat(wchar_t *ucs1, const wchar_t *ucs2, size_t n) 140{ 141 wchar_t *anchor = ucs1; /* save pointer to string 1 */ 142 143 while (*ucs1++) 144 /*NULL*/; 145 ucs1--; /* point to null terminator of s1 */ 146 while (n-- && (*ucs1 = *ucs2)) { /* copy s2 after s1 */ 147 ucs1++; 148 ucs2++; 149 } 150 *ucs1 = 0; /* Null terminate the result */ 151 return anchor; 152} 153 154/* 155 * UniStrncmp: Compare length limited string 156 */ 157static inline int UniStrncmp(const wchar_t *ucs1, const wchar_t *ucs2, size_t n) 158{ 159 if (!n) 160 return 0; /* Null strings are equal */ 161 while ((*ucs1 == *ucs2) && *ucs1 && --n) { 162 ucs1++; 163 ucs2++; 164 } 165 return (int)*ucs1 - (int)*ucs2; 166} 167 168/* 169 * UniStrncmp_le: Compare length limited string - native to little-endian 170 */ 171static inline int 172UniStrncmp_le(const wchar_t *ucs1, const wchar_t *ucs2, size_t n) 173{ 174 if (!n) 175 return 0; /* Null strings are equal */ 176 while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) { 177 ucs1++; 178 ucs2++; 179 } 180 return (int)*ucs1 - (int)__le16_to_cpu(*ucs2); 181} 182 183/* 184 * UniStrncpy: Copy length limited string with pad 185 */ 186static inline wchar_t *UniStrncpy(wchar_t *ucs1, const wchar_t *ucs2, size_t n) 187{ 188 wchar_t *anchor = ucs1; 189 190 while (n-- && *ucs2) /* Copy the strings */ 191 *ucs1++ = *ucs2++; 192 193 n++; 194 while (n--) /* Pad with nulls */ 195 *ucs1++ = 0; 196 return anchor; 197} 198 199/* 200 * UniStrncpy_le: Copy length limited string with pad to little-endian 201 */ 202static inline wchar_t *UniStrncpy_le(wchar_t *ucs1, const wchar_t *ucs2, size_t n) 203{ 204 wchar_t *anchor = ucs1; 205 206 while (n-- && *ucs2) /* Copy the strings */ 207 *ucs1++ = __le16_to_cpu(*ucs2++); 208 209 n++; 210 while (n--) /* Pad with nulls */ 211 *ucs1++ = 0; 212 return anchor; 213} 214 215/* 216 * UniStrstr: Find a string in a string 217 * 218 * Returns: 219 * Address of first match found 220 * NULL if no matching string is found 221 */ 222static inline wchar_t *UniStrstr(const wchar_t *ucs1, const wchar_t *ucs2) 223{ 224 const wchar_t *anchor1 = ucs1; 225 const wchar_t *anchor2 = ucs2; 226 227 while (*ucs1) { 228 if (*ucs1 == *ucs2) { 229 /* Partial match found */ 230 ucs1++; 231 ucs2++; 232 } else { 233 if (!*ucs2) /* Match found */ 234 return (wchar_t *)anchor1; 235 ucs1 = ++anchor1; /* No match */ 236 ucs2 = anchor2; 237 } 238 } 239 240 if (!*ucs2) /* Both end together */ 241 return (wchar_t *)anchor1; /* Match found */ 242 return NULL; /* No match */ 243} 244 245#ifndef UNIUPR_NOUPPER 246/* 247 * UniToupper: Convert a unicode character to upper case 248 */ 249static inline wchar_t UniToupper(register wchar_t uc) 250{ 251 register const struct UniCaseRange *rp; 252 253 if (uc < sizeof(NlsUniUpperTable)) { 254 /* Latin characters */ 255 return uc + NlsUniUpperTable[uc]; /* Use base tables */ 256 } 257 258 rp = NlsUniUpperRange; /* Use range tables */ 259 while (rp->start) { 260 if (uc < rp->start) /* Before start of range */ 261 return uc; /* Uppercase = input */ 262 if (uc <= rp->end) /* In range */ 263 return uc + rp->table[uc - rp->start]; 264 rp++; /* Try next range */ 265 } 266 return uc; /* Past last range */ 267} 268 269/* 270 * UniStrupr: Upper case a unicode string 271 */ 272static inline __le16 *UniStrupr(register __le16 *upin) 273{ 274 register __le16 *up; 275 276 up = upin; 277 while (*up) { /* For all characters */ 278 *up = cpu_to_le16(UniToupper(le16_to_cpu(*up))); 279 up++; 280 } 281 return upin; /* Return input pointer */ 282} 283#endif /* UNIUPR_NOUPPER */ 284 285#endif /* _NLS_UCS2_UTILS_H */ 286