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 }