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

Last change on this file since 286 was 165, checked in by Paul Smedley, 16 years ago

Add 'missing' 3.0.34 diffs

File size: 18.3 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#ifdef HAVE_NATIVE_ICONV
132/* if there was an error then reset the internal state,
133 this ensures that we don't have a shift state remaining for
134 character sets like SJIS */
135static size_t sys_iconv(void *cd,
136 const char **inbuf, size_t *inbytesleft,
137 char **outbuf, size_t *outbytesleft)
138{
139#ifdef __OS2__
140 uint16 *outbuf_uc = ( uint16 * )*outbuf;
141#endif
142
143 size_t ret = iconv((iconv_t)cd,
144 (char **)inbuf, inbytesleft,
145 outbuf, outbytesleft);
146 if (ret == (size_t)-1) {
147 int saved_errno = errno;
148 iconv(cd, NULL, NULL, NULL, NULL);
149 errno = saved_errno;
150 }
151#ifdef __OS2__
152 /* Workaround for path separator on OS/2 */
153 else
154 {
155 while(( char * )outbuf_uc < *outbuf )
156 {
157 if( *outbuf_uc == 0x20a9 || /* Korean WON */
158 *outbuf_uc == 0x00a5 ) /* Japanese YEN */
159 *outbuf_uc = '\\';
160
161 outbuf_uc++;
162 }
163 }
164#endif
165 return ret;
166}
167#endif
168
169/**
170 * This is a simple portable iconv() implementaion.
171 *
172 * It only knows about a very small number of character sets - just
173 * enough that Samba works on systems that don't have iconv.
174 **/
175size_t smb_iconv(smb_iconv_t cd,
176 const char **inbuf, size_t *inbytesleft,
177 char **outbuf, size_t *outbytesleft)
178{
179 char cvtbuf[2048];
180 char *bufp = cvtbuf;
181 size_t bufsize;
182
183 /* in many cases we can go direct */
184 if (cd->direct) {
185 return cd->direct(cd->cd_direct,
186 inbuf, inbytesleft, outbuf, outbytesleft);
187 }
188
189
190 /* otherwise we have to do it chunks at a time */
191 while (*inbytesleft > 0) {
192 bufp = cvtbuf;
193 bufsize = sizeof(cvtbuf);
194
195 if (cd->pull(cd->cd_pull,
196 inbuf, inbytesleft, &bufp, &bufsize) == -1
197 && errno != E2BIG) {
198DEBUG(0,("smb_iconv 2\n"));
199return -1;}
200
201 bufp = cvtbuf;
202 bufsize = sizeof(cvtbuf) - bufsize;
203
204 if (cd->push(cd->cd_push,
205 (const char **)&bufp, &bufsize,
206 outbuf, outbytesleft) == -1) {
207DEBUG(0,("smb_iconv 3\n"));
208return -1;}
209 }
210
211 return 0;
212}
213
214
215static BOOL is_utf16(const char *name)
216{
217 return strcasecmp(name, "UCS-2LE") == 0 ||
218 strcasecmp(name, "UTF-16LE") == 0;
219}
220
221/*
222 simple iconv_open() wrapper
223 */
224smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode)
225{
226 smb_iconv_t ret;
227 struct charset_functions *from, *to;
228
229 lazy_initialize_iconv();
230 from = charsets;
231 to = charsets;
232
233 ret = SMB_MALLOC_P(struct _smb_iconv_t);
234 if (!ret) {
235 errno = ENOMEM;
236 return (smb_iconv_t)-1;
237 }
238 memset(ret, 0, sizeof(struct _smb_iconv_t));
239
240 ret->from_name = SMB_STRDUP(fromcode);
241 ret->to_name = SMB_STRDUP(tocode);
242
243 /* check for the simplest null conversion */
244 if (strcasecmp(fromcode, tocode) == 0) {
245 ret->direct = iconv_copy;
246 return ret;
247 }
248
249 /* check if we have a builtin function for this conversion */
250 from = find_charset_functions(fromcode);
251 if(from)ret->pull = from->pull;
252
253 to = find_charset_functions(tocode);
254 if(to)ret->push = to->push;
255
256 /* check if we can use iconv for this conversion */
257#ifdef HAVE_NATIVE_ICONV
258 if (!ret->pull) {
259 ret->cd_pull = iconv_open("UTF-16LE", fromcode);
260 if (ret->cd_pull == (iconv_t)-1)
261 ret->cd_pull = iconv_open("UCS-2LE", fromcode);
262 if (ret->cd_pull != (iconv_t)-1)
263 ret->pull = sys_iconv;
264 }
265
266 if (!ret->push) {
267 ret->cd_push = iconv_open(tocode, "UTF-16LE");
268 if (ret->cd_push == (iconv_t)-1)
269 ret->cd_push = iconv_open(tocode, "UCS-2LE");
270 if (ret->cd_push != (iconv_t)-1)
271 ret->push = sys_iconv;
272 }
273#endif
274
275 /* check if there is a module available that can do this conversion */
276 if (!ret->pull && NT_STATUS_IS_OK(smb_probe_module("charset", fromcode))) {
277 if(!(from = find_charset_functions(fromcode)))
278 DEBUG(0, ("Module %s doesn't provide charset %s!\n", fromcode, fromcode));
279 else
280 ret->pull = from->pull;
281 }
282
283 if (!ret->push && NT_STATUS_IS_OK(smb_probe_module("charset", tocode))) {
284 if(!(to = find_charset_functions(tocode)))
285 DEBUG(0, ("Module %s doesn't provide charset %s!\n", tocode, tocode));
286 else
287 ret->push = to->push;
288 }
289
290 if (!ret->push || !ret->pull) {
291 SAFE_FREE(ret->from_name);
292 SAFE_FREE(ret->to_name);
293 SAFE_FREE(ret);
294 errno = EINVAL;
295 return (smb_iconv_t)-1;
296 }
297
298 /* check for conversion to/from ucs2 */
299 if (is_utf16(fromcode) && to) {
300 ret->direct = to->push;
301 ret->push = ret->pull = NULL;
302 return ret;
303 }
304
305 if (is_utf16(tocode) && from) {
306 ret->direct = from->pull;
307 ret->push = ret->pull = NULL;
308 return ret;
309 }
310
311 /* Check if we can do the conversion direct */
312#ifdef HAVE_NATIVE_ICONV
313 if (is_utf16(fromcode)) {
314 ret->direct = sys_iconv;
315 ret->cd_direct = ret->cd_push;
316 ret->cd_push = NULL;
317 return ret;
318 }
319 if (is_utf16(tocode)) {
320 ret->direct = sys_iconv;
321 ret->cd_direct = ret->cd_pull;
322 ret->cd_pull = NULL;
323 return ret;
324 }
325#endif
326
327 return ret;
328}
329
330/*
331 simple iconv_close() wrapper
332*/
333int smb_iconv_close (smb_iconv_t cd)
334{
335#ifdef HAVE_NATIVE_ICONV
336 if (cd->cd_direct) iconv_close((iconv_t)cd->cd_direct);
337 if (cd->cd_pull) iconv_close((iconv_t)cd->cd_pull);
338 if (cd->cd_push) iconv_close((iconv_t)cd->cd_push);
339#endif
340
341 SAFE_FREE(cd->from_name);
342 SAFE_FREE(cd->to_name);
343
344 memset(cd, 0, sizeof(*cd));
345 SAFE_FREE(cd);
346 return 0;
347}
348
349
350/**********************************************************************
351 the following functions implement the builtin character sets in Samba
352 and also the "test" character sets that are designed to test
353 multi-byte character set support for english users
354***********************************************************************/
355
356static size_t ascii_pull(void *cd, const char **inbuf, size_t *inbytesleft,
357 char **outbuf, size_t *outbytesleft)
358{
359 while (*inbytesleft >= 1 && *outbytesleft >= 2) {
360 (*outbuf)[0] = (*inbuf)[0];
361 (*outbuf)[1] = 0;
362 (*inbytesleft) -= 1;
363 (*outbytesleft) -= 2;
364 (*inbuf) += 1;
365 (*outbuf) += 2;
366 }
367
368 if (*inbytesleft > 0) {
369 errno = E2BIG;
370 return -1;
371 }
372
373 return 0;
374}
375
376static size_t ascii_push(void *cd, const char **inbuf, size_t *inbytesleft,
377 char **outbuf, size_t *outbytesleft)
378{
379 int ir_count=0;
380
381 while (*inbytesleft >= 2 && *outbytesleft >= 1) {
382 (*outbuf)[0] = (*inbuf)[0] & 0x7F;
383 if ((*inbuf)[1]) ir_count++;
384 (*inbytesleft) -= 2;
385 (*outbytesleft) -= 1;
386 (*inbuf) += 2;
387 (*outbuf) += 1;
388 }
389
390 if (*inbytesleft == 1) {
391 errno = EINVAL;
392 return -1;
393 }
394
395 if (*inbytesleft > 1) {
396 errno = E2BIG;
397 return -1;
398 }
399
400 return ir_count;
401}
402
403static size_t latin1_push(void *cd, const char **inbuf, size_t *inbytesleft,
404 char **outbuf, size_t *outbytesleft)
405{
406 int ir_count=0;
407
408 while (*inbytesleft >= 2 && *outbytesleft >= 1) {
409 (*outbuf)[0] = (*inbuf)[0];
410 if ((*inbuf)[1]) ir_count++;
411 (*inbytesleft) -= 2;
412 (*outbytesleft) -= 1;
413 (*inbuf) += 2;
414 (*outbuf) += 1;
415 }
416
417 if (*inbytesleft == 1) {
418 errno = EINVAL;
419 return -1;
420 }
421
422 if (*inbytesleft > 1) {
423 errno = E2BIG;
424 return -1;
425 }
426
427 return ir_count;
428}
429
430static size_t ucs2hex_pull(void *cd, const char **inbuf, size_t *inbytesleft,
431 char **outbuf, size_t *outbytesleft)
432{
433 while (*inbytesleft >= 1 && *outbytesleft >= 2) {
434 unsigned v;
435
436 if ((*inbuf)[0] != '@') {
437 /* seven bit ascii case */
438 (*outbuf)[0] = (*inbuf)[0];
439 (*outbuf)[1] = 0;
440 (*inbytesleft) -= 1;
441 (*outbytesleft) -= 2;
442 (*inbuf) += 1;
443 (*outbuf) += 2;
444 continue;
445 }
446 /* it's a hex character */
447 if (*inbytesleft < 5) {
448 errno = EINVAL;
449 return -1;
450 }
451
452 if (sscanf(&(*inbuf)[1], "%04x", &v) != 1) {
453 errno = EILSEQ;
454 return -1;
455 }
456
457 (*outbuf)[0] = v&0xff;
458 (*outbuf)[1] = v>>8;
459 (*inbytesleft) -= 5;
460 (*outbytesleft) -= 2;
461 (*inbuf) += 5;
462 (*outbuf) += 2;
463 }
464
465 if (*inbytesleft > 0) {
466 errno = E2BIG;
467 return -1;
468 }
469
470 return 0;
471}
472
473static size_t ucs2hex_push(void *cd, const char **inbuf, size_t *inbytesleft,
474 char **outbuf, size_t *outbytesleft)
475{
476 while (*inbytesleft >= 2 && *outbytesleft >= 1) {
477 char buf[6];
478
479 if ((*inbuf)[1] == 0 &&
480 ((*inbuf)[0] & 0x80) == 0 &&
481 (*inbuf)[0] != '@') {
482 (*outbuf)[0] = (*inbuf)[0];
483 (*inbytesleft) -= 2;
484 (*outbytesleft) -= 1;
485 (*inbuf) += 2;
486 (*outbuf) += 1;
487 continue;
488 }
489 if (*outbytesleft < 5) {
490 errno = E2BIG;
491 return -1;
492 }
493 snprintf(buf, 6, "@%04x", SVAL(*inbuf, 0));
494 memcpy(*outbuf, buf, 5);
495 (*inbytesleft) -= 2;
496 (*outbytesleft) -= 5;
497 (*inbuf) += 2;
498 (*outbuf) += 5;
499 }
500
501 if (*inbytesleft == 1) {
502 errno = EINVAL;
503 return -1;
504 }
505
506 if (*inbytesleft > 1) {
507 errno = E2BIG;
508 return -1;
509 }
510
511 return 0;
512}
513
514static size_t iconv_swab(void *cd, const char **inbuf, size_t *inbytesleft,
515 char **outbuf, size_t *outbytesleft)
516{
517 int n;
518
519 n = MIN(*inbytesleft, *outbytesleft);
520
521 swab(*inbuf, *outbuf, (n&~1));
522 if (n&1) {
523 (*outbuf)[n-1] = 0;
524 }
525
526 (*inbytesleft) -= n;
527 (*outbytesleft) -= n;
528 (*inbuf) += n;
529 (*outbuf) += n;
530
531 if (*inbytesleft > 0) {
532 errno = E2BIG;
533 return -1;
534 }
535
536 return 0;
537}
538
539static size_t iconv_copy(void *cd, const char **inbuf, size_t *inbytesleft,
540 char **outbuf, size_t *outbytesleft)
541{
542 int n;
543
544 n = MIN(*inbytesleft, *outbytesleft);
545
546 memmove(*outbuf, *inbuf, n);
547
548 (*inbytesleft) -= n;
549 (*outbytesleft) -= n;
550 (*inbuf) += n;
551 (*outbuf) += n;
552
553 if (*inbytesleft > 0) {
554 errno = E2BIG;
555 return -1;
556 }
557
558 return 0;
559}
560
561static size_t utf8_pull(void *cd, const char **inbuf, size_t *inbytesleft,
562 char **outbuf, size_t *outbytesleft)
563{
564 size_t in_left=*inbytesleft, out_left=*outbytesleft;
565 const uint8 *c = (const uint8 *)*inbuf;
566 uint8 *uc = (uint8 *)*outbuf;
567
568 while (in_left >= 1 && out_left >= 2) {
569 unsigned int codepoint;
570
571 if ((c[0] & 0x80) == 0) {
572 uc[0] = c[0];
573 uc[1] = 0;
574 c += 1;
575 in_left -= 1;
576 out_left -= 2;
577 uc += 2;
578 continue;
579 }
580
581 if ((c[0] & 0xe0) == 0xc0) {
582 if (in_left < 2 ||
583 (c[1] & 0xc0) != 0x80) {
584 errno = EILSEQ;
585 goto error;
586 }
587 codepoint = (c[1]&0x3f) | ((c[0]&0x1f)<<6);
588 if (codepoint < 0x80) {
589 /* don't accept UTF-8 characters that are not minimally packed */
590 errno = EILSEQ;
591 goto error;
592 }
593 uc[1] = codepoint >> 8;
594 uc[0] = codepoint & 0xff;
595 c += 2;
596 in_left -= 2;
597 out_left -= 2;
598 uc += 2;
599 continue;
600 }
601
602 if ((c[0] & 0xf0) == 0xe0) {
603 if (in_left < 3 ||
604 (c[1] & 0xc0) != 0x80 ||
605 (c[2] & 0xc0) != 0x80) {
606 errno = EILSEQ;
607 goto error;
608 }
609 codepoint = (c[2]&0x3f) | ((c[1]&0x3f)<<6) | ((c[0]&0xf)<<12);
610 if (codepoint < 0x800) {
611 /* don't accept UTF-8 characters that are not minimally packed */
612 errno = EILSEQ;
613 goto error;
614 }
615 uc[1] = codepoint >> 8;
616 uc[0] = codepoint & 0xff;
617 c += 3;
618 in_left -= 3;
619 out_left -= 2;
620 uc += 2;
621 continue;
622 }
623
624 if ((c[0] & 0xf8) == 0xf0) {
625 if (in_left < 4 ||
626 (c[1] & 0xc0) != 0x80 ||
627 (c[2] & 0xc0) != 0x80 ||
628 (c[3] & 0xc0) != 0x80) {
629 errno = EILSEQ;
630 goto error;
631 }
632 codepoint =
633 (c[3]&0x3f) |
634 ((c[2]&0x3f)<<6) |
635 ((c[1]&0x3f)<<12) |
636 ((c[0]&0x7)<<18);
637 if (codepoint < 0x10000 || codepoint > 0x10ffff) {
638 /* don't accept UTF-8 characters that are not minimally packed */
639 errno = EILSEQ;
640 goto error;
641 }
642
643 codepoint -= 0x10000;
644
645 if (out_left < 4) {
646 errno = E2BIG;
647 goto error;
648 }
649
650 uc[0] = (codepoint>>10) & 0xFF;
651 uc[1] = (codepoint>>18) | 0xd8;
652 uc[2] = codepoint & 0xFF;
653 uc[3] = ((codepoint>>8) & 0x3) | 0xdc;
654 c += 4;
655 in_left -= 4;
656 out_left -= 4;
657 uc += 4;
658 continue;
659 }
660
661 /* we don't handle 5 byte sequences */
662 errno = EINVAL;
663 goto error;
664 }
665
666 if (in_left > 0) {
667 errno = E2BIG;
668 goto error;
669 }
670
671 *inbytesleft = in_left;
672 *outbytesleft = out_left;
673 *inbuf = (char *)c;
674 *outbuf = (char *)uc;
675 return 0;
676
677error:
678 *inbytesleft = in_left;
679 *outbytesleft = out_left;
680 *inbuf = (char *)c;
681 *outbuf = (char *)uc;
682 return -1;
683}
684
685static size_t utf8_push(void *cd, const char **inbuf, size_t *inbytesleft,
686 char **outbuf, size_t *outbytesleft)
687{
688 size_t in_left=*inbytesleft, out_left=*outbytesleft;
689 uint8 *c = (uint8 *)*outbuf;
690 const uint8 *uc = (const uint8 *)*inbuf;
691
692 while (in_left >= 2 && out_left >= 1) {
693 unsigned int codepoint;
694
695 if (uc[1] == 0 && !(uc[0] & 0x80)) {
696 /* simplest case */
697 c[0] = uc[0];
698 in_left -= 2;
699 out_left -= 1;
700 uc += 2;
701 c += 1;
702 continue;
703 }
704
705 if ((uc[1]&0xf8) == 0) {
706 /* next simplest case */
707 if (out_left < 2) {
708 errno = E2BIG;
709 goto error;
710 }
711 c[0] = 0xc0 | (uc[0]>>6) | (uc[1]<<2);
712 c[1] = 0x80 | (uc[0] & 0x3f);
713 in_left -= 2;
714 out_left -= 2;
715 uc += 2;
716 c += 2;
717 continue;
718 }
719
720 if ((uc[1] & 0xfc) == 0xdc) {
721 /* its the second part of a 4 byte sequence. Illegal */
722 if (in_left < 4) {
723 errno = EINVAL;
724 } else {
725 errno = EILSEQ;
726 }
727 goto error;
728 }
729
730 if ((uc[1] & 0xfc) != 0xd8) {
731 codepoint = uc[0] | (uc[1]<<8);
732 if (out_left < 3) {
733 errno = E2BIG;
734 goto error;
735 }
736 c[0] = 0xe0 | (codepoint >> 12);
737 c[1] = 0x80 | ((codepoint >> 6) & 0x3f);
738 c[2] = 0x80 | (codepoint & 0x3f);
739
740 in_left -= 2;
741 out_left -= 3;
742 uc += 2;
743 c += 3;
744 continue;
745 }
746
747 /* its the first part of a 4 byte sequence */
748 if (in_left < 4) {
749 errno = EINVAL;
750 goto error;
751 }
752 if ((uc[3] & 0xfc) != 0xdc) {
753 errno = EILSEQ;
754 goto error;
755 }
756 codepoint = 0x10000 + (uc[2] | ((uc[3] & 0x3)<<8) |
757 (uc[0]<<10) | ((uc[1] & 0x3)<<18));
758
759 if (out_left < 4) {
760 errno = E2BIG;
761 goto error;
762 }
763 c[0] = 0xf0 | (codepoint >> 18);
764 c[1] = 0x80 | ((codepoint >> 12) & 0x3f);
765 c[2] = 0x80 | ((codepoint >> 6) & 0x3f);
766 c[3] = 0x80 | (codepoint & 0x3f);
767
768 in_left -= 4;
769 out_left -= 4;
770 uc += 4;
771 c += 4;
772 }
773
774 if (in_left == 1) {
775 errno = EINVAL;
776 goto error;
777 }
778
779 if (in_left > 1) {
780 errno = E2BIG;
781 goto error;
782 }
783
784 *inbytesleft = in_left;
785 *outbytesleft = out_left;
786 *inbuf = (char *)uc;
787 *outbuf = (char *)c;
788
789 return 0;
790
791error:
792 *inbytesleft = in_left;
793 *outbytesleft = out_left;
794 *inbuf = (char *)uc;
795 *outbuf = (char *)c;
796 return -1;
797}
798
Note: See TracBrowser for help on using the repository browser.