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