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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
26 */
27
28 /*
29 * Multibyte/wide-char conversion routines. Wide-char encoding provides
30 * a fixed size character encoding that maps to the Unicode 16-bit
31 * (UCS-2) character set standard. Multibyte or UCS transformation
32 * format (UTF) encoding is a variable length character encoding scheme
33 * that s compatible with existing ASCII characters and guarantees that
34 * the resultant strings do not contain embedded null characters. Both
35 * types of encoding provide a null terminator: single byte for UTF-8
36 * and a wide-char null for Unicode. See RFC 2044.
37 *
38 * The table below illustrates the UTF-8 encoding scheme. The letter x
39 * indicates bits available for encoding the character value.
40 *
41 * UCS-2 UTF-8 octet sequence (binary)
42 * 0x0000-0x007F 0xxxxxxx
43 * 0x0080-0x07FF 110xxxxx 10xxxxxx
44 * 0x0800-0xFFFF 1110xxxx 10xxxxxx 10xxxxxx
45 *
46 * RFC 2044
47 * UTF-8,a transformation format of UNICODE and ISO 10646
48 * F. Yergeau
49 * Alis Technologies
50 * October 1996
51 */
52
53 #if defined(_KERNEL) || defined(_FAKE_KERNEL)
54 #include <sys/types.h>
55 #include <sys/sunddi.h>
56 #else
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <assert.h>
60 #include <strings.h>
61 #endif
62 #include <smbsrv/string.h>
63
64
65 /*
66 * mbstowcs
67 *
68 * The mbstowcs() function converts a multibyte character string
69 * mbstring into a wide character string wcstring. No more than
70 * nwchars wide characters are stored. A terminating null wide
71 * character is appended if there is room.
72 *
73 * Returns the number of wide characters converted, not counting
74 * any terminating null wide character. Returns -1 if an invalid
75 * multibyte character is encountered.
76 */
77 size_t
78 smb_mbstowcs(smb_wchar_t *wcstring, const char *mbstring, size_t nwchars)
79 {
80 int len;
81 smb_wchar_t *start = wcstring;
82
83 while (nwchars--) {
84 len = smb_mbtowc(wcstring, mbstring, MTS_MB_CHAR_MAX);
85 if (len < 0) {
86 *wcstring = 0;
87 return ((size_t)-1);
88 }
89
90 if (*mbstring == 0)
91 break;
92
93 ++wcstring;
94 mbstring += len;
95 }
96
97 return (wcstring - start);
98 }
99
100
101 /*
102 * mbtowc
103 *
104 * The mbtowc() function converts a multibyte character mbchar into
105 * a wide character and stores the result in the object pointed to
106 * by wcharp. Up to nbytes bytes are examined.
107 *
108 * If mbchar is NULL, mbtowc() returns zero to indicate that shift
109 * states are not supported. Shift states are used to switch between
110 * representation modes using reserved bytes to signal shifting
111 * without them being interpreted as characters. If mbchar is null
112 * mbtowc should return non-zero if the current locale requires shift
113 * states. Otherwise it should be return 0.
114 *
115 * If mbchar is non-null, returns the number of bytes processed in
116 * mbchar. If mbchar is invalid, returns -1.
117 */
118 int /*ARGSUSED*/
119 smb_mbtowc(smb_wchar_t *wcharp, const char *mbchar, size_t nbytes)
120 {
121 unsigned char mbyte;
122 smb_wchar_t wide_char;
123 int count;
124 int bytes_left;
125
126 if (mbchar == NULL)
127 return (0); /* no shift states */
128
129 /* 0xxxxxxx -> 1 byte ASCII encoding */
130 if (((mbyte = *mbchar++) & 0x80) == 0) {
131 if (wcharp)
132 *wcharp = (smb_wchar_t)mbyte;
133
134 return (mbyte ? 1 : 0);
135 }
136
137 /* 10xxxxxx -> invalid first byte */
138 if ((mbyte & 0x40) == 0)
139 return (-1);
140
141 wide_char = mbyte;
142 if ((mbyte & 0x20) == 0) {
143 wide_char &= 0x1f;
144 bytes_left = 1;
145 } else if ((mbyte & 0x10) == 0) {
146 wide_char &= 0x0f;
147 bytes_left = 2;
148 } else {
149 return (-1);
150 }
151
152 count = 1;
153 while (bytes_left--) {
154 if (((mbyte = *mbchar++) & 0xc0) != 0x80)
155 return (-1);
156
157 count++;
158 wide_char = (wide_char << 6) | (mbyte & 0x3f);
159 }
160
161 if (wcharp)
162 *wcharp = wide_char;
163
164 return (count);
165 }
166
167
168 /*
169 * wctomb
170 *
171 * The wctomb() function converts a wide character wchar into a multibyte
172 * character and stores the result in mbchar. The object pointed to by
173 * mbchar must be large enough to accommodate the multibyte character.
174 *
175 * Returns the numberof bytes written to mbchar.
176 */
177 int
178 smb_wctomb(char *mbchar, smb_wchar_t wchar)
179 {
180 if ((wchar & ~0x7f) == 0) {
181 *mbchar = (char)wchar;
182 return (1);
183 }
184
185 if ((wchar & ~0x7ff) == 0) {
186 *mbchar++ = (wchar >> 6) | 0xc0;
187 *mbchar = (wchar & 0x3f) | 0x80;
188 return (2);
189 }
190
191 *mbchar++ = (wchar >> 12) | 0xe0;
192 *mbchar++ = ((wchar >> 6) & 0x3f) | 0x80;
193 *mbchar = (wchar & 0x3f) | 0x80;
194 return (3);
195 }
196
197
198 /*
199 * wcstombs
200 *
201 * The wcstombs() function converts a wide character string wcstring
202 * into a multibyte character string mbstring. Up to nbytes bytes are
203 * stored in mbstring. Partial multibyte characters at the end of the
204 * string are not stored. The multibyte character string is null
205 * terminated if there is room.
206 *
207 * Returns the number of bytes converted, not counting the terminating
208 * null byte.
209 */
210 size_t
211 smb_wcstombs(char *mbstring, const smb_wchar_t *wcstring, size_t nbytes)
212 {
213 char *start = mbstring;
214 const smb_wchar_t *wcp = wcstring;
215 smb_wchar_t wide_char = 0;
216 char buf[4];
217 size_t len;
218
219 if ((mbstring == NULL) || (wcstring == NULL))
220 return (0);
221
222 while (nbytes > MTS_MB_CHAR_MAX) {
223 wide_char = *wcp++;
224 len = smb_wctomb(mbstring, wide_char);
225
226 if (wide_char == 0)
227 /*LINTED E_PTRDIFF_OVERFLOW*/
228 return (mbstring - start);
229
230 mbstring += len;
231 nbytes -= len;
232 }
233
234 while (wide_char && nbytes) {
235 wide_char = *wcp++;
236 if ((len = smb_wctomb(buf, wide_char)) > nbytes) {
237 *mbstring = 0;
238 break;
239 }
240
241 bcopy(buf, mbstring, len);
242 mbstring += len;
243 nbytes -= len;
244 }
245
246 /*LINTED E_PTRDIFF_OVERFLOW*/
247 return (mbstring - start);
248 }
249
250
251 /*
252 * Returns the number of bytes that would be written if the multi-
253 * byte string mbs was converted to a wide character string, not
254 * counting the terminating null wide character.
255 */
256 size_t
257 smb_wcequiv_strlen(const char *mbs)
258 {
259 smb_wchar_t wide_char;
260 size_t bytes;
261 size_t len = 0;
262
263 while (*mbs) {
264 bytes = smb_mbtowc(&wide_char, mbs, MTS_MB_CHAR_MAX);
265 if (bytes == ((size_t)-1))
266 return ((size_t)-1);
267
268 len += sizeof (smb_wchar_t);
269 mbs += bytes;
270 }
271
272 return (len);
273 }
274
275
276 /*
277 * Returns the number of bytes that would be written if the multi-
278 * byte string mbs was converted to a single byte character string,
279 * not counting the terminating null character.
280 */
281 size_t
282 smb_sbequiv_strlen(const char *mbs)
283 {
284 smb_wchar_t wide_char;
285 size_t nbytes;
286 size_t len = 0;
287
288 while (*mbs) {
289 nbytes = smb_mbtowc(&wide_char, mbs, MTS_MB_CHAR_MAX);
290 if (nbytes == ((size_t)-1))
291 return ((size_t)-1);
292
293 if (wide_char & 0xFF00)
294 len += sizeof (smb_wchar_t);
295 else
296 ++len;
297
298 mbs += nbytes;
299 }
300
301 return (len);
302 }
303
304
305 /*
306 * stombs
307 *
308 * Convert a regular null terminated string 'string' to a UTF-8 encoded
309 * null terminated multi-byte string 'mbstring'. Only full converted
310 * UTF-8 characters will be written 'mbstring'. If a character will not
311 * fit within the remaining buffer space or 'mbstring' will overflow
312 * max_mblen, the conversion process will be terminated and 'mbstring'
313 * will be null terminated.
314 *
315 * Returns the number of bytes written to 'mbstring', excluding the
316 * terminating null character.
317 *
318 * If either mbstring or string is a null pointer, -1 is returned.
319 */
320 int
321 smb_stombs(char *mbstring, char *string, int max_mblen)
322 {
323 char *start = mbstring;
324 unsigned char *p = (unsigned char *)string;
325 int space_left = max_mblen;
326 int len;
327 smb_wchar_t wide_char;
328 char buf[4];
329
330 if (!mbstring || !string)
331 return (-1);
332
333 while (*p && space_left > 2) {
334 wide_char = *p++;
335 len = smb_wctomb(mbstring, wide_char);
336 mbstring += len;
337 space_left -= len;
338 }
339
340 if (*p) {
341 wide_char = *p;
342 if ((len = smb_wctomb(buf, wide_char)) < 2) {
343 *mbstring = *buf;
344 mbstring += len;
345 space_left -= len;
346 }
347 }
348
349 *mbstring = '\0';
350
351 /*LINTED E_PTRDIFF_OVERFLOW*/
352 return (mbstring - start);
353 }
354
355
356 /*
357 * mbstos
358 *
359 * Convert a null terminated multi-byte string 'mbstring' to a regular
360 * null terminated string 'string'. A 1-byte character in 'mbstring'
361 * maps to a 1-byte character in 'string'. A 2-byte character in
362 * 'mbstring' will be mapped to 2-bytes, if the upper byte is non-null.
363 * Otherwise the upper byte null will be discarded to ensure that the
364 * output stream does not contain embedded null characters.
365 *
366 * If the input stream contains invalid multi-byte characters, a value
367 * of -1 will be returned. Otherwise the length of 'string', excluding
368 * the terminating null character, is returned.
369 *
370 * If either mbstring or string is a null pointer, -1 is returned.
371 */
372 int
373 smb_mbstos(char *string, const char *mbstring)
374 {
375 smb_wchar_t wc;
376 unsigned char *start = (unsigned char *)string;
377 int len;
378
379 if (string == NULL || mbstring == NULL)
380 return (-1);
381
382 while (*mbstring) {
383 if ((len = smb_mbtowc(&wc, mbstring, MTS_MB_CHAR_MAX)) < 0) {
384 *string = 0;
385 return (-1);
386 }
387
388 if (wc & 0xFF00) {
389 /*LINTED E_BAD_PTR_CAST_ALIGN*/
390 *((smb_wchar_t *)string) = wc;
391 string += sizeof (smb_wchar_t);
392 }
393 else
394 {
395 *string = (unsigned char)wc;
396 string++;
397 }
398
399 mbstring += len;
400 }
401
402 *string = 0;
403
404 /*LINTED E_PTRDIFF_OVERFLOW*/
405 return ((unsigned char *)string - start);
406 }
|
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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
26 */
27
28 /*
29 * Multibyte/wide-char conversion routines. SMB uses UTF-16 on the wire
30 * (smb_wchar_t) and we use UTF-8 internally (our multi-byte, or mbs).
31 */
32
33 #if defined(_KERNEL) || defined(_FAKE_KERNEL)
34 #include <sys/types.h>
35 #include <sys/sunddi.h>
36 #else /* _KERNEL || _FAKE_KERNEL */
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <strings.h>
40 #include <iconv.h>
41 #include <assert.h>
42 #endif /* _KERNEL || _FAKE_KERNEL */
43 #include <sys/u8_textprep.h>
44 #include <smbsrv/string.h>
45
46
47 /*
48 * mbstowcs
49 *
50 * The mbstowcs() function converts a multibyte character string
51 * mbstring into a wide character string wcstring. No more than
52 * nwchars wide characters are stored. A terminating null wide
53 * character is appended if there is room.
54 *
55 * Returns the number of wide characters converted, not counting
56 * any terminating null wide character. Returns -1 if an invalid
57 * multibyte character is encountered.
58 */
59 size_t
60 smb_mbstowcs(smb_wchar_t *wcs, const char *mbs, size_t nwchars)
61 {
62 size_t mbslen, wcslen;
63 int err;
64
65 /* NULL or empty input is allowed. */
66 if (mbs == NULL || *mbs == '\0') {
67 if (wcs != NULL && nwchars > 0)
68 *wcs = 0;
69 return (0);
70 }
71
72 /*
73 * Traditional mbstowcs(3C) allows wcs==NULL to get the length.
74 * SMB never calls it that way, but let's future-proof.
75 */
76 if (wcs == NULL) {
77 return ((size_t)-1);
78 }
79
80 mbslen = strlen(mbs);
81 wcslen = nwchars;
82 err = uconv_u8tou16((const uchar_t *)mbs, &mbslen,
83 wcs, &wcslen, UCONV_OUT_LITTLE_ENDIAN);
84 if (err != 0)
85 return ((size_t)-1);
86
87 if (wcslen < nwchars)
88 wcs[wcslen] = 0;
89
90 return (wcslen);
91 }
92
93
94 /*
95 * mbtowc
96 *
97 * The mbtowc() function converts a multibyte character mbchar into
98 * a wide character and stores the result in the object pointed to
99 * by wcharp. Up to nbytes bytes are examined.
100 *
101 * If mbchar is NULL, mbtowc() returns zero to indicate that shift
102 * states are not supported. Shift states are used to switch between
103 * representation modes using reserved bytes to signal shifting
104 * without them being interpreted as characters. If mbchar is null
105 * mbtowc should return non-zero if the current locale requires shift
106 * states. Otherwise it should be return 0.
107 *
108 * If mbchar is non-null, returns the number of bytes processed in
109 * mbchar. If mbchar is null, convert the null (wcharp=0) but
110 * return length zero. If mbchar is invalid, returns -1.
111 */
112 int /*ARGSUSED*/
113 smb_mbtowc(uint32_t *wcharp, const char *mbchar, size_t nbytes)
114 {
115 uint32_t wide_char;
116 int count, err;
117 size_t mblen;
118 size_t wclen;
119
120 if (mbchar == NULL)
121 return (0); /* no shift states */
122
123 /*
124 * How many bytes in this symbol?
125 */
126 count = u8_validate((char *)mbchar, nbytes, NULL, 0, &err);
127 if (count < 0)
128 return (-1);
129
130 mblen = count;
131 wclen = 1;
132 err = uconv_u8tou32((const uchar_t *)mbchar, &mblen,
133 &wide_char, &wclen, UCONV_OUT_SYSTEM_ENDIAN);
134 if (err != 0)
135 return (-1);
136 if (wclen == 0) {
137 wide_char = 0;
138 count = 0;
139 }
140
141 if (wcharp)
142 *wcharp = wide_char;
143
144 return (count);
145 }
146
147
148 /*
149 * wctomb
150 *
151 * The wctomb() function converts a wide character wchar into a multibyte
152 * character and stores the result in mbchar. The object pointed to by
153 * mbchar must be large enough to accommodate the multibyte character.
154 *
155 * Returns the numberof bytes written to mbchar.
156 * Note: handles null like any 1-byte char.
157 */
158 int
159 smb_wctomb(char *mbchar, uint32_t wchar)
160 {
161 char junk[MTS_MB_CUR_MAX+1];
162 size_t mblen;
163 size_t wclen;
164 int err;
165
166 if (mbchar == NULL)
167 mbchar = junk;
168
169 mblen = MTS_MB_CUR_MAX;
170 wclen = 1;
171 err = uconv_u32tou8(&wchar, &wclen, (uchar_t *)mbchar, &mblen,
172 UCONV_IN_SYSTEM_ENDIAN | UCONV_IGNORE_NULL);
173 if (err != 0)
174 return (-1);
175
176 return ((int)mblen);
177 }
178
179
180 /*
181 * wcstombs
182 *
183 * The wcstombs() function converts a wide character string wcstring
184 * into a multibyte character string mbstring. Up to nbytes bytes are
185 * stored in mbstring. Partial multibyte characters at the end of the
186 * string are not stored. The multibyte character string is null
187 * terminated if there is room.
188 *
189 * Returns the number of bytes converted, not counting the terminating
190 * null byte. Returns -1 if an invalid WC sequence is encountered.
191 */
192 size_t
193 smb_wcstombs(char *mbs, const smb_wchar_t *wcs, size_t nbytes)
194 {
195 size_t mbslen, wcslen;
196 int err;
197
198 /* NULL or empty input is allowed. */
199 if (wcs == NULL || *wcs == 0) {
200 if (mbs != NULL && nbytes > 0)
201 *mbs = '\0';
202 return (0);
203 }
204
205 /*
206 * Traditional wcstombs(3C) allows mbs==NULL to get the length.
207 * SMB never calls it that way, but let's future-proof.
208 */
209 if (mbs == NULL) {
210 return ((size_t)-1);
211 }
212
213 /*
214 * Compute wcslen
215 */
216 wcslen = 0;
217 while (wcs[wcslen] != 0)
218 wcslen++;
219
220 mbslen = nbytes;
221 err = uconv_u16tou8(wcs, &wcslen,
222 (uchar_t *)mbs, &mbslen, UCONV_IN_LITTLE_ENDIAN);
223 if (err != 0)
224 return ((size_t)-1);
225
226 if (mbslen < nbytes)
227 mbs[mbslen] = '\0';
228
229 return (mbslen);
230 }
231
232
233 /*
234 * Returns the number of bytes that would be written if the multi-
235 * byte string mbs was converted to a wide character string, not
236 * counting the terminating null wide character.
237 */
238 size_t
239 smb_wcequiv_strlen(const char *mbs)
240 {
241 uint32_t wide_char;
242 size_t bytes;
243 size_t len = 0;
244
245 while (*mbs) {
246 bytes = smb_mbtowc(&wide_char, mbs, MTS_MB_CHAR_MAX);
247 if (bytes == ((size_t)-1))
248 return ((size_t)-1);
249 mbs += bytes;
250
251 len += sizeof (smb_wchar_t);
252 if (bytes > 3) {
253 /*
254 * Extended unicode, so TWO smb_wchar_t
255 */
256 len += sizeof (smb_wchar_t);
257 }
258 }
259
260 return (len);
261 }
262
263
264 /*
265 * Returns the number of bytes that would be written if the multi-
266 * byte string mbs was converted to an OEM character string,
267 * (smb_mbstooem) not counting the terminating null character.
268 */
269 size_t
270 smb_sbequiv_strlen(const char *mbs)
271 {
272 size_t nbytes;
273 size_t len = 0;
274
275 while (*mbs) {
276 nbytes = smb_mbtowc(NULL, mbs, MTS_MB_CHAR_MAX);
277 if (nbytes == ((size_t)-1))
278 return ((size_t)-1);
279 if (nbytes == 0)
280 break;
281
282 if (nbytes == 1) {
283 /* ASCII */
284 len++;
285 } else if (nbytes < 8) {
286 /* Compute OEM length */
287 char mbsbuf[8];
288 uint8_t oembuf[8];
289 int oemlen;
290 (void) strlcpy(mbsbuf, mbs, nbytes+1);
291 oemlen = smb_mbstooem(oembuf, mbsbuf, 8);
292 if (oemlen < 0)
293 return ((size_t)-1);
294 len += oemlen;
295 } else {
296 return ((size_t)-1);
297 }
298
299 mbs += nbytes;
300 }
301
302 return (len);
303 }
304
305 /*
306 * Convert OEM strings to/from internal (UTF-8) form.
307 *
308 * We rarely encounter these anymore because all modern
309 * SMB clients use Unicode (UTF-16). The few cases where
310 * this IS still called are normally using ASCII, i.e.
311 * tag names etc. so short-cut those cases. If we get
312 * something non-ASCII we have to call iconv.
313 *
314 * If we were to really support OEM code pages, we would
315 * need to have a way to set the OEM code page from some
316 * configuration value. For now it's always CP850.
317 * See also ./smb_oem.c
318 */
319 static char smb_oem_codepage[32] = "CP850";
320
321 /*
322 * stombs
323 *
324 * Convert a null terminated OEM string 'string' to a UTF-8 string
325 * no longer than max_mblen (null terminated if space).
326 *
327 * If the input string contains invalid OEM characters, a value
328 * of -1 will be returned. Otherwise returns the length of 'mbs',
329 * excluding the terminating null character.
330 *
331 * If either mbstring or string is a null pointer, -1 is returned.
332 */
333 int
334 smb_oemtombs(char *mbs, const uint8_t *oems, int max_mblen)
335 {
336 uchar_t *p;
337 int oemlen;
338 int rlen;
339 boolean_t need_iconv = B_FALSE;
340
341 if (mbs == NULL || oems == NULL)
342 return (-1);
343
344 /*
345 * Check if the oems is all ASCII (and get the length
346 * while we're at it) so we know if we need to iconv.
347 * We usually can avoid the iconv calls.
348 */
349 oemlen = 0;
350 p = (uchar_t *)oems;
351 while (*p != '\0') {
352 oemlen++;
353 if (*p & 0x80)
354 need_iconv = B_TRUE;
355 p++;
356 }
357
358 if (need_iconv) {
359 int rc;
360 char *obuf = mbs;
361 size_t olen = max_mblen;
362 size_t ilen = oemlen;
363 #if defined(_KERNEL) || defined(_FAKE_KERNEL)
364 char *ibuf = (char *)oems;
365 kiconv_t ic;
366 int err;
367
368 ic = kiconv_open("UTF-8", smb_oem_codepage);
369 if (ic == (kiconv_t)-1)
370 goto just_copy;
371 rc = kiconv(ic, &ibuf, &ilen, &obuf, &olen, &err);
372 (void) kiconv_close(ic);
373 #else /* _KERNEL || _FAKE_KERNEL */
374 const char *ibuf = (char *)oems;
375 iconv_t ic;
376 ic = iconv_open("UTF-8", smb_oem_codepage);
377 if (ic == (iconv_t)-1)
378 goto just_copy;
379 rc = iconv(ic, &ibuf, &ilen, &obuf, &olen);
380 (void) iconv_close(ic);
381 #endif /* _KERNEL || _FAKE_KERNEL */
382 if (rc < 0)
383 return (-1);
384 /* Return val. is output bytes. */
385 rlen = (max_mblen - olen);
386 } else {
387 just_copy:
388 rlen = oemlen;
389 if (rlen > max_mblen)
390 rlen = max_mblen;
391 bcopy(oems, mbs, rlen);
392 }
393 if (rlen < max_mblen)
394 mbs[rlen] = '\0';
395
396 return (rlen);
397 }
398
399
400 /*
401 * mbstos
402 *
403 * Convert a null terminated multi-byte string 'mbs' to an OEM string
404 * no longer than max_oemlen (null terminated if space).
405 *
406 * If the input string contains invalid multi-byte characters, a value
407 * of -1 will be returned. Otherwise returns the length of 'oems',
408 * excluding the terminating null character.
409 *
410 * If either mbstring or string is a null pointer, -1 is returned.
411 */
412 int
413 smb_mbstooem(uint8_t *oems, const char *mbs, int max_oemlen)
414 {
415 uchar_t *p;
416 int mbslen;
417 int rlen;
418 boolean_t need_iconv = B_FALSE;
419
420 if (oems == NULL || mbs == NULL)
421 return (-1);
422
423 /*
424 * Check if the mbs is all ASCII (and get the length
425 * while we're at it) so we know if we need to iconv.
426 * We usually can avoid the iconv calls.
427 */
428 mbslen = 0;
429 p = (uchar_t *)mbs;
430 while (*p != '\0') {
431 mbslen++;
432 if (*p & 0x80)
433 need_iconv = B_TRUE;
434 p++;
435 }
436
437 if (need_iconv) {
438 int rc;
439 char *obuf = (char *)oems;
440 size_t olen = max_oemlen;
441 size_t ilen = mbslen;
442 #if defined(_KERNEL) || defined(_FAKE_KERNEL)
443 char *ibuf = (char *)mbs;
444 kiconv_t ic;
445 int err;
446
447 ic = kiconv_open(smb_oem_codepage, "UTF-8");
448 if (ic == (kiconv_t)-1)
449 goto just_copy;
450 rc = kiconv(ic, &ibuf, &ilen, &obuf, &olen, &err);
451 (void) kiconv_close(ic);
452 #else /* _KERNEL || _FAKE_KERNEL */
453 const char *ibuf = mbs;
454 iconv_t ic;
455 ic = iconv_open(smb_oem_codepage, "UTF-8");
456 if (ic == (iconv_t)-1)
457 goto just_copy;
458 rc = iconv(ic, &ibuf, &ilen, &obuf, &olen);
459 (void) iconv_close(ic);
460 #endif /* _KERNEL || _FAKE_KERNEL */
461 if (rc < 0)
462 return (-1);
463 /* Return val. is output bytes. */
464 rlen = (max_oemlen - olen);
465 } else {
466 just_copy:
467 rlen = mbslen;
468 if (rlen > max_oemlen)
469 rlen = max_oemlen;
470 bcopy(mbs, oems, rlen);
471 }
472 if (rlen < max_oemlen)
473 oems[rlen] = '\0';
474
475 return (rlen);
476 }
|