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