xref: /illumos-gate/usr/src/common/smbsrv/smb_oem.c (revision 8622ec45)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
22*8622ec45SGordon Ross  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
23bbf6f00cSJordan Brown  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24da6c28aaSamw  * Use is subject to license terms.
25da6c28aaSamw  */
26da6c28aaSamw 
27da6c28aaSamw /*
28da6c28aaSamw  * Support for oem <-> unicode translations.
29da6c28aaSamw  */
30da6c28aaSamw 
31da6c28aaSamw #ifndef _KERNEL
32da6c28aaSamw #include <stdlib.h>
33da6c28aaSamw #include <thread.h>
34da6c28aaSamw #include <synch.h>
35da6c28aaSamw #include <string.h>
36bbf6f00cSJordan Brown #else
37bbf6f00cSJordan Brown #include <sys/ksynch.h>
38da6c28aaSamw #endif /* _KERNEL */
39bbf6f00cSJordan Brown 
40bbf6f00cSJordan Brown #include <sys/byteorder.h>
41da6c28aaSamw #include <smbsrv/alloc.h>
42da6c28aaSamw #include <smbsrv/string.h>
43bbf6f00cSJordan Brown 
44da6c28aaSamw /*
45bbf6f00cSJordan Brown  * cpid		The oemcpg_table index for this oempage.
46bbf6f00cSJordan Brown  * value	The conversion values.
47bbf6f00cSJordan Brown  */
48bbf6f00cSJordan Brown typedef struct oempage {
49bbf6f00cSJordan Brown 	uint32_t	cpid;
50bbf6f00cSJordan Brown 	smb_wchar_t	*value;
51bbf6f00cSJordan Brown } oempage_t;
52bbf6f00cSJordan Brown 
53bbf6f00cSJordan Brown /*
54bbf6f00cSJordan Brown  * filename	The actual filename contains the codepage.
55bbf6f00cSJordan Brown  * bytesperchar	The codepage uses double or single bytes per char.
56bbf6f00cSJordan Brown  * oempage	The oempage is used to convert Unicode characters to
57bbf6f00cSJordan Brown  *		OEM characters.  Memory needs to be allocated for
58bbf6f00cSJordan Brown  *		the value field of oempage to store the table.
59bbf6f00cSJordan Brown  * ucspage	The unicode page is used to convert OEM characters
60bbf6f00cSJordan Brown  *		to Unicode characters.  Memory needs to be allocated
61bbf6f00cSJordan Brown  *		for the value field of ucspage to store the table.
62bbf6f00cSJordan Brown  * valid	True if the codepage has been initialized.
63da6c28aaSamw  */
64da6c28aaSamw typedef struct oem_codepage {
65bbf6f00cSJordan Brown 	char		*filename;
66bbf6f00cSJordan Brown 	uint32_t	bytesperchar;
67bbf6f00cSJordan Brown 	oempage_t	oempage;
68bbf6f00cSJordan Brown 	oempage_t	ucspage;
69bbf6f00cSJordan Brown 	boolean_t	valid;
70da6c28aaSamw } oem_codepage_t;
71da6c28aaSamw 
72bbf6f00cSJordan Brown static oem_codepage_t oemcpg_table[] = {
73bbf6f00cSJordan Brown 	{"850.cpg",  1, {0, 0},  {0, 0},  0},	/* Multilingual Latin1 */
74bbf6f00cSJordan Brown 	{"950.cpg",  2, {1, 0},  {1, 0},  0},	/* Chinese Traditional */
75bbf6f00cSJordan Brown 	{"1252.cpg", 1, {2, 0},  {2, 0},  0},	/* MS Latin1 */
76bbf6f00cSJordan Brown 	{"949.cpg",  2, {3, 0},  {3, 0},  0},	/* Korean */
77bbf6f00cSJordan Brown 	{"936.cpg",  2, {4, 0},  {4, 0},  0},	/* Chinese Simplified */
78bbf6f00cSJordan Brown 	{"932.cpg",  2, {5, 0},  {5, 0},  0},	/* Japanese */
79bbf6f00cSJordan Brown 	{"852.cpg",  1, {6, 0},  {6, 0},  0},	/* Multilingual Latin2 */
80bbf6f00cSJordan Brown 	{"1250.cpg", 1, {7, 0},  {7, 0},  0},	/* MS Latin2 */
81bbf6f00cSJordan Brown 	{"1253.cpg", 1, {8, 0},  {8, 0},  0},	/* MS Greek */
82bbf6f00cSJordan Brown 	{"737.cpg",  1, {9, 0},  {9, 0},  0},	/* Greek */
83bbf6f00cSJordan Brown 	{"1254.cpg", 1, {10, 0}, {10, 0}, 0},	/* MS Turkish */
84bbf6f00cSJordan Brown 	{"857.cpg",  1, {11, 0}, {11, 0}, 0},	/* Multilingual Latin5 */
85bbf6f00cSJordan Brown 	{"1251.cpg", 1, {12, 0}, {12, 0}, 0},	/* MS Cyrillic */
86bbf6f00cSJordan Brown 	{"866.cpg",  1, {13, 0}, {13, 0}, 0},	/* Cyrillic II */
87bbf6f00cSJordan Brown 	{"1255.cpg", 1, {14, 0}, {14, 0}, 0},	/* MS Hebrew */
88bbf6f00cSJordan Brown 	{"862.cpg",  1, {15, 0}, {15, 0}, 0},	/* Hebrew */
89bbf6f00cSJordan Brown 	{"1256.cpg", 1, {16, 0}, {16, 0}, 0},	/* MS Arabic */
90bbf6f00cSJordan Brown 	{"720.cpg",  1, {17, 0}, {17, 0}, 0}	/* Arabic */
91da6c28aaSamw };
92da6c28aaSamw 
93bbf6f00cSJordan Brown #define	MAX_OEMPAGES	(sizeof (oemcpg_table) / sizeof (oemcpg_table[0]))
94bbf6f00cSJordan Brown #define	MAX_UNICODE_IDX	65536
95da6c28aaSamw 
96da6c28aaSamw /*
97bbf6f00cSJordan Brown  * The default SMB OEM codepage for English is codepage 850.
98da6c28aaSamw  */
99*8622ec45SGordon Ross const smb_wchar_t oem_codepage_850[256] = {
100da6c28aaSamw 	0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
101da6c28aaSamw 	0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
102da6c28aaSamw 	0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
103da6c28aaSamw 	0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
104da6c28aaSamw 	0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
105da6c28aaSamw 	0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
106da6c28aaSamw 	0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
107da6c28aaSamw 	0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
108da6c28aaSamw 	0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
109da6c28aaSamw 	0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
110da6c28aaSamw 	0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
111da6c28aaSamw 	0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
112da6c28aaSamw 	0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
113da6c28aaSamw 	0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
114da6c28aaSamw 	0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
115da6c28aaSamw 	0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
116da6c28aaSamw 	0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
117da6c28aaSamw 	0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
118da6c28aaSamw 	0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
119da6c28aaSamw 	0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
120da6c28aaSamw 	0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
121da6c28aaSamw 	0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
122da6c28aaSamw 	0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
123da6c28aaSamw 	0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
124da6c28aaSamw 	0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
125da6c28aaSamw 	0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
126da6c28aaSamw 	0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE,
127da6c28aaSamw 	0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
128da6c28aaSamw 	0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE,
129da6c28aaSamw 	0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
130da6c28aaSamw 	0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
131da6c28aaSamw 	0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
132da6c28aaSamw };
133da6c28aaSamw 
134da6c28aaSamw /*
135bbf6f00cSJordan Brown  * The default telnet OEM codepage for English is codepage 1252.
136da6c28aaSamw  */
137*8622ec45SGordon Ross const smb_wchar_t oem_codepage_1252[256] = {
138da6c28aaSamw 	0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8,
139da6c28aaSamw 	0x9, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x10,
140da6c28aaSamw 	0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
141da6c28aaSamw 	0x19, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x20,
142da6c28aaSamw 	0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
143da6c28aaSamw 	0x29, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x30,
144da6c28aaSamw 	0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
145da6c28aaSamw 	0x39, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, 0x40,
146da6c28aaSamw 	0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
147da6c28aaSamw 	0x49, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x50,
148da6c28aaSamw 	0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
149da6c28aaSamw 	0x59, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 0x60,
150da6c28aaSamw 	0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
151da6c28aaSamw 	0x69, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x70,
152da6c28aaSamw 	0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
153da6c28aaSamw 	0x79, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, 0x20AC,
154da6c28aaSamw 	0x81, 0x201A, 0x192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6,
155da6c28aaSamw 	0x2030, 0x160, 0x2039, 0x152, 0x8D, 0x017D, 0x8F, 0x90,
156da6c28aaSamw 	0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC,
157da6c28aaSamw 	0x2122, 0x161, 0x203A, 0x153, 0x9D, 0x017E, 0x178, 0x00A0,
158da6c28aaSamw 	0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8,
159da6c28aaSamw 	0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0,
160da6c28aaSamw 	0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8,
161da6c28aaSamw 	0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, 0x00C0,
162da6c28aaSamw 	0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8,
163da6c28aaSamw 	0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x00D0,
164da6c28aaSamw 	0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8,
165da6c28aaSamw 	0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x00E0,
166da6c28aaSamw 	0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8,
167da6c28aaSamw 	0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x00F0,
168da6c28aaSamw 	0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8,
169da6c28aaSamw 	0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF
170da6c28aaSamw };
171da6c28aaSamw 
172bbf6f00cSJordan Brown static oempage_t *oem_get_oempage(uint32_t);
173bbf6f00cSJordan Brown static oempage_t *oem_get_ucspage(uint32_t);
174bbf6f00cSJordan Brown static void oem_codepage_init(uint32_t);
175bbf6f00cSJordan Brown static void oem_codepage_setup(uint32_t);
176da6c28aaSamw 
177da6c28aaSamw /*
178bbf6f00cSJordan Brown  * Convert a unicode string to an oem string.
179da6c28aaSamw  *
180bbf6f00cSJordan Brown  * The conversion will stop at the end of the unicode string
181bbf6f00cSJordan Brown  * or when (nbytes - 1) oem characters have been stored.
182da6c28aaSamw  *
183bbf6f00cSJordan Brown  * The number of converted unicode characters is returned,
184bbf6f00cSJordan Brown  * or 0 on error.
185da6c28aaSamw  */
186da6c28aaSamw size_t
187bbf6f00cSJordan Brown ucstooem(char *oem, const smb_wchar_t *ucs, size_t nbytes, uint32_t cpid)
188da6c28aaSamw {
189bbf6f00cSJordan Brown 	oempage_t	*ucspage;
190bbf6f00cSJordan Brown 	uint32_t	count = 0;
191bbf6f00cSJordan Brown 	smb_wchar_t	oemchar;
192da6c28aaSamw 
193bbf6f00cSJordan Brown 	if (ucs == NULL || oem == NULL)
194da6c28aaSamw 		return (0);
195da6c28aaSamw 
196bbf6f00cSJordan Brown 	if ((ucspage = oem_get_ucspage(cpid)) == NULL)
197da6c28aaSamw 		return (0);
198da6c28aaSamw 
199bbf6f00cSJordan Brown 	while (nbytes != 0 && (oemchar = ucspage->value[*ucs]) != 0) {
200da6c28aaSamw 		if (oemchar & 0xff00 && nbytes >= MTS_MB_CHAR_MAX) {
201bbf6f00cSJordan Brown 			*oem++ = oemchar >> 8;
202bbf6f00cSJordan Brown 			*oem++ = (char)oemchar;
203da6c28aaSamw 			nbytes -= 2;
204da6c28aaSamw 		} else if (nbytes > 1) {
205bbf6f00cSJordan Brown 			*oem++ = (char)oemchar;
206da6c28aaSamw 			nbytes--;
207bbf6f00cSJordan Brown 		} else {
208da6c28aaSamw 			break;
209bbf6f00cSJordan Brown 		}
210da6c28aaSamw 
211da6c28aaSamw 		count++;
212bbf6f00cSJordan Brown 		ucs++;
213da6c28aaSamw 	}
214da6c28aaSamw 
215bbf6f00cSJordan Brown 	*oem = '\0';
216da6c28aaSamw 	return (count);
217da6c28aaSamw }
218da6c28aaSamw 
219da6c28aaSamw /*
220bbf6f00cSJordan Brown  * Convert an oem string to a unicode string.
221da6c28aaSamw  *
222bbf6f00cSJordan Brown  * The conversion will stop at the end of the oem string or
223bbf6f00cSJordan Brown  * when nwchars - 1 have been converted.
224bbf6f00cSJordan Brown  *
225bbf6f00cSJordan Brown  * The number of converted oem chars is returned, or 0 on error.
226bbf6f00cSJordan Brown  * An oem char may be either 1 or 2 bytes.
227da6c28aaSamw  */
228da6c28aaSamw size_t
229bbf6f00cSJordan Brown oemtoucs(smb_wchar_t *ucs, const char *oem, size_t nwchars, uint32_t cpid)
230da6c28aaSamw {
231bbf6f00cSJordan Brown 	oempage_t	*oempage;
232bbf6f00cSJordan Brown 	size_t		count = nwchars;
233bbf6f00cSJordan Brown 	smb_wchar_t	oemchar;
234da6c28aaSamw 
235bbf6f00cSJordan Brown 	if (ucs == NULL || oem == NULL)
236da6c28aaSamw 		return (0);
237da6c28aaSamw 
238bbf6f00cSJordan Brown 	if ((oempage = oem_get_oempage(cpid)) == NULL)
239da6c28aaSamw 		return (0);
240da6c28aaSamw 
241bbf6f00cSJordan Brown 	while ((oemchar = (smb_wchar_t)*oem++ & 0xff) != 0) {
242da6c28aaSamw 		/*
243bbf6f00cSJordan Brown 		 * Cannot find one byte oemchar in table.
244bbf6f00cSJordan Brown 		 * Must be a lead byte. Try two bytes.
245da6c28aaSamw 		 */
246da6c28aaSamw 		if ((oempage->value[oemchar] == 0) && (oemchar != 0)) {
247bbf6f00cSJordan Brown 			oemchar = oemchar << 8 | (*oem++ & 0xff);
248da6c28aaSamw 			if (oempage->value[oemchar] == 0) {
249bbf6f00cSJordan Brown 				*ucs = 0;
250da6c28aaSamw 				break;
251da6c28aaSamw 			}
252da6c28aaSamw 		}
253da6c28aaSamw #ifdef _BIG_ENDIAN
254bbf6f00cSJordan Brown 		*ucs = LE_IN16(&oempage->value[oemchar]);
255da6c28aaSamw #else
256bbf6f00cSJordan Brown 		*ucs = oempage->value[oemchar];
257da6c28aaSamw #endif
258da6c28aaSamw 		count--;
259bbf6f00cSJordan Brown 		ucs++;
260da6c28aaSamw 	}
261da6c28aaSamw 
262bbf6f00cSJordan Brown 	*ucs = 0;
263da6c28aaSamw 	return (nwchars - count);
264da6c28aaSamw }
265da6c28aaSamw 
266da6c28aaSamw /*
267bbf6f00cSJordan Brown  * Get a pointer to the oem page for the specific codepage id.
268da6c28aaSamw  */
269bbf6f00cSJordan Brown static oempage_t *
270bbf6f00cSJordan Brown oem_get_oempage(uint32_t cpid)
271da6c28aaSamw {
272bbf6f00cSJordan Brown 	if (cpid >= MAX_OEMPAGES)
273bbf6f00cSJordan Brown 		return (NULL);
274bbf6f00cSJordan Brown 
275bbf6f00cSJordan Brown 	if (!oemcpg_table[cpid].valid) {
276bbf6f00cSJordan Brown 		oem_codepage_init(cpid);
277bbf6f00cSJordan Brown 
278bbf6f00cSJordan Brown 		if (!oemcpg_table[cpid].valid)
279bbf6f00cSJordan Brown 			return (NULL);
280bbf6f00cSJordan Brown 	}
281bbf6f00cSJordan Brown 
282bbf6f00cSJordan Brown 	return (&oemcpg_table[cpid].oempage);
283da6c28aaSamw }
284da6c28aaSamw 
285da6c28aaSamw /*
286bbf6f00cSJordan Brown  * Get a pointer to the ucs page for the specific codepage id.
287da6c28aaSamw  */
288bbf6f00cSJordan Brown static oempage_t *
289bbf6f00cSJordan Brown oem_get_ucspage(uint32_t cpid)
290da6c28aaSamw {
291bbf6f00cSJordan Brown 	if (cpid >= MAX_OEMPAGES)
292bbf6f00cSJordan Brown 		return (NULL);
293da6c28aaSamw 
294bbf6f00cSJordan Brown 	if (!oemcpg_table[cpid].valid) {
295bbf6f00cSJordan Brown 		oem_codepage_init(cpid);
296bbf6f00cSJordan Brown 
297bbf6f00cSJordan Brown 		if (!oemcpg_table[cpid].valid)
298bbf6f00cSJordan Brown 			return (NULL);
299bbf6f00cSJordan Brown 	}
300bbf6f00cSJordan Brown 
301bbf6f00cSJordan Brown 	return (&oemcpg_table[cpid].ucspage);
302bbf6f00cSJordan Brown }
303da6c28aaSamw 
304da6c28aaSamw /*
305bbf6f00cSJordan Brown  * Initialize the oem page in the oem table.
306da6c28aaSamw  */
307bbf6f00cSJordan Brown static void
308bbf6f00cSJordan Brown oem_codepage_init(uint32_t cpid)
309da6c28aaSamw {
310bbf6f00cSJordan Brown #ifndef _KERNEL
311bbf6f00cSJordan Brown 	static mutex_t mutex;
312da6c28aaSamw 
313bbf6f00cSJordan Brown 	(void) mutex_lock(&mutex);
314bbf6f00cSJordan Brown 	oem_codepage_setup(cpid);
315bbf6f00cSJordan Brown 	(void) mutex_unlock(&mutex);
316bbf6f00cSJordan Brown #else
317bbf6f00cSJordan Brown 	static kmutex_t mutex;
318da6c28aaSamw 
319bbf6f00cSJordan Brown 	mutex_enter(&mutex);
320bbf6f00cSJordan Brown 	oem_codepage_setup(cpid);
321bbf6f00cSJordan Brown 	mutex_exit(&mutex);
322bbf6f00cSJordan Brown #endif /* _KERNEL */
323bbf6f00cSJordan Brown }
324da6c28aaSamw 
325bbf6f00cSJordan Brown static void
326bbf6f00cSJordan Brown oem_codepage_setup(uint32_t cpid)
327bbf6f00cSJordan Brown {
328*8622ec45SGordon Ross 	const smb_wchar_t *default_oem_cp;
329bbf6f00cSJordan Brown 	oem_codepage_t	*oemcpg;
330bbf6f00cSJordan Brown 	uint32_t	bytesperchar;
331bbf6f00cSJordan Brown 	uint32_t	max_oem_index;
332bbf6f00cSJordan Brown 	int		i;
333bbf6f00cSJordan Brown 
334bbf6f00cSJordan Brown 	switch (cpid) {
335bbf6f00cSJordan Brown 	case OEM_CPG_850:
336bbf6f00cSJordan Brown 		default_oem_cp = oem_codepage_850;
337bbf6f00cSJordan Brown 		break;
338bbf6f00cSJordan Brown 	case OEM_CPG_1252:
339bbf6f00cSJordan Brown 		default_oem_cp = oem_codepage_1252;
340bbf6f00cSJordan Brown 	default:
341da6c28aaSamw 		return;
342da6c28aaSamw 	}
343da6c28aaSamw 
344bbf6f00cSJordan Brown 	oemcpg = &oemcpg_table[cpid];
345bbf6f00cSJordan Brown 	if (oemcpg->valid)
346da6c28aaSamw 		return;
347da6c28aaSamw 
348da6c28aaSamw 	/*
349bbf6f00cSJordan Brown 	 * max_oem_index will be 256 or 65536 dependent
350bbf6f00cSJordan Brown 	 * on the OEM codepage.
351da6c28aaSamw 	 */
352bbf6f00cSJordan Brown 	bytesperchar = oemcpg_table[cpid].bytesperchar;
353bbf6f00cSJordan Brown 	max_oem_index = 1 << (bytesperchar * 8);
354da6c28aaSamw 
355bbf6f00cSJordan Brown 	oemcpg->oempage.value =
356bbf6f00cSJordan Brown 	    MEM_ZALLOC("oem", max_oem_index * sizeof (smb_wchar_t));
357bbf6f00cSJordan Brown 	if (oemcpg->oempage.value == NULL)
358bbf6f00cSJordan Brown 		return;
359da6c28aaSamw 
360bbf6f00cSJordan Brown 	oemcpg->ucspage.value =
361bbf6f00cSJordan Brown 	    MEM_ZALLOC("oem", MAX_UNICODE_IDX * sizeof (smb_wchar_t));
362bbf6f00cSJordan Brown 	if (oemcpg->ucspage.value == NULL) {
363bbf6f00cSJordan Brown 		MEM_FREE("oem", oemcpg->oempage.value);
364bbf6f00cSJordan Brown 		oemcpg->oempage.value = NULL;
365bbf6f00cSJordan Brown 		return;
366bbf6f00cSJordan Brown 	}
367da6c28aaSamw 
368bbf6f00cSJordan Brown 	for (i = 0; i < max_oem_index; i++) {
369bbf6f00cSJordan Brown 		oemcpg->oempage.value[i] = default_oem_cp[i];
370bbf6f00cSJordan Brown 		oemcpg->ucspage.value[default_oem_cp[i]] = (smb_wchar_t)i;
371bbf6f00cSJordan Brown 	}
372da6c28aaSamw 
373bbf6f00cSJordan Brown 	oemcpg->valid = B_TRUE;
374da6c28aaSamw }
375