1/* Test of conversion from UTF-16 to legacy encodings.
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 "uniconv.h"
22
23#include <errno.h>
24#include <stdlib.h>
25#include <string.h>
26
27#include "macros.h"
28
29/* Magic number for detecting bounds violations.  */
30#define MAGIC 0x1983EFF1
31
32static size_t *
33new_offsets (size_t n)
34{
35  size_t *offsets = (size_t *) malloc ((n + 1) * sizeof (size_t));
36  offsets[n] = MAGIC;
37  return offsets;
38}
39
40int
41main ()
42{
43  static enum iconv_ilseq_handler handlers[] =
44    { iconveh_error, iconveh_question_mark, iconveh_escape_sequence };
45  size_t h;
46  size_t o;
47  size_t i;
48
49#if HAVE_ICONV
50  /* Assume that iconv() supports at least the encodings ASCII, ISO-8859-1,
51     ISO-8859-2, and UTF-8.  */
52
53  /* Test conversion from UTF-16 to ISO-8859-1 with no errors.  */
54  for (h = 0; h < SIZEOF (handlers); h++)
55    {
56      enum iconv_ilseq_handler handler = handlers[h];
57      static const uint16_t input[] = /* ��rger mit b��sen B��bchen ohne Augenma�� */
58        {
59          0xC4, 'r', 'g', 'e', 'r', ' ', 'm', 'i', 't', ' ', 'b', 0xF6, 's',
60          'e', 'n', ' ', 'B', 0xFC, 'b', 'c', 'h', 'e', 'n', ' ', 'o', 'h',
61          'n', 'e', ' ', 'A', 'u', 'g', 'e', 'n', 'm', 'a', 0xDF
62        };
63      static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
64      for (o = 0; o < 2; o++)
65        {
66          size_t *offsets = (o ? new_offsets (SIZEOF (input)) : NULL);
67          size_t length;
68          char *result = u16_conv_to_encoding ("ISO-8859-1", handler,
69                                               input, SIZEOF (input),
70                                               offsets,
71                                               NULL, &length);
72          ASSERT (result != NULL);
73          ASSERT (length == strlen (expected));
74          ASSERT (memcmp (result, expected, length) == 0);
75          if (o)
76            {
77              for (i = 0; i < 37; i++)
78                ASSERT (offsets[i] == i);
79              ASSERT (offsets[37] == MAGIC);
80              free (offsets);
81            }
82          free (result);
83        }
84    }
85
86  /* Test conversion from UTF-16 to ISO-8859-1 with EILSEQ.  */
87  for (h = 0; h < SIZEOF (handlers); h++)
88    {
89      enum iconv_ilseq_handler handler = handlers[h];
90      static const uint16_t input[] = /* Rafa�� Maszkowski */
91        {
92          'R', 'a', 'f', 'a', 0x0142, ' ', 'M', 'a', 's', 'z', 'k', 'o', 'w',
93          's', 'k', 'i'
94        };
95      for (o = 0; o < 2; o++)
96        {
97          size_t *offsets = (o ? new_offsets (SIZEOF (input)) : NULL);
98          size_t length = 0xdead;
99          char *result = u16_conv_to_encoding ("ISO-8859-1", handler,
100                                               input, SIZEOF (input),
101                                               offsets,
102                                               NULL, &length);
103          switch (handler)
104            {
105            case iconveh_error:
106              ASSERT (result == NULL);
107              ASSERT (errno == EILSEQ);
108              ASSERT (length == 0xdead);
109              break;
110            case iconveh_question_mark:
111              {
112                static const char expected[] = "Rafa? Maszkowski";
113                static const char expected_translit[] = "Rafal Maszkowski";
114                ASSERT (result != NULL);
115                ASSERT (length == strlen (expected));
116                ASSERT (memcmp (result, expected, length) == 0
117                        || memcmp (result, expected_translit, length) == 0);
118                if (o)
119                  {
120                    for (i = 0; i < 16; i++)
121                      ASSERT (offsets[i] == i);
122                    ASSERT (offsets[16] == MAGIC);
123                    free (offsets);
124                  }
125                free (result);
126              }
127              break;
128            case iconveh_escape_sequence:
129              {
130                static const char expected[] = "Rafa\\u0142 Maszkowski";
131                ASSERT (result != NULL);
132                ASSERT (length == strlen (expected));
133                ASSERT (memcmp (result, expected, length) == 0);
134                if (o)
135                  {
136                    for (i = 0; i < 16; i++)
137                      ASSERT (offsets[i] == (i < 5 ? i : i + 5));
138                    ASSERT (offsets[16] == MAGIC);
139                    free (offsets);
140                  }
141                free (result);
142              }
143              break;
144            }
145        }
146    }
147
148  /* Test conversion from UTF-16 to ISO-8859-1 with EINVAL.  */
149  for (h = 0; h < SIZEOF (handlers); h++)
150    {
151      enum iconv_ilseq_handler handler = handlers[h];
152      static const uint16_t input[] = { 0xD845 };
153      for (o = 0; o < 2; o++)
154        {
155          size_t *offsets = (o ? new_offsets (SIZEOF (input)) : NULL);
156          size_t length;
157          char *result = u16_conv_to_encoding ("ISO-8859-1", handler,
158                                               input, SIZEOF (input),
159                                               offsets,
160                                               NULL, &length);
161          ASSERT (result != NULL);
162          ASSERT (length == strlen (""));
163          if (o)
164            {
165              ASSERT (offsets[0] == 0);
166              ASSERT (offsets[1] == MAGIC);
167              free (offsets);
168            }
169          free (result);
170        }
171    }
172
173#endif
174
175  return 0;
176}
177