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