1*8d67ca89SAndroid Build Coastguard Worker /*
2*8d67ca89SAndroid Build Coastguard Worker * Copyright (C) 2017 The Android Open Source Project
3*8d67ca89SAndroid Build Coastguard Worker *
4*8d67ca89SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*8d67ca89SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*8d67ca89SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*8d67ca89SAndroid Build Coastguard Worker *
8*8d67ca89SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*8d67ca89SAndroid Build Coastguard Worker *
10*8d67ca89SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*8d67ca89SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*8d67ca89SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*8d67ca89SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*8d67ca89SAndroid Build Coastguard Worker * limitations under the License.
15*8d67ca89SAndroid Build Coastguard Worker */
16*8d67ca89SAndroid Build Coastguard Worker
17*8d67ca89SAndroid Build Coastguard Worker #include <gtest/gtest.h>
18*8d67ca89SAndroid Build Coastguard Worker
19*8d67ca89SAndroid Build Coastguard Worker #include <iconv.h>
20*8d67ca89SAndroid Build Coastguard Worker
21*8d67ca89SAndroid Build Coastguard Worker #include "utils.h"
22*8d67ca89SAndroid Build Coastguard Worker
23*8d67ca89SAndroid Build Coastguard Worker #define INVALID_ICONV_T reinterpret_cast<iconv_t>(-1)
24*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_open_EINVAL)25*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_open_EINVAL) {
26*8d67ca89SAndroid Build Coastguard Worker errno = 0;
27*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(INVALID_ICONV_T, iconv_open("silly", "silly"));
28*8d67ca89SAndroid Build Coastguard Worker ASSERT_ERRNO(EINVAL);
29*8d67ca89SAndroid Build Coastguard Worker errno = 0;
30*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(INVALID_ICONV_T, iconv_open("silly", "UTF-8"));
31*8d67ca89SAndroid Build Coastguard Worker ASSERT_ERRNO(EINVAL);
32*8d67ca89SAndroid Build Coastguard Worker errno = 0;
33*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(INVALID_ICONV_T, iconv_open("UTF-8", "silly"));
34*8d67ca89SAndroid Build Coastguard Worker ASSERT_ERRNO(EINVAL);
35*8d67ca89SAndroid Build Coastguard Worker }
36*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_open_comparator)37*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_open_comparator) {
38*8d67ca89SAndroid Build Coastguard Worker // Examples from http://www.unicode.org/reports/tr22/#Charset_Alias_Matching:
39*8d67ca89SAndroid Build Coastguard Worker // "For example, the following names should match: "UTF-8", "utf8", "u.t.f-008", ..."
40*8d67ca89SAndroid Build Coastguard Worker iconv_t c;
41*8d67ca89SAndroid Build Coastguard Worker ASSERT_NE(INVALID_ICONV_T, c = iconv_open("UTF-8", "utf8"));
42*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(0, iconv_close(c));
43*8d67ca89SAndroid Build Coastguard Worker ASSERT_NE(INVALID_ICONV_T, c = iconv_open("UTF-8", "u.t.f-008"));
44*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(0, iconv_close(c));
45*8d67ca89SAndroid Build Coastguard Worker
46*8d67ca89SAndroid Build Coastguard Worker // "...but not "utf-80" or "ut8"."
47*8d67ca89SAndroid Build Coastguard Worker errno = 0;
48*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(INVALID_ICONV_T, iconv_open("UTF-8", "utf-80"));
49*8d67ca89SAndroid Build Coastguard Worker ASSERT_ERRNO(EINVAL);
50*8d67ca89SAndroid Build Coastguard Worker errno = 0;
51*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(INVALID_ICONV_T, iconv_open("UTF-8", "ut80"));
52*8d67ca89SAndroid Build Coastguard Worker ASSERT_ERRNO(EINVAL);
53*8d67ca89SAndroid Build Coastguard Worker }
54*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_smoke)55*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_smoke) {
56*8d67ca89SAndroid Build Coastguard Worker const char* utf8 = "a٦ᄀ"; // U+0666 ٦ 0xd9 0xa6 // U+1100 ᄀ 0xe1 0x84 0x80
57*8d67ca89SAndroid Build Coastguard Worker char buf[BUFSIZ] = {};
58*8d67ca89SAndroid Build Coastguard Worker
59*8d67ca89SAndroid Build Coastguard Worker iconv_t c = iconv_open("UTF-32LE", "UTF-8");
60*8d67ca89SAndroid Build Coastguard Worker ASSERT_NE(INVALID_ICONV_T, c);
61*8d67ca89SAndroid Build Coastguard Worker
62*8d67ca89SAndroid Build Coastguard Worker char* in = const_cast<char*>(utf8);
63*8d67ca89SAndroid Build Coastguard Worker size_t in_bytes = strlen(in);
64*8d67ca89SAndroid Build Coastguard Worker
65*8d67ca89SAndroid Build Coastguard Worker char* out = buf;
66*8d67ca89SAndroid Build Coastguard Worker size_t out_bytes = sizeof(buf);
67*8d67ca89SAndroid Build Coastguard Worker
68*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0U, iconv(c, &in, &in_bytes, &out, &out_bytes));
69*8d67ca89SAndroid Build Coastguard Worker
70*8d67ca89SAndroid Build Coastguard Worker wchar_t* utf16 = reinterpret_cast<wchar_t*>(buf);
71*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(L'a', utf16[0]);
72*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(L'٦', utf16[1]);
73*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(L'ᄀ', utf16[2]);
74*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(L'\0', utf16[3]);
75*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0U, in_bytes);
76*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(sizeof(buf) - (3 /* chars */ * 4 /* bytes each */), out_bytes);
77*8d67ca89SAndroid Build Coastguard Worker
78*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(0, iconv_close(c));
79*8d67ca89SAndroid Build Coastguard Worker }
80*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_lossy_TRANSLIT)81*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_lossy_TRANSLIT) {
82*8d67ca89SAndroid Build Coastguard Worker const char* utf8 = "a٦ᄀz"; // U+0666 ٦ 0xd9 0xa6 // U+1100 ᄀ 0xe1 0x84 0x80
83*8d67ca89SAndroid Build Coastguard Worker char buf[BUFSIZ] = {};
84*8d67ca89SAndroid Build Coastguard Worker
85*8d67ca89SAndroid Build Coastguard Worker iconv_t c = iconv_open("ASCII//TRANSLIT", "UTF-8");
86*8d67ca89SAndroid Build Coastguard Worker ASSERT_NE(INVALID_ICONV_T, c);
87*8d67ca89SAndroid Build Coastguard Worker
88*8d67ca89SAndroid Build Coastguard Worker char* in = const_cast<char*>(utf8);
89*8d67ca89SAndroid Build Coastguard Worker size_t in_bytes = strlen(in);
90*8d67ca89SAndroid Build Coastguard Worker
91*8d67ca89SAndroid Build Coastguard Worker char* out = buf;
92*8d67ca89SAndroid Build Coastguard Worker size_t out_bytes = sizeof(buf);
93*8d67ca89SAndroid Build Coastguard Worker
94*8d67ca89SAndroid Build Coastguard Worker // Two of the input characters (5 input bytes) aren't representable as ASCII.
95*8d67ca89SAndroid Build Coastguard Worker // With "//TRANSLIT", we use a replacement character, and report the number
96*8d67ca89SAndroid Build Coastguard Worker // of replacements.
97*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(2U, iconv(c, &in, &in_bytes, &out, &out_bytes));
98*8d67ca89SAndroid Build Coastguard Worker
99*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ('a', buf[0]);
100*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ('?', buf[1]);
101*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ('?', buf[2]);
102*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ('z', buf[3]);
103*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0, buf[4]);
104*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0U, in_bytes);
105*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(sizeof(buf) - 4, out_bytes);
106*8d67ca89SAndroid Build Coastguard Worker
107*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(0, iconv_close(c));
108*8d67ca89SAndroid Build Coastguard Worker }
109*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_lossy_IGNORE)110*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_lossy_IGNORE) {
111*8d67ca89SAndroid Build Coastguard Worker const char* utf8 = "a٦ᄀz"; // U+0666 ٦ 0xd9 0xa6 // U+1100 ᄀ 0xe1 0x84 0x80
112*8d67ca89SAndroid Build Coastguard Worker char buf[BUFSIZ] = {};
113*8d67ca89SAndroid Build Coastguard Worker
114*8d67ca89SAndroid Build Coastguard Worker iconv_t c = iconv_open("ASCII//IGNORE", "UTF-8");
115*8d67ca89SAndroid Build Coastguard Worker ASSERT_NE(INVALID_ICONV_T, c);
116*8d67ca89SAndroid Build Coastguard Worker
117*8d67ca89SAndroid Build Coastguard Worker char* in = const_cast<char*>(utf8);
118*8d67ca89SAndroid Build Coastguard Worker size_t in_bytes = strlen(in);
119*8d67ca89SAndroid Build Coastguard Worker
120*8d67ca89SAndroid Build Coastguard Worker char* out = buf;
121*8d67ca89SAndroid Build Coastguard Worker size_t out_bytes = sizeof(buf);
122*8d67ca89SAndroid Build Coastguard Worker
123*8d67ca89SAndroid Build Coastguard Worker // Two of the input characters (5 input bytes) aren't representable as ASCII.
124*8d67ca89SAndroid Build Coastguard Worker // With "//IGNORE", we just skip them (but return failure).
125*8d67ca89SAndroid Build Coastguard Worker errno = 0;
126*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(static_cast<size_t>(-1), iconv(c, &in, &in_bytes, &out, &out_bytes));
127*8d67ca89SAndroid Build Coastguard Worker EXPECT_ERRNO(EILSEQ);
128*8d67ca89SAndroid Build Coastguard Worker
129*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ('a', buf[0]);
130*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ('z', buf[1]);
131*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0, buf[2]);
132*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0U, in_bytes);
133*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(sizeof(buf) - 2, out_bytes);
134*8d67ca89SAndroid Build Coastguard Worker
135*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(0, iconv_close(c));
136*8d67ca89SAndroid Build Coastguard Worker }
137*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_lossy)138*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_lossy) {
139*8d67ca89SAndroid Build Coastguard Worker const char* utf8 = "a٦ᄀz"; // U+0666 ٦ 0xd9 0xa6 // U+1100 ᄀ 0xe1 0x84 0x80
140*8d67ca89SAndroid Build Coastguard Worker char buf[BUFSIZ] = {};
141*8d67ca89SAndroid Build Coastguard Worker
142*8d67ca89SAndroid Build Coastguard Worker iconv_t c = iconv_open("ASCII", "UTF-8");
143*8d67ca89SAndroid Build Coastguard Worker ASSERT_NE(INVALID_ICONV_T, c);
144*8d67ca89SAndroid Build Coastguard Worker
145*8d67ca89SAndroid Build Coastguard Worker char* in = const_cast<char*>(utf8);
146*8d67ca89SAndroid Build Coastguard Worker size_t in_bytes = strlen(in);
147*8d67ca89SAndroid Build Coastguard Worker
148*8d67ca89SAndroid Build Coastguard Worker char* out = buf;
149*8d67ca89SAndroid Build Coastguard Worker size_t out_bytes = sizeof(buf);
150*8d67ca89SAndroid Build Coastguard Worker
151*8d67ca89SAndroid Build Coastguard Worker // The second input character isn't representable as ASCII, so we stop there.
152*8d67ca89SAndroid Build Coastguard Worker errno = 0;
153*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(static_cast<size_t>(-1), iconv(c, &in, &in_bytes, &out, &out_bytes));
154*8d67ca89SAndroid Build Coastguard Worker EXPECT_ERRNO(EILSEQ);
155*8d67ca89SAndroid Build Coastguard Worker
156*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ('a', buf[0]);
157*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0, buf[1]);
158*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(6U, in_bytes); // Two bytes for ٦, three bytes for ᄀ, and one byte for z.
159*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(sizeof(buf) - 1, out_bytes);
160*8d67ca89SAndroid Build Coastguard Worker
161*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(0, iconv_close(c));
162*8d67ca89SAndroid Build Coastguard Worker }
163*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_malformed_sequence_EILSEQ)164*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_malformed_sequence_EILSEQ) {
165*8d67ca89SAndroid Build Coastguard Worker const char* utf8 = "a\xd9z"; // 0xd9 is the first byte of the two-byte U+0666 ٦.
166*8d67ca89SAndroid Build Coastguard Worker char buf[BUFSIZ] = {};
167*8d67ca89SAndroid Build Coastguard Worker
168*8d67ca89SAndroid Build Coastguard Worker iconv_t c = iconv_open("UTF-8", "UTF-8");
169*8d67ca89SAndroid Build Coastguard Worker ASSERT_NE(INVALID_ICONV_T, c);
170*8d67ca89SAndroid Build Coastguard Worker
171*8d67ca89SAndroid Build Coastguard Worker char* in = const_cast<char*>(utf8);
172*8d67ca89SAndroid Build Coastguard Worker size_t in_bytes = strlen(in);
173*8d67ca89SAndroid Build Coastguard Worker
174*8d67ca89SAndroid Build Coastguard Worker char* out = buf;
175*8d67ca89SAndroid Build Coastguard Worker size_t out_bytes = sizeof(buf);
176*8d67ca89SAndroid Build Coastguard Worker
177*8d67ca89SAndroid Build Coastguard Worker // The second input byte is a malformed character, so we stop there.
178*8d67ca89SAndroid Build Coastguard Worker errno = 0;
179*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(static_cast<size_t>(-1), iconv(c, &in, &in_bytes, &out, &out_bytes));
180*8d67ca89SAndroid Build Coastguard Worker EXPECT_ERRNO(EILSEQ);
181*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ('\xd9', *in); // *in is left pointing to the start of the invalid sequence.
182*8d67ca89SAndroid Build Coastguard Worker ++in;
183*8d67ca89SAndroid Build Coastguard Worker --in_bytes;
184*8d67ca89SAndroid Build Coastguard Worker errno = 0;
185*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0U, iconv(c, &in, &in_bytes, &out, &out_bytes));
186*8d67ca89SAndroid Build Coastguard Worker EXPECT_ERRNO(0);
187*8d67ca89SAndroid Build Coastguard Worker
188*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ('a', buf[0]);
189*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ('z', buf[1]);
190*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0, buf[2]);
191*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0U, in_bytes);
192*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(sizeof(buf) - 2, out_bytes);
193*8d67ca89SAndroid Build Coastguard Worker
194*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(0, iconv_close(c));
195*8d67ca89SAndroid Build Coastguard Worker }
196*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_incomplete_sequence_EINVAL)197*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_incomplete_sequence_EINVAL) {
198*8d67ca89SAndroid Build Coastguard Worker const char* utf8 = "a\xd9"; // 0xd9 is the first byte of the two-byte U+0666 ٦.
199*8d67ca89SAndroid Build Coastguard Worker char buf[BUFSIZ] = {};
200*8d67ca89SAndroid Build Coastguard Worker
201*8d67ca89SAndroid Build Coastguard Worker iconv_t c = iconv_open("UTF-8", "UTF-8");
202*8d67ca89SAndroid Build Coastguard Worker ASSERT_NE(INVALID_ICONV_T, c);
203*8d67ca89SAndroid Build Coastguard Worker
204*8d67ca89SAndroid Build Coastguard Worker char* in = const_cast<char*>(utf8);
205*8d67ca89SAndroid Build Coastguard Worker size_t in_bytes = strlen(in);
206*8d67ca89SAndroid Build Coastguard Worker
207*8d67ca89SAndroid Build Coastguard Worker char* out = buf;
208*8d67ca89SAndroid Build Coastguard Worker size_t out_bytes = sizeof(buf);
209*8d67ca89SAndroid Build Coastguard Worker
210*8d67ca89SAndroid Build Coastguard Worker // The second input byte is just the start of a character, and we don't have any more bytes.
211*8d67ca89SAndroid Build Coastguard Worker errno = 0;
212*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(static_cast<size_t>(-1), iconv(c, &in, &in_bytes, &out, &out_bytes));
213*8d67ca89SAndroid Build Coastguard Worker EXPECT_ERRNO(EINVAL);
214*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ('\xd9', *in); // *in is left pointing to the start of the incomplete sequence.
215*8d67ca89SAndroid Build Coastguard Worker
216*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ('a', buf[0]);
217*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0, buf[1]);
218*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(1U, in_bytes);
219*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(sizeof(buf) - 1, out_bytes);
220*8d67ca89SAndroid Build Coastguard Worker
221*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(0, iconv_close(c));
222*8d67ca89SAndroid Build Coastguard Worker }
223*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_E2BIG)224*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_E2BIG) {
225*8d67ca89SAndroid Build Coastguard Worker const char* utf8 = "abc";
226*8d67ca89SAndroid Build Coastguard Worker char buf[BUFSIZ] = {};
227*8d67ca89SAndroid Build Coastguard Worker
228*8d67ca89SAndroid Build Coastguard Worker iconv_t c = iconv_open("UTF-8", "UTF-8");
229*8d67ca89SAndroid Build Coastguard Worker ASSERT_NE(INVALID_ICONV_T, c);
230*8d67ca89SAndroid Build Coastguard Worker
231*8d67ca89SAndroid Build Coastguard Worker char* in = const_cast<char*>(utf8);
232*8d67ca89SAndroid Build Coastguard Worker size_t in_bytes = strlen(in);
233*8d67ca89SAndroid Build Coastguard Worker
234*8d67ca89SAndroid Build Coastguard Worker char* out = buf;
235*8d67ca89SAndroid Build Coastguard Worker size_t out_bytes = 1;
236*8d67ca89SAndroid Build Coastguard Worker
237*8d67ca89SAndroid Build Coastguard Worker // We need three bytes, so one isn't enough (but we will make progress).
238*8d67ca89SAndroid Build Coastguard Worker out_bytes = 1;
239*8d67ca89SAndroid Build Coastguard Worker errno = 0;
240*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(static_cast<size_t>(-1), iconv(c, &in, &in_bytes, &out, &out_bytes));
241*8d67ca89SAndroid Build Coastguard Worker EXPECT_ERRNO(E2BIG);
242*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(2U, in_bytes);
243*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0U, out_bytes);
244*8d67ca89SAndroid Build Coastguard Worker
245*8d67ca89SAndroid Build Coastguard Worker // Two bytes left, so zero isn't enough (and we can't even make progress).
246*8d67ca89SAndroid Build Coastguard Worker out_bytes = 0;
247*8d67ca89SAndroid Build Coastguard Worker errno = 0;
248*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(static_cast<size_t>(-1), iconv(c, &in, &in_bytes, &out, &out_bytes));
249*8d67ca89SAndroid Build Coastguard Worker EXPECT_ERRNO(E2BIG);
250*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(2U, in_bytes);
251*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0U, out_bytes);
252*8d67ca89SAndroid Build Coastguard Worker
253*8d67ca89SAndroid Build Coastguard Worker // Two bytes left, so one isn't enough (but we will make progress).
254*8d67ca89SAndroid Build Coastguard Worker out_bytes = 1;
255*8d67ca89SAndroid Build Coastguard Worker errno = 0;
256*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(static_cast<size_t>(-1), iconv(c, &in, &in_bytes, &out, &out_bytes));
257*8d67ca89SAndroid Build Coastguard Worker EXPECT_ERRNO(E2BIG);
258*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(1U, in_bytes);
259*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0U, out_bytes);
260*8d67ca89SAndroid Build Coastguard Worker
261*8d67ca89SAndroid Build Coastguard Worker // One byte left, so one byte is now enough.
262*8d67ca89SAndroid Build Coastguard Worker out_bytes = 1;
263*8d67ca89SAndroid Build Coastguard Worker errno = 0;
264*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0U, iconv(c, &in, &in_bytes, &out, &out_bytes));
265*8d67ca89SAndroid Build Coastguard Worker EXPECT_ERRNO(0);
266*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0U, in_bytes);
267*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0U, out_bytes);
268*8d67ca89SAndroid Build Coastguard Worker
269*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ('a', buf[0]);
270*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ('b', buf[1]);
271*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ('c', buf[2]);
272*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0, buf[3]);
273*8d67ca89SAndroid Build Coastguard Worker
274*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(0, iconv_close(c));
275*8d67ca89SAndroid Build Coastguard Worker }
276*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_invalid_converter_EBADF)277*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_invalid_converter_EBADF) {
278*8d67ca89SAndroid Build Coastguard Worker char* in = nullptr;
279*8d67ca89SAndroid Build Coastguard Worker char* out = nullptr;
280*8d67ca89SAndroid Build Coastguard Worker size_t in_bytes = 0;
281*8d67ca89SAndroid Build Coastguard Worker size_t out_bytes = 0;
282*8d67ca89SAndroid Build Coastguard Worker errno = 0;
283*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(static_cast<size_t>(-1), iconv(INVALID_ICONV_T, &in, &in_bytes, &out, &out_bytes));
284*8d67ca89SAndroid Build Coastguard Worker ASSERT_ERRNO(EBADF);
285*8d67ca89SAndroid Build Coastguard Worker }
286*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_close_invalid_converter_EBADF)287*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_close_invalid_converter_EBADF) {
288*8d67ca89SAndroid Build Coastguard Worker errno = 0;
289*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(-1, iconv_close(INVALID_ICONV_T));
290*8d67ca89SAndroid Build Coastguard Worker ASSERT_ERRNO(EBADF);
291*8d67ca89SAndroid Build Coastguard Worker }
292*8d67ca89SAndroid Build Coastguard Worker
RoundTrip(const char * dst_enc,const char * expected_bytes,size_t n)293*8d67ca89SAndroid Build Coastguard Worker static void RoundTrip(const char* dst_enc, const char* expected_bytes, size_t n) {
294*8d67ca89SAndroid Build Coastguard Worker // Examples from https://en.wikipedia.org/wiki/UTF-16.
295*8d67ca89SAndroid Build Coastguard Worker const char* utf8 = "$€"; // U+0024, U+20AC, U+10437.
296*8d67ca89SAndroid Build Coastguard Worker
297*8d67ca89SAndroid Build Coastguard Worker iconv_t c = iconv_open(dst_enc, "UTF-8");
298*8d67ca89SAndroid Build Coastguard Worker ASSERT_NE(INVALID_ICONV_T, c) << dst_enc;
299*8d67ca89SAndroid Build Coastguard Worker
300*8d67ca89SAndroid Build Coastguard Worker char* in = const_cast<char*>(utf8);
301*8d67ca89SAndroid Build Coastguard Worker size_t in_bytes = strlen(utf8);
302*8d67ca89SAndroid Build Coastguard Worker char buf[BUFSIZ] = {};
303*8d67ca89SAndroid Build Coastguard Worker char* out = buf;
304*8d67ca89SAndroid Build Coastguard Worker size_t out_bytes = sizeof(buf);
305*8d67ca89SAndroid Build Coastguard Worker size_t replacement_count = iconv(c, &in, &in_bytes, &out, &out_bytes);
306*8d67ca89SAndroid Build Coastguard Worker
307*8d67ca89SAndroid Build Coastguard Worker // Check we got the bytes we were expecting.
308*8d67ca89SAndroid Build Coastguard Worker for (size_t i = 0; i < n; ++i) {
309*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(expected_bytes[i], buf[i]) << i << ' '<< dst_enc;
310*8d67ca89SAndroid Build Coastguard Worker }
311*8d67ca89SAndroid Build Coastguard Worker
312*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(0, iconv_close(c));
313*8d67ca89SAndroid Build Coastguard Worker
314*8d67ca89SAndroid Build Coastguard Worker // We can't round-trip if there were replacements.
315*8d67ca89SAndroid Build Coastguard Worker if (strstr(dst_enc, "ascii")) {
316*8d67ca89SAndroid Build Coastguard Worker GTEST_LOG_(INFO) << "can't round-trip " << dst_enc << "\n";
317*8d67ca89SAndroid Build Coastguard Worker return;
318*8d67ca89SAndroid Build Coastguard Worker }
319*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(0U, replacement_count);
320*8d67ca89SAndroid Build Coastguard Worker
321*8d67ca89SAndroid Build Coastguard Worker c = iconv_open("UTF-8", dst_enc);
322*8d67ca89SAndroid Build Coastguard Worker ASSERT_NE(INVALID_ICONV_T, c) << dst_enc;
323*8d67ca89SAndroid Build Coastguard Worker
324*8d67ca89SAndroid Build Coastguard Worker in = buf;
325*8d67ca89SAndroid Build Coastguard Worker in_bytes = n;
326*8d67ca89SAndroid Build Coastguard Worker char buf2[BUFSIZ] = {};
327*8d67ca89SAndroid Build Coastguard Worker out = buf2;
328*8d67ca89SAndroid Build Coastguard Worker out_bytes = sizeof(buf2);
329*8d67ca89SAndroid Build Coastguard Worker iconv(c, &in, &in_bytes, &out, &out_bytes);
330*8d67ca89SAndroid Build Coastguard Worker
331*8d67ca89SAndroid Build Coastguard Worker ASSERT_STREQ(utf8, buf2) << dst_enc;
332*8d67ca89SAndroid Build Coastguard Worker
333*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(0, iconv_close(c));
334*8d67ca89SAndroid Build Coastguard Worker }
335*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_round_trip_ascii)336*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_round_trip_ascii) {
337*8d67ca89SAndroid Build Coastguard Worker RoundTrip("ascii//TRANSLIT", "$??", 3);
338*8d67ca89SAndroid Build Coastguard Worker }
339*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_round_trip_utf8)340*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_round_trip_utf8) {
341*8d67ca89SAndroid Build Coastguard Worker RoundTrip("utf8", "\x24\xe2\x82\xac\xf0\x90\x90\xb7", 8);
342*8d67ca89SAndroid Build Coastguard Worker }
343*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_round_trip_utf16be)344*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_round_trip_utf16be) {
345*8d67ca89SAndroid Build Coastguard Worker RoundTrip("utf16be", "\x00\x24" "\x20\xac" "\xd8\x01\xdc\x37", 8);
346*8d67ca89SAndroid Build Coastguard Worker }
347*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_round_trip_utf16le)348*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_round_trip_utf16le) {
349*8d67ca89SAndroid Build Coastguard Worker RoundTrip("utf16le", "\x24\x00" "\xac\x20" "\x01\xd8\x37\xdc", 8);
350*8d67ca89SAndroid Build Coastguard Worker }
351*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_round_trip_utf32be)352*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_round_trip_utf32be) {
353*8d67ca89SAndroid Build Coastguard Worker RoundTrip("utf32be", "\x00\x00\x00\x24" "\x00\x00\x20\xac" "\x00\x01\x04\x37", 12);
354*8d67ca89SAndroid Build Coastguard Worker }
355*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_round_trip_utf32le)356*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_round_trip_utf32le) {
357*8d67ca89SAndroid Build Coastguard Worker RoundTrip("utf32le", "\x24\x00\x00\x00" "\xac\x20\x00\x00" "\x37\x04\x01\x00", 12);
358*8d67ca89SAndroid Build Coastguard Worker }
359*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_round_trip_wchar_t)360*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_round_trip_wchar_t) {
361*8d67ca89SAndroid Build Coastguard Worker RoundTrip("wchar_t", "\x24\x00\x00\x00" "\xac\x20\x00\x00" "\x37\x04\x01\x00", 12);
362*8d67ca89SAndroid Build Coastguard Worker }
363*8d67ca89SAndroid Build Coastguard Worker
Check(int expected_errno,const char * src_enc,const char * src,size_t n)364*8d67ca89SAndroid Build Coastguard Worker static void Check(int expected_errno, const char* src_enc, const char* src, size_t n) {
365*8d67ca89SAndroid Build Coastguard Worker iconv_t c = iconv_open("wchar_t", src_enc);
366*8d67ca89SAndroid Build Coastguard Worker char* in = const_cast<char*>(src);
367*8d67ca89SAndroid Build Coastguard Worker size_t in_bytes = n;
368*8d67ca89SAndroid Build Coastguard Worker wchar_t out_buf[16];
369*8d67ca89SAndroid Build Coastguard Worker size_t out_bytes = sizeof(out_buf);
370*8d67ca89SAndroid Build Coastguard Worker char* out = reinterpret_cast<char*>(out_buf);
371*8d67ca89SAndroid Build Coastguard Worker errno = 0;
372*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(static_cast<size_t>(-1), iconv(c, &in, &in_bytes, &out, &out_bytes));
373*8d67ca89SAndroid Build Coastguard Worker EXPECT_ERRNO(expected_errno);
374*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0, iconv_close(c));
375*8d67ca89SAndroid Build Coastguard Worker }
376*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_EILSEQ_ascii)377*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_EILSEQ_ascii) {
378*8d67ca89SAndroid Build Coastguard Worker Check(EILSEQ, "ASCII", "\xac", 1); // > 0x7f, so not ASCII.
379*8d67ca89SAndroid Build Coastguard Worker }
380*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_EILSEQ_utf8_initial)381*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_EILSEQ_utf8_initial) {
382*8d67ca89SAndroid Build Coastguard Worker Check(EILSEQ, "utf8", "\x82", 1); // Invalid initial byte.
383*8d67ca89SAndroid Build Coastguard Worker }
384*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_EILSEQ_utf8_non_initial)385*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_EILSEQ_utf8_non_initial) {
386*8d67ca89SAndroid Build Coastguard Worker Check(EILSEQ, "utf8", "\xe2\xe2\x82", 3); // Invalid second byte.
387*8d67ca89SAndroid Build Coastguard Worker }
388*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_EILSEQ_utf16be_low_surrogate_first)389*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_EILSEQ_utf16be_low_surrogate_first) {
390*8d67ca89SAndroid Build Coastguard Worker Check(EILSEQ, "utf16be", "\xdc\x37" "\xd8\x01", 4);
391*8d67ca89SAndroid Build Coastguard Worker }
392*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_EILSEQ_utf16le_low_surrogate_first)393*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_EILSEQ_utf16le_low_surrogate_first) {
394*8d67ca89SAndroid Build Coastguard Worker Check(EILSEQ, "utf16le", "\x37\xdc" "\x01\xd8", 4);
395*8d67ca89SAndroid Build Coastguard Worker }
396*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_EINVAL_utf8_short)397*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_EINVAL_utf8_short) {
398*8d67ca89SAndroid Build Coastguard Worker Check(EINVAL, "utf8", "\xe2\x82", 2); // Missing final byte of 3-byte sequence.
399*8d67ca89SAndroid Build Coastguard Worker }
400*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_EINVAL_utf16be_short)401*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_EINVAL_utf16be_short) {
402*8d67ca89SAndroid Build Coastguard Worker Check(EINVAL, "utf16be", "\x00", 1); // Missing second byte.
403*8d67ca89SAndroid Build Coastguard Worker }
404*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_EINVAL_utf16be_missing_low_surrogate)405*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_EINVAL_utf16be_missing_low_surrogate) {
406*8d67ca89SAndroid Build Coastguard Worker Check(EINVAL, "utf16be", "\xd8\x01", 2);
407*8d67ca89SAndroid Build Coastguard Worker }
408*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_EINVAL_utf16be_half_low_surrogate)409*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_EINVAL_utf16be_half_low_surrogate) {
410*8d67ca89SAndroid Build Coastguard Worker Check(EINVAL, "utf16be", "\xd8\x01\xdc", 3);
411*8d67ca89SAndroid Build Coastguard Worker }
412*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_EINVAL_utf16le_short)413*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_EINVAL_utf16le_short) {
414*8d67ca89SAndroid Build Coastguard Worker Check(EINVAL, "utf16le", "\x24", 1); // Missing second byte.
415*8d67ca89SAndroid Build Coastguard Worker }
416*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_EINVAL_utf16le_missing_low_surrogate)417*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_EINVAL_utf16le_missing_low_surrogate) {
418*8d67ca89SAndroid Build Coastguard Worker Check(EINVAL, "utf16le", "\x01\xd8", 2);
419*8d67ca89SAndroid Build Coastguard Worker }
420*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_EINVAL_utf16le_half_low_surrogate)421*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_EINVAL_utf16le_half_low_surrogate) {
422*8d67ca89SAndroid Build Coastguard Worker Check(EINVAL, "utf16le", "\x01\xd8\x37", 3);
423*8d67ca89SAndroid Build Coastguard Worker }
424*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_EINVAL_utf32be_short)425*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_EINVAL_utf32be_short) {
426*8d67ca89SAndroid Build Coastguard Worker Check(EINVAL, "utf32be", "\x00\x00\x00", 3); // Missing final byte.
427*8d67ca89SAndroid Build Coastguard Worker }
428*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_EINVAL_utf32le_short)429*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_EINVAL_utf32le_short) {
430*8d67ca89SAndroid Build Coastguard Worker Check(EINVAL, "utf32le", "\x24\x00\x00", 3); // Missing final byte.
431*8d67ca89SAndroid Build Coastguard Worker }
432*8d67ca89SAndroid Build Coastguard Worker
TEST(iconv,iconv_initial_shift_state)433*8d67ca89SAndroid Build Coastguard Worker TEST(iconv, iconv_initial_shift_state) {
434*8d67ca89SAndroid Build Coastguard Worker // POSIX: "For state-dependent encodings, the conversion descriptor
435*8d67ca89SAndroid Build Coastguard Worker // cd is placed into its initial shift state by a call for which inbuf
436*8d67ca89SAndroid Build Coastguard Worker // is a null pointer, or for which inbuf points to a null pointer."
437*8d67ca89SAndroid Build Coastguard Worker iconv_t c = iconv_open("utf8", "utf8");
438*8d67ca89SAndroid Build Coastguard Worker char* in = nullptr;
439*8d67ca89SAndroid Build Coastguard Worker size_t in_bytes = 0;
440*8d67ca89SAndroid Build Coastguard Worker wchar_t out_buf[16];
441*8d67ca89SAndroid Build Coastguard Worker size_t out_bytes = sizeof(out_buf);
442*8d67ca89SAndroid Build Coastguard Worker char* out = reinterpret_cast<char*>(out_buf);
443*8d67ca89SAndroid Build Coastguard Worker
444*8d67ca89SAndroid Build Coastguard Worker // Points to a null pointer...
445*8d67ca89SAndroid Build Coastguard Worker errno = 0;
446*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(static_cast<size_t>(0), iconv(c, &in, &in_bytes, &out, &out_bytes));
447*8d67ca89SAndroid Build Coastguard Worker EXPECT_ERRNO(0);
448*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(sizeof(out_buf), out_bytes);
449*8d67ca89SAndroid Build Coastguard Worker
450*8d67ca89SAndroid Build Coastguard Worker // Is a null pointer...
451*8d67ca89SAndroid Build Coastguard Worker errno = 0;
452*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(static_cast<size_t>(0), iconv(c, nullptr, &in_bytes, &out, &out_bytes));
453*8d67ca89SAndroid Build Coastguard Worker EXPECT_ERRNO(0);
454*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(sizeof(out_buf), out_bytes);
455*8d67ca89SAndroid Build Coastguard Worker
456*8d67ca89SAndroid Build Coastguard Worker // Is a null pointer and so is in_bytes. This isn't specified by POSIX, but
457*8d67ca89SAndroid Build Coastguard Worker // glibc and macOS both allow that, where Android historically didn't.
458*8d67ca89SAndroid Build Coastguard Worker // https://issuetracker.google.com/180598400
459*8d67ca89SAndroid Build Coastguard Worker errno = 0;
460*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(static_cast<size_t>(0), iconv(c, nullptr, nullptr, &out, &out_bytes));
461*8d67ca89SAndroid Build Coastguard Worker EXPECT_ERRNO(0);
462*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(sizeof(out_buf), out_bytes);
463*8d67ca89SAndroid Build Coastguard Worker
464*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0, iconv_close(c));
465*8d67ca89SAndroid Build Coastguard Worker }
466