Imported Upstream version 0.9.3
[platform/upstream/libunistring.git] / tests / test-striconveh.c
1 /* Test of character set conversion with error handling.
2    Copyright (C) 2007-2010 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 /* Written by Bruno Haible <bruno@clisp.org>, 2007.  */
18
19 #include <config.h>
20
21 #include "striconveh.h"
22
23 #if HAVE_ICONV
24 # include <iconv.h>
25 #endif
26
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "macros.h"
32
33 /* Magic number for detecting bounds violations.  */
34 #define MAGIC 0x1983EFF1
35
36 static size_t *
37 new_offsets (size_t n)
38 {
39   size_t *offsets = (size_t *) malloc ((n + 1) * sizeof (size_t));
40   offsets[n] = MAGIC;
41   return offsets;
42 }
43
44 int
45 main ()
46 {
47   static enum iconv_ilseq_handler handlers[] =
48     { iconveh_error, iconveh_question_mark, iconveh_escape_sequence };
49   size_t indirect;
50   size_t h;
51   size_t o;
52   size_t i;
53
54 #if HAVE_ICONV
55   /* Assume that iconv() supports at least the encodings ASCII, ISO-8859-1,
56      ISO-8859-2, and UTF-8.  */
57   iconv_t cd_ascii_to_88591 = iconv_open ("ISO-8859-1", "ASCII");
58   iconv_t cd_88591_to_88592 = iconv_open ("ISO-8859-2", "ISO-8859-1");
59   iconv_t cd_88592_to_88591 = iconv_open ("ISO-8859-1", "ISO-8859-2");
60   iconv_t cd_ascii_to_utf8 = iconv_open ("UTF-8", "ASCII");
61   iconv_t cd_88591_to_utf8 = iconv_open ("UTF-8", "ISO-8859-1");
62   iconv_t cd_utf8_to_88591 = iconv_open ("ISO-8859-1", "UTF-8");
63   iconv_t cd_88592_to_utf8 = iconv_open ("UTF-8", "ISO-8859-2");
64   iconv_t cd_utf8_to_88592 = iconv_open ("ISO-8859-2", "UTF-8");
65   iconv_t cd_utf7_to_utf8 = iconv_open ("UTF-8", "UTF-7");
66   iconveh_t cdeh_ascii_to_88591;
67   iconveh_t cdeh_ascii_to_88591_indirectly;
68   iconveh_t cdeh_88592_to_88591;
69   iconveh_t cdeh_88592_to_88591_indirectly;
70   iconveh_t cdeh_ascii_to_utf8;
71   iconveh_t cdeh_88591_to_utf8;
72   iconveh_t cdeh_utf8_to_88591;
73   iconveh_t cdeh_utf7_to_utf8;
74
75   ASSERT (cd_ascii_to_utf8 != (iconv_t)(-1));
76   ASSERT (cd_88591_to_utf8 != (iconv_t)(-1));
77   ASSERT (cd_utf8_to_88591 != (iconv_t)(-1));
78   ASSERT (cd_88592_to_utf8 != (iconv_t)(-1));
79   ASSERT (cd_utf8_to_88592 != (iconv_t)(-1));
80
81   cdeh_ascii_to_88591.cd = cd_ascii_to_88591;
82   cdeh_ascii_to_88591.cd1 = cd_ascii_to_utf8;
83   cdeh_ascii_to_88591.cd2 = cd_utf8_to_88591;
84
85   cdeh_ascii_to_88591_indirectly.cd = (iconv_t)(-1);
86   cdeh_ascii_to_88591_indirectly.cd1 = cd_ascii_to_utf8;
87   cdeh_ascii_to_88591_indirectly.cd2 = cd_utf8_to_88591;
88
89   cdeh_88592_to_88591.cd = cd_88592_to_88591;
90   cdeh_88592_to_88591.cd1 = cd_88592_to_utf8;
91   cdeh_88592_to_88591.cd2 = cd_utf8_to_88591;
92
93   cdeh_88592_to_88591_indirectly.cd = (iconv_t)(-1);
94   cdeh_88592_to_88591_indirectly.cd1 = cd_88592_to_utf8;
95   cdeh_88592_to_88591_indirectly.cd2 = cd_utf8_to_88591;
96
97   cdeh_ascii_to_utf8.cd = cd_ascii_to_utf8;
98   cdeh_ascii_to_utf8.cd1 = cd_ascii_to_utf8;
99   cdeh_ascii_to_utf8.cd2 = (iconv_t)(-1);
100
101   cdeh_88591_to_utf8.cd = cd_88591_to_utf8;
102   cdeh_88591_to_utf8.cd1 = cd_88591_to_utf8;
103   cdeh_88591_to_utf8.cd2 = (iconv_t)(-1);
104
105   cdeh_utf8_to_88591.cd = cd_utf8_to_88591;
106   cdeh_utf8_to_88591.cd1 = (iconv_t)(-1);
107   cdeh_utf8_to_88591.cd2 = cd_utf8_to_88591;
108
109   cdeh_utf7_to_utf8.cd = cd_utf7_to_utf8;
110   cdeh_utf7_to_utf8.cd1 = cd_utf7_to_utf8;
111   cdeh_utf7_to_utf8.cd2 = (iconv_t)(-1);
112
113   /* ------------------------ Test mem_cd_iconveh() ------------------------ */
114
115   /* Test conversion from ISO-8859-2 to ISO-8859-1 with no errors.  */
116   for (indirect = 0; indirect <= 1; indirect++)
117     {
118       for (h = 0; h < SIZEOF (handlers); h++)
119         {
120           enum iconv_ilseq_handler handler = handlers[h];
121           static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
122           static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
123           for (o = 0; o < 2; o++)
124             {
125               size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
126               char *result = NULL;
127               size_t length = 0;
128               int retval = mem_cd_iconveh (input, strlen (input),
129                                            (indirect
130                                             ? &cdeh_88592_to_88591_indirectly
131                                             : &cdeh_88592_to_88591),
132                                            handler,
133                                            offsets,
134                                            &result, &length);
135               ASSERT (retval == 0);
136               ASSERT (length == strlen (expected));
137               ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
138               if (o)
139                 {
140                   for (i = 0; i < 37; i++)
141                     ASSERT (offsets[i] == i);
142                   ASSERT (offsets[37] == MAGIC);
143                   free (offsets);
144                 }
145               free (result);
146             }
147         }
148     }
149
150   /* Test conversion from ASCII to ISO-8859-1 with invalid input (EILSEQ).  */
151   for (indirect = 0; indirect <= 1; indirect++)
152     {
153       for (h = 0; h < SIZEOF (handlers); h++)
154         {
155           enum iconv_ilseq_handler handler = handlers[h];
156           static const char input[] = "Rafa\263 Maszkowski"; /* Rafa? Maszkowski */
157           for (o = 0; o < 2; o++)
158             {
159               size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
160               char *result = NULL;
161               size_t length = 0;
162               int retval = mem_cd_iconveh (input, strlen (input),
163                                            (indirect
164                                             ? &cdeh_ascii_to_88591_indirectly
165                                             : &cdeh_ascii_to_88591),
166                                            handler,
167                                            offsets,
168                                            &result, &length);
169               switch (handler)
170                 {
171                 case iconveh_error:
172                   ASSERT (retval == -1 && errno == EILSEQ);
173                   ASSERT (result == NULL);
174                   if (o)
175                     free (offsets);
176                   break;
177                 case iconveh_question_mark:
178                 case iconveh_escape_sequence:
179                   {
180                     static const char expected[] = "Rafa? Maszkowski";
181                     ASSERT (retval == 0);
182                     ASSERT (length == strlen (expected));
183                     ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
184                     if (o)
185                       {
186                         for (i = 0; i < 16; i++)
187                           ASSERT (offsets[i] == i);
188                         ASSERT (offsets[16] == MAGIC);
189                         free (offsets);
190                       }
191                     free (result);
192                   }
193                   break;
194                 }
195             }
196         }
197     }
198
199   /* Test conversion from ISO-8859-2 to ISO-8859-1 with EILSEQ.  */
200   for (indirect = 0; indirect <= 1; indirect++)
201     {
202       for (h = 0; h < SIZEOF (handlers); h++)
203         {
204           enum iconv_ilseq_handler handler = handlers[h];
205           static const char input[] = "Rafa\263 Maszkowski"; /* RafaƂ Maszkowski */
206           for (o = 0; o < 2; o++)
207             {
208               size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
209               char *result = NULL;
210               size_t length = 0;
211               int retval = mem_cd_iconveh (input, strlen (input),
212                                            (indirect
213                                             ? &cdeh_88592_to_88591_indirectly
214                                             : &cdeh_88592_to_88591),
215                                            handler,
216                                            offsets,
217                                            &result, &length);
218               switch (handler)
219                 {
220                 case iconveh_error:
221                   ASSERT (retval == -1 && errno == EILSEQ);
222                   ASSERT (result == NULL);
223                   if (o)
224                     free (offsets);
225                   break;
226                 case iconveh_question_mark:
227                   {
228                     static const char expected[] = "Rafa? Maszkowski";
229                     ASSERT (retval == 0);
230                     ASSERT (length == strlen (expected));
231                     ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
232                     if (o)
233                       {
234                         for (i = 0; i < 16; i++)
235                           ASSERT (offsets[i] == i);
236                         ASSERT (offsets[16] == MAGIC);
237                         free (offsets);
238                       }
239                     free (result);
240                   }
241                   break;
242                 case iconveh_escape_sequence:
243                   {
244                     static const char expected[] = "Rafa\\u0142 Maszkowski";
245                     ASSERT (retval == 0);
246                     ASSERT (length == strlen (expected));
247                     ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
248                     if (o)
249                       {
250                         for (i = 0; i < 16; i++)
251                           ASSERT (offsets[i] == (i < 5 ? i :
252                                                  i + 5));
253                         ASSERT (offsets[16] == MAGIC);
254                         free (offsets);
255                       }
256                     free (result);
257                   }
258                   break;
259                 }
260             }
261         }
262     }
263
264   /* Test conversion from ISO-8859-1 to UTF-8 with no errors.  */
265   for (h = 0; h < SIZEOF (handlers); h++)
266     {
267       enum iconv_ilseq_handler handler = handlers[h];
268       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
269       static const char expected[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
270       for (o = 0; o < 2; o++)
271         {
272           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
273           char *result = NULL;
274           size_t length = 0;
275           int retval = mem_cd_iconveh (input, strlen (input),
276                                        &cdeh_88591_to_utf8,
277                                        handler,
278                                        offsets,
279                                        &result, &length);
280           ASSERT (retval == 0);
281           ASSERT (length == strlen (expected));
282           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
283           if (o)
284             {
285               for (i = 0; i < 37; i++)
286                 ASSERT (offsets[i] == (i < 1 ? i :
287                                        i < 12 ? i + 1 :
288                                        i < 18 ? i + 2 :
289                                        i + 3));
290               ASSERT (offsets[37] == MAGIC);
291               free (offsets);
292             }
293           free (result);
294         }
295     }
296
297   /* Test conversion from UTF-8 to ISO-8859-1 with no errors.  */
298   for (h = 0; h < SIZEOF (handlers); h++)
299     {
300       enum iconv_ilseq_handler handler = handlers[h];
301       static const char input[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
302       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
303       for (o = 0; o < 2; o++)
304         {
305           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
306           char *result = NULL;
307           size_t length = 0;
308           int retval = mem_cd_iconveh (input, strlen (input),
309                                        &cdeh_utf8_to_88591,
310                                        handler,
311                                        offsets,
312                                        &result, &length);
313           ASSERT (retval == 0);
314           ASSERT (length == strlen (expected));
315           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
316           if (o)
317             {
318               for (i = 0; i < 41; i++)
319                 ASSERT (offsets[i] == (i < 1 ? i :
320                                        i == 1 ? (size_t)(-1) :
321                                        i < 13 ? i - 1 :
322                                        i == 13 ? (size_t)(-1) :
323                                        i < 20 ? i - 2 :
324                                        i == 20 ? (size_t)(-1) :
325                                        i < 40 ? i - 3 :
326                                        (size_t)(-1)));
327               ASSERT (offsets[41] == MAGIC);
328               free (offsets);
329             }
330           free (result);
331         }
332     }
333
334   /* Test conversion from ASCII to UTF-8 with invalid input (EILSEQ).  */
335   for (h = 0; h < SIZEOF (handlers); h++)
336     {
337       enum iconv_ilseq_handler handler = handlers[h];
338       static const char input[] = "Rafa\263 Maszkowski"; /* Rafa? Maszkowski */
339       for (o = 0; o < 2; o++)
340         {
341           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
342           char *result = NULL;
343           size_t length = 0;
344           int retval = mem_cd_iconveh (input, strlen (input),
345                                        &cdeh_ascii_to_utf8,
346                                        handler,
347                                        offsets,
348                                        &result, &length);
349           switch (handler)
350             {
351             case iconveh_error:
352               ASSERT (retval == -1 && errno == EILSEQ);
353               ASSERT (result == NULL);
354               if (o)
355                 free (offsets);
356               break;
357             case iconveh_question_mark:
358             case iconveh_escape_sequence:
359               {
360                 static const char expected[] = "Rafa? Maszkowski";
361                 ASSERT (retval == 0);
362                 ASSERT (length == strlen (expected));
363                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
364                 if (o)
365                   {
366                     for (i = 0; i < 16; i++)
367                       ASSERT (offsets[i] == i);
368                     ASSERT (offsets[16] == MAGIC);
369                     free (offsets);
370                   }
371                 free (result);
372               }
373               break;
374             }
375         }
376     }
377
378   /* Test conversion from UTF-8 to ISO-8859-1 with EILSEQ.  */
379   for (h = 0; h < SIZEOF (handlers); h++)
380     {
381       enum iconv_ilseq_handler handler = handlers[h];
382       static const char input[] = "Rafa\305\202 Maszkowski"; /* RafaƂ Maszkowski */
383       for (o = 0; o < 2; o++)
384         {
385           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
386           char *result = NULL;
387           size_t length = 0;
388           int retval = mem_cd_iconveh (input, strlen (input),
389                                        &cdeh_utf8_to_88591,
390                                        handler,
391                                        offsets,
392                                        &result, &length);
393           switch (handler)
394             {
395             case iconveh_error:
396               ASSERT (retval == -1 && errno == EILSEQ);
397               ASSERT (result == NULL);
398               if (o)
399                 free (offsets);
400               break;
401             case iconveh_question_mark:
402               {
403                 static const char expected[] = "Rafa? Maszkowski";
404                 ASSERT (retval == 0);
405                 ASSERT (length == strlen (expected));
406                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
407                 if (o)
408                   {
409                     for (i = 0; i < 17; i++)
410                       ASSERT (offsets[i] == (i < 5 ? i :
411                                              i == 5 ? (size_t)(-1) :
412                                              i - 1));
413                     ASSERT (offsets[17] == MAGIC);
414                     free (offsets);
415                   }
416                 free (result);
417               }
418               break;
419             case iconveh_escape_sequence:
420               {
421                 static const char expected[] = "Rafa\\u0142 Maszkowski";
422                 ASSERT (retval == 0);
423                 ASSERT (length == strlen (expected));
424                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
425                 if (o)
426                   {
427                     for (i = 0; i < 17; i++)
428                       ASSERT (offsets[i] == (i < 5 ? i :
429                                              i == 5 ? (size_t)(-1) :
430                                              i + 4));
431                     ASSERT (offsets[17] == MAGIC);
432                     free (offsets);
433                   }
434                 free (result);
435               }
436               break;
437             }
438         }
439     }
440
441   /* Test conversion from UTF-8 to ISO-8859-1 with EINVAL.  */
442   for (h = 0; h < SIZEOF (handlers); h++)
443     {
444       enum iconv_ilseq_handler handler = handlers[h];
445       static const char input[] = "\342";
446       for (o = 0; o < 2; o++)
447         {
448           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
449           char *result = NULL;
450           size_t length = 0;
451           int retval = mem_cd_iconveh (input, strlen (input),
452                                        &cdeh_utf8_to_88591,
453                                        handler,
454                                        offsets,
455                                        &result, &length);
456           ASSERT (retval == 0);
457           ASSERT (length == 0);
458           if (o)
459             {
460               ASSERT (offsets[0] == 0);
461               ASSERT (offsets[1] == MAGIC);
462               free (offsets);
463             }
464           free (result);
465         }
466     }
467
468   if (cd_utf7_to_utf8 != (iconv_t)(-1))
469     {
470       /* Disabled on Solaris, because Solaris 9 iconv() is buggy: it returns
471          -1 / EILSEQ when converting the 7th byte of the input "+VDLYP9hA".  */
472 # if !(defined __sun && !defined _LIBICONV_VERSION)
473       /* Test conversion from UTF-7 to UTF-8 with EINVAL.  */
474       for (h = 0; h < SIZEOF (handlers); h++)
475         {
476           enum iconv_ilseq_handler handler = handlers[h];
477           /* This is base64 encoded 0x54 0x32 0xD8 0x3F 0xD8 0x40.  It would
478              convert to U+5432 U+D83F U+D840 but these are Unicode surrogates.  */
479           static const char input[] = "+VDLYP9hA";
480           static const char expected1[] = "\345\220\262"; /* ćČ glibc */
481           static const char expected2[] = ""; /* libiconv */
482           char *result = NULL;
483           size_t length = 0;
484           int retval = mem_cd_iconveh (input, 7,
485                                        &cdeh_utf7_to_utf8,
486                                        handler,
487                                        NULL,
488                                        &result, &length);
489           ASSERT (retval == 0);
490           ASSERT (length == strlen (expected1) || length == strlen (expected2));
491           ASSERT (result != NULL);
492           if (length == strlen (expected1))
493             ASSERT (memcmp (result, expected1, strlen (expected1)) == 0);
494           else
495             ASSERT (memcmp (result, expected2, strlen (expected2)) == 0);
496           free (result);
497         }
498
499       /* Test conversion from UTF-7 to UTF-8 with EILSEQ.  */
500       for (h = 0; h < SIZEOF (handlers); h++)
501         {
502           enum iconv_ilseq_handler handler = handlers[h];
503           /* This is base64 encoded 0xD8 0x3F 0xD8 0x40 0xD8 0x41.  It would
504              convert to U+D83F U+D840 U+D841 but these are Unicode surrogates.  */
505           static const char input[] = "+2D/YQNhB";
506           char *result = NULL;
507           size_t length = 0;
508           int retval = mem_cd_iconveh (input, strlen (input),
509                                        &cdeh_utf7_to_utf8,
510                                        handler,
511                                        NULL,
512                                        &result, &length);
513           switch (handler)
514             {
515             case iconveh_error:
516               ASSERT (retval == -1 && errno == EILSEQ);
517               ASSERT (result == NULL);
518               break;
519             case iconveh_question_mark:
520             case iconveh_escape_sequence:
521               {
522                 /* glibc result */
523                 static const char expected1[] = "?????";
524                 /* libiconv <= 1.12 result */
525                 static const char expected2[] = "?2D/YQNhB";
526                 /* libiconv behaviour changed in version 1.13: the result is
527                    '?' U+0FF6 U+1036; this is U+D83F U+D840 U+D841 shifted left
528                    by 6 bits.  */
529                 static const char expected3[] = "?\340\277\266\341\200\266";
530                 ASSERT (retval == 0);
531                 ASSERT (length == strlen (expected1)
532                         || length == strlen (expected2)
533                         || length == strlen (expected3));
534                 ASSERT (result != NULL);
535                 if (length == strlen (expected1))
536                   ASSERT (memcmp (result, expected1, strlen (expected1)) == 0);
537                 else if (length == strlen (expected2))
538                   ASSERT (memcmp (result, expected2, strlen (expected2)) == 0);
539                 else
540                   ASSERT (memcmp (result, expected3, strlen (expected3)) == 0);
541                 free (result);
542               }
543               break;
544             }
545         }
546 # endif
547     }
548
549   /* ------------------------ Test str_cd_iconveh() ------------------------ */
550
551   /* Test conversion from ISO-8859-2 to ISO-8859-1 with no errors.  */
552   for (indirect = 0; indirect <= 1; indirect++)
553     {
554       for (h = 0; h < SIZEOF (handlers); h++)
555         {
556           enum iconv_ilseq_handler handler = handlers[h];
557           static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
558           static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
559           char *result = str_cd_iconveh (input,
560                                          (indirect
561                                           ? &cdeh_88592_to_88591_indirectly
562                                           : &cdeh_88592_to_88591),
563                                          handler);
564           ASSERT (result != NULL);
565           ASSERT (strcmp (result, expected) == 0);
566           free (result);
567         }
568     }
569
570   /* Test conversion from ASCII to ISO-8859-1 with invalid input (EILSEQ).  */
571   for (indirect = 0; indirect <= 1; indirect++)
572     {
573       for (h = 0; h < SIZEOF (handlers); h++)
574         {
575           enum iconv_ilseq_handler handler = handlers[h];
576           static const char input[] = "Rafa\263 Maszkowski"; /* Rafa? Maszkowski */
577           char *result = str_cd_iconveh (input,
578                                          (indirect
579                                           ? &cdeh_ascii_to_88591_indirectly
580                                           : &cdeh_ascii_to_88591),
581                                          handler);
582           switch (handler)
583             {
584             case iconveh_error:
585               ASSERT (result == NULL && errno == EILSEQ);
586               break;
587             case iconveh_question_mark:
588             case iconveh_escape_sequence:
589               {
590                 static const char expected[] = "Rafa? Maszkowski";
591                 ASSERT (result != NULL);
592                 ASSERT (strcmp (result, expected) == 0);
593                 free (result);
594               }
595               break;
596             }
597         }
598     }
599
600   /* Test conversion from ISO-8859-2 to ISO-8859-1 with EILSEQ.  */
601   for (indirect = 0; indirect <= 1; indirect++)
602     {
603       for (h = 0; h < SIZEOF (handlers); h++)
604         {
605           enum iconv_ilseq_handler handler = handlers[h];
606           static const char input[] = "Rafa\263 Maszkowski"; /* RafaƂ Maszkowski */
607           char *result = str_cd_iconveh (input,
608                                          (indirect
609                                           ? &cdeh_88592_to_88591_indirectly
610                                           : &cdeh_88592_to_88591),
611                                          handler);
612           switch (handler)
613             {
614             case iconveh_error:
615               ASSERT (result == NULL && errno == EILSEQ);
616               break;
617             case iconveh_question_mark:
618               {
619                 static const char expected[] = "Rafa? Maszkowski";
620                 ASSERT (result != NULL);
621                 ASSERT (strcmp (result, expected) == 0);
622                 free (result);
623               }
624               break;
625             case iconveh_escape_sequence:
626               {
627                 static const char expected[] = "Rafa\\u0142 Maszkowski";
628                 ASSERT (result != NULL);
629                 ASSERT (strcmp (result, expected) == 0);
630                 free (result);
631               }
632               break;
633             }
634         }
635     }
636
637   /* Test conversion from ISO-8859-1 to UTF-8 with no errors.  */
638   for (h = 0; h < SIZEOF (handlers); h++)
639     {
640       enum iconv_ilseq_handler handler = handlers[h];
641       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
642       static const char expected[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
643       char *result = str_cd_iconveh (input,
644                                      &cdeh_88591_to_utf8,
645                                      handler);
646       ASSERT (result != NULL);
647       ASSERT (strcmp (result, expected) == 0);
648       free (result);
649     }
650
651   /* Test conversion from UTF-8 to ISO-8859-1 with no errors.  */
652   for (h = 0; h < SIZEOF (handlers); h++)
653     {
654       enum iconv_ilseq_handler handler = handlers[h];
655       static const char input[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
656       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
657       char *result = str_cd_iconveh (input,
658                                      &cdeh_utf8_to_88591,
659                                      handler);
660       ASSERT (result != NULL);
661       ASSERT (strcmp (result, expected) == 0);
662       free (result);
663     }
664
665   /* Test conversion from ASCII to UTF-8 with invalid input (EILSEQ).  */
666   for (h = 0; h < SIZEOF (handlers); h++)
667     {
668       enum iconv_ilseq_handler handler = handlers[h];
669       static const char input[] = "Rafa\263 Maszkowski"; /* Rafa? Maszkowski */
670       char *result = str_cd_iconveh (input,
671                                      &cdeh_ascii_to_utf8,
672                                      handler);
673       switch (handler)
674         {
675         case iconveh_error:
676           ASSERT (result == NULL && errno == EILSEQ);
677           break;
678         case iconveh_question_mark:
679         case iconveh_escape_sequence:
680           {
681             static const char expected[] = "Rafa? Maszkowski";
682             ASSERT (result != NULL);
683             ASSERT (strcmp (result, expected) == 0);
684             free (result);
685           }
686           break;
687         }
688     }
689
690   /* Test conversion from UTF-8 to ISO-8859-1 with EILSEQ.  */
691   for (h = 0; h < SIZEOF (handlers); h++)
692     {
693       enum iconv_ilseq_handler handler = handlers[h];
694       static const char input[] = "Costs: 27 \342\202\254"; /* EURO SIGN */
695       char *result = str_cd_iconveh (input,
696                                      &cdeh_utf8_to_88591,
697                                      handler);
698       switch (handler)
699         {
700         case iconveh_error:
701           ASSERT (result == NULL && errno == EILSEQ);
702           break;
703         case iconveh_question_mark:
704           {
705             static const char expected[] = "Costs: 27 ?";
706             ASSERT (result != NULL);
707             ASSERT (strcmp (result, expected) == 0);
708             free (result);
709           }
710           break;
711         case iconveh_escape_sequence:
712           {
713             static const char expected[] = "Costs: 27 \\u20AC";
714             ASSERT (result != NULL);
715             ASSERT (strcmp (result, expected) == 0);
716             free (result);
717           }
718           break;
719         }
720     }
721
722   /* Test conversion from UTF-8 to ISO-8859-1 with EINVAL.  */
723   for (h = 0; h < SIZEOF (handlers); h++)
724     {
725       enum iconv_ilseq_handler handler = handlers[h];
726       static const char input[] = "\342";
727       char *result = str_cd_iconveh (input,
728                                      &cdeh_utf8_to_88591,
729                                      handler);
730       ASSERT (result != NULL);
731       ASSERT (strcmp (result, "") == 0);
732       free (result);
733     }
734
735   if (cd_88591_to_88592 != (iconv_t)(-1))
736     iconv_close (cd_88591_to_88592);
737   if (cd_88592_to_88591 != (iconv_t)(-1))
738     iconv_close (cd_88592_to_88591);
739   iconv_close (cd_88591_to_utf8);
740   iconv_close (cd_utf8_to_88591);
741   iconv_close (cd_88592_to_utf8);
742   iconv_close (cd_utf8_to_88592);
743
744   /* ------------------------- Test mem_iconveh() ------------------------- */
745
746   /* Test conversion from ISO-8859-2 to ISO-8859-1 with no errors.  */
747   for (h = 0; h < SIZEOF (handlers); h++)
748     {
749       enum iconv_ilseq_handler handler = handlers[h];
750       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
751       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
752       for (o = 0; o < 2; o++)
753         {
754           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
755           char *result = NULL;
756           size_t length = 0;
757           int retval = mem_iconveh (input, strlen (input),
758                                     "ISO-8859-2", "ISO-8859-1",
759                                     handler,
760                                     offsets,
761                                     &result, &length);
762           ASSERT (retval == 0);
763           ASSERT (length == strlen (expected));
764           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
765           if (o)
766             {
767               for (i = 0; i < 37; i++)
768                 ASSERT (offsets[i] == i);
769               ASSERT (offsets[37] == MAGIC);
770               free (offsets);
771             }
772           free (result);
773         }
774     }
775
776   /* Test conversion from ISO-8859-2 to ISO-8859-1 with EILSEQ.  */
777   for (h = 0; h < SIZEOF (handlers); h++)
778     {
779       enum iconv_ilseq_handler handler = handlers[h];
780       static const char input[] = "Rafa\263 Maszkowski"; /* RafaƂ Maszkowski */
781       for (o = 0; o < 2; o++)
782         {
783           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
784           char *result = NULL;
785           size_t length = 0;
786           int retval = mem_iconveh (input, strlen (input),
787                                     "ISO-8859-2", "ISO-8859-1",
788                                     handler,
789                                     offsets,
790                                     &result, &length);
791           switch (handler)
792             {
793             case iconveh_error:
794               ASSERT (retval == -1 && errno == EILSEQ);
795               ASSERT (result == NULL);
796               if (o)
797                 free (offsets);
798               break;
799             case iconveh_question_mark:
800               {
801                 static const char expected[] = "Rafa? Maszkowski";
802                 ASSERT (retval == 0);
803                 ASSERT (length == strlen (expected));
804                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
805                 if (o)
806                   {
807                     for (i = 0; i < 16; i++)
808                       ASSERT (offsets[i] == i);
809                     ASSERT (offsets[16] == MAGIC);
810                     free (offsets);
811                   }
812                 free (result);
813               }
814               break;
815             case iconveh_escape_sequence:
816               {
817                 static const char expected[] = "Rafa\\u0142 Maszkowski";
818                 ASSERT (retval == 0);
819                 ASSERT (length == strlen (expected));
820                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
821                 if (o)
822                   {
823                     for (i = 0; i < 16; i++)
824                       ASSERT (offsets[i] == (i < 5 ? i :
825                                              i + 5));
826                     ASSERT (offsets[16] == MAGIC);
827                     free (offsets);
828                   }
829                 free (result);
830               }
831               break;
832             }
833         }
834     }
835
836   /* Test conversion from ISO-8859-1 to UTF-8 with no errors.  */
837   for (h = 0; h < SIZEOF (handlers); h++)
838     {
839       enum iconv_ilseq_handler handler = handlers[h];
840       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
841       static const char expected[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
842       for (o = 0; o < 2; o++)
843         {
844           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
845           char *result = NULL;
846           size_t length = 0;
847           int retval = mem_iconveh (input, strlen (input),
848                                     "ISO-8859-1", "UTF-8",
849                                     handler,
850                                     offsets,
851                                     &result, &length);
852           ASSERT (retval == 0);
853           ASSERT (length == strlen (expected));
854           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
855           if (o)
856             {
857               for (i = 0; i < 37; i++)
858                 ASSERT (offsets[i] == (i < 1 ? i :
859                                        i < 12 ? i + 1 :
860                                        i < 18 ? i + 2 :
861                                        i + 3));
862               ASSERT (offsets[37] == MAGIC);
863               free (offsets);
864             }
865           free (result);
866         }
867     }
868
869   /* Test conversion from UTF-8 to ISO-8859-1 with no errors.  */
870   for (h = 0; h < SIZEOF (handlers); h++)
871     {
872       enum iconv_ilseq_handler handler = handlers[h];
873       static const char input[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
874       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
875       for (o = 0; o < 2; o++)
876         {
877           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
878           char *result = NULL;
879           size_t length = 0;
880           int retval = mem_iconveh (input, strlen (input),
881                                     "UTF-8", "ISO-8859-1",
882                                     handler,
883                                     offsets,
884                                     &result, &length);
885           ASSERT (retval == 0);
886           ASSERT (length == strlen (expected));
887           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
888           if (o)
889             {
890               for (i = 0; i < 41; i++)
891                 ASSERT (offsets[i] == (i < 1 ? i :
892                                        i == 1 ? (size_t)(-1) :
893                                        i < 13 ? i - 1 :
894                                        i == 13 ? (size_t)(-1) :
895                                        i < 20 ? i - 2 :
896                                        i == 20 ? (size_t)(-1) :
897                                        i < 40 ? i - 3 :
898                                        (size_t)(-1)));
899               ASSERT (offsets[41] == MAGIC);
900               free (offsets);
901             }
902           free (result);
903         }
904     }
905
906   /* Test conversion from UTF-8 to ISO-8859-1 with EILSEQ.  */
907   for (h = 0; h < SIZEOF (handlers); h++)
908     {
909       enum iconv_ilseq_handler handler = handlers[h];
910       static const char input[] = "Rafa\305\202 Maszkowski"; /* RafaƂ Maszkowski */
911       for (o = 0; o < 2; o++)
912         {
913           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
914           char *result = NULL;
915           size_t length = 0;
916           int retval = mem_iconveh (input, strlen (input),
917                                     "UTF-8", "ISO-8859-1",
918                                     handler,
919                                     offsets,
920                                     &result, &length);
921           switch (handler)
922             {
923             case iconveh_error:
924               ASSERT (retval == -1 && errno == EILSEQ);
925               ASSERT (result == NULL);
926               if (o)
927                 free (offsets);
928               break;
929             case iconveh_question_mark:
930               {
931                 static const char expected[] = "Rafa? Maszkowski";
932                 ASSERT (retval == 0);
933                 ASSERT (length == strlen (expected));
934                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
935                 if (o)
936                   {
937                     for (i = 0; i < 17; i++)
938                       ASSERT (offsets[i] == (i < 5 ? i :
939                                              i == 5 ? (size_t)(-1) :
940                                              i - 1));
941                     ASSERT (offsets[17] == MAGIC);
942                     free (offsets);
943                   }
944                 free (result);
945               }
946               break;
947             case iconveh_escape_sequence:
948               {
949                 static const char expected[] = "Rafa\\u0142 Maszkowski";
950                 ASSERT (retval == 0);
951                 ASSERT (length == strlen (expected));
952                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
953                 if (o)
954                   {
955                     for (i = 0; i < 17; i++)
956                       ASSERT (offsets[i] == (i < 5 ? i :
957                                              i == 5 ? (size_t)(-1) :
958                                              i + 4));
959                     ASSERT (offsets[17] == MAGIC);
960                     free (offsets);
961                   }
962                 free (result);
963               }
964               break;
965             }
966         }
967     }
968
969   /* Test conversion from UTF-8 to ISO-8859-1 with EINVAL.  */
970   for (h = 0; h < SIZEOF (handlers); h++)
971     {
972       enum iconv_ilseq_handler handler = handlers[h];
973       static const char input[] = "\342";
974       for (o = 0; o < 2; o++)
975         {
976           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
977           char *result = NULL;
978           size_t length = 0;
979           int retval = mem_iconveh (input, strlen (input),
980                                     "UTF-8", "ISO-8859-1",
981                                     handler,
982                                     offsets,
983                                     &result, &length);
984           ASSERT (retval == 0);
985           ASSERT (length == 0);
986           if (o)
987             {
988               ASSERT (offsets[0] == 0);
989               ASSERT (offsets[1] == MAGIC);
990               free (offsets);
991             }
992           free (result);
993         }
994     }
995
996   /* ------------------------- Test str_iconveh() ------------------------- */
997
998   /* Test conversion from ISO-8859-2 to ISO-8859-1 with no errors.  */
999   for (h = 0; h < SIZEOF (handlers); h++)
1000     {
1001       enum iconv_ilseq_handler handler = handlers[h];
1002       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
1003       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
1004       char *result = str_iconveh (input, "ISO-8859-2", "ISO-8859-1", handler);
1005       ASSERT (result != NULL);
1006       ASSERT (strcmp (result, expected) == 0);
1007       free (result);
1008     }
1009
1010   /* Test conversion from ISO-8859-2 to ISO-8859-1 with EILSEQ.  */
1011   for (h = 0; h < SIZEOF (handlers); h++)
1012     {
1013       enum iconv_ilseq_handler handler = handlers[h];
1014       static const char input[] = "Rafa\263 Maszkowski"; /* RafaƂ Maszkowski */
1015       char *result = str_iconveh (input, "ISO-8859-2", "ISO-8859-1", handler);
1016       switch (handler)
1017         {
1018         case iconveh_error:
1019           ASSERT (result == NULL && errno == EILSEQ);
1020           break;
1021         case iconveh_question_mark:
1022           {
1023             static const char expected[] = "Rafa? Maszkowski";
1024             ASSERT (result != NULL);
1025             ASSERT (strcmp (result, expected) == 0);
1026             free (result);
1027           }
1028           break;
1029         case iconveh_escape_sequence:
1030           {
1031             static const char expected[] = "Rafa\\u0142 Maszkowski";
1032             ASSERT (result != NULL);
1033             ASSERT (strcmp (result, expected) == 0);
1034             free (result);
1035           }
1036           break;
1037         }
1038     }
1039
1040   /* Test conversion from ISO-8859-1 to UTF-8 with no errors.  */
1041   for (h = 0; h < SIZEOF (handlers); h++)
1042     {
1043       enum iconv_ilseq_handler handler = handlers[h];
1044       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
1045       static const char expected[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
1046       char *result = str_iconveh (input, "ISO-8859-1", "UTF-8", handler);
1047       ASSERT (result != NULL);
1048       ASSERT (strcmp (result, expected) == 0);
1049       free (result);
1050     }
1051
1052   /* Test conversion from UTF-8 to ISO-8859-1 with no errors.  */
1053   for (h = 0; h < SIZEOF (handlers); h++)
1054     {
1055       enum iconv_ilseq_handler handler = handlers[h];
1056       static const char input[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
1057       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
1058       char *result = str_iconveh (input, "UTF-8", "ISO-8859-1", handler);
1059       ASSERT (result != NULL);
1060       ASSERT (strcmp (result, expected) == 0);
1061       free (result);
1062     }
1063
1064   /* Test conversion from UTF-8 to ISO-8859-1 with EILSEQ.  */
1065   for (h = 0; h < SIZEOF (handlers); h++)
1066     {
1067       enum iconv_ilseq_handler handler = handlers[h];
1068       static const char input[] = "Costs: 27 \342\202\254"; /* EURO SIGN */
1069       char *result = str_iconveh (input, "UTF-8", "ISO-8859-1", handler);
1070       switch (handler)
1071         {
1072         case iconveh_error:
1073           ASSERT (result == NULL && errno == EILSEQ);
1074           break;
1075         case iconveh_question_mark:
1076           {
1077             static const char expected[] = "Costs: 27 ?";
1078             ASSERT (result != NULL);
1079             ASSERT (strcmp (result, expected) == 0);
1080             free (result);
1081           }
1082           break;
1083         case iconveh_escape_sequence:
1084           {
1085             static const char expected[] = "Costs: 27 \\u20AC";
1086             ASSERT (result != NULL);
1087             ASSERT (strcmp (result, expected) == 0);
1088             free (result);
1089           }
1090           break;
1091         }
1092     }
1093
1094   /* Test conversion from UTF-8 to ISO-8859-1 with EINVAL.  */
1095   for (h = 0; h < SIZEOF (handlers); h++)
1096     {
1097       enum iconv_ilseq_handler handler = handlers[h];
1098       static const char input[] = "\342";
1099       char *result = str_iconveh (input, "UTF-8", "ISO-8859-1", handler);
1100       ASSERT (result != NULL);
1101       ASSERT (strcmp (result, "") == 0);
1102       free (result);
1103     }
1104
1105 #endif
1106
1107   return 0;
1108 }