1 /*- 2 * Copyright (C) 2009 Gabor Kovesdan <gabor@FreeBSD.org> 3 * 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 27 #include <sys/param.h> 28 #include <sys/endian.h> 29 30 #include <err.h> 31 #include <errno.h> 32 #include <iconv.h> 33 #include <stdbool.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 37 /* 38 * iconv_open must return (iconv_t)-1 on non-existing encoding 39 * and set errno to EINVAL. 40 */ 41 static int 42 open_1(void) 43 { 44 iconv_t cd; 45 46 errno = 0; 47 cd = iconv_open("nonexisting", "foobar"); 48 49 if ((cd == (iconv_t)-1) && (errno == EINVAL)) 50 return (0); 51 else { 52 iconv_close(cd); 53 return (1); 54 } 55 } 56 57 /* 58 * iconv_open must return (iconv_t)-1 if too much files are open 59 * and set errno to ENFILE. 60 */ 61 #define MAX_LIMIT 1025 62 static int 63 open_2(void) 64 { 65 iconv_t cd[MAX_LIMIT]; 66 size_t i; 67 int ret; 68 69 errno = 0; 70 ret = 1; 71 for (i = 0; i < MAX_LIMIT; i++) { 72 cd[i] = iconv_open("ASCII", "UTF8"); 73 if (cd[i] == (iconv_t)-1) { 74 if (errno == ENFILE || errno == EMFILE) 75 ret = 0; 76 cd[i] = NULL; 77 break; 78 } 79 } 80 81 for (i = MIN(i, nitems(cd) - 1); i > 0; i--) 82 iconv_close(cd[i]); 83 return (ret); 84 } 85 86 /* 87 * iconv_close must return (iconv_t)-1 if conversion descriptor is 88 * invalid and set errno to EBADF. 89 */ 90 static int 91 close_1(void) 92 { 93 iconv_t cd = (iconv_t)-1; 94 95 return ((iconv_close(cd) == -1) && (errno = EBADF) ? 0 : 1); 96 } 97 98 static int 99 conv_ebadf(void) 100 { 101 iconv_t cd = (iconv_t)-1; 102 103 errno = 0; 104 return ((iconv(cd, NULL, 0, NULL, 0) == (size_t)-1 && errno == EBADF) ? 0 : 1); 105 } 106 107 static int 108 conv_ret(void) 109 { 110 iconv_t cd; 111 size_t inbytesleft, outbytesleft; 112 char *inptr; 113 char *outptr; 114 uint32_t outbuf[4]; 115 uint32_t inbuf[2] = { 0x00000151, 0x00000171 }; 116 117 if ((cd = iconv_open("ASCII", "UTF-32LE")) == (iconv_t)-1) 118 return (1); 119 120 inptr = (char *)inbuf; 121 outptr = (char *)outbuf; 122 inbytesleft = 8; 123 outbytesleft = 16; 124 125 return (iconv(cd, &inptr, &inbytesleft, &outptr, &outbytesleft) == 2 ? 0 : 1); 126 } 127 128 static int 129 conv_2big(void) 130 { 131 iconv_t cd; 132 size_t inbytesleft, outbytesleft; 133 char *inptr; 134 char *outptr; 135 uint32_t inbuf[4]; 136 uint32_t outbuf[2]; 137 int ret; 138 139 if ((cd = iconv_open("ASCII", "ASCII")) == (iconv_t)-1) 140 return (1); 141 142 inptr = (char *)inbuf; 143 outptr = (char *)outbuf; 144 inbytesleft = 16; 145 outbytesleft = 8; 146 147 errno = 0; 148 ret = iconv(cd, &inptr, &inbytesleft, &outptr, &outbytesleft); 149 150 #ifdef VERBOSE 151 printf("inptr - inbuf = %d\n", (const uint8_t *)inptr - (uint8_t *)inbuf); 152 printf("inbytesleft = %d\n", inbytesleft); 153 printf("outbytesleft = %d\n", outbytesleft); 154 printf("outptr - outbuf = %d\n", (uint8_t *)outptr - (uint8_t *)outbuf); 155 printf("errno = %d\n", errno); 156 printf("ret = %d\n", (int)ret); 157 #endif 158 159 if (((const uint8_t *)inptr - (uint8_t *)inbuf == 8) && (inbytesleft == 8) && 160 (outbytesleft == 0) && ((uint8_t *)outptr - (uint8_t *)outbuf == 8) && 161 (errno == E2BIG) && ((size_t)ret == (size_t)-1)) 162 return (0); 163 else 164 return (1); 165 } 166 167 static int 168 conv_einval(void) 169 { 170 iconv_t cd; 171 size_t inbytesleft, outbytesleft; 172 char *inptr; 173 char *outptr; 174 uint32_t outbuf[4]; 175 uint16_t inbuf[1] = { 0xEA42 }; 176 int ret; 177 178 if ((cd = iconv_open("UTF-32", "BIG5")) == (iconv_t)-1) 179 return (1); 180 181 inptr = (char *)inbuf; 182 outptr = (char *)outbuf; 183 inbytesleft = 2; 184 outbytesleft = 16; 185 186 errno = 0; 187 ret = iconv(cd, &inptr, &inbytesleft, &outptr, &outbytesleft); 188 189 #ifdef VERBOSE 190 printf("inptr - inbuf = %d\n", (const uint8_t *)inptr - (uint8_t *)inbuf); 191 printf("inbytesleft = %d\n", inbytesleft); 192 printf("outbytesleft = %d\n", outbytesleft); 193 printf("outptr - outbuf = %d\n", (uint8_t *)outptr - (uint8_t *)outbuf); 194 printf("errno = %d\n", errno); 195 printf("ret = %d\n", (int)ret); 196 #endif 197 198 if (((const uint8_t *)inptr - (uint8_t *)inbuf == 1) && (inbytesleft == 1) && 199 (outbytesleft == 8) && ((uint8_t *)outptr - (uint8_t *)outbuf == 8) && 200 (errno == EINVAL) && ((size_t)ret == (size_t)-1)) 201 return (0); 202 else 203 return (1); 204 } 205 206 static int 207 conv_eilseq(void) 208 { 209 iconv_t cd; 210 size_t inbytesleft, outbytesleft; 211 char *inptr; 212 char *outptr; 213 uint32_t outbuf[4]; 214 uint16_t inbuf[1] = { 0x8AC0 }; 215 int ret; 216 217 if ((cd = iconv_open("Latin2", "UTF-16LE")) == (iconv_t)-1) 218 return (1); 219 220 inptr = (char *)inbuf; 221 outptr = (char *)outbuf; 222 inbytesleft = 4; 223 outbytesleft = 16; 224 225 errno = 0; 226 ret = iconv(cd, &inptr, &inbytesleft, &outptr, &outbytesleft); 227 228 #ifdef VERBOSE 229 printf("inptr - inbuf = %d\n", (const uint8_t *)inptr - (uint8_t *)inbuf); 230 printf("inbytesleft = %d\n", inbytesleft); 231 printf("outbytesleft = %d\n", outbytesleft); 232 printf("outptr - outbuf = %d\n", (uint8_t *)outptr - (uint8_t *)outbuf); 233 printf("errno = %d\n", errno); 234 printf("ret = %d\n", (int)ret); 235 #endif 236 237 if (((const uint8_t *)inptr - (uint8_t *)inbuf == 0) && (inbytesleft == 4) && 238 (outbytesleft == 16) && ((uint8_t *)outptr - (uint8_t *)outbuf == 0) && 239 (errno == EILSEQ) && ((size_t)ret == (size_t)-1)) 240 return (0); 241 else 242 return (1); 243 } 244 245 static void 246 test(int (tester) (void), const char * label) 247 { 248 int ret; 249 250 if ((ret = tester())) 251 printf("%s failed (%d)\n", label, ret); 252 else 253 printf("%s succeeded\n", label); 254 } 255 256 int 257 main(void) 258 { 259 260 test(open_1, "open_1"); 261 test(open_2, "open_2"); 262 test(close_1, "close_1"); 263 test(conv_ret, "conv_ret"); 264 test(conv_ebadf, "conv_ebadf"); 265 test(conv_2big, "conv_2big"); 266 test(conv_einval, "conv_einval"); 267 test(conv_eilseq, "conv_eilseq"); 268 } 269