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
ndr__mbstowcs(uint16_t * wcs,const char * mbs,size_t nwchars)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
ndr__mbstowcs_le(uint16_t * wcs,const char * mbs,size_t nwchars)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
ndr__mbstowcs_x(uint16_t * wcs,const char * mbs,size_t nwchars,int flags)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
ndr__wcstombs(char * mbs,const uint16_t * wcs,size_t nbytes)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
ndr__wcslen(const uint16_t * wc)156 ndr__wcslen(const uint16_t *wc)
157 {
158 	size_t len = 0;
159 	while (*wc++)
160 		len++;
161 	return (len);
162 }
163