1 // Copyright (C) 2017-2021 Free Software Foundation, Inc.
2 //
3 // This file is part of the GNU ISO C++ Library.  This library is free
4 // software; you can redistribute it and/or modify it under the
5 // terms of the GNU General Public License as published by the
6 // Free Software Foundation; either version 3, or (at your option)
7 // any later version.
8 
9 // This library 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 along
15 // with this library; see the file COPYING3.  If not see
16 // <http://www.gnu.org/licenses/>.
17 
18 // { dg-do run { target c++11 } }
19 
20 #include <locale>
21 #include <codecvt>
22 #include <testsuite_hooks.h>
23 
24 // PR libstdc++/79980
25 
mode(std::codecvt_mode m)26 constexpr std::codecvt_mode mode(std::codecvt_mode m)
27 { return static_cast<std::codecvt_mode>(m | std::consume_header); }
28 
29 template<typename WCh, unsigned long Max = 0x10FFFF,
30 	 std::codecvt_mode Mode = std::consume_header>
31   using Conv
32     = std::wstring_convert<std::codecvt_utf16<WCh, Max, mode(Mode)>, WCh>;
33 
34 void
test01()35 test01()
36 {
37   const char src[] = "\xFE\xFF\xAB\xCD";
38   Conv<char16_t> conv;
39   auto dst = conv.from_bytes(src, src+4);
40   VERIFY( dst[0] == 0xabcd );
41 }
42 
43 void
test02()44 test02()
45 {
46   const char src[] = "\xFF\xFE\xAB\xCD";
47   Conv<char16_t> conv;
48   auto dst = conv.from_bytes(src, src+4);
49   VERIFY( dst[0] == 0xcdab );
50 }
51 
52 void
test03()53 test03()
54 {
55   const char src[] = "\xFE\xFF\xAB\xCD";
56   Conv<char16_t, 0x10FFFF, std::little_endian> conv;
57   auto dst = conv.from_bytes(src, src+4);
58   VERIFY( dst[0] == 0xabcd );
59 }
60 
61 void
test04()62 test04()
63 {
64   const char src[] = "\xFF\xFE\xAB\xCD";
65   Conv<char16_t, 0x10FFFF, std::little_endian> conv;
66   auto dst = conv.from_bytes(src, src+4);
67   VERIFY( dst[0] == 0xcdab );
68 }
69 
70 void
test05()71 test05()
72 {
73   const char src[] = "\0\x61\xAB\xCD"; // character greater than 0x00FF
74   Conv<char16_t, 0xFF> conv("to_bytes failed", u"from_bytes failed");
75   std::u16string result = conv.from_bytes(src, src+4);
76   VERIFY( result == u"from_bytes failed" );
77   VERIFY( conv.converted() == 2 );
78 }
79 
80 void
test06()81 test06()
82 {
83   const char src[] = "\0\x61\xAB\xCD";
84   Conv<char16_t> conv("to_bytes failed", u"from_bytes failed");
85   std::u16string result = conv.from_bytes(src, src+3); // incomplete character
86   VERIFY( result == u"from_bytes failed" );
87   VERIFY( conv.converted() == 2 );
88 }
89 
90 void
test07()91 test07()
92 {
93   Conv<char16_t> conv("to_bytes failed", u"from_bytes failed");
94   // ucs2 to utf-16 conversion should fail on invalid ucs2 input:
95   std::u16string utf16 = u"1234\U00001111\U0001ffff";
96   auto out = conv.to_bytes(utf16);
97   VERIFY( out == "to_bytes failed" );
98   VERIFY( conv.converted() == 5 );
99 
100   // And should also fail on incomplete surrogate pair (not return partial):
101   out = conv.to_bytes(utf16.substr(0, utf16.size()-1));
102   VERIFY( out == "to_bytes failed" );
103   VERIFY( conv.converted() == 5 );
104 }
105 
106 void
test08()107 test08()
108 {
109   // Read/write UTF-16 code units from data not correctly aligned for char16_t
110   Conv<char16_t, 0x10FFFF, std::generate_header> conv;
111   const char src[] = "-\xFE\xFF\0\x61\xAB\xCD";
112   auto out = conv.from_bytes(src + 1, src + 7);
113   VERIFY( out[0] == 0x0061 );
114   VERIFY( out[1] == 0xabcd );
115   auto bytes = conv.to_bytes(out);
116   VERIFY( bytes == std::string(src + 1, 6) );
117 }
118 
119 void
test09()120 test09()
121 {
122   // Read/write UTF-16 code units from data not correctly aligned for char16_t
123   Conv<char32_t, 0x10FFFF, std::generate_header> conv;
124   const char src[] = "-\xFE\xFF\xD8\x08\xDF\x45";
125   auto out = conv.from_bytes(src + 1, src + 7);
126   VERIFY( out == U"\U00012345" );
127   auto bytes = conv.to_bytes(out);
128   VERIFY( bytes == std::string(src + 1, 6) );
129 }
130 
main()131 int main()
132 {
133   test01();
134   test02();
135   test03();
136   test04();
137   test05();
138   test06();
139   test07();
140   test08();
141   test09();
142 }
143