1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  *
  26  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
  27  */
  28 
  29 /*
  30  * Some wchar support functions used by this library.
  31  * Mostlly just wrappers that call sys/u8_textprep.h
  32  * functions: uconv_u8tou16, uconv_u16tou8.
  33  */
  34 
  35 #include <sys/types.h>
  36 #include <sys/u8_textprep.h>
  37 #include <string.h>
  38 
  39 #include "ndr_wchar.h"
  40 
  41 /*
  42  * When we just want lengths, we need an output buffer to pass to the
  43  * uconv_... functions.  Nothing ever reads this output, so we can
  44  * use shared space for the unwanted output.
  45  */
  46 static uint16_t junk_wcs[NDR_STRING_MAX];
  47 static char junk_mbs[NDR_MB_CUR_MAX * NDR_STRING_MAX];
  48 
  49 static size_t
  50 ndr__mbstowcs_x(uint16_t *, const char *, size_t, int);
  51 
  52 /*
  53  * Like mbstowcs(3C), but with UCS-2 wchar_t
  54  */
  55 size_t
  56 ndr__mbstowcs(uint16_t *wcs, const char *mbs, size_t nwchars)
  57 {
  58         return (ndr__mbstowcs_x(wcs, mbs, nwchars,
  59             UCONV_OUT_SYSTEM_ENDIAN));
  60 }
  61 
  62 /*
  63  * Like above, but put UCS-2 little-endian.
  64  */
  65 size_t
  66 ndr__mbstowcs_le(uint16_t *wcs, const char *mbs, size_t nwchars)
  67 {
  68         return (ndr__mbstowcs_x(wcs, mbs, nwchars,
  69             UCONV_OUT_LITTLE_ENDIAN));
  70 }
  71 
  72 /*
  73  * Like mbstowcs(3C), but with UCS-2 wchar_t, and
  74  * one extra arg for the byte order flags.
  75  */
  76 static size_t
  77 ndr__mbstowcs_x(uint16_t *wcs, const char *mbs, size_t nwchars, int flags)
  78 {
  79         size_t obytes, mbslen, wcslen;
  80         int err;
  81 
  82         /* NULL or empty input is allowed. */
  83         if (mbs == NULL || *mbs == '\0') {
  84                 if (wcs != NULL && nwchars > 0)
  85                         *wcs = 0;
  86                 return (0);
  87         }
  88 
  89         /*
  90          * If wcs == NULL, caller just wants the length.
  91          * Convert into some throw-away space.
  92          */
  93         obytes = nwchars * 2;
  94         if (wcs == NULL) {
  95                 if (obytes > sizeof (junk_wcs))
  96                         return ((size_t)-1);
  97                 wcs = junk_wcs;
  98         }
  99 
 100         mbslen = strlen(mbs);
 101         wcslen = nwchars;
 102         err = uconv_u8tou16((const uchar_t *)mbs, &mbslen,
 103             wcs, &wcslen, flags);
 104         if (err != 0)
 105                 return ((size_t)-1);
 106 
 107         if (wcslen < nwchars)
 108                 wcs[wcslen] = 0;
 109 
 110         return (wcslen);
 111 }
 112 
 113 /*
 114  * Like wcstombs(3C), but with UCS-2 wchar_t.
 115  */
 116 size_t
 117 ndr__wcstombs(char *mbs, const uint16_t *wcs, size_t nbytes)
 118 {
 119         size_t mbslen, wcslen;
 120         int err;
 121 
 122         /* NULL or empty input is allowed. */
 123         if (wcs == NULL || *wcs == 0) {
 124                 if (mbs != NULL && nbytes > 0)
 125                         *mbs = '\0';
 126                 return (0);
 127         }
 128 
 129         /*
 130          * If mbs == NULL, caller just wants the length.
 131          * Convert into some throw-away space.
 132          */
 133         if (mbs == NULL) {
 134                 if (nbytes > sizeof (junk_mbs))
 135                         return ((size_t)-1);
 136                 mbs = junk_mbs;
 137         }
 138 
 139         wcslen = ndr__wcslen(wcs);
 140         mbslen = nbytes;
 141         err = uconv_u16tou8(wcs, &wcslen,
 142             (uchar_t *)mbs, &mbslen, UCONV_IN_SYSTEM_ENDIAN);
 143         if (err != 0)
 144                 return ((size_t)-1);
 145 
 146         if (mbslen < nbytes)
 147                 mbs[mbslen] = '\0';
 148 
 149         return (mbslen);
 150 }
 151 
 152 /*
 153  * Like wcslen(3C), but with UCS-2 wchar_t.
 154  */
 155 size_t
 156 ndr__wcslen(const uint16_t *wc)
 157 {
 158         size_t len = 0;
 159         while (*wc++)
 160                 len++;
 161         return (len);
 162 }