1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
14  */
15 
16 /*
17  * Test conversion of strings UTF-8 to/from UTF-16 etc.
18  *
19  * This tests both 16-bit unicode symbols (UCS-2) and so called
20  * "enhanced" unicode symbols such as the "poop emoji" that are
21  * above 65535 and encode to four bytes as UTF-8.
22  */
23 
24 #include <sys/types.h>
25 #include <sys/debug.h>
26 #include <sys/u8_textprep.h>
27 #include <smbsrv/string.h>
28 #include <stdio.h>
29 #include <string.h>
30 
31 #include "test_defs.h"
32 
33 #define	U_FW_A	0xff21		// full-width A (A)
34 static const char fwA[4] = "\xef\xbc\xa1";
35 
36 #define	U_POOP	0x1f4a9		// poop emoji (��)
37 static const char poop[5] = "\xf0\x9f\x92\xa9";
38 
39 static char mbsa[] = "A\xef\xbc\xa1.";		// A fwA . (5)
40 static char mbsp[] = "P\xf0\x9f\x92\xa9.";	// P poop . (6)
41 static smb_wchar_t wcsa[] = { 'A', U_FW_A, '.', 0 };	// (3)
42 static smb_wchar_t wcsp[] = { 'P', 0xd83d, 0xdca9, '.', 0 }; // (4)
43 
44 
45 static void
conv_wctomb()46 conv_wctomb()
47 {
48 	char mbs[8];
49 	int len;
50 
51 	len = smb_wctomb(mbs, U_FW_A);
52 	if (len != 3) {
53 		printf("Fail: conv_wctomb fwA ret=%d\n", len);
54 		return;
55 	}
56 	mbs[len] = '\0';
57 	if (strcmp(mbs, fwA)) {
58 		printf("Fail: conv_wctomb fwA cmp:\n");
59 		hexdump((uchar_t *)mbs, len+1);
60 		return;
61 	}
62 
63 	len = smb_wctomb(mbs, U_POOP);
64 	if (len != 4) {
65 		printf("Fail: conv_wctomb poop ret=%d\n", len);
66 		return;
67 	}
68 	mbs[len] = '\0';
69 	if (strcmp(mbs, poop)) {
70 		printf("Fail: conv_wctomb poop cmp:\n");
71 		hexdump((uchar_t *)mbs, len+1);
72 		return;
73 	}
74 
75 	/* null wc to mbs should return 1 and put a null */
76 	len = smb_wctomb(mbs, 0);
77 	if (len != 1) {
78 		printf("Fail: conv_wctomb null ret=%d\n", len);
79 		return;
80 	}
81 	if (mbs[0] != '\0') {
82 		printf("Fail: conv_wctomb null cmp:\n");
83 		hexdump((uchar_t *)mbs, len+1);
84 		return;
85 	}
86 
87 	printf("Pass: conv_wctomb\n");
88 }
89 
90 static void
conv_mbtowc()91 conv_mbtowc()
92 {
93 	uint32_t wch = 0;
94 	int len;
95 
96 	/*
97 	 * The (void *) cast here is to let this build both
98 	 * before and after an interface change in smb_mbtowc
99 	 * (uint16_t vs uint32_t)
100 	 */
101 	len = smb_mbtowc((void *)&wch, fwA, 4);
102 	if (len != 3) {
103 		printf("Fail: conv_mbtowc fwA ret=%d\n", len);
104 		return;
105 	}
106 	if (wch != U_FW_A) {
107 		printf("Fail: conv_mbtowc fwA cmp: 0x%x\n", wch);
108 		return;
109 	}
110 
111 	len = smb_mbtowc((void *)&wch, poop, 4); // poop emoji
112 	if (len != 4) {
113 		printf("Fail: conv_mbtowc poop ret=%d\n", len);
114 		return;
115 	}
116 	if (wch != U_POOP) {
117 		printf("Fail: conv_mbtowc poop cmp: 0x%x\n", wch);
118 		return;
119 	}
120 
121 	/* null mbs to wc should return 0 (and set wch=0) */
122 	len = smb_mbtowc((void *)&wch, "", 4);
123 	if (len != 0) {
124 		printf("Fail: conv_mbtowc null ret=%d\n", len);
125 		return;
126 	}
127 	if (wch != 0) {
128 		printf("Fail: conv_mbtowc null cmp: 0x%x\n", wch);
129 		return;
130 	}
131 
132 	printf("Pass: conv_mbtowc\n");
133 }
134 
135 static void
conv_wcstombs()136 conv_wcstombs()
137 {
138 	char tmbs[16];
139 	int len;
140 
141 	len = smb_wcstombs(tmbs, wcsa, sizeof (tmbs));
142 	if (len != 5) {
143 		printf("Fail: conv_wcstombs A ret=%d\n", len);
144 		return;
145 	}
146 	if (strcmp(tmbs, mbsa)) {
147 		printf("Fail: conv_wcstombs A cmp:\n");
148 		hexdump((uchar_t *)tmbs, len+2);
149 		return;
150 	}
151 
152 	len = smb_wcstombs(tmbs, wcsp, sizeof (tmbs));
153 	if (len != 6) {
154 		printf("Fail: conv_wcstombs f ret=%d\n", len);
155 		return;
156 	}
157 	if (strcmp(tmbs, mbsp)) {
158 		printf("Fail: conv_wcstombs f cmp:\n");
159 		hexdump((uchar_t *)tmbs, len+2);
160 		return;
161 	}
162 
163 	printf("Pass: conv_wcstombs\n");
164 }
165 
166 static void
conv_mbstowcs()167 conv_mbstowcs()
168 {
169 	smb_wchar_t twcs[8];
170 	uint32_t wch = 0;
171 	int len;
172 
173 	len = smb_mbstowcs(twcs, mbsa, sizeof (twcs));
174 	if (len != 3) {
175 		printf("Fail: conv_mbstowcs A ret=%d\n", len);
176 		return;
177 	}
178 	if (memcmp(twcs, wcsa, len+2)) {
179 		printf("Fail: conv_mbstowcs A cmp: 0x%x\n", wch);
180 		hexdump((uchar_t *)twcs, len+2);
181 		return;
182 	}
183 
184 	len = smb_mbstowcs(twcs, mbsp, sizeof (twcs));
185 	if (len != 4) {
186 		printf("Fail: conv_mbstowcs P ret=%d\n", len);
187 		return;
188 	}
189 	if (memcmp(twcs, wcsp, len+2)) {
190 		printf("Fail: conv_mbstowcs P cmp: 0x%x\n", wch);
191 		hexdump((uchar_t *)twcs, len+2);
192 		return;
193 	}
194 
195 	printf("Pass: conv_mbstowcs\n");
196 }
197 
198 /*
199  * An OEM string that will require iconv.
200  */
201 static uchar_t fubar_oem[] = "F\201bar";	// CP850 x81 (ü)
202 static char fubar_mbs[] = "F\303\274bar";	// UTF8 xC3 xBC
203 
204 
205 static void
conv_oemtombs()206 conv_oemtombs()
207 {
208 	char tmbs[16];
209 	int len;
210 
211 	len = smb_oemtombs(tmbs, (uchar_t *)"foo", 4);
212 	if (len != 3) {
213 		printf("Fail: conv_wctomb foo ret=%d\n", len);
214 		return;
215 	}
216 	if (strcmp(tmbs, "foo")) {
217 		printf("Fail: conv_wctomb foo cmp:\n");
218 		hexdump((uchar_t *)tmbs, len+1);
219 		return;
220 	}
221 
222 	len = smb_oemtombs(tmbs, fubar_oem, 7);
223 	if (len != 6) {
224 		printf("Fail: conv_oemtombs fubar ret=%d\n", len);
225 		return;
226 	}
227 	if (strcmp(tmbs, fubar_mbs)) {
228 		printf("Fail: conv_oemtombs fubar cmp:\n");
229 		hexdump((uchar_t *)tmbs, len+1);
230 		return;
231 	}
232 
233 	printf("Pass: conv_oemtombs\n");
234 }
235 
236 static void
conv_mbstooem()237 conv_mbstooem()
238 {
239 	uint8_t oemcs[8];
240 	uint32_t wch = 0;
241 	int len;
242 
243 	len = smb_mbstooem(oemcs, "foo", 8);
244 	if (len != 3) {
245 		printf("Fail: conv_mbstooem foo ret=%d\n", len);
246 		return;
247 	}
248 	if (memcmp(oemcs, "foo", len+1)) {
249 		printf("Fail: conv_mbstooem P cmp: 0x%x\n", wch);
250 		hexdump((uchar_t *)oemcs, len+1);
251 		return;
252 	}
253 
254 	len = smb_mbstooem(oemcs, fubar_mbs, 8);
255 	if (len != 5) {
256 		printf("Fail: conv_mbstooem fubar ret=%d\n", len);
257 		return;
258 	}
259 	if (memcmp(oemcs, (char *)fubar_oem, len+1)) {
260 		printf("Fail: conv_mbstooem fubar cmp: 0x%x\n", wch);
261 		hexdump((uchar_t *)oemcs, len+1);
262 		return;
263 	}
264 
265 	len = smb_mbstooem(oemcs, mbsp, 8);
266 	if (len != 3) {
267 		printf("Fail: conv_mbstooem poop ret=%d\n", len);
268 		return;
269 	}
270 	if (memcmp(oemcs, "P?.", len+1)) {
271 		printf("Fail: conv_mbstooem poop cmp: 0x%x\n", wch);
272 		hexdump((uchar_t *)oemcs, len+1);
273 		return;
274 	}
275 
276 	printf("Pass: conv_mbstooem\n");
277 }
278 
279 static void
conv_sbequiv_strlen()280 conv_sbequiv_strlen()
281 {
282 	int len;
283 
284 	len = (int)smb_sbequiv_strlen("a");
285 	if (len != 1) {
286 		printf("Fail: conv_sbequiv_strlen (a) len=%d\n", len);
287 		return;
288 	}
289 
290 	len = (int)smb_sbequiv_strlen(fubar_mbs);
291 	if (len != strlen((char *)fubar_oem)) {
292 		printf("Fail: conv_sbequiv_strlen (fubar) len=%d\n", len);
293 		return;
294 	}
295 
296 	len = (int)smb_sbequiv_strlen(mbsp);
297 	if (len != 3) {	// "P?."
298 		printf("Fail: conv_sbequiv_strlen (poop) len=%d\n", len);
299 		return;
300 	}
301 
302 	printf("Pass: conv_sbequiv_strlen\n");
303 }
304 
305 static void
conv_wcequiv_strlen()306 conv_wcequiv_strlen()
307 {
308 	int len;
309 
310 	len = (int)smb_wcequiv_strlen("a");
311 	if (len != 2) {
312 		printf("Fail: conv_wcequiv_strlen (a) len=%d\n", len);
313 		return;
314 	}
315 
316 	len = (int)smb_wcequiv_strlen(fwA);
317 	if (len != 2) {
318 		printf("Fail: conv_wcequiv_strlen (fwA) len=%d\n", len);
319 		return;
320 	}
321 
322 	len = (int)smb_wcequiv_strlen(poop);
323 	if (len != 4) {
324 		printf("Fail: conv_wcequiv_strlen (poop) len=%d\n", len);
325 		return;
326 	}
327 
328 	printf("Pass: conv_wcequiv_strlen\n");
329 }
330 
331 void
test_conv()332 test_conv()
333 {
334 	conv_wctomb();
335 	conv_mbtowc();
336 	conv_wcstombs();
337 	conv_mbstowcs();
338 	conv_oemtombs();
339 	conv_mbstooem();
340 	conv_sbequiv_strlen();
341 	conv_wcequiv_strlen();
342 }
343