3892c89aefe75513294b8b2f977935e16e5e553b
[yaz-moved-to-github.git] / test / tsticonv.c
1 /*
2  * Copyright (C) 1995-2005, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: tsticonv.c,v 1.16 2006-03-25 14:42:16 adam Exp $
6  */
7
8 #if HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11
12 #include <stdlib.h>
13 #include <errno.h>
14 #include <string.h>
15 #include <ctype.h>
16
17 #include <yaz/yaz-util.h>
18 #include <yaz/test.h>
19
20 static int compare_buffers(char *msg, int no,
21                            int expect_len, const char *expect_buf,
22                            int got_len, const char *got_buf)
23 {
24     if (expect_len == got_len
25         && !memcmp(expect_buf, got_buf, expect_len))
26         return 1;
27     
28     if (0) /* use 1 see how the buffers differ (for debug purposes) */
29     {
30         int i;
31         printf("tsticonv test=%s i=%d failed\n", msg, no);
32         printf("off got exp\n");
33         for (i = 0; i<got_len || i<expect_len; i++)
34         {
35             char got_char[10];
36             char expect_char[10];
37             
38             if (i < got_len)
39                 sprintf(got_char, "%02X", got_buf[i]);
40             else
41                 sprintf(got_char, "?  ");
42             
43             if (i < expect_len)
44                 sprintf(expect_char, "%02X", expect_buf[i]);
45             else
46                 sprintf(expect_char, "?  ");
47             
48             printf("%02d  %s  %s %c\n",
49                    i, got_char, expect_char, got_buf[i] == expect_buf[i] ?
50                    ' ' : '*');
51             
52         }
53     }
54     return 0;
55 }
56
57 /* some test strings in ISO-8859-1 format */
58 static const char *iso_8859_1_a[] = {
59     "ax" ,
60     "\xd8",
61     "eneb\346r",
62     "\xe5" "\xd8",
63     "\xe5" "\xd8" "b",
64     "\xe5" "\xe5",
65     0 };
66
67 /* same test strings in MARC-8 format */
68 static const char *marc8_a[] = {
69     "ax",   
70     "\xa2",          /* latin capital letter o with stroke */
71     "eneb\xb5r",     /* latin small letter ae */
72     "\xea" "a\xa2",
73     "\xea" "a\xa2" "b",
74     "\xea" "a"  "\xea" "a",
75     0
76 };
77
78 static void tst_marc8_to_iso_8859_1()
79 {
80     int i;
81     yaz_iconv_t cd;
82     int ret;
83
84     cd = yaz_iconv_open("ISO-8859-1", "MARC8");
85     YAZ_CHECK(cd);
86     if (!cd)
87         return;
88     for (i = 0; iso_8859_1_a[i]; i++)
89     {
90         size_t r;
91         char *inbuf= (char*) marc8_a[i];
92         size_t inbytesleft = strlen(inbuf);
93         char outbuf0[32];
94         char *outbuf = outbuf0;
95         size_t outbytesleft = sizeof(outbuf0);
96
97         r = yaz_iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
98         YAZ_CHECK(r != (size_t)(-1));
99         if (r == (size_t) (-1))
100             break;
101
102         ret = compare_buffers("tsticonv 11", i,
103                               strlen(iso_8859_1_a[i]), iso_8859_1_a[i],
104                               outbuf - outbuf0, outbuf0);
105         YAZ_CHECK(ret);
106     }
107     yaz_iconv_close(cd);
108 }
109
110 static void tst_marc8_to_ucs4b()
111 {
112     static struct {
113         const char *marc8_b;
114         int len;
115         const char *ucs4_b;
116     } ar[] = {
117     { 
118         "\033$1" "\x21\x2B\x3B" /* FF1F */ "\033(B" "o",
119         8, "\x00\x00\xFF\x1F" "\x00\x00\x00o"
120     }, {
121         "\033$1" "\x6F\x77\x29" /* AE0E */ "\x6F\x52\x7C" /* c0F4 */ "\033(B",
122         8, "\x00\x00\xAE\x0E" "\x00\x00\xC0\xF4",
123     }, {
124         "\033$1"
125         "\x21\x50\x6E"  /* UCS 7CFB */
126         "\x21\x51\x31"  /* UCS 7D71 */
127         "\x21\x3A\x67"  /* UCS 5B89 */
128         "\x21\x33\x22"  /* UCS 5168 */
129         "\x21\x33\x53"  /* UCS 5206 */
130         "\x21\x44\x2B"  /* UCS 6790 */
131         "\033(B",
132         24, "\x00\x00\x7C\xFB"
133         "\x00\x00\x7D\x71"
134         "\x00\x00\x5B\x89"
135         "\x00\x00\x51\x68"
136         "\x00\x00\x52\x06"
137         "\x00\x00\x67\x90"
138     }, {
139         "\xB0\xB2",     /* AYN and oSLASH */
140         8, "\x00\x00\x02\xBB"  "\x00\x00\x00\xF8"
141     }, {
142         "\xF6\x61",     /* a underscore */
143         8, "\x00\x00\x00\x61"  "\x00\x00\x03\x32"
144     }, {
145         "\x61\xC2",     /* a, phonorecord mark */
146         8, "\x00\x00\x00\x61"  "\x00\x00\x21\x17"
147     },
148     {  /* bug #258 */
149         "el" "\xe8" "am\xe8" "an", /* elaman where a is a" */
150         32,
151         "\x00\x00\x00" "e"
152         "\x00\x00\x00" "l"
153         "\x00\x00\x00" "a"
154         "\x00\x00\x03\x08"
155         "\x00\x00\x00" "m"
156         "\x00\x00\x00" "a"
157         "\x00\x00\x03\x08"
158         "\x00\x00\x00" "n"
159     }, 
160     { /* bug #260 */
161         "\xe5\xe8\x41",
162         12, "\x00\x00\x00\x41" "\x00\x00\x03\x04" "\x00\x00\x03\x08"
163     }, 
164     { /* bug #416 */
165         "\xEB\x74\xEC\x73",
166         12, "\x00\x00\x00\x74" "\x00\x00\x03\x61" "\x00\x00\x00\x73"
167     },
168     { /* bug #416 */
169         "\xFA\x74\xFB\x73",
170         12, "\x00\x00\x00\x74" "\x00\x00\x03\x60" "\x00\x00\x00\x73"
171     },
172     {
173         0, 0, 0
174     }
175     };
176     int i;
177     int ret;
178     yaz_iconv_t cd;
179
180     cd = yaz_iconv_open("UCS4", "MARC8");
181     YAZ_CHECK(cd);
182     if (!cd)
183         return;
184     for (i = 0; ar[i].len; i++)
185     {
186         size_t r;
187         size_t expect_len = ar[i].len;
188         char *inbuf= (char*) ar[i].marc8_b;
189         size_t inbytesleft = strlen(inbuf);
190         char outbuf0[64];
191         char *outbuf = outbuf0;
192
193         while (inbytesleft)
194         {
195             size_t outbytesleft = outbuf0 + sizeof(outbuf0) - outbuf;
196             if (outbytesleft > 12)
197                 outbytesleft = 12;
198             r = yaz_iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
199             if (r == (size_t) (-1))
200             {
201                 int e = yaz_iconv_error(cd);
202                 YAZ_CHECK(e == YAZ_ICONV_E2BIG);
203                 if (e != YAZ_ICONV_E2BIG)
204                     return;
205             }
206             else
207                 break;
208         }
209         ret = compare_buffers("tsticonv 22", i,
210                               expect_len, ar[i].ucs4_b,
211                               outbuf - outbuf0, outbuf0);
212         YAZ_CHECK(ret);
213     }
214     yaz_iconv_close(cd);
215 }
216
217 static void tst_ucs4b_to_utf8()
218 {
219     static const char *ucs4_c[] = {
220         "\x00\x00\xFF\x1F\x00\x00\x00o",
221         "\x00\x00\xAE\x0E\x00\x00\xC0\xF4",
222         0
223     };
224     static const char *utf8_c[] = {
225         "\xEF\xBC\x9F\x6F",
226         "\xEA\xB8\x8E\xEC\x83\xB4",
227         0
228     };
229     
230     int i;
231     int ret;
232     yaz_iconv_t cd;
233
234     cd = yaz_iconv_open("UTF8", "UCS4");
235     YAZ_CHECK(cd);
236     if (!cd)
237         return;
238     for (i = 0; ucs4_c[i]; i++)
239     {
240         size_t r;
241         char *inbuf= (char*) ucs4_c[i];
242         size_t inbytesleft = 8;
243         char outbuf0[24];
244         char *outbuf = outbuf0;
245         size_t outbytesleft = sizeof(outbuf0);
246
247         r = yaz_iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
248         YAZ_CHECK(r != (size_t) (-1));
249         if (r == (size_t) (-1))
250             return;
251         ret = compare_buffers("tsticonv 32", i,
252                               strlen(utf8_c[i]), utf8_c[i],
253                               outbuf - outbuf0, outbuf0);
254         YAZ_CHECK(ret);
255     }
256     yaz_iconv_close(cd);
257 }
258
259 static void dconvert(int mandatory, const char *tmpcode)
260 {
261     int i;
262     int ret;
263     yaz_iconv_t cd;
264     for (i = 0; iso_8859_1_a[i]; i++)
265     {
266         size_t r;
267         char *inbuf = (char*) iso_8859_1_a[i];
268         size_t inbytesleft = strlen(inbuf);
269         char outbuf0[24];
270         char outbuf1[10];
271         char *outbuf = outbuf0;
272         size_t outbytesleft = sizeof(outbuf0);
273
274         cd = yaz_iconv_open(tmpcode, "ISO-8859-1");
275         YAZ_CHECK(cd || !mandatory);
276         if (!cd)
277             return;
278         r = yaz_iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
279         YAZ_CHECK(r != (size_t) (-1));
280         yaz_iconv_close(cd);
281         if (r == (size_t) (-1))
282             return;
283         
284         cd = yaz_iconv_open("ISO-8859-1", tmpcode);
285         YAZ_CHECK(cd || !mandatory);
286         if (!cd)
287             return;
288         inbuf = outbuf0;
289         inbytesleft = sizeof(outbuf0) - outbytesleft;
290
291         outbuf = outbuf1;
292         outbytesleft = sizeof(outbuf1);
293         r = yaz_iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
294         YAZ_CHECK(r != (size_t) (-1));
295         if (r != (size_t)(-1)) 
296         {
297             ret = compare_buffers("dconvert", i,
298                                   strlen(iso_8859_1_a[i]), iso_8859_1_a[i],
299                               sizeof(outbuf1) - outbytesleft, outbuf1);
300             YAZ_CHECK(ret);
301         }
302         yaz_iconv_close(cd);
303     }
304 }
305
306 int utf8_check(unsigned c)
307 {
308     if (sizeof(c) >= 4)
309     {
310         size_t r;
311         char src[4];
312         char dst[4];
313         char utf8buf[6];
314         char *inbuf = src;
315         size_t inbytesleft = 4;
316         char *outbuf = utf8buf;
317         size_t outbytesleft = sizeof(utf8buf);
318         int i;
319         yaz_iconv_t cd = yaz_iconv_open("UTF-8", "UCS4LE");
320         if (!cd)
321             return 0;
322         for (i = 0; i<4; i++)
323             src[i] = c >> (i*8);
324         
325         r = yaz_iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
326         yaz_iconv_close(cd);
327
328         if (r == (size_t)(-1))
329             return 0;
330
331         cd = yaz_iconv_open("UCS4LE", "UTF-8");
332         if (!cd)
333             return 0;
334         inbytesleft = sizeof(utf8buf) - outbytesleft;
335         inbuf = utf8buf;
336
337         outbuf = dst;
338         outbytesleft = 4;
339
340         r = yaz_iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
341         if (r == (size_t)(-1))
342             return 0;
343
344         yaz_iconv_close(cd);
345
346         if (memcmp(src, dst, 4))
347             return 0;
348     }
349     return 1;
350 }
351         
352
353 static int tst_convert(yaz_iconv_t cd, const char *buf, const char *cmpbuf)
354 {
355     int ret = 0;
356     WRBUF b = wrbuf_alloc();
357     char outbuf[12];
358     size_t inbytesleft = strlen(buf);
359     const char *inp = buf;
360     while (inbytesleft)
361     {
362         size_t outbytesleft = sizeof(outbuf);
363         char *outp = outbuf;
364         size_t r = yaz_iconv(cd, (char**) &inp,  &inbytesleft,
365                              &outp, &outbytesleft);
366         if (r == (size_t) (-1))
367         {
368             int e = yaz_iconv_error(cd);
369             if (e != YAZ_ICONV_E2BIG)
370                 break;
371         }
372         wrbuf_write(b, outbuf, outp - outbuf);
373     }
374     if (wrbuf_len(b) == strlen(cmpbuf) 
375         && !memcmp(cmpbuf, wrbuf_buf(b), wrbuf_len(b)))
376         ret = 1;
377     else
378         yaz_log(YLOG_LOG, "GOT (%.*s)", wrbuf_len(b), wrbuf_buf(b));
379     wrbuf_free(b, 1);
380     return ret;
381 }
382
383 static void tst_x()
384 {
385     yaz_iconv_t cd = yaz_iconv_open("ISO-8859-1", "MARC8");
386
387     YAZ_CHECK(cd);
388
389     YAZ_CHECK(tst_convert(cd, "Cours de math", 
390                           "Cours de math"));
391     YAZ_CHECK(tst_convert(cd, "Cours de mathâe", 
392                           "Cours de mathé"));
393     YAZ_CHECK(tst_convert(cd, "12345678âe", 
394                           "12345678é"));
395     YAZ_CHECK(tst_convert(cd, "123456789âe", 
396                           "123456789é"));
397     YAZ_CHECK(tst_convert(cd, "1234567890âe", 
398                           "1234567890é"));
399     YAZ_CHECK(tst_convert(cd, "12345678901âe", 
400                           "12345678901é"));
401     YAZ_CHECK(tst_convert(cd, "Cours de mathâem", 
402                           "Cours de mathém"));
403     YAZ_CHECK(tst_convert(cd, "Cours de mathâematiques", 
404                           "Cours de mathématiques"));
405
406     yaz_iconv_close(cd);
407 }
408
409 int main (int argc, char **argv)
410 {
411     YAZ_CHECK_INIT(argc, argv);
412
413     tst_x();
414
415     YAZ_CHECK(utf8_check(3));
416     YAZ_CHECK(utf8_check(127));
417     YAZ_CHECK(utf8_check(128));
418     YAZ_CHECK(utf8_check(255));
419     YAZ_CHECK(utf8_check(256));
420     YAZ_CHECK(utf8_check(900));
421     YAZ_CHECK(utf8_check(1000));
422     YAZ_CHECK(utf8_check(10000));
423     YAZ_CHECK(utf8_check(100000));
424     YAZ_CHECK(utf8_check(1000000));
425     YAZ_CHECK(utf8_check(10000000));
426     YAZ_CHECK(utf8_check(100000000));
427
428     dconvert(1, "UTF-8");
429     dconvert(1, "ISO-8859-1");
430     dconvert(1, "UCS4");
431     dconvert(1, "UCS4LE");
432     dconvert(0, "CP865");
433     tst_marc8_to_iso_8859_1();
434     tst_marc8_to_ucs4b();
435     tst_ucs4b_to_utf8();
436
437     YAZ_CHECK_TERM;
438 }
439 /*
440  * Local variables:
441  * c-basic-offset: 4
442  * indent-tabs-mode: nil
443  * End:
444  * vim: shiftwidth=4 tabstop=8 expandtab
445  */