]> git.samba.org - kamenim/samba.git/blob - source4/torture/local/iconv.c
r3324: made the smbtorture code completely warning free
[kamenim/samba.git] / source4 / torture / local / iconv.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    local testing of iconv routines. This tests the system iconv code against
5    the built-in iconv code
6
7    Copyright (C) Andrew Tridgell 2004
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25
26 #if HAVE_NATIVE_ICONV
27 /*
28   generate a UTF-16LE buffer for a given unicode codepoint
29 */
30 static int gen_codepoint_utf16(unsigned int codepoint,
31                                char *buf, size_t *size)
32 {
33         static iconv_t cd;
34         uint8_t in[4];
35         char *ptr_in;
36         size_t size_in, size_out, ret;
37         if (!cd) {
38                 cd = iconv_open("UTF-16LE", "UCS-4LE");
39         }
40
41         in[0] = codepoint & 0xFF;
42         in[1] = (codepoint>>8) & 0xFF;
43         in[2] = (codepoint>>16) & 0xFF;
44         in[3] = (codepoint>>24) & 0xFF;
45
46         ptr_in = in;
47         size_in = 4;
48         size_out = 8;
49
50         ret = iconv(cd, &ptr_in, &size_in, &buf, &size_out);
51
52         *size = 8 - size_out;
53
54         return ret;
55 }
56
57
58 /*
59   work out the unicode codepoint of the first UTF-8 character in the buffer
60 */
61 static unsigned int get_codepoint(char *buf, size_t size, const char *charset)
62 {
63         iconv_t cd;
64         uint8_t out[4];
65         char *ptr_out;
66         size_t size_out, size_in, ret;
67
68         cd = iconv_open("UCS-4LE", charset);
69
70         size_in = size;
71         ptr_out = out;
72         size_out = sizeof(out);
73         memset(out, 0, sizeof(out));
74
75         ret = iconv(cd, &buf, &size_in, &ptr_out, &size_out);
76
77         iconv_close(cd);
78
79         return out[0] | (out[1]<<8) | (out[2]<<16) | (out[3]<<24);
80 }
81
82 /*
83   display a buffer with name prefix
84 */
85 static void show_buf(const char *name, uint8_t *buf, size_t size)
86 {
87         int i;
88         printf("%s ", name);
89         for (i=0;i<size;i++) {
90                 printf("%02x ", buf[i]);
91         }
92         printf("\n");
93 }
94
95 /*
96   given a UTF-16LE buffer, test the system and built-in iconv code to
97   make sure they do exactly the same thing in converting the buffer to
98   "charset", then convert it back again and ensure we get the same
99   buffer back
100 */
101 static int test_buffer(uint8_t *inbuf, size_t size, const char *charset)
102 {
103         uint8_t buf1[1000], buf2[1000], buf3[1000];
104         size_t outsize1, outsize2, outsize3;
105         const char *ptr_in;
106         char *ptr_out;
107         size_t size_in1, size_in2, size_in3;
108         size_t ret1, ret2, ret3, len1, len2;
109         int ok = 1;
110         int errno1, errno2;
111         static iconv_t cd;
112         static smb_iconv_t cd2, cd3;
113         static const char *last_charset;
114
115         if (cd && last_charset) {
116                 iconv_close(cd);
117                 smb_iconv_close(cd2);
118                 smb_iconv_close(cd3);
119                 cd = NULL;
120         }
121
122         if (!cd) {
123                 cd = iconv_open(charset, "UTF-16LE");
124                 cd2 = smb_iconv_open(charset, "UTF-16LE");
125                 cd3 = smb_iconv_open("UTF-16LE", charset);
126                 last_charset = charset;
127         }
128
129 #if 0
130         int i;
131         for (i=0;i<50;i++) {
132                 ptr_in = inbuf;
133                 ptr_out = buf1;
134                 size_in1 = size;
135                 outsize1 = sizeof(buf1);
136
137                 memset(ptr_out, 0, outsize1);
138                 errno = 0;
139                 ret1 = smb_iconv(cd2, &ptr_in, &size_in1, &ptr_out, &outsize1);
140                 errno1 = errno;
141         }
142 #endif
143
144         ptr_in = inbuf;
145         ptr_out = buf1;
146         size_in1 = size;
147         outsize1 = sizeof(buf1);
148
149         memset(ptr_out, 0, outsize1);
150         errno = 0;
151         ret1 = smb_iconv(cd2, &ptr_in, &size_in1, &ptr_out, &outsize1);
152         errno1 = errno;
153
154         ptr_in = inbuf;
155         ptr_out = buf2;
156         size_in2 = size;
157         outsize2 = sizeof(buf2);
158         
159         memset(ptr_out, 0, outsize2);
160         errno = 0;
161         ret2 = iconv(cd, discard_const_p(char *, &ptr_in), &size_in2, &ptr_out, &outsize2);
162         errno2 = errno;
163
164         len1 = sizeof(buf1) - outsize1;
165         len2 = sizeof(buf2) - outsize2;
166
167         /* codepoints above 1M are not interesting for now */
168         if (len2 > len1 && 
169             memcmp(buf1, buf2, len1) == 0 && 
170             get_codepoint(buf2+len1, len2-len1, charset) >= (1<<20)) {
171                 return ok;
172         }
173         if (len1 > len2 && 
174             memcmp(buf1, buf2, len2) == 0 && 
175             get_codepoint(buf1+len2, len1-len2, charset) >= (1<<20)) {
176                 return ok;
177         }
178
179         if (ret1 != ret2) {
180                 printf("ret1=%d ret2=%d\n", ret1, ret2);
181                 ok = 0;
182         }
183
184         if (errno1 != errno2) {
185                 printf("e1=%s e2=%s\n", strerror(errno1), strerror(errno2));
186                 show_buf(" rem1:", inbuf+(size-size_in1), size_in1);
187                 show_buf(" rem2:", inbuf+(size-size_in2), size_in2);
188                 ok = 0;
189         }
190         
191         if (outsize1 != outsize2) {
192                 printf("\noutsize mismatch outsize1=%d outsize2=%d\n",
193                        outsize1, outsize2);
194                 ok = 0;
195         }
196         
197         if (size_in1 != size_in2) {
198                 printf("\nsize_in mismatch size_in1=%d size_in2=%d\n",
199                        size_in1, size_in2);
200                 ok = 0;
201         }
202
203         if (!ok ||
204             len1 != len2 ||
205             memcmp(buf1, buf2, len1) != 0) {
206                 printf("\nsize=%d ret1=%d ret2=%d\n", size, ret1, ret2);
207                 show_buf(" IN1:", inbuf, size-size_in1);
208                 show_buf(" IN2:", inbuf, size-size_in2);
209                 show_buf("OUT1:", buf1, len1);
210                 show_buf("OUT2:", buf2, len2);
211                 if (len2 > len1 && memcmp(buf1, buf2, len1) == 0) {
212                         printf("next codepoint is %u\n", 
213                                get_codepoint(buf2+len1, len2-len1, charset));
214                 }
215                 if (len1 > len2 && memcmp(buf1, buf2, len2) == 0) {
216                         printf("next codepoint is %u\n", 
217                                get_codepoint(buf1+len2,len1-len2, charset));
218                 }
219
220                 ok = 0;
221         }
222         
223         size = size - size_in1;
224         ptr_in = buf1;
225         ptr_out = buf3;
226         size_in3 = len1;
227         outsize3 = sizeof(buf3);
228
229         memset(ptr_out, 0, outsize3);
230         ret3 = smb_iconv(cd3, &ptr_in, &size_in3, &ptr_out, &outsize3);
231         
232         if (ret3 != 0) {
233                 printf("pull failed - %s\n", strerror(errno));
234                 ok = 0;
235         }
236         
237         if (outsize3 != sizeof(buf3) - size) {
238                 printf("wrong outsize3 - %d should be %d\n", 
239                        outsize3, sizeof(buf3) - size);
240                 ok = 0;
241         }
242         
243         if (memcmp(buf3, inbuf, size) != 0) {
244                 printf("pull bytes mismatch:\n");
245                 show_buf("inbuf", inbuf, size);
246                 show_buf(" buf3", buf3, size);
247                 ok = 0;
248         }
249
250         if (!ok) {
251                 printf("test_buffer failed for charset %s\n", charset);
252         }
253
254         return ok;
255 }
256
257
258 /*
259   test the push_codepoint() and next_codepoint() functions for a given
260   codepoint
261 */
262 static int test_codepoint(unsigned int codepoint)
263 {
264         uint8_t buf[10];
265         size_t size, size2;
266         codepoint_t c;
267
268         size = push_codepoint(buf, codepoint);
269         if (size == -1) {
270                 if (codepoint < 0xd800 || codepoint > 0x10000) {
271                         return 0;
272                 }
273                 return 1;
274         }
275         buf[size] = random();
276         buf[size+1] = random();
277         buf[size+2] = random();
278         buf[size+3] = random();
279
280         c = next_codepoint(buf, &size2);
281
282         if (c != codepoint) {
283                 printf("next_codepoint(%u) failed - gave %u\n", codepoint, c);
284                 return 0;
285         }
286
287         if (size2 != size) {
288                 printf("next_codepoint(%u) gave wrong size %d (should be %d)\n", 
289                        codepoint, size2, size);
290                 return 0;
291         }
292
293         return 1;
294 }
295
296 BOOL torture_local_iconv(void) 
297 {
298         size_t size;
299         unsigned char inbuf[1000];
300         int ok = 1;
301         unsigned int codepoint, i, c;
302
303         srandom(time(NULL));
304
305         printf("Testing next_codepoint()\n");
306         for (codepoint=0;ok && codepoint<(1<<20);codepoint++) {
307                 ok = test_codepoint(codepoint);
308         }
309
310         printf("Testing first 1M codepoints\n");
311         for (codepoint=0;ok && codepoint<(1<<20);codepoint++) {
312                 if (gen_codepoint_utf16(codepoint, inbuf, &size) != 0) {
313                         continue;
314                 }
315
316                 if (codepoint % 1000 == 0) {
317                         printf("codepoint=%u   \r", codepoint);
318                 }
319
320                 ok = test_buffer(inbuf, size, "UTF-8");
321         }
322
323
324         printf("Testing 5M random UTF-16LE sequences\n");
325         for (i=0;ok && i<500000;i++) {
326                 if (i % 1000 == 0) {
327                         printf("i=%u              \r", i);
328                 }
329
330                 size = random() % 100;
331                 for (c=0;c<size;c++) {
332                         if (random() % 100 < 80) {
333                                 inbuf[c] = random() % 128;
334                         } else {
335                                 inbuf[c] = random();
336                         }
337                         if (random() % 10 == 0) {
338                                 inbuf[c] |= 0xd8;
339                         }
340                         if (random() % 10 == 0) {
341                                 inbuf[c] |= 0xdc;
342                         }
343                 }
344                 ok &= test_buffer(inbuf, size, "UTF-8");
345                 ok &= test_buffer(inbuf, size, "CP850");
346         }
347
348         return ok == 1;
349 }
350
351
352 #else
353
354 BOOL torture_local_iconv(void) 
355 {
356         printf("No native iconv library - can't run iconv test\n");
357         return True;
358 }
359
360 #endif