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 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 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 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 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 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 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 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 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 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