// Copyright (C) 2017-2020 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 3, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License along // with this library; see the file COPYING3. If not see // . // { dg-do run { target c++11 } } #include #include #include using std::codecvt_base; using std::codecvt_mode; using std::codecvt_utf16; using std::wstring_convert; using std::mbstate_t; constexpr codecvt_mode operator|(codecvt_mode m1, codecvt_mode m2) { using underlying = std::underlying_type::type; return static_cast(static_cast(m1) | m2); } // Read/write UTF-16 code units from data not correctly aligned for char16_t void test01() { mbstate_t st; constexpr codecvt_mode m = std::consume_header|std::generate_header; codecvt_utf16 conv; const char src[] = "-\xFE\xFF\0\x61\xAB\xCD"; const char* const src_end = src + 7; int len = conv.length(st, src + 1, src_end, 1); VERIFY( len == 4 ); len = conv.length(st, src + 1, src_end, 2); VERIFY( len == 6 ); char16_t dst[2]; char16_t* const dst_end = dst + 2; char16_t* dst_next; const char* src_cnext; auto res = conv.in(st, src + 1, src_end, src_cnext, dst, dst_end, dst_next); VERIFY( res == codecvt_base::ok ); VERIFY( dst[0] == 0x0061 ); VERIFY( dst[1] == 0xabcd ); VERIFY( src_cnext == src_end ); VERIFY( dst_next == dst_end ); char out[sizeof(src)] = { src[0] }; char* const out_end = out + 7; char* out_next; const char16_t* dst_cnext; res = conv.out(st, dst, dst_end, dst_cnext, out + 1, out_end, out_next); VERIFY( res == codecvt_base::ok ); VERIFY( out_next == out_end ); VERIFY( dst_cnext == dst_end ); VERIFY( out[1] == src[1] ); VERIFY( out[2] == src[2] ); VERIFY( out[3] == src[3] ); VERIFY( out[4] == src[4] ); VERIFY( out[5] == src[5] ); VERIFY( out[6] == src[6] ); codecvt_utf16 conv_le; len = conv_le.length(st, src + 1, src_end, 1); VERIFY( len == 4 ); len = conv_le.length(st, src + 1, src_end, 2); VERIFY( len == 6 ); res = conv_le.in(st, src + 1, src_end, src_cnext, dst, dst_end, dst_next); VERIFY( res == codecvt_base::ok ); VERIFY( dst[0] == 0x0061 ); VERIFY( dst[1] == 0xabcd ); VERIFY( src_cnext == src_end ); VERIFY( dst_next == dst_end ); res = conv_le.out(st, dst, dst_end, dst_cnext, out + 1, out_end, out_next); VERIFY( res == codecvt_base::ok ); VERIFY( out_next == out_end ); VERIFY( dst_cnext == dst_end ); VERIFY( out[1] == src[2] ); VERIFY( out[2] == src[1] ); VERIFY( out[3] == src[4] ); VERIFY( out[4] == src[3] ); VERIFY( out[5] == src[6] ); VERIFY( out[6] == src[5] ); } void test02() { mbstate_t st; constexpr codecvt_mode m = std::consume_header|std::generate_header; codecvt_utf16 conv; const char src[] = "-\xFE\xFF\0\x61\xAB\xCD\xD8\x08\xDF\x45"; const char* const src_end = src + 11; int len = conv.length(st, src + 1, src_end, 1); VERIFY( len == 4 ); len = conv.length(st, src + 1, src_end, 2); VERIFY( len == 6 ); len = conv.length(st, src + 1, src_end, -1ul); VERIFY( len == 10 ); char32_t dst[3]; char32_t* const dst_end = dst + 3; char32_t* dst_next; const char* src_cnext; auto res = conv.in(st, src + 1, src_end, src_cnext, dst, dst_end, dst_next); VERIFY( res == codecvt_base::ok ); VERIFY( dst[0] == 0x0061 ); VERIFY( dst[1] == 0xabcd ); VERIFY( dst[2] == 0x012345 ); VERIFY( src_cnext == src_end ); VERIFY( dst_next == dst_end ); char out[sizeof(src)] = { src[0] }; char* const out_end = out + 11; char* out_next; const char32_t* dst_cnext; res = conv.out(st, dst, dst_end, dst_cnext, out + 1, out_end, out_next); VERIFY( res == codecvt_base::ok ); VERIFY( out_next == out_end ); VERIFY( dst_cnext == dst_end ); VERIFY( out[1] == src[1] ); VERIFY( out[2] == src[2] ); VERIFY( out[3] == src[3] ); VERIFY( out[4] == src[4] ); VERIFY( out[5] == src[5] ); VERIFY( out[6] == src[6] ); VERIFY( out[7] == src[7] ); VERIFY( out[8] == src[8] ); VERIFY( out[9] == src[9] ); VERIFY( out[10] == src[10] ); codecvt_utf16 conv_le; len = conv_le.length(st, src + 1, src_end, 1); VERIFY( len == 4 ); len = conv_le.length(st, src + 1, src_end, 2); VERIFY( len == 6 ); len = conv.length(st, src + 1, src_end, -1ul); VERIFY( len == 10 ); res = conv_le.in(st, src + 1, src_end, src_cnext, dst, dst_end, dst_next); VERIFY( res == codecvt_base::ok ); VERIFY( dst[0] == 0x0061 ); VERIFY( dst[1] == 0xabcd ); VERIFY( dst[2] == 0x012345 ); VERIFY( src_cnext == src_end ); VERIFY( dst_next == dst_end ); res = conv_le.out(st, dst, dst_end, dst_cnext, out + 1, out_end, out_next); VERIFY( res == codecvt_base::ok ); VERIFY( out_next == out_end ); VERIFY( dst_cnext == dst_end ); VERIFY( out[1] == src[2] ); VERIFY( out[2] == src[1] ); VERIFY( out[3] == src[4] ); VERIFY( out[4] == src[3] ); VERIFY( out[5] == src[6] ); VERIFY( out[6] == src[5] ); VERIFY( out[7] == src[8] ); VERIFY( out[8] == src[7] ); VERIFY( out[9] == src[10] ); VERIFY( out[10] == src[9] ); } void test03() { #ifdef _GLIBCXX_USE_WCHAR_T mbstate_t st; constexpr codecvt_mode m = std::consume_header|std::generate_header; codecvt_utf16 conv; const char src[] = "-\xFE\xFF\0\x61\xAB\xCD\xD8\x08\xDF\x45"; const size_t in_len = sizeof(wchar_t) == 4 ? 11 : 7; const size_t out_len = sizeof(wchar_t) == 4 ? 3 : 2; const char* const src_end = src + in_len; int len = conv.length(st, src + 1, src_end, 1); VERIFY( len == 4 ); len = conv.length(st, src + 1, src_end, 2); VERIFY( len == 6 ); if (sizeof(wchar_t) == 4) { len = conv.length(st, src + 1, src_end, -1ul); VERIFY( len == 10 ); } wchar_t dst[out_len]; wchar_t* const dst_end = dst + out_len; wchar_t* dst_next; const char* src_cnext; auto res = conv.in(st, src + 1, src_end, src_cnext, dst, dst_end, dst_next); VERIFY( res == codecvt_base::ok ); VERIFY( dst[0] == 0x0061 ); VERIFY( dst[1] == 0xabcd ); if (sizeof(wchar_t) == 4) VERIFY( dst[2] == 0x012345 ); VERIFY( src_cnext == src_end ); VERIFY( dst_next == dst_end ); char out[sizeof(src)] = { src[0] }; char* const out_end = out + in_len; char* out_next; const wchar_t* dst_cnext; res = conv.out(st, dst, dst_end, dst_cnext, out + 1, out_end, out_next); VERIFY( res == codecvt_base::ok ); VERIFY( out_next == out_end ); VERIFY( dst_cnext == dst_end ); VERIFY( out[1] == src[1] ); VERIFY( out[2] == src[2] ); VERIFY( out[3] == src[3] ); VERIFY( out[4] == src[4] ); VERIFY( out[5] == src[5] ); VERIFY( out[6] == src[6] ); if (sizeof(wchar_t) == 4) { VERIFY( out[7] == src[7] ); VERIFY( out[8] == src[8] ); VERIFY( out[9] == src[9] ); VERIFY( out[10] == src[10] ); } codecvt_utf16 conv_le; len = conv_le.length(st, src + 1, src_end, 1); VERIFY( len == 4 ); len = conv_le.length(st, src + 1, src_end, 2); VERIFY( len == 6 ); if (sizeof(wchar_t) == 4) { len = conv.length(st, src + 1, src_end, -1ul); VERIFY( len == 10 ); } res = conv_le.in(st, src + 1, src_end, src_cnext, dst, dst_end, dst_next); VERIFY( res == codecvt_base::ok ); VERIFY( dst[0] == 0x0061 ); VERIFY( dst[1] == 0xabcd ); if (sizeof(wchar_t) == 4) VERIFY( dst[2] == 0x012345 ); VERIFY( src_cnext == src_end ); VERIFY( dst_next == dst_end ); res = conv_le.out(st, dst, dst_end, dst_cnext, out + 1, out_end, out_next); VERIFY( res == codecvt_base::ok ); VERIFY( out_next == out_end ); VERIFY( dst_cnext == dst_end ); VERIFY( out[1] == src[2] ); VERIFY( out[2] == src[1] ); VERIFY( out[3] == src[4] ); VERIFY( out[4] == src[3] ); VERIFY( out[5] == src[6] ); VERIFY( out[6] == src[5] ); if (sizeof(wchar_t) == 4) { VERIFY( out[7] == src[8] ); VERIFY( out[8] == src[7] ); VERIFY( out[9] == src[10] ); VERIFY( out[10] == src[9] ); } #endif } int main() { test01(); test02(); test03(); }