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