1 /*- 2 * Copyright (c) 1999,2000 3 * Konstantin Chuguev. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * iconv (Charset Conversion Library) v2.0 27 */ 28 #include <errno.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <assert.h> 32 #include <reent.h> 33 #include <limits.h> 34 #include "local.h" 35 36 static iconv_converter_t * 37 _DEFUN(converter_init, (rptr, conv_func, close_func, extra), 38 struct _reent *rptr _AND 39 iconv_conv_t conv_func _AND 40 iconv_close_t close_func _AND 41 size_t extra) 42 { 43 iconv_converter_t *res = _malloc_r(rptr, sizeof(iconv_converter_t) + extra); 44 memset(res, 0, sizeof(iconv_converter_t) + extra); 45 if (res) { 46 res->convert = conv_func; 47 res->close = close_func; 48 } 49 return res; 50 } 51 52 static int 53 _DEFUN(unicode_close, (rptr, data), 54 struct _reent *rptr _AND 55 _VOID_PTR data) 56 { 57 int res; 58 unicode_converter_t *uc = (unicode_converter_t *)data; 59 60 res = ICONV_CES_CLOSE(rptr, &(uc->from)); 61 res = ICONV_CES_CLOSE(rptr, &(uc->to)) || res; 62 return res; 63 } 64 65 static size_t 66 _DEFUN(unicode_conv, (rptr, data, inbuf, inbytesleft, outbuf, outbytesleft), 67 struct _reent *rptr _AND 68 _VOID_PTR data _AND 69 _CONST unsigned char **inbuf _AND 70 size_t *inbytesleft _AND 71 unsigned char **outbuf _AND 72 size_t *outbytesleft) 73 { 74 size_t res = 0; 75 unicode_converter_t *uc = (unicode_converter_t *)data; 76 77 if (inbuf == NULL || *inbuf == NULL) { 78 if (ICONV_CES_CONVERT_FROM_UCS(&(uc->to), UCS_CHAR_NONE, 79 outbuf, outbytesleft) <= 0) { 80 __errno_r(rptr) = E2BIG; 81 return (size_t)(-1); 82 } 83 ICONV_CES_RESET(&(uc->from)); 84 ICONV_CES_RESET(&(uc->to)); 85 return res; 86 } 87 if (inbytesleft == NULL || *inbytesleft == 0) 88 return 0; 89 while (*inbytesleft > 0) { 90 ssize_t size; 91 _CONST unsigned char *ptr = *inbuf; 92 ucs_t ch = ICONV_CES_CONVERT_TO_UCS(&(uc->from), inbuf, 93 inbytesleft); 94 95 if (ch == UCS_CHAR_NONE) { 96 /* Incomplete character in input buffer */ 97 __errno_r(rptr) = EINVAL; 98 return (size_t)(-1); 99 } 100 if (ch == UCS_CHAR_INVALID) { 101 /* Invalid character in source buffer */ 102 *inbytesleft += *inbuf - ptr; 103 *inbuf = ptr; 104 __errno_r(rptr) = EILSEQ; 105 return (size_t)(-1); 106 } 107 size = ICONV_CES_CONVERT_FROM_UCS(&(uc->to), ch, 108 outbuf, outbytesleft); 109 110 if (size < 0) { 111 /* No equivalent in destination charset. */ 112 113 size = ICONV_CES_CONVERT_FROM_UCS(&(uc->to), 114 uc->missing, 115 outbuf, outbytesleft); 116 if (size) 117 res ++; 118 } 119 if (!size) { 120 /* Not enough space in output buffer */ 121 *inbytesleft += *inbuf - ptr; 122 *inbuf = ptr; 123 __errno_r(rptr) = E2BIG; 124 return (size_t)(-1); 125 } 126 } 127 return res; 128 } 129 130 iconv_converter_t * 131 _DEFUN(_iconv_unicode_conv_init, (rptr, to, from), 132 struct _reent *rptr _AND 133 _CONST char *to _AND 134 _CONST char *from) 135 { 136 unicode_converter_t *uc; 137 iconv_converter_t *ic = converter_init(rptr, unicode_conv, unicode_close, 138 sizeof(unicode_converter_t)); 139 140 if (ic == NULL) 141 return NULL; 142 uc = (unicode_converter_t *)(ic + 1); 143 if (!_iconv_ces_init(rptr, &(uc->from), from)) { 144 if(!_iconv_ces_init(rptr, &(uc->to), to)) 145 { 146 uc->missing = '_'; 147 return ic; 148 } 149 ICONV_CES_CLOSE(rptr, &(uc->from)); 150 } 151 _free_r(rptr, ic); 152 return NULL; 153 } 154 155 static int 156 _DEFUN(null_close, (rptr, data), 157 struct _reent *rptr _AND 158 _VOID_PTR data) 159 { 160 return 0; 161 } 162 163 static size_t 164 _DEFUN(null_conv, (rptr, data, inbuf, inbytesleft, outbuf, outbytesleft), 165 struct _reent *rptr _AND 166 _VOID_PTR data _AND 167 _CONST unsigned char **inbuf _AND 168 size_t *inbytesleft _AND 169 unsigned char **outbuf _AND 170 size_t *outbytesleft) 171 { 172 if (inbuf && *inbuf && inbytesleft && *inbytesleft > 0 && outbuf 173 && *outbuf && outbytesleft) { 174 size_t result, len; 175 if (*inbytesleft < *outbytesleft) { 176 result = 0; 177 len = *inbytesleft; 178 } else { 179 result = (size_t)(-1); 180 __errno_r(rptr) = E2BIG; 181 len = *outbytesleft; 182 } 183 bcopy(*inbuf, *outbuf, len); 184 *inbuf += len; 185 *inbytesleft -= len; 186 *outbuf += len; 187 *outbytesleft -= len; 188 189 return result; 190 } 191 192 return 0; 193 } 194 195 iconv_converter_t * 196 _DEFUN(_iconv_null_conv_init, (rptr, to, from), 197 struct _reent *rptr _AND 198 _CONST char *to _AND 199 _CONST char *from) 200 { 201 return converter_init(rptr, null_conv, null_close, 0); 202 } 203 204