d1ce8ccfee6bc1dc7de3b399656ed50e4fc71562
[yaz-moved-to-github.git] / test / tsticonv.c
1 /*
2  * Copyright (C) 1995-2007, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: tsticonv.c,v 1.24 2007-01-03 08: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 static int tst_convert_l(yaz_iconv_t cd, size_t in_len, const char *in_buf,
58                          size_t expect_len, const char *expect_buf)
59 {
60     size_t r;
61     char *inbuf= (char*) in_buf;
62     size_t inbytesleft = in_len > 0 ? in_len : strlen(in_buf);
63     char outbuf0[64];
64     char *outbuf = outbuf0;
65
66     while (inbytesleft)
67     {
68         size_t outbytesleft = outbuf0 + sizeof(outbuf0) - outbuf;
69         if (outbytesleft > 12)
70             outbytesleft = 12;
71         r = yaz_iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
72         if (r == (size_t) (-1))
73         {
74             int e = yaz_iconv_error(cd);
75             if (e != YAZ_ICONV_E2BIG)
76                 return 0;
77         }
78         else
79             break;
80     }
81     return compare_buffers("tsticonv 22", 0,
82                            expect_len, expect_buf,
83                            outbuf - outbuf0, outbuf0);
84 }
85
86 static int tst_convert(yaz_iconv_t cd, const char *buf, const char *cmpbuf)
87 {
88     int ret = 0;
89     WRBUF b = wrbuf_alloc();
90     char outbuf[12];
91     size_t inbytesleft = strlen(buf);
92     const char *inp = buf;
93     while (inbytesleft)
94     {
95         size_t outbytesleft = sizeof(outbuf);
96         char *outp = outbuf;
97         size_t r = yaz_iconv(cd, (char**) &inp,  &inbytesleft,
98                              &outp, &outbytesleft);
99         if (r == (size_t) (-1))
100         {
101             int e = yaz_iconv_error(cd);
102             if (e != YAZ_ICONV_E2BIG)
103                 break;
104         }
105         wrbuf_write(b, outbuf, outp - outbuf);
106     }
107     if (wrbuf_len(b) == strlen(cmpbuf) 
108         && !memcmp(cmpbuf, wrbuf_buf(b), wrbuf_len(b)))
109         ret = 1;
110     else
111         yaz_log(YLOG_LOG, "GOT (%.*s)", wrbuf_len(b), wrbuf_buf(b));
112     wrbuf_free(b, 1);
113     return ret;
114 }
115
116
117 /* some test strings in ISO-8859-1 format */
118 static const char *iso_8859_1_a[] = {
119     "ax" ,
120     "\xd8",
121     "eneb\346r",
122     "\xe5" "\xd8",
123     "\xe5" "\xd8" "b",
124     "\xe5" "\xe5",
125     0 };
126
127 static void tst_marc8_to_ucs4b(void)
128 {
129     yaz_iconv_t cd = yaz_iconv_open("UCS4", "MARC8");
130     YAZ_CHECK(cd);
131     if (!cd)
132         return;
133     
134     YAZ_CHECK(tst_convert_l(
135                   cd,
136                   0,
137                   "\033$1" "\x21\x2B\x3B" /* FF1F */ "\033(B" "o",
138                   8, 
139                   "\x00\x00\xFF\x1F" "\x00\x00\x00o"));
140     YAZ_CHECK(tst_convert_l(
141                   cd,
142                   0,
143                   "\033$1" "\x6F\x77\x29" /* AE0E */
144                   "\x6F\x52\x7C" /* c0F4 */ "\033(B",
145                   8,
146                   "\x00\x00\xAE\x0E" "\x00\x00\xC0\xF4"));
147     YAZ_CHECK(tst_convert_l(
148                   cd,
149                   0,
150                   "\033$1"
151                   "\x21\x50\x6E"  /* UCS 7CFB */
152                   "\x21\x51\x31"  /* UCS 7D71 */
153                   "\x21\x3A\x67"  /* UCS 5B89 */
154                   "\x21\x33\x22"  /* UCS 5168 */
155                   "\x21\x33\x53"  /* UCS 5206 */
156                   "\x21\x44\x2B"  /* UCS 6790 */
157                   "\033(B",
158                   24, 
159                   "\x00\x00\x7C\xFB"
160                   "\x00\x00\x7D\x71"
161                   "\x00\x00\x5B\x89"
162                   "\x00\x00\x51\x68"
163                   "\x00\x00\x52\x06"
164                   "\x00\x00\x67\x90"));
165
166     YAZ_CHECK(tst_convert_l(
167                   cd,
168                   0,
169                   "\xB0\xB2",     /* AYN and oSLASH */
170                   8, 
171                   "\x00\x00\x02\xBB"  "\x00\x00\x00\xF8"));
172     YAZ_CHECK(tst_convert_l(
173                   cd,
174                   0,
175                   "\xF6\x61",     /* a underscore */
176                   8, 
177                   "\x00\x00\x00\x61"  "\x00\x00\x03\x32"));
178
179     YAZ_CHECK(tst_convert_l(
180                   cd,
181                   0,
182                   "\x61\xC2",     /* a, phonorecord mark */
183                   8,
184                   "\x00\x00\x00\x61"  "\x00\x00\x21\x17"));
185
186     /* bug #258 */
187     YAZ_CHECK(tst_convert_l(
188                   cd,
189                   0,
190                   "el" "\xe8" "am\xe8" "an", /* elaman where a is a" */
191                   32,
192                   "\x00\x00\x00" "e"
193                   "\x00\x00\x00" "l"
194                   "\x00\x00\x00" "a"
195                   "\x00\x00\x03\x08"
196                   "\x00\x00\x00" "m"
197                   "\x00\x00\x00" "a"
198                   "\x00\x00\x03\x08"
199                   "\x00\x00\x00" "n"));
200     /* bug #260 */
201     YAZ_CHECK(tst_convert_l(
202                   cd,
203                   0,
204                   "\xe5\xe8\x41",
205                   12, 
206                   "\x00\x00\x00\x41" "\x00\x00\x03\x04" "\x00\x00\x03\x08"));
207     /* bug #416 */
208     YAZ_CHECK(tst_convert_l(
209                   cd,
210                   0,
211                   "\xEB\x74\xEC\x73",
212                   12,
213                   "\x00\x00\x00\x74" "\x00\x00\x03\x61" "\x00\x00\x00\x73"));
214     /* bug #416 */
215     YAZ_CHECK(tst_convert_l(
216                   cd,
217                   0,
218                   "\xFA\x74\xFB\x73",
219                   12, 
220                   "\x00\x00\x00\x74" "\x00\x00\x03\x60" "\x00\x00\x00\x73"));
221
222     yaz_iconv_close(cd);
223 }
224
225 static void tst_ucs4b_to_utf8(void)
226 {
227     yaz_iconv_t cd = yaz_iconv_open("UTF8", "UCS4");
228     YAZ_CHECK(cd);
229     if (!cd)
230         return;
231     YAZ_CHECK(tst_convert_l(
232                   cd,
233                   8,
234                   "\x00\x00\xFF\x1F\x00\x00\x00o",
235                   4,
236                   "\xEF\xBC\x9F\x6F"));
237
238     YAZ_CHECK(tst_convert_l(
239                   cd,
240                   8, 
241                   "\x00\x00\xAE\x0E\x00\x00\xC0\xF4",
242                   6,
243                   "\xEA\xB8\x8E\xEC\x83\xB4"));
244     yaz_iconv_close(cd);
245 }
246
247 static void dconvert(int mandatory, const char *tmpcode)
248 {
249     int i;
250     int ret;
251     yaz_iconv_t cd;
252     for (i = 0; iso_8859_1_a[i]; i++)
253     {
254         size_t r;
255         char *inbuf = (char*) iso_8859_1_a[i];
256         size_t inbytesleft = strlen(inbuf);
257         char outbuf0[24];
258         char outbuf1[10];
259         char *outbuf = outbuf0;
260         size_t outbytesleft = sizeof(outbuf0);
261
262         cd = yaz_iconv_open(tmpcode, "ISO-8859-1");
263         YAZ_CHECK(cd || !mandatory);
264         if (!cd)
265             return;
266         r = yaz_iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
267         YAZ_CHECK(r != (size_t) (-1));
268         yaz_iconv_close(cd);
269         if (r == (size_t) (-1))
270             return;
271         
272         cd = yaz_iconv_open("ISO-8859-1", tmpcode);
273         YAZ_CHECK(cd || !mandatory);
274         if (!cd)
275             return;
276         inbuf = outbuf0;
277         inbytesleft = sizeof(outbuf0) - outbytesleft;
278
279         outbuf = outbuf1;
280         outbytesleft = sizeof(outbuf1);
281         r = yaz_iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
282         YAZ_CHECK(r != (size_t) (-1));
283         if (r != (size_t)(-1)) 
284         {
285             ret = compare_buffers("dconvert", i,
286                                   strlen(iso_8859_1_a[i]), iso_8859_1_a[i],
287                               sizeof(outbuf1) - outbytesleft, outbuf1);
288             YAZ_CHECK(ret);
289         }
290         yaz_iconv_close(cd);
291     }
292 }
293
294 int utf8_check(unsigned c)
295 {
296     if (sizeof(c) >= 4)
297     {
298         size_t r;
299         char src[4];
300         char dst[4];
301         char utf8buf[6];
302         char *inbuf = src;
303         size_t inbytesleft = 4;
304         char *outbuf = utf8buf;
305         size_t outbytesleft = sizeof(utf8buf);
306         int i;
307         yaz_iconv_t cd = yaz_iconv_open("UTF-8", "UCS4LE");
308         if (!cd)
309             return 0;
310         for (i = 0; i<4; i++)
311             src[i] = c >> (i*8);
312         
313         r = yaz_iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
314         yaz_iconv_close(cd);
315
316         if (r == (size_t)(-1))
317             return 0;
318
319         cd = yaz_iconv_open("UCS4LE", "UTF-8");
320         if (!cd)
321             return 0;
322         inbytesleft = sizeof(utf8buf) - outbytesleft;
323         inbuf = utf8buf;
324
325         outbuf = dst;
326         outbytesleft = 4;
327
328         r = yaz_iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
329         if (r == (size_t)(-1))
330             return 0;
331
332         yaz_iconv_close(cd);
333
334         if (memcmp(src, dst, 4))
335             return 0;
336     }
337     return 1;
338 }
339         
340 static void tst_marc8_to_utf8(void)
341 {
342     yaz_iconv_t cd = yaz_iconv_open("UTF-8", "MARC8");
343
344     YAZ_CHECK(cd);
345     if (!cd)
346         return;
347
348     YAZ_CHECK(tst_convert(cd, "Cours de math", 
349                           "Cours de math"));
350     /* COMBINING ACUTE ACCENT */
351     YAZ_CHECK(tst_convert(cd, "Cours de mathâe", 
352                           "Cours de mathe\xcc\x81"));
353     yaz_iconv_close(cd);
354 }
355
356 static void tst_marc8s_to_utf8(void)
357 {
358     yaz_iconv_t cd = yaz_iconv_open("UTF-8", "MARC8s");
359
360     YAZ_CHECK(cd);
361     if (!cd)
362         return;
363
364     YAZ_CHECK(tst_convert(cd, "Cours de math", 
365                           "Cours de math"));
366     /* E9: LATIN SMALL LETTER E WITH ACUTE */
367     YAZ_CHECK(tst_convert(cd, "Cours de mathâe", 
368                           "Cours de math\xc3\xa9"));
369
370     yaz_iconv_close(cd);
371 }
372
373
374 static void tst_marc8_to_latin1(void)
375 {
376     yaz_iconv_t cd = yaz_iconv_open("ISO-8859-1", "MARC8");
377
378     YAZ_CHECK(cd);
379     if (!cd)
380         return;
381
382     YAZ_CHECK(tst_convert(cd, "ax", "ax"));
383
384     /* latin capital letter o with stroke */
385     YAZ_CHECK(tst_convert(cd, "\xa2", "\xd8"));
386
387     /* with latin small letter ae */
388     YAZ_CHECK(tst_convert(cd, "eneb\xb5r", "eneb\346r"));
389
390     YAZ_CHECK(tst_convert(cd, "\xea" "a\xa2", "\xe5" "\xd8"));
391
392     YAZ_CHECK(tst_convert(cd, "\xea" "a\xa2" "b", "\xe5" "\xd8" "b"));
393
394     YAZ_CHECK(tst_convert(cd, "\xea" "a"  "\xea" "a", "\xe5" "\xe5"));
395
396     YAZ_CHECK(tst_convert(cd, "Cours de math", 
397                           "Cours de math"));
398     YAZ_CHECK(tst_convert(cd, "Cours de mathâe", 
399                           "Cours de mathé"));
400     YAZ_CHECK(tst_convert(cd, "12345678âe", 
401                           "12345678é"));
402     YAZ_CHECK(tst_convert(cd, "123456789âe", 
403                           "123456789é"));
404     YAZ_CHECK(tst_convert(cd, "1234567890âe", 
405                           "1234567890é"));
406     YAZ_CHECK(tst_convert(cd, "12345678901âe", 
407                           "12345678901é"));
408     YAZ_CHECK(tst_convert(cd, "Cours de mathâem", 
409                           "Cours de mathém"));
410     YAZ_CHECK(tst_convert(cd, "Cours de mathâematiques", 
411                           "Cours de mathématiques"));
412
413     yaz_iconv_close(cd);
414 }
415
416 static void tst_utf8_to_marc8(void)
417 {
418     yaz_iconv_t cd = yaz_iconv_open("MARC8", "UTF-8");
419
420     YAZ_CHECK(cd);
421     if (!cd)
422         return;
423
424     YAZ_CHECK(tst_convert(cd, "Cours ", "Cours "));
425
426     /** Pure ASCII. 11 characters (sizeof(outbuf)-1) */
427     YAZ_CHECK(tst_convert(cd, "Cours de mat", "Cours de mat"));
428
429     /** Pure ASCII. 12 characters (sizeof(outbuf)) */
430     YAZ_CHECK(tst_convert(cd, "Cours de math", "Cours de math"));
431
432     /** Pure ASCII. 13 characters (sizeof(outbuf)) */
433     YAZ_CHECK(tst_convert(cd, "Cours de math.", "Cours de math."));
434
435     /** UPPERCASE SCANDINAVIAN O */
436     YAZ_CHECK(tst_convert(cd, "S\xc3\x98", "S\xa2"));
437
438     /** ARING */
439     YAZ_CHECK(tst_convert(cd, "A" "\xCC\x8A", "\xEA" "A"));
440
441     /** A MACRON + UMLAUT, DIAERESIS */
442     YAZ_CHECK(tst_convert(cd, "A" "\xCC\x84" "\xCC\x88",
443                           "\xE5\xE8\x41"));
444     
445     /* Ligature spanning two characters */
446     YAZ_CHECK(tst_convert(cd,
447                           "\x74" "\xCD\xA1" "\x73",  /* UTF-8 */
448                           "\xEB\x74\xEC\x73"));      /* MARC-8 */
449
450     /* Double title spanning two characters */
451     YAZ_CHECK(tst_convert(cd,
452                           "\x74" "\xCD\xA0" "\x73",  /* UTF-8 */
453                           "\xFA\x74\xFB\x73"));      /* MARC-8 */
454
455     /** Ideographic question mark (Unicode FF1F) */
456     YAZ_CHECK(tst_convert(cd,
457                           "\xEF\xBC\x9F" "o",        /* UTF-8 */
458                           "\033$1" "\x21\x2B\x3B" "\033(B" "o" ));
459
460
461     /** Superscript 0 . bug #642 */
462     YAZ_CHECK(tst_convert(cd,
463                           "(\xe2\x81\xb0)",        /* UTF-8 */
464                           "(\033p0\x1bs)"));
465     
466  
467     yaz_iconv_close(cd);
468 }
469
470
471 static void tst_latin1_to_marc8(void)
472 {
473     yaz_iconv_t cd = yaz_iconv_open("MARC8", "ISO-8859-1");
474
475     YAZ_CHECK(cd);
476     if (!cd)
477         return;
478
479     YAZ_CHECK(tst_convert(cd, "Cours ", "Cours "));
480
481     /** Pure ASCII. 11 characters (sizeof(outbuf)-1) */
482     YAZ_CHECK(tst_convert(cd, "Cours de mat", "Cours de mat"));
483
484     /** Pure ASCII. 12 characters (sizeof(outbuf)) */
485     YAZ_CHECK(tst_convert(cd, "Cours de math", "Cours de math"));
486
487     /** Pure ASCII. 13 characters (sizeof(outbuf)) */
488     YAZ_CHECK(tst_convert(cd, "Cours de math.", "Cours de math."));
489
490     /** D8: UPPERCASE SCANDINAVIAN O */
491     YAZ_CHECK(tst_convert(cd, "S\xd8", "S\xa2"));
492
493     /** E9: LATIN SMALL LETTER E WITH ACUTE */
494     YAZ_CHECK(tst_convert(cd, "Cours de math\xe9", "Cours de mathâe"));
495     YAZ_CHECK(tst_convert(cd, "Cours de math", "Cours de math"
496                   ));
497     YAZ_CHECK(tst_convert(cd, "Cours de mathé", "Cours de mathâe" ));
498     YAZ_CHECK(tst_convert(cd, "12345678é","12345678âe"));
499     YAZ_CHECK(tst_convert(cd, "123456789é", "123456789âe"));
500     YAZ_CHECK(tst_convert(cd, "1234567890é","1234567890âe"));
501     YAZ_CHECK(tst_convert(cd, "12345678901é", "12345678901âe"));
502     YAZ_CHECK(tst_convert(cd, "Cours de mathém", "Cours de mathâem"));
503     YAZ_CHECK(tst_convert(cd, "Cours de mathématiques",
504                           "Cours de mathâematiques"));
505     yaz_iconv_close(cd);
506 }
507
508 static void tst_utf8_codes(void)
509 {
510     YAZ_CHECK(utf8_check(3));
511     YAZ_CHECK(utf8_check(127));
512     YAZ_CHECK(utf8_check(128));
513     YAZ_CHECK(utf8_check(255));
514     YAZ_CHECK(utf8_check(256));
515     YAZ_CHECK(utf8_check(900));
516     YAZ_CHECK(utf8_check(1000));
517     YAZ_CHECK(utf8_check(10000));
518     YAZ_CHECK(utf8_check(100000));
519     YAZ_CHECK(utf8_check(1000000));
520     YAZ_CHECK(utf8_check(10000000));
521     YAZ_CHECK(utf8_check(100000000));
522 }
523
524 int main (int argc, char **argv)
525 {
526     YAZ_CHECK_INIT(argc, argv);
527
528     tst_utf8_codes();
529
530     tst_marc8_to_utf8();
531
532     tst_marc8s_to_utf8();
533
534     tst_marc8_to_latin1();
535
536     tst_utf8_to_marc8();
537
538     tst_latin1_to_marc8();
539
540     tst_marc8_to_ucs4b();
541     tst_ucs4b_to_utf8();
542
543     dconvert(1, "UTF-8");
544     dconvert(1, "ISO-8859-1");
545     dconvert(1, "UCS4");
546     dconvert(1, "UCS4LE");
547     dconvert(0, "CP865");
548
549     YAZ_CHECK_TERM;
550 }
551 /*
552  * Local variables:
553  * c-basic-offset: 4
554  * indent-tabs-mode: nil
555  * End:
556  * vim: shiftwidth=4 tabstop=8 expandtab
557  */