1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Support for oem <-> unicode translations. 30 */ 31 32 #ifndef _KERNEL 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <thread.h> 36 #include <synch.h> 37 #include <string.h> 38 #endif /* _KERNEL */ 39 #include <smbsrv/alloc.h> 40 #include <smbsrv/string.h> 41 #include <smbsrv/oem.h> 42 #include <sys/byteorder.h> 43 /* 44 * name: Name used to show on the telnet/GUI. 45 * filename: The actual filename contains the codepage. 46 * doublebytes: The codepage is double or single byte. 47 * oempage: The oempage is used to convert Unicode to OEM chars. 48 * Memory needs to be allocated for value field of oempage 49 * to store the entire table. 50 * unipage: The unipage is used to convert OEM to Unicode chars. 51 * Memory needs to be allocated for value field of unipage 52 * to store the entire table. 53 * valid: This field indicates if the page is valid or not. 54 * ref: This ref count is used to keep track of the usage of BOTH 55 * oempage and unipage. 56 * Note: If the cpid of the table is changed, please change the 57 * codepage_id in oem.h as well. 58 */ 59 typedef struct oem_codepage { 60 char *filename; 61 unsigned int bytesperchar; 62 oempage_t oempage; 63 oempage_t unicodepage; 64 unsigned int valid; 65 unsigned int ref; 66 } oem_codepage_t; 67 68 static oem_codepage_t oemcp_table[] = { 69 {"850.cpg", 1, {0, 0}, {0, 0}, 0, 0}, /* Multilingual Latin1 */ 70 {"950.cpg", 2, {1, 0}, {1, 0}, 0, 0}, /* Chinese Traditional */ 71 {"1252.cpg", 1, {2, 0}, {2, 0}, 0, 0}, /* MS Latin1 */ 72 {"949.cpg", 2, {3, 0}, {3, 0}, 0, 0}, /* Korean */ 73 {"936.cpg", 2, {4, 0}, {4, 0}, 0, 0}, /* Chinese Simplified */ 74 {"932.cpg", 2, {5, 0}, {5, 0}, 0, 0}, /* Japanese */ 75 {"852.cpg", 1, {6, 0}, {6, 0}, 0, 0}, /* Multilingual Latin2 */ 76 {"1250.cpg", 1, {7, 0}, {7, 0}, 0, 0}, /* MS Latin2 */ 77 {"1253.cpg", 1, {8, 0}, {8, 0}, 0, 0}, /* MS Greek */ 78 {"737.cpg", 1, {9, 0}, {9, 0}, 0, 0}, /* Greek */ 79 {"1254.cpg", 1, {10, 0}, {10, 0}, 0, 0}, /* MS Turkish */ 80 {"857.cpg", 1, {11, 0}, {11, 0}, 0, 0}, /* Multilingual Latin5 */ 81 {"1251.cpg", 1, {12, 0}, {12, 0}, 0, 0}, /* MS Cyrillic */ 82 {"866.cpg", 1, {13, 0}, {13, 0}, 0, 0}, /* Cyrillic II */ 83 {"1255.cpg", 1, {14, 0}, {14, 0}, 0, 0}, /* MS Hebrew */ 84 {"862.cpg", 1, {15, 0}, {15, 0}, 0, 0}, /* Hebrew */ 85 {"1256.cpg", 1, {16, 0}, {16, 0}, 0, 0}, /* MS Arabic */ 86 {"720.cpg", 1, {17, 0}, {17, 0}, 0, 0} /* Arabic */ 87 }; 88 89 static language lang_table[] = { 90 {"Arabic", OEM_CP_IND_720, OEM_CP_IND_1256}, 91 {"Brazilian", OEM_CP_IND_850, OEM_CP_IND_1252}, 92 {"Chinese Traditional", OEM_CP_IND_950, OEM_CP_IND_950}, 93 {"Chinese Simplified", OEM_CP_IND_936, OEM_CP_IND_936}, 94 {"Czech", OEM_CP_IND_852, OEM_CP_IND_1250}, 95 {"Danish", OEM_CP_IND_850, OEM_CP_IND_1252}, 96 {"Dutch", OEM_CP_IND_850, OEM_CP_IND_1252}, 97 {"English", OEM_CP_IND_850, OEM_CP_IND_1252}, 98 {"Finnish", OEM_CP_IND_850, OEM_CP_IND_1252}, 99 {"French", OEM_CP_IND_850, OEM_CP_IND_1252}, 100 {"German", OEM_CP_IND_850, OEM_CP_IND_1252}, 101 {"Greek", OEM_CP_IND_737, OEM_CP_IND_1253}, 102 {"Hebrew", OEM_CP_IND_862, OEM_CP_IND_1255}, 103 {"Hungarian", OEM_CP_IND_852, OEM_CP_IND_1250}, 104 {"Italian", OEM_CP_IND_850, OEM_CP_IND_1252}, 105 {"Japanese", OEM_CP_IND_932, OEM_CP_IND_932}, 106 {"Korean", OEM_CP_IND_949, OEM_CP_IND_949}, 107 {"Norwegian", OEM_CP_IND_850, OEM_CP_IND_1252}, 108 {"Polish", OEM_CP_IND_852, OEM_CP_IND_1250}, 109 {"Russian", OEM_CP_IND_866, OEM_CP_IND_1251}, 110 {"Slovak", OEM_CP_IND_852, OEM_CP_IND_1250}, 111 {"Slovenian", OEM_CP_IND_852, OEM_CP_IND_1250}, 112 {"Spanish", OEM_CP_IND_850, OEM_CP_IND_1252}, 113 {"Swedish", OEM_CP_IND_850, OEM_CP_IND_1252}, 114 {"Turkish", OEM_CP_IND_857, OEM_CP_IND_1254} 115 }; 116 117 118 119 /* 120 * The oem_default_smb_cp is the default smb codepage for English. 121 * It is actually codepage 850. 122 */ 123 mts_wchar_t oem_default_smb_cp[256] = { 124 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 125 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 126 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 127 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 128 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 129 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 130 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 131 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, 132 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 133 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 134 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 135 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 136 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 137 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 138 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 139 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, 140 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 141 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 142 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 143 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, 144 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 145 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 146 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 147 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, 148 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 149 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, 150 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, 151 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, 152 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 153 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, 154 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 155 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 156 }; 157 158 159 160 /* 161 * The oem_default_telnet_cp is the default telnet codepage for English. 162 * It is actually codepage 1252. 163 */ 164 mts_wchar_t oem_default_telnet_cp[256] = { 165 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 166 0x9, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x10, 167 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 168 0x19, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x20, 169 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 170 0x29, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x30, 171 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 172 0x39, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, 0x40, 173 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 174 0x49, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x50, 175 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 176 0x59, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 0x60, 177 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 178 0x69, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x70, 179 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 180 0x79, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, 0x20AC, 181 0x81, 0x201A, 0x192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, 182 0x2030, 0x160, 0x2039, 0x152, 0x8D, 0x017D, 0x8F, 0x90, 183 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC, 184 0x2122, 0x161, 0x203A, 0x153, 0x9D, 0x017E, 0x178, 0x00A0, 185 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 186 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0, 187 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 188 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, 0x00C0, 189 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 190 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x00D0, 191 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 192 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x00E0, 193 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 194 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x00F0, 195 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 196 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF 197 }; 198 199 200 #define MAX_OEMPAGES (sizeof (oemcp_table) / sizeof (oemcp_table[0])) 201 #define MAX_UNI_IDX 65536 202 203 204 205 /* 206 * oem_codepage_bytesperchar 207 * 208 * This function returns the max bytes per oem char for the specified 209 * oem table. This basically shows if the oem codepage is single or 210 * double bytes. 211 */ 212 static unsigned int 213 oem_codepage_bytesperchar(unsigned int cpid) 214 { 215 if (cpid >= MAX_OEMPAGES) 216 return (0); 217 else 218 return (oemcp_table[cpid].bytesperchar); 219 } 220 221 222 223 /* 224 * oem_get_codepage_path 225 * 226 * This function will get the codepage path. 227 */ 228 const char * 229 oem_get_codepage_path(void) 230 { 231 #ifdef PBSHORTCUT /* */ 232 const char *path = getenv("codepage.oem.directory"); 233 if (path == 0) 234 return ("/"); 235 else 236 return (path); 237 #else /* PBSHORTCUT */ 238 return ("/"); 239 #endif /* PBSHORTCUT */ 240 } 241 242 /* 243 * oem_codepage_init 244 * 245 * This function will init oem page via the cpid of the oem table. 246 * The function oem_codepage_free must be called when the oempage is 247 * no longer needed to free up the allocated memory. If the codepage is 248 * successfully initialized, zero will be the return value; otherwise 249 * -1 will be the return value. 250 */ 251 int 252 oem_codepage_init(unsigned int cpid) 253 { 254 #ifndef _KERNEL 255 FILE *fp; 256 static mutex_t mutex; 257 char buf[32]; 258 char filePath[100]; 259 #endif /* _KERNEL */ 260 unsigned int max_oem_index; 261 const char *codepagePath = oem_get_codepage_path(); 262 mts_wchar_t *default_oem_cp = 0; 263 oem_codepage_t *oemcp; 264 265 /* 266 * The OEM codepages 850 and 1252 are stored in kernel; therefore, 267 * no need for codepagePath to be defined to work. 268 */ 269 if (cpid >= MAX_OEMPAGES || 270 (codepagePath == 0 && 271 cpid != oem_default_smb_cpid && cpid != oem_default_telnet_cpid)) 272 return (-1); 273 274 max_oem_index = 1 << oem_codepage_bytesperchar(cpid) * 8; 275 /* 276 * Use mutex so no two same index can be initialize 277 * at the same time. 278 */ 279 #ifndef _KERNEL 280 (void) mutex_lock(&mutex); 281 #endif /* _KERNEL */ 282 283 oemcp = &oemcp_table[cpid]; 284 if (oemcp->valid) { 285 oemcp->valid++; 286 #ifndef _KERNEL 287 (void) mutex_unlock(&mutex); 288 #endif /* _KERNEL */ 289 return (0); 290 } 291 292 oemcp->oempage.value = 293 MEM_ZALLOC("oem", max_oem_index * sizeof (mts_wchar_t)); 294 if (oemcp->oempage.value == 0) { 295 #ifndef _KERNEL 296 (void) mutex_unlock(&mutex); 297 #endif /* _KERNEL */ 298 return (-1); 299 } 300 301 oemcp->unicodepage.value = 302 MEM_ZALLOC("oem", MAX_UNI_IDX * sizeof (mts_wchar_t)); 303 if (oemcp->unicodepage.value == 0) { 304 MEM_FREE("oem", oemcp->oempage.value); 305 oemcp->oempage.value = 0; 306 #ifndef _KERNEL 307 (void) mutex_unlock(&mutex); 308 #endif /* _KERNEL */ 309 return (-1); 310 } 311 312 /* 313 * The default English page is stored in kernel. 314 * Therefore, no need to go to codepage files. 315 */ 316 #ifndef _KERNEL 317 if (cpid == oem_default_smb_cpid) 318 default_oem_cp = oem_default_smb_cp; 319 else if (cpid == oem_default_telnet_cpid) 320 default_oem_cp = oem_default_telnet_cp; 321 else 322 default_oem_cp = 0; 323 #else /* _KERNEL */ 324 default_oem_cp = oem_default_smb_cp; 325 #endif /* _KERNEL */ 326 327 if (default_oem_cp) { 328 int i; 329 330 for (i = 0; i < max_oem_index; i++) { 331 oemcp->oempage.value[i] = default_oem_cp[i]; 332 oemcp->unicodepage.value[default_oem_cp[i]] = 333 (mts_wchar_t)i; 334 } 335 #ifdef _KERNEL 336 } 337 /* 338 * XXX This doesn't seem right. How do we handle the situation 339 * where default_oem_cp == 0 in the kernel? 340 * Is this a PBSHORTCUT? 341 */ 342 #else 343 } else { 344 345 /* 346 * The codepage is not one of the default that stores 347 * in the include 348 * file; therefore, we need to read from the file. 349 */ 350 (void) snprintf(filePath, sizeof (filePath), 351 "%s/%s", codepagePath, oemcp->filename); 352 fp = fopen(filePath, "r"); 353 354 if (fp == 0) { 355 MEM_FREE("oem", oemcp->oempage.value); 356 MEM_FREE("oem", oemcp->unicodepage.value); 357 #ifndef _KERNEL 358 (void) mutex_unlock(&mutex); 359 #endif /* _KERNEL */ 360 return (-1); 361 } 362 363 while (fgets(buf, 32, fp) != 0) { 364 char *endptr; 365 unsigned int oemval, unival; 366 367 endptr = (char *)strchr(buf, ' '); 368 if (endptr == 0) { 369 continue; 370 } 371 372 oemval = strtol(buf, &endptr, 0); 373 unival = strtol(endptr+1, 0, 0); 374 375 if (oemval >= max_oem_index || unival >= MAX_UNI_IDX) { 376 continue; 377 } 378 379 oemcp->oempage.value[oemval] = unival; 380 oemcp->unicodepage.value[unival] = oemval; 381 } 382 (void) fclose(fp); 383 } 384 #endif /* _KERNEL */ 385 386 oemcp->valid = 1; 387 #ifndef _KERNEL 388 (void) mutex_unlock(&mutex); 389 #endif /* _KERNEL */ 390 return (0); 391 } 392 393 394 395 396 /* 397 * oem_codepage_free 398 * 399 * This function will clear the valid bit and free the memory 400 * allocated to the oem/unipage by oem_codepage_init if the ref count 401 * is zero. 402 */ 403 void 404 oem_codepage_free(unsigned int cpid) 405 { 406 oem_codepage_t *oemcp; 407 408 if (cpid >= MAX_OEMPAGES || !oemcp_table[cpid].valid) 409 return; 410 411 oemcp = &oemcp_table[cpid]; 412 oemcp->valid--; 413 414 if (oemcp->ref != 0 || oemcp->valid != 0) 415 return; 416 417 if (oemcp->oempage.value != 0) { 418 MEM_FREE("oem", oemcp->oempage.value); 419 oemcp->oempage.value = 0; 420 } 421 422 if (oemcp->unicodepage.value != 0) { 423 MEM_FREE("oem", oemcp->unicodepage.value); 424 oemcp->unicodepage.value = 0; 425 } 426 } 427 428 429 430 /* 431 * oem_get_oempage 432 * 433 * This function will return the current oempage and increment 434 * the ref count. The function oem_release_page should always 435 * be called when finish using the oempage to decrement the 436 * ref count. 437 */ 438 static oempage_t * 439 oem_get_oempage(unsigned int cpid) 440 { 441 if (cpid >= MAX_OEMPAGES) 442 return (0); 443 444 if (oemcp_table[cpid].valid) { 445 oemcp_table[cpid].ref++; 446 return (&oemcp_table[cpid].oempage); 447 } 448 return (0); 449 } 450 451 452 453 /* 454 * oem_get_unipage 455 * 456 * This function will return the current unipage and increment 457 * the ref count. The function oem_release_page should always 458 * be called when finish using the unipage to decrement the 459 * ref count. 460 */ 461 static oempage_t * 462 oem_get_unipage(unsigned int cpid) 463 { 464 if (cpid >= MAX_OEMPAGES) 465 return (0); 466 467 if (oemcp_table[cpid].valid) { 468 oemcp_table[cpid].ref++; 469 return (&oemcp_table[cpid].unicodepage); 470 } 471 return (0); 472 } 473 474 475 476 /* 477 * oem_release_page 478 * 479 * This function will decrement the ref count and check the valid 480 * bit. It will free the memory allocated for the pages 481 * if the 482 * valid bit is not set, ref count is zero and the page is not 483 * already freed. 484 */ 485 static void 486 oem_release_page(oempage_t *page) 487 { 488 oem_codepage_t *oemcp = &oemcp_table[page->cpid]; 489 490 page = 0; 491 492 if (oemcp->ref > 0) 493 oemcp->ref--; 494 495 if (oemcp->ref != 0 || oemcp->valid) 496 return; 497 498 if (oemcp->oempage.value != 0) { 499 MEM_FREE("oem", oemcp->oempage.value); 500 oemcp->oempage.value = 0; 501 } 502 503 if (oemcp->unicodepage.value != 0) { 504 MEM_FREE("oem", oemcp->unicodepage.value); 505 oemcp->unicodepage.value = 0; 506 } 507 } 508 509 510 511 /* 512 * unicodestooems 513 * 514 * Convert unicode string to oem string. The function will stop 515 * converting the unicode string when size nbytes - 1 is reached 516 * or when there is not enough room to store another unicode. 517 * If the function is called when the codepage is not initialized 518 * or when the codepage initialize failed, it will return 0. 519 * Otherwise, the total # of the converted unicode is returned. 520 */ 521 size_t 522 unicodestooems( 523 char *oemstring, 524 const mts_wchar_t *unicodestring, 525 size_t nbytes, 526 unsigned int cpid) 527 { 528 oempage_t *unipage; 529 unsigned int count = 0; 530 mts_wchar_t oemchar; 531 532 if (cpid >= MAX_OEMPAGES) 533 return (0); 534 535 if (unicodestring == 0 || oemstring == 0) 536 return (0); 537 538 if ((unipage = oem_get_unipage(cpid)) == 0) 539 return (0); 540 541 while ((oemchar = unipage->value[*unicodestring]) != 0) { 542 if (oemchar & 0xff00 && nbytes >= MTS_MB_CHAR_MAX) { 543 *oemstring++ = oemchar >> 8; 544 *oemstring++ = (char)oemchar; 545 nbytes -= 2; 546 } else if (nbytes > 1) { 547 *oemstring++ = (char)oemchar; 548 nbytes--; 549 } else 550 break; 551 552 count++; 553 unicodestring++; 554 } 555 556 *oemstring = 0; 557 558 oem_release_page(unipage); 559 560 return (count); 561 } 562 563 564 565 /* 566 * oemstounicodes 567 * 568 * Convert oem string to unicode string. The function will stop 569 * converting the oem string when unicodestring len reaches nwchars - 1. 570 * or when there is not enough room to store another oem char. 571 * If the function is called when the codepage is not initialized 572 * or when the codepage initialize failed, it will return 0. 573 * Otherwise, the total # of the converted oem chars is returned. 574 * The oem char can be either 1 or 2 bytes. 575 */ 576 size_t 577 oemstounicodes( 578 mts_wchar_t *unicodestring, 579 const char *oemstring, 580 size_t nwchars, 581 unsigned int cpid) 582 { 583 oempage_t *oempage; 584 size_t count = nwchars; 585 mts_wchar_t oemchar; 586 587 if (cpid >= MAX_OEMPAGES) 588 return (0); 589 590 if (unicodestring == 0 || oemstring == 0) 591 return (0); 592 593 if ((oempage = oem_get_oempage(cpid)) == 0) 594 return (0); 595 596 while ((oemchar = (mts_wchar_t)*oemstring++ & 0xff) != 0) { 597 /* 598 * Cannot find one byte oemchar in table. Must be 599 * a lead byte. Try two bytes. 600 */ 601 602 if ((oempage->value[oemchar] == 0) && (oemchar != 0)) { 603 oemchar = oemchar << 8 | (*oemstring++ & 0xff); 604 if (oempage->value[oemchar] == 0) { 605 *unicodestring = 0; 606 break; 607 } 608 } 609 #ifdef _BIG_ENDIAN 610 *unicodestring = LE_IN16(&oempage->value[oemchar]); 611 #else 612 *unicodestring = oempage->value[oemchar]; 613 #endif 614 count--; 615 unicodestring++; 616 } 617 618 *unicodestring = 0; 619 620 oem_release_page(oempage); 621 622 return (nwchars - count); 623 } 624 625 /* 626 * oem_get_lang_table 627 * 628 * This function returns a pointer to the language table. 629 */ 630 language * 631 oem_get_lang_table(void) 632 { 633 return (lang_table); 634 } 635 636 /* 637 * oem_no_of_languages 638 * 639 * This function returns total languages support in the system. 640 */ 641 int 642 oem_no_of_languages(void) 643 { 644 return (sizeof (lang_table)/sizeof (lang_table[0])); 645 } 646 647 648 #ifndef _KERNEL 649 #if 1 650 /* 651 * TESTING Functions 652 */ 653 void 654 oemcp_print(unsigned int cpid) 655 { 656 unsigned int bytesperchar, max_index, i; 657 oempage_t *oempage, *unipage; 658 unsigned int counter = 0; 659 660 if (cpid >= MAX_OEMPAGES) { 661 (void) printf("oemcp cpid %d is invalid\n", cpid); 662 return; 663 } 664 665 if ((oempage = oem_get_oempage(cpid)) == 0) { 666 (void) printf("oemcp of cpid %d is invalid\n", cpid); 667 return; 668 } 669 670 if ((unipage = oem_get_unipage(cpid)) == 0) { 671 (void) printf("unicp of cpid %d is invalid\n", cpid); 672 return; 673 } 674 675 if ((bytesperchar = oem_codepage_bytesperchar(cpid)) == 0) { 676 (void) printf("bytesperchar of cpid %d is not correct\n", cpid); 677 return; 678 } 679 680 max_index = 1 << bytesperchar * 8; 681 682 (void) printf("OEMPAGE:\n"); 683 for (i = 0; i < max_index; i++) { 684 if ((counter + 1) % 4 == 0 && 685 (oempage->value[i] != 0 || i == 0)) { 686 (void) printf("%x %x\n", i, oempage->value[i]); 687 counter++; 688 } else if (oempage->value[i] != 0 || i == 0) { 689 (void) printf("%x %x, ", i, oempage->value[i]); 690 counter++; 691 } 692 } 693 counter = 0; 694 (void) printf("\n\nUNIPAGE:\n"); 695 for (i = 0; i < 65536; i++) { 696 if ((counter + 1) % 8 == 0 && 697 (unipage->value[i] != 0 || i == 0)) { 698 (void) printf("%x %x\n", i, unipage->value[i]); 699 counter++; 700 } else if (unipage->value[i] != 0 || i == 0) { 701 (void) printf("%x %x, ", i, unipage->value[i]); 702 counter++; 703 } 704 } 705 (void) printf("\n"); 706 oem_release_page(oempage); 707 oem_release_page(unipage); 708 } 709 710 711 712 void 713 oemstringtest(unsigned int cpid) 714 { 715 unsigned char *c, *cbuf; 716 unsigned char cbuf1[100] = {0xfe, 0xfd, 0xf2, 0xe9, 717 0x63, 0xce, 0xdb, 0x8c, 0x9c, 0x21, 0}; 718 unsigned char cbuf2[100] = {0xfe, 0xfc, 0x63, 0x81, 0x42, 719 0x91, 0x40, 0x24, 0xff, 0x49}; 720 mts_wchar_t buf[100], *wc; 721 722 if (cpid == 1) 723 cbuf = cbuf1; 724 else if (cpid == 2) 725 cbuf = cbuf2; 726 727 /* 728 * Before oem->uni conversion. 729 */ 730 (void) printf("Before oem->uni conversion: "); 731 for (c = cbuf; *c != 0; c++) 732 (void) printf("%x ", *c); 733 (void) printf("\n"); 734 735 /* 736 * oem->uni conversion 737 */ 738 (void) oemstounicodes(buf, (const char *)cbuf, 100, cpid); 739 740 /* 741 * After oem->uni conversion. 742 */ 743 (void) printf("After oem->uni conversion: "); 744 for (wc = buf; *wc != 0; wc++) 745 (void) printf("%x ", *wc); 746 (void) printf("\n"); 747 748 /* 749 * uni->oem conversion 750 */ 751 (void) unicodestooems((char *)cbuf, buf, 100, cpid); 752 753 /* 754 * After uni->oem conversion. 755 */ 756 (void) printf("After uni->oem conversion: "); 757 for (c = cbuf; *c != 0; c++) 758 (void) printf("%x ", *c); 759 (void) printf("\n"); 760 } 761 #endif 762 #endif /* _KERNEL */ 763