source: branches/samba-3.2.x/source/lib/iconv.c@ 285

Last change on this file since 285 was 133, checked in by Paul Smedley, 17 years ago

Update trunk to 3.2.0pre3

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