source: branches/samba-3.0/source/lib/iconv.c

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

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