source: branches/samba-3.3.x/source/lib/iconv.c@ 538

Last change on this file since 538 was 538, checked in by Silvan Scherrer, 15 years ago

Samba Server 3.3: fix for ticket 130 thx komh

File size: 18.6 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 minimal iconv implementation
4 Copyright (C) Andrew Tridgell 2001
5 Copyright (C) Jelmer Vernooij 2002,2003
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#include "includes.h"
22
23/*
24 * We have to use strcasecmp here as the character conversions
25 * haven't been initialised yet. JRA.
26 */
27
28#undef strcasecmp
29
30/**
31 * @file
32 *
33 * @brief Samba wrapper/stub for iconv character set conversion.
34 *
35 * iconv is the XPG2 interface for converting between character
36 * encodings. This file provides a Samba wrapper around it, and also
37 * a simple reimplementation that is used if the system does not
38 * implement iconv.
39 *
40 * Samba only works with encodings that are supersets of ASCII: ascii
41 * characters like whitespace can be tested for directly, multibyte
42 * sequences start with a byte with the high bit set, and strings are
43 * terminated by a nul byte.
44 *
45 * Note that the only function provided by iconv is conversion between
46 * characters. It doesn't directly support operations like
47 * uppercasing or comparison. We have to convert to UCS-2 and compare
48 * there.
49 *
50 * @sa Samba Developers Guide
51 **/
52
53static_decl_charset;
54
55static size_t ascii_pull(void *,const char **, size_t *, char **, size_t *);
56static size_t ascii_push(void *,const char **, size_t *, char **, size_t *);
57static size_t latin1_push(void *,const char **, size_t *, char **, size_t *);
58static size_t utf8_pull(void *,const char **, size_t *, char **, size_t *);
59static size_t utf8_push(void *,const char **, size_t *, char **, size_t *);
60static size_t ucs2hex_pull(void *,const char **, size_t *, char **, size_t *);
61static size_t ucs2hex_push(void *,const char **, size_t *, char **, size_t *);
62static size_t iconv_copy(void *,const char **, size_t *, char **, size_t *);
63static size_t iconv_swab (void *,const char **, size_t *, char **, size_t *);
64
65static struct charset_functions builtin_functions[] = {
66 /* windows is really neither UCS-2 not UTF-16 */
67 {"UCS-2LE", iconv_copy, iconv_copy},
68 {"UTF-16LE", iconv_copy, iconv_copy},
69 {"UCS-2BE", iconv_swab, iconv_swab},
70 {"UTF-16BE", iconv_swab, iconv_swab},
71
72 /* we include the UTF-8 alias to cope with differing locale settings */
73 {"UTF8", utf8_pull, utf8_push},
74 {"UTF-8", utf8_pull, utf8_push},
75 {"ASCII", ascii_pull, ascii_push},
76 {"646", ascii_pull, ascii_push},
77 {"ISO-8859-1", ascii_pull, latin1_push},
78 {"UCS2-HEX", ucs2hex_pull, ucs2hex_push},
79 {NULL, NULL, NULL}
80};
81
82static struct charset_functions *charsets = NULL;
83
84static struct charset_functions *find_charset_functions(const char *name)
85{
86 struct charset_functions *c = charsets;
87
88 while(c) {
89 if (strcasecmp(name, c->name) == 0) {
90 return c;
91 }
92 c = c->next;
93 }
94
95 return NULL;
96}
97
98NTSTATUS smb_register_charset(struct charset_functions *funcs)
99{
100 if (!funcs) {
101 return NT_STATUS_INVALID_PARAMETER;
102 }
103
104 DEBUG(5, ("Attempting to register new charset %s\n", funcs->name));
105 /* Check whether we already have this charset... */
106 if (find_charset_functions(funcs->name)) {
107 DEBUG(0, ("Duplicate charset %s, not registering\n", funcs->name));
108 return NT_STATUS_OBJECT_NAME_COLLISION;
109 }
110
111 funcs->next = funcs->prev = NULL;
112 DEBUG(5, ("Registered charset %s\n", funcs->name));
113 DLIST_ADD(charsets, funcs);
114 return NT_STATUS_OK;
115}
116
117static void lazy_initialize_iconv(void)
118{
119 static bool initialized;
120 int i;
121
122 if (!initialized) {
123 initialized = True;
124 for(i = 0; builtin_functions[i].name; i++)
125 smb_register_charset(&builtin_functions[i]);
126 static_init_charset;
127 }
128}
129
130#if defined(__OS2__) && defined(__INNOTEK_LIBC__)
131#include <uconv.h>
132
133typedef struct os2_iconv_t
134{
135 UconvObject from;
136} os2_iconv_t;
137
138iconv_t os2_iconv_open (const char *tocode, const char *fromcode)
139{
140 os2_iconv_t *os2_cd = (os2_iconv_t *)iconv_open(tocode, fromcode);
141
142 if (os2_cd != (iconv_t)(-1))
143 {
144 /* Assume strings contain pathnames */
145 uconv_attribute_t attr;
146
147 UniQueryUconvObject(os2_cd->from, &attr,
148 sizeof(uconv_attribute_t),
149 NULL, NULL, NULL );
150 attr.converttype |= CVTTYPE_PATH;
151 UniSetUconvObject(os2_cd->from, &attr);
152 }
153
154 return (iconv_t)os2_cd;
155}
156
157#define iconv_open os2_iconv_open
158#endif
159
160#ifdef HAVE_NATIVE_ICONV
161/* if there was an error then reset the internal state,
162 this ensures that we don't have a shift state remaining for
163 character sets like SJIS */
164static size_t sys_iconv(void *cd,
165 const char **inbuf, size_t *inbytesleft,
166 char **outbuf, size_t *outbytesleft)
167{
168
169 size_t ret = iconv((iconv_t)cd,
170 (void *)inbuf, inbytesleft,
171 outbuf, outbytesleft);
172 if (ret == (size_t)-1) {
173 int saved_errno = errno;
174 iconv(cd, NULL, NULL, NULL, NULL);
175 errno = saved_errno;
176 }
177 return ret;
178}
179#endif
180
181/**
182 * This is a simple portable iconv() implementaion.
183 *
184 * It only knows about a very small number of character sets - just
185 * enough that Samba works on systems that don't have iconv.
186 **/
187size_t smb_iconv(smb_iconv_t cd,
188 const char **inbuf, size_t *inbytesleft,
189 char **outbuf, size_t *outbytesleft)
190{
191 char cvtbuf[2048];
192 char *bufp = cvtbuf;
193 size_t bufsize;
194
195 /* in many cases we can go direct */
196 if (cd->direct) {
197 return cd->direct(cd->cd_direct,
198 inbuf, inbytesleft, outbuf, outbytesleft);
199 }
200
201
202 /* otherwise we have to do it chunks at a time */
203 while (*inbytesleft > 0) {
204 bufp = cvtbuf;
205 bufsize = sizeof(cvtbuf);
206
207 if (cd->pull(cd->cd_pull,
208 inbuf, inbytesleft, &bufp, &bufsize) == -1
209 && errno != E2BIG)
210 return -1;
211
212 bufp = cvtbuf;
213 bufsize = sizeof(cvtbuf) - bufsize;
214
215 if (cd->push(cd->cd_push,
216 (const char **)&bufp, &bufsize,
217 outbuf, outbytesleft) == -1)
218 return -1;
219 }
220
221 return 0;
222}
223
224
225static bool is_utf16(const char *name)
226{
227 return strcasecmp(name, "UCS-2LE") == 0 ||
228 strcasecmp(name, "UTF-16LE") == 0;
229}
230
231/*
232 simple iconv_open() wrapper
233 */
234smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode)
235{
236 smb_iconv_t ret;
237 struct charset_functions *from, *to;
238
239 lazy_initialize_iconv();
240 from = charsets;
241 to = charsets;
242
243 ret = SMB_MALLOC_P(struct _smb_iconv_t);
244 if (!ret) {
245 errno = ENOMEM;
246 return (smb_iconv_t)-1;
247 }
248 memset(ret, 0, sizeof(struct _smb_iconv_t));
249
250 ret->from_name = SMB_STRDUP(fromcode);
251 ret->to_name = SMB_STRDUP(tocode);
252
253 /* check for the simplest null conversion */
254 if (strcasecmp(fromcode, tocode) == 0) {
255 ret->direct = iconv_copy;
256 return ret;
257 }
258
259 /* check if we have a builtin function for this conversion */
260 from = find_charset_functions(fromcode);
261 if(from)ret->pull = from->pull;
262
263 to = find_charset_functions(tocode);
264 if(to)ret->push = to->push;
265
266 /* check if we can use iconv for this conversion */
267#ifdef HAVE_NATIVE_ICONV
268 if (!ret->pull) {
269 ret->cd_pull = iconv_open("UTF-16LE", fromcode);
270 if (ret->cd_pull == (iconv_t)-1)
271 ret->cd_pull = iconv_open("UCS-2LE", fromcode);
272 if (ret->cd_pull != (iconv_t)-1)
273 ret->pull = sys_iconv;
274 }
275
276 if (!ret->push) {
277 ret->cd_push = iconv_open(tocode, "UTF-16LE");
278 if (ret->cd_push == (iconv_t)-1)
279 ret->cd_push = iconv_open(tocode, "UCS-2LE");
280 if (ret->cd_push != (iconv_t)-1)
281 ret->push = sys_iconv;
282 }
283#endif
284
285 /* check if there is a module available that can do this conversion */
286 if (!ret->pull && NT_STATUS_IS_OK(smb_probe_module("charset", fromcode))) {
287 if(!(from = find_charset_functions(fromcode)))
288 DEBUG(0, ("Module %s doesn't provide charset %s!\n", fromcode, fromcode));
289 else
290 ret->pull = from->pull;
291 }
292
293 if (!ret->push && NT_STATUS_IS_OK(smb_probe_module("charset", tocode))) {
294 if(!(to = find_charset_functions(tocode)))
295 DEBUG(0, ("Module %s doesn't provide charset %s!\n", tocode, tocode));
296 else
297 ret->push = to->push;
298 }
299
300 if (!ret->push || !ret->pull) {
301 SAFE_FREE(ret->from_name);
302 SAFE_FREE(ret->to_name);
303 SAFE_FREE(ret);
304 errno = EINVAL;
305 return (smb_iconv_t)-1;
306 }
307
308 /* check for conversion to/from ucs2 */
309 if (is_utf16(fromcode) && to) {
310 ret->direct = to->push;
311 ret->push = ret->pull = NULL;
312 return ret;
313 }
314
315 if (is_utf16(tocode) && from) {
316 ret->direct = from->pull;
317 ret->push = ret->pull = NULL;
318 return ret;
319 }
320
321 /* Check if we can do the conversion direct */
322#ifdef HAVE_NATIVE_ICONV
323 if (is_utf16(fromcode)) {
324 ret->direct = sys_iconv;
325 ret->cd_direct = ret->cd_push;
326 ret->cd_push = NULL;
327 return ret;
328 }
329 if (is_utf16(tocode)) {
330 ret->direct = sys_iconv;
331 ret->cd_direct = ret->cd_pull;
332 ret->cd_pull = NULL;
333 return ret;
334 }
335#endif
336
337 return ret;
338}
339
340/*
341 simple iconv_close() wrapper
342*/
343int smb_iconv_close (smb_iconv_t cd)
344{
345#ifdef HAVE_NATIVE_ICONV
346 if (cd->cd_direct) iconv_close((iconv_t)cd->cd_direct);
347 if (cd->cd_pull) iconv_close((iconv_t)cd->cd_pull);
348 if (cd->cd_push) iconv_close((iconv_t)cd->cd_push);
349#endif
350
351 SAFE_FREE(cd->from_name);
352 SAFE_FREE(cd->to_name);
353
354 memset(cd, 0, sizeof(*cd));
355 SAFE_FREE(cd);
356 return 0;
357}
358
359
360/**********************************************************************
361 the following functions implement the builtin character sets in Samba
362 and also the "test" character sets that are designed to test
363 multi-byte character set support for english users
364***********************************************************************/
365
366static size_t ascii_pull(void *cd, const char **inbuf, size_t *inbytesleft,
367 char **outbuf, size_t *outbytesleft)
368{
369 while (*inbytesleft >= 1 && *outbytesleft >= 2) {
370 (*outbuf)[0] = (*inbuf)[0];
371 (*outbuf)[1] = 0;
372 (*inbytesleft) -= 1;
373 (*outbytesleft) -= 2;
374 (*inbuf) += 1;
375 (*outbuf) += 2;
376 }
377
378 if (*inbytesleft > 0) {
379 errno = E2BIG;
380 return -1;
381 }
382
383 return 0;
384}
385
386static size_t ascii_push(void *cd, const char **inbuf, size_t *inbytesleft,
387 char **outbuf, size_t *outbytesleft)
388{
389 int ir_count=0;
390
391 while (*inbytesleft >= 2 && *outbytesleft >= 1) {
392 (*outbuf)[0] = (*inbuf)[0] & 0x7F;
393 if ((*inbuf)[1]) ir_count++;
394 (*inbytesleft) -= 2;
395 (*outbytesleft) -= 1;
396 (*inbuf) += 2;
397 (*outbuf) += 1;
398 }
399
400 if (*inbytesleft == 1) {
401 errno = EINVAL;
402 return -1;
403 }
404
405 if (*inbytesleft > 1) {
406 errno = E2BIG;
407 return -1;
408 }
409
410 return ir_count;
411}
412
413static size_t latin1_push(void *cd, const char **inbuf, size_t *inbytesleft,
414 char **outbuf, size_t *outbytesleft)
415{
416 int ir_count=0;
417
418 while (*inbytesleft >= 2 && *outbytesleft >= 1) {
419 (*outbuf)[0] = (*inbuf)[0];
420 if ((*inbuf)[1]) ir_count++;
421 (*inbytesleft) -= 2;
422 (*outbytesleft) -= 1;
423 (*inbuf) += 2;
424 (*outbuf) += 1;
425 }
426
427 if (*inbytesleft == 1) {
428 errno = EINVAL;
429 return -1;
430 }
431
432 if (*inbytesleft > 1) {
433 errno = E2BIG;
434 return -1;
435 }
436
437 return ir_count;
438}
439
440static size_t ucs2hex_pull(void *cd, const char **inbuf, size_t *inbytesleft,
441 char **outbuf, size_t *outbytesleft)
442{
443 while (*inbytesleft >= 1 && *outbytesleft >= 2) {
444 unsigned v;
445
446 if ((*inbuf)[0] != '@') {
447 /* seven bit ascii case */
448 (*outbuf)[0] = (*inbuf)[0];
449 (*outbuf)[1] = 0;
450 (*inbytesleft) -= 1;
451 (*outbytesleft) -= 2;
452 (*inbuf) += 1;
453 (*outbuf) += 2;
454 continue;
455 }
456 /* it's a hex character */
457 if (*inbytesleft < 5) {
458 errno = EINVAL;
459 return -1;
460 }
461
462 if (sscanf(&(*inbuf)[1], "%04x", &v) != 1) {
463 errno = EILSEQ;
464 return -1;
465 }
466
467 (*outbuf)[0] = v&0xff;
468 (*outbuf)[1] = v>>8;
469 (*inbytesleft) -= 5;
470 (*outbytesleft) -= 2;
471 (*inbuf) += 5;
472 (*outbuf) += 2;
473 }
474
475 if (*inbytesleft > 0) {
476 errno = E2BIG;
477 return -1;
478 }
479
480 return 0;
481}
482
483static size_t ucs2hex_push(void *cd, const char **inbuf, size_t *inbytesleft,
484 char **outbuf, size_t *outbytesleft)
485{
486 while (*inbytesleft >= 2 && *outbytesleft >= 1) {
487 char buf[6];
488
489 if ((*inbuf)[1] == 0 &&
490 ((*inbuf)[0] & 0x80) == 0 &&
491 (*inbuf)[0] != '@') {
492 (*outbuf)[0] = (*inbuf)[0];
493 (*inbytesleft) -= 2;
494 (*outbytesleft) -= 1;
495 (*inbuf) += 2;
496 (*outbuf) += 1;
497 continue;
498 }
499 if (*outbytesleft < 5) {
500 errno = E2BIG;
501 return -1;
502 }
503 snprintf(buf, 6, "@%04x", SVAL(*inbuf, 0));
504 memcpy(*outbuf, buf, 5);
505 (*inbytesleft) -= 2;
506 (*outbytesleft) -= 5;
507 (*inbuf) += 2;
508 (*outbuf) += 5;
509 }
510
511 if (*inbytesleft == 1) {
512 errno = EINVAL;
513 return -1;
514 }
515
516 if (*inbytesleft > 1) {
517 errno = E2BIG;
518 return -1;
519 }
520
521 return 0;
522}
523
524static size_t iconv_swab(void *cd, const char **inbuf, size_t *inbytesleft,
525 char **outbuf, size_t *outbytesleft)
526{
527 int n;
528
529 n = MIN(*inbytesleft, *outbytesleft);
530
531 swab(*inbuf, *outbuf, (n&~1));
532 if (n&1) {
533 (*outbuf)[n-1] = 0;
534 }
535
536 (*inbytesleft) -= n;
537 (*outbytesleft) -= n;
538 (*inbuf) += n;
539 (*outbuf) += n;
540
541 if (*inbytesleft > 0) {
542 errno = E2BIG;
543 return -1;
544 }
545
546 return 0;
547}
548
549static size_t iconv_copy(void *cd, const char **inbuf, size_t *inbytesleft,
550 char **outbuf, size_t *outbytesleft)
551{
552 int n;
553
554 n = MIN(*inbytesleft, *outbytesleft);
555
556 memmove(*outbuf, *inbuf, n);
557
558 (*inbytesleft) -= n;
559 (*outbytesleft) -= n;
560 (*inbuf) += n;
561 (*outbuf) += n;
562
563 if (*inbytesleft > 0) {
564 errno = E2BIG;
565 return -1;
566 }
567
568 return 0;
569}
570
571static size_t utf8_pull(void *cd, const char **inbuf, size_t *inbytesleft,
572 char **outbuf, size_t *outbytesleft)
573{
574 size_t in_left=*inbytesleft, out_left=*outbytesleft;
575 const uint8 *c = (const uint8 *)*inbuf;
576 uint8 *uc = (uint8 *)*outbuf;
577
578 while (in_left >= 1 && out_left >= 2) {
579 unsigned int codepoint;
580
581 if ((c[0] & 0x80) == 0) {
582 uc[0] = c[0];
583 uc[1] = 0;
584 c += 1;
585 in_left -= 1;
586 out_left -= 2;
587 uc += 2;
588 continue;
589 }
590
591 if ((c[0] & 0xe0) == 0xc0) {
592 if (in_left < 2 ||
593 (c[1] & 0xc0) != 0x80) {
594 errno = EILSEQ;
595 goto error;
596 }
597 codepoint = (c[1]&0x3f) | ((c[0]&0x1f)<<6);
598 if (codepoint < 0x80) {
599 /* don't accept UTF-8 characters that are not minimally packed */
600 errno = EILSEQ;
601 goto error;
602 }
603 uc[1] = codepoint >> 8;
604 uc[0] = codepoint & 0xff;
605 c += 2;
606 in_left -= 2;
607 out_left -= 2;
608 uc += 2;
609 continue;
610 }
611
612 if ((c[0] & 0xf0) == 0xe0) {
613 if (in_left < 3 ||
614 (c[1] & 0xc0) != 0x80 ||
615 (c[2] & 0xc0) != 0x80) {
616 errno = EILSEQ;
617 goto error;
618 }
619 codepoint = (c[2]&0x3f) | ((c[1]&0x3f)<<6) | ((c[0]&0xf)<<12);
620 if (codepoint < 0x800) {
621 /* don't accept UTF-8 characters that are not minimally packed */
622 errno = EILSEQ;
623 goto error;
624 }
625 uc[1] = codepoint >> 8;
626 uc[0] = codepoint & 0xff;
627 c += 3;
628 in_left -= 3;
629 out_left -= 2;
630 uc += 2;
631 continue;
632 }
633
634 if ((c[0] & 0xf8) == 0xf0) {
635 if (in_left < 4 ||
636 (c[1] & 0xc0) != 0x80 ||
637 (c[2] & 0xc0) != 0x80 ||
638 (c[3] & 0xc0) != 0x80) {
639 errno = EILSEQ;
640 goto error;
641 }
642 codepoint =
643 (c[3]&0x3f) |
644 ((c[2]&0x3f)<<6) |
645 ((c[1]&0x3f)<<12) |
646 ((c[0]&0x7)<<18);
647 if (codepoint < 0x10000 || codepoint > 0x10ffff) {
648 /* don't accept UTF-8 characters that are not minimally packed */
649 errno = EILSEQ;
650 goto error;
651 }
652
653 codepoint -= 0x10000;
654
655 if (out_left < 4) {
656 errno = E2BIG;
657 goto error;
658 }
659
660 uc[0] = (codepoint>>10) & 0xFF;
661 uc[1] = (codepoint>>18) | 0xd8;
662 uc[2] = codepoint & 0xFF;
663 uc[3] = ((codepoint>>8) & 0x3) | 0xdc;
664 c += 4;
665 in_left -= 4;
666 out_left -= 4;
667 uc += 4;
668 continue;
669 }
670
671 /* we don't handle 5 byte sequences */
672 errno = EINVAL;
673 goto error;
674 }
675
676 if (in_left > 0) {
677 errno = E2BIG;
678 goto error;
679 }
680
681 *inbytesleft = in_left;
682 *outbytesleft = out_left;
683 *inbuf = (char *)c;
684 *outbuf = (char *)uc;
685 return 0;
686
687error:
688 *inbytesleft = in_left;
689 *outbytesleft = out_left;
690 *inbuf = (char *)c;
691 *outbuf = (char *)uc;
692 return -1;
693}
694
695static size_t utf8_push(void *cd, const char **inbuf, size_t *inbytesleft,
696 char **outbuf, size_t *outbytesleft)
697{
698 size_t in_left=*inbytesleft, out_left=*outbytesleft;
699 uint8 *c = (uint8 *)*outbuf;
700 const uint8 *uc = (const uint8 *)*inbuf;
701
702 while (in_left >= 2 && out_left >= 1) {
703 unsigned int codepoint;
704
705 if (uc[1] == 0 && !(uc[0] & 0x80)) {
706 /* simplest case */
707 c[0] = uc[0];
708 in_left -= 2;
709 out_left -= 1;
710 uc += 2;
711 c += 1;
712 continue;
713 }
714
715 if ((uc[1]&0xf8) == 0) {
716 /* next simplest case */
717 if (out_left < 2) {
718 errno = E2BIG;
719 goto error;
720 }
721 c[0] = 0xc0 | (uc[0]>>6) | (uc[1]<<2);
722 c[1] = 0x80 | (uc[0] & 0x3f);
723 in_left -= 2;
724 out_left -= 2;
725 uc += 2;
726 c += 2;
727 continue;
728 }
729
730 if ((uc[1] & 0xfc) == 0xdc) {
731 /* its the second part of a 4 byte sequence. Illegal */
732 if (in_left < 4) {
733 errno = EINVAL;
734 } else {
735 errno = EILSEQ;
736 }
737 goto error;
738 }
739
740 if ((uc[1] & 0xfc) != 0xd8) {
741 codepoint = uc[0] | (uc[1]<<8);
742 if (out_left < 3) {
743 errno = E2BIG;
744 goto error;
745 }
746 c[0] = 0xe0 | (codepoint >> 12);
747 c[1] = 0x80 | ((codepoint >> 6) & 0x3f);
748 c[2] = 0x80 | (codepoint & 0x3f);
749
750 in_left -= 2;
751 out_left -= 3;
752 uc += 2;
753 c += 3;
754 continue;
755 }
756
757 /* its the first part of a 4 byte sequence */
758 if (in_left < 4) {
759 errno = EINVAL;
760 goto error;
761 }
762 if ((uc[3] & 0xfc) != 0xdc) {
763 errno = EILSEQ;
764 goto error;
765 }
766 codepoint = 0x10000 + (uc[2] | ((uc[3] & 0x3)<<8) |
767 (uc[0]<<10) | ((uc[1] & 0x3)<<18));
768
769 if (out_left < 4) {
770 errno = E2BIG;
771 goto error;
772 }
773 c[0] = 0xf0 | (codepoint >> 18);
774 c[1] = 0x80 | ((codepoint >> 12) & 0x3f);
775 c[2] = 0x80 | ((codepoint >> 6) & 0x3f);
776 c[3] = 0x80 | (codepoint & 0x3f);
777
778 in_left -= 4;
779 out_left -= 4;
780 uc += 4;
781 c += 4;
782 }
783
784 if (in_left == 1) {
785 errno = EINVAL;
786 goto error;
787 }
788
789 if (in_left > 1) {
790 errno = E2BIG;
791 goto error;
792 }
793
794 *inbytesleft = in_left;
795 *outbytesleft = out_left;
796 *inbuf = (char *)uc;
797 *outbuf = (char *)c;
798
799 return 0;
800
801error:
802 *inbytesleft = in_left;
803 *outbytesleft = out_left;
804 *inbuf = (char *)uc;
805 *outbuf = (char *)c;
806 return -1;
807}
808
Note: See TracBrowser for help on using the repository browser.