1 /* Test of character set conversion.
2    Copyright (C) 2007-2020 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 <https://www.gnu.org/licenses/>.  */
16 
17 /* Written by Bruno Haible <bruno@clisp.org>, 2007.  */
18 
19 #include <config.h>
20 
21 #if HAVE_ICONV
22 # include <iconv.h>
23 
24 # ifndef ICONV_CONST
25 #  define ICONV_CONST /* empty */
26 # endif
27 
28 #include "signature.h"
29 SIGNATURE_CHECK (iconv, size_t, (iconv_t, ICONV_CONST char **, size_t *,
30                                  char **, size_t *));
31 SIGNATURE_CHECK (iconv_close, int, (iconv_t x));
32 SIGNATURE_CHECK (iconv_open, iconv_t, (char const *, char const *));
33 
34 #endif
35 
36 #include <errno.h>
37 #include <string.h>
38 
39 #include "macros.h"
40 
41 int
main()42 main ()
43 {
44 #if HAVE_ICONV
45   /* Assume that iconv() supports at least the encodings ASCII, ISO-8859-1,
46      and UTF-8.  */
47   iconv_t cd_88591_to_utf8 = iconv_open ("UTF-8", "ISO-8859-1");
48   iconv_t cd_utf8_to_88591 = iconv_open ("ISO-8859-1", "UTF-8");
49 
50 #if defined __MVS__ && defined __IBMC__
51   /* String literals below are in ASCII, not EBCDIC.  */
52 # pragma convert("ISO8859-1")
53 # define CONVERT_ENABLED
54 #endif
55 
56   ASSERT (cd_88591_to_utf8 != (iconv_t)(-1));
57   ASSERT (cd_utf8_to_88591 != (iconv_t)(-1));
58 
59   /* Test conversion from ISO-8859-1 to UTF-8 with no errors.  */
60   {
61     static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
62     static const char expected[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
63     char buf[50];
64     const char *inptr = input;
65     size_t inbytesleft = strlen (input);
66     char *outptr = buf;
67     size_t outbytesleft = sizeof (buf);
68     size_t res = iconv (cd_88591_to_utf8,
69                         (ICONV_CONST char **) &inptr, &inbytesleft,
70                         &outptr, &outbytesleft);
71     ASSERT (res == 0 && inbytesleft == 0);
72     ASSERT (outptr == buf + strlen (expected));
73     ASSERT (memcmp (buf, expected, strlen (expected)) == 0);
74   }
75 
76   /* Test conversion from ISO-8859-1 to UTF-8 with E2BIG.  */
77   {
78     static const char input[] = "\304";
79     static char buf[2] = { (char)0xDE, (char)0xAD };
80     const char *inptr = input;
81     size_t inbytesleft = 1;
82     char *outptr = buf;
83     size_t outbytesleft = 1;
84     size_t res = iconv (cd_88591_to_utf8,
85                         (ICONV_CONST char **) &inptr, &inbytesleft,
86                         &outptr, &outbytesleft);
87     ASSERT (res == (size_t)(-1) && errno == E2BIG);
88     ASSERT (inbytesleft == 1);
89     ASSERT (outbytesleft == 1);
90     ASSERT ((unsigned char) buf[1] == 0xAD);
91     ASSERT ((unsigned char) buf[0] == 0xDE);
92   }
93 
94   /* Test conversion from UTF-8 to ISO-8859-1 with no errors.  */
95   {
96     static const char input[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
97     static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
98     char buf[50];
99     const char *inptr = input;
100     size_t inbytesleft = strlen (input);
101     char *outptr = buf;
102     size_t outbytesleft = sizeof (buf);
103     size_t res = iconv (cd_utf8_to_88591,
104                         (ICONV_CONST char **) &inptr, &inbytesleft,
105                         &outptr, &outbytesleft);
106     ASSERT (res == 0 && inbytesleft == 0);
107     ASSERT (outptr == buf + strlen (expected));
108     ASSERT (memcmp (buf, expected, strlen (expected)) == 0);
109   }
110 
111   /* Test conversion from UTF-8 to ISO-8859-1 with EILSEQ.  */
112   {
113     static const char input[] = "\342\202\254"; /* EURO SIGN */
114     char buf[10];
115     const char *inptr = input;
116     size_t inbytesleft = strlen (input);
117     char *outptr = buf;
118     size_t outbytesleft = sizeof (buf);
119     size_t res = iconv (cd_utf8_to_88591,
120                         (ICONV_CONST char **) &inptr, &inbytesleft,
121                         &outptr, &outbytesleft);
122     if (res == (size_t)(-1))
123       {
124         ASSERT (errno == EILSEQ);
125         ASSERT (inbytesleft == strlen (input) && outptr == buf);
126       }
127     else
128       {
129         ASSERT (res == 1);
130         ASSERT (inbytesleft == 0);
131       }
132   }
133 
134   /* Test conversion from UTF-8 to ISO-8859-1 with EINVAL.  */
135   {
136     static const char input[] = "\342";
137     char buf[10];
138     const char *inptr = input;
139     size_t inbytesleft = 1;
140     char *outptr = buf;
141     size_t outbytesleft = sizeof (buf);
142     size_t res = iconv (cd_utf8_to_88591,
143                         (ICONV_CONST char **) &inptr, &inbytesleft,
144                         &outptr, &outbytesleft);
145     ASSERT (res == (size_t)(-1) && errno == EINVAL);
146     ASSERT (inbytesleft == 1 && outptr == buf);
147   }
148 
149   iconv_close (cd_88591_to_utf8);
150   iconv_close (cd_utf8_to_88591);
151 
152 #ifdef CONVERT_ENABLED
153 # pragma convert(pop)
154 #endif
155 
156 #endif /* HAVE_ICONV */
157 
158   return 0;
159 }
160