1 #include <string>
2
3 #if !defined (STLPORT) || !defined (_STLP_USE_NO_IOSTREAMS)
4 # include <fstream>
5 # include <locale>
6 # include <stdexcept>
7 # include <cstdio> // for WEOF
8
9 # include "cppunit/cppunit_proxy.h"
10
11 # if !defined (STLPORT) || defined(_STLP_USE_NAMESPACES)
12 using namespace std;
13 # endif
14
15 //
16 // TestCase class
17 //
18 class CodecvtTest : public CPPUNIT_NS::TestCase
19 {
20 CPPUNIT_TEST_SUITE(CodecvtTest);
21 #if defined (STLPORT) && defined (_STLP_NO_MEMBER_TEMPLATES)
22 CPPUNIT_IGNORE;
23 #endif
24 CPPUNIT_TEST(variable_encoding);
25 CPPUNIT_STOP_IGNORE;
26 #if defined (STLPORT) && (defined (_STLP_NO_WCHAR_T) || !defined (_STLP_USE_EXCEPTIONS))
27 CPPUNIT_IGNORE;
28 #endif
29 CPPUNIT_TEST(in_out_test);
30 CPPUNIT_TEST(length_test);
31 CPPUNIT_TEST(imbue_while_reading);
32 CPPUNIT_TEST(special_encodings);
33 CPPUNIT_TEST_SUITE_END();
34
35 protected:
36 void variable_encoding();
37 void in_out_test();
38 void length_test();
39 void imbue_while_reading();
40 void special_encodings();
41 };
42
43 CPPUNIT_TEST_SUITE_REGISTRATION(CodecvtTest);
44
45 #if defined (STLPORT)
46 # define __NO_THROW _STLP_NOTHROW
47 #else
48 # define __NO_THROW throw()
49 #endif
50
51
52 /* Codecvt facet eating some characters from the external buffer.
53 * Transform '01' in 'a'
54 */
55 struct eater_codecvt : public codecvt<char, char, mbstate_t> {
56 typedef codecvt<char,char,mbstate_t> base;
57
eater_codecvteater_codecvt58 explicit eater_codecvt(size_t refs = 0) : base(refs) {}
59
60 // primitive conversion
61 virtual base::result
do_ineater_codecvt62 do_in(mbstate_t& mb,
63 const char* ebegin, const char* eend, const char*& ecur,
64 char* ibegin, char* iend, char*& icur) const __NO_THROW {
65 char *state = (char*)&mb;
66 ecur = ebegin;
67 icur = ibegin;
68
69 while (ecur != eend) {
70 if (icur == iend)
71 return partial;
72 if (*ecur == '0' || *state == 1) {
73 if (*state != 1) {
74 ++ecur;
75 }
76 if (ecur == eend) {
77 *state = 1;
78 return ok;
79 }
80
81 if (*ecur == '1') {
82 *icur = 'a';
83 }
84 else {
85 *(icur++) = '0';
86 if (icur == iend) {
87 if (*state != 1) {
88 --ecur;
89 }
90 return partial;
91 }
92 *icur = *ecur;
93 }
94 }
95 else {
96 *icur = *ecur;
97 }
98
99 *state = 0;
100 ++icur;
101 ++ecur;
102 }
103
104 return ok;
105 }
106
107 // claim it's not a null-conversion
do_always_noconveater_codecvt108 virtual bool do_always_noconv() const __NO_THROW
109 { return false; }
110
111 // claim it doesn't have a fixed-length encoding
do_encodingeater_codecvt112 virtual int do_encoding() const __NO_THROW
113 { return 0; }
114
115 // implemented for consistency with do_in overload
do_lengtheater_codecvt116 virtual int do_length(mbstate_t &state,
117 const char *efrom, const char *eend, size_t m) const {
118 char *ibegin = new char[m];
119 const char *ecur = efrom;
120 char *icur = ibegin;
121 mbstate_t tmp = state;
122 do_in(tmp, efrom, eend, ecur, ibegin, ibegin + m, icur);
123 delete[] ibegin;
124 return ecur - efrom;
125 }
126
do_max_lengtheater_codecvt127 virtual int do_max_length() const __NO_THROW
128 { return 2; }
129
130 #ifdef __DMC__
131 static locale::id id;
132 #endif
133 };
134
135 #ifdef __DMC__
136 locale::id eater_codecvt::id;
137
_GetFacetId(const eater_codecvt *)138 locale::id& _GetFacetId(const eater_codecvt*)
139 { return eater_codecvt::id; }
140 #endif
141
142 /* Codecvt facet generating more characters than the ones read from the
143 * external buffer, transform '01' in 'abc'
144 * This kind of facet do not allow systematical positionning in the external
145 * buffer (tellg -> -1), when you just read a 'a' you are at an undefined
146 * external buffer position.
147 */
148 struct generator_codecvt : public codecvt<char, char, mbstate_t> {
149 typedef codecvt<char,char,mbstate_t> base;
150
generator_codecvtgenerator_codecvt151 explicit generator_codecvt(size_t refs = 0) : base(refs) {}
152
153 // primitive conversion
154 virtual base::result
do_ingenerator_codecvt155 do_in(mbstate_t& mb,
156 const char* ebegin, const char* eend, const char*& ecur,
157 char* ibegin, char* iend, char*& icur) const __NO_THROW {
158 //Access the mbstate information in a portable way:
159 char *state = (char*)&mb;
160 ecur = ebegin;
161 icur = ibegin;
162
163 if (icur == iend) return ok;
164
165 if (*state == 2) {
166 *(icur++) = 'b';
167 if (icur == iend) {
168 *state = 3;
169 return ok;
170 }
171 *(icur++) = 'c';
172 *state = 0;
173 }
174 else if (*state == 3) {
175 *(icur++) = 'c';
176 *state = 0;
177 }
178
179 while (ecur != eend) {
180 if (icur == iend)
181 return ok;
182 if (*ecur == '0' || *state == 1) {
183 if (*state != 1) {
184 ++ecur;
185 }
186 if (ecur == eend) {
187 *state = 1;
188 return partial;
189 }
190
191 if (*ecur == '1') {
192 *(icur++) = 'a';
193 if (icur == iend) {
194 *state = 2;
195 return ok;
196 }
197 *(icur++) = 'b';
198 if (icur == iend) {
199 *state = 3;
200 return ok;
201 }
202 *icur = 'c';
203 }
204 else {
205 *(icur++) = '0';
206 if (icur == iend) {
207 if (*state != 1) {
208 --ecur;
209 }
210 return ok;
211 }
212 *icur = *ecur;
213 }
214 }
215 else {
216 *icur = *ecur;
217 }
218
219 *state = 0;
220 ++icur;
221 ++ecur;
222 }
223
224 return ok;
225 }
226
227 // claim it's not a null-conversion
do_always_noconvgenerator_codecvt228 virtual bool do_always_noconv() const __NO_THROW
229 { return false; }
230
231 // claim it doesn't have a fixed-length encoding
do_encodinggenerator_codecvt232 virtual int do_encoding() const __NO_THROW
233 { return 0; }
234
235 // implemented for consistency with do_in overload
do_lengthgenerator_codecvt236 virtual int do_length(mbstate_t &mb,
237 const char *efrom, const char *eend, size_t m) const {
238 const char *state = (const char*)&mb;
239 int offset = 0;
240 if (*state == 2)
241 offset = 2;
242 else if (*state == 3)
243 offset = 1;
244
245 char *ibegin = new char[m + offset];
246 const char *ecur = efrom;
247 char *icur = ibegin;
248 mbstate_t tmpState = mb;
249 do_in(tmpState, efrom, eend, ecur, ibegin, ibegin + m + offset, icur);
250 /*
251 char *state = (char*)&tmpState;
252 if (*state != 0) {
253 if (*state == 1)
254 --ecur;
255 else if (*state == 2 || *state == 3) {
256 //Undefined position, we return -1:
257 ecur = efrom - 1;
258 }
259 }
260 else {
261 if (*((char*)&mb) != 0) {
262 //We take into account the character that hasn't been counted yet in
263 //the previous decoding step:
264 ecur++;
265 }
266 }
267 */
268 delete[] ibegin;
269 return (int)min((size_t)(ecur - efrom), m);
270 }
271
do_max_lengthgenerator_codecvt272 virtual int do_max_length() const __NO_THROW
273 { return 0; }
274 #ifdef __DMC__
275 static locale::id id;
276 #endif
277 };
278
279 #ifdef __DMC__
280 locale::id generator_codecvt::id;
281
_GetFacetId(const generator_codecvt *)282 locale::id& _GetFacetId(const generator_codecvt*)
283 { return generator_codecvt::id; }
284 #endif
285
286 //
287 // tests implementation
288 //
variable_encoding()289 void CodecvtTest::variable_encoding()
290 {
291 #if !defined (STLPORT) || !defined (_STLP_NO_MEMBER_TEMPLATES)
292 //We first generate the file used for test:
293 const char* fileName = "test_file.txt";
294 {
295 ofstream ostr(fileName);
296 //Maybe we simply do not have write access to repository
297 CPPUNIT_ASSERT( ostr.good() );
298 for (int i = 0; i < 2048; ++i) {
299 ostr << "0123456789";
300 }
301 CPPUNIT_ASSERT( ostr.good() );
302 }
303
304 {
305 ifstream istr(fileName);
306 CPPUNIT_ASSERT( istr.good() );
307 CPPUNIT_ASSERT( !istr.eof() );
308
309 eater_codecvt codec(1);
310 locale loc(locale::classic(), &codec);
311
312 istr.imbue(loc);
313 CPPUNIT_ASSERT( istr.good() );
314 CPPUNIT_ASSERT( (int)istr.tellg() == 0 );
315
316 int theoricalPos = 0;
317 do {
318 int c = istr.get();
319 if (char_traits<char>::eq_int_type(c, char_traits<char>::eof())) {
320 break;
321 }
322 ++theoricalPos;
323 if (c == 'a') {
324 ++theoricalPos;
325 }
326
327 CPPUNIT_ASSERT( (int)istr.tellg() == theoricalPos );
328 }
329 while (!istr.eof());
330
331 CPPUNIT_ASSERT( istr.eof() );
332 }
333
334 # if 0
335 /* This test is broken, not sure if it is really possible to get a position in
336 * a locale having a codecvt such as generator_codecvt. Maybe generator_codecvt
337 * is not a valid theorical example of codecvt implementation. */
338 {
339 ifstream istr(fileName);
340 CPPUNIT_ASSERT( istr.good() );
341 CPPUNIT_ASSERT( !istr.eof() );
342
343 generator_codecvt codec(1);
344 locale loc(locale::classic(), &codec);
345
346 istr.imbue(loc);
347 CPPUNIT_ASSERT( istr.good() );
348 CPPUNIT_ASSERT( (int)istr.tellg() == 0 );
349
350 int theoricalPos = 0;
351 int theoricalTellg;
352 do {
353 char c = istr.get();
354 if (c == char_traits<char>::eof()) {
355 break;
356 }
357 switch (c) {
358 case 'a':
359 case 'b':
360 theoricalTellg = -1;
361 break;
362 case 'c':
363 ++theoricalPos;
364 default:
365 ++theoricalPos;
366 theoricalTellg = theoricalPos;
367 break;
368 }
369
370 if ((int)istr.tellg() != theoricalTellg) {
371 CPPUNIT_ASSERT( (int)istr.tellg() == theoricalTellg );
372 }
373 }
374 while (!istr.eof());
375
376 CPPUNIT_ASSERT( istr.eof() );
377 }
378 # endif
379 #endif
380 }
381
in_out_test()382 void CodecvtTest::in_out_test()
383 {
384 #if !defined (STLPORT) || !(defined (_STLP_NO_WCHAR_T) || !defined (_STLP_USE_EXCEPTIONS))
385 try {
386 locale loc("");
387
388 typedef codecvt<wchar_t, char, mbstate_t> cdecvt_type;
389 if (has_facet<cdecvt_type>(loc)) {
390 cdecvt_type const& cdect = use_facet<cdecvt_type>(loc);
391 {
392 cdecvt_type::state_type state;
393 memset(&state, 0, sizeof(cdecvt_type::state_type));
394 string from("abcdef");
395 const char* next_from;
396 wchar_t to[1];
397 wchar_t *next_to;
398 cdecvt_type::result res = cdect.in(state, from.data(), from.data() + from.size(), next_from,
399 to, to + sizeof(to) / sizeof(wchar_t), next_to);
400 CPPUNIT_ASSERT( res == cdecvt_type::ok );
401 CPPUNIT_ASSERT( next_from == from.data() + 1 );
402 CPPUNIT_ASSERT( next_to == &to[0] + 1 );
403 CPPUNIT_ASSERT( to[0] == L'a');
404 }
405 {
406 cdecvt_type::state_type state;
407 memset(&state, 0, sizeof(cdecvt_type::state_type));
408 wstring from(L"abcdef");
409 const wchar_t* next_from;
410 char to[1];
411 char *next_to;
412 cdecvt_type::result res = cdect.out(state, from.data(), from.data() + from.size(), next_from,
413 to, to + sizeof(to) / sizeof(char), next_to);
414 CPPUNIT_ASSERT( res == cdecvt_type::ok );
415 CPPUNIT_ASSERT( next_from == from.data() + 1 );
416 CPPUNIT_ASSERT( next_to == &to[0] + 1 );
417 CPPUNIT_ASSERT( to[0] == 'a');
418 }
419 }
420 }
421 catch (runtime_error const&) {
422 }
423 catch (...) {
424 CPPUNIT_FAIL;
425 }
426 #endif
427 }
428
length_test()429 void CodecvtTest::length_test()
430 {
431 #if !defined (STLPORT) || !(defined (_STLP_NO_WCHAR_T) || !defined (_STLP_USE_EXCEPTIONS))
432 try {
433 locale loc("");
434
435 typedef codecvt<wchar_t, char, mbstate_t> cdecvt_type;
436 if (has_facet<cdecvt_type>(loc)) {
437 cdecvt_type const& cdect = use_facet<cdecvt_type>(loc);
438 {
439 cdecvt_type::state_type state;
440 memset(&state, 0, sizeof(cdecvt_type::state_type));
441 string from("abcdef");
442 int res = cdect.length(state, from.data(), from.data() + from.size(), from.size());
443 CPPUNIT_ASSERT( (size_t)res == from.size() );
444 }
445 }
446 }
447 catch (runtime_error const&) {
448 }
449 catch (...) {
450 CPPUNIT_FAIL;
451 }
452 #endif
453 }
454
455 #if !defined (STLPORT) || !(defined (_STLP_NO_WCHAR_T) || !defined (_STLP_USE_EXCEPTIONS))
456 typedef std::codecvt<wchar_t, char, mbstate_t> my_codecvt_base;
457
458 class my_codecvt : public my_codecvt_base {
459 public:
my_codecvt(size_t r=0)460 explicit my_codecvt(size_t r = 0)
461 : my_codecvt_base(r) {}
462
463 protected:
do_in(state_type &,const extern_type * first1,const extern_type * last1,const extern_type * & next1,intern_type * first2,intern_type * last2,intern_type * & next2) const464 virtual result do_in(state_type& /*state*/, const extern_type* first1,
465 const extern_type* last1, const extern_type*& next1,
466 intern_type* first2, intern_type* last2,
467 intern_type*& next2) const {
468 for ( next1 = first1, next2 = first2; next1 < last1; next1 += 2 ) {
469 if ( (last1 - next1) < 2 || (last2 - next2) < 1 )
470 return partial;
471 *next2++ = (intern_type)((*(next1 + 1) << 8) | (*next1 & 255));
472 }
473 return ok;
474 }
do_always_noconv() const475 virtual bool do_always_noconv() const __NO_THROW
476 { return false; }
do_max_length() const477 virtual int do_max_length() const __NO_THROW
478 { return 2; }
do_encoding() const479 virtual int do_encoding() const __NO_THROW
480 { return 2; }
481 };
482 #endif
483
imbue_while_reading()484 void CodecvtTest::imbue_while_reading()
485 {
486 #if !defined (STLPORT) || !(defined (_STLP_NO_WCHAR_T) || !defined (_STLP_USE_EXCEPTIONS))
487 {
488 wofstream ofs( "test.txt" );
489 const wchar_t buf[] = L" ";
490 for ( int i = 0; i < 4098; ++i ) {
491 ofs << buf[0];
492 }
493 }
494
495 wifstream ifs("test.txt"); // a file containing 4098 wchars
496
497 ifs.imbue( locale(locale(), new my_codecvt) );
498 ifs.get();
499 ifs.seekg(0);
500 ifs.imbue( locale() );
501 ifs.ignore(4096);
502 int ch = ifs.get();
503 CPPUNIT_CHECK( ch != (int)WEOF );
504 #endif
505 }
506
special_encodings()507 void CodecvtTest::special_encodings()
508 {
509 #if !defined (STLPORT) || (!defined (_STLP_NO_WCHAR_T) && defined (_STLP_USE_EXCEPTIONS))
510 {
511 locale loc(locale::classic(), new codecvt_byname<wchar_t, char, mbstate_t>("C"));
512 codecvt<wchar_t, char, mbstate_t> const& cvt = use_facet<codecvt<wchar_t, char, mbstate_t> >(loc);
513 mbstate_t state;
514 memset(&state, 0, sizeof(mbstate_t));
515 char c = '0';
516 const char *from_next;
517 wchar_t wc;
518 wchar_t *to_next;
519 CPPUNIT_ASSERT( cvt.in(state, &c, &c + 1, from_next, &wc, &wc, to_next) == codecvt_base::ok );
520 CPPUNIT_ASSERT( to_next == &wc );
521 CPPUNIT_ASSERT( cvt.in(state, &c, &c + 1, from_next, &wc, &wc + 1, to_next) == codecvt_base::ok );
522 CPPUNIT_ASSERT( wc == L'0' );
523 CPPUNIT_ASSERT( to_next == &wc + 1 );
524 }
525 try
526 {
527 wstring cp936_wstr;
528 const string cp936_str = "\xd6\xd0\xb9\xfa\xc9\xe7\xbb\xe1\xbf\xc6\xd1\xa7\xd4\xba\xb7\xa2\xb2\xbc\x32\x30\x30\x38\xc4\xea\xa1\xb6\xbe\xad\xbc\xc3\xc0\xb6\xc6\xa4\xca\xe9\xa1\xb7\xd6\xb8\xb3\xf6\xa3\xac\x32\x30\x30\x37\xc4\xea\xd6\xd0\xb9\xfa\xbe\xad\xbc\xc3\xd4\xf6\xb3\xa4\xd3\xc9\xc6\xab\xbf\xec\xd7\xaa\xcf\xf2\xb9\xfd\xc8\xc8\xb5\xc4\xc7\xf7\xca\xc6\xc3\xf7\xcf\xd4\xd4\xa4\xbc\xc6\xc8\xab\xc4\xea\x47\x44\x50\xd4\xf6\xcb\xd9\xbd\xab\xb4\xef\x31\x31\x2e\x36\x25\xa1\xa3";
529 locale loc(locale::classic(), ".936", locale::ctype);
530 codecvt<wchar_t, char, mbstate_t> const& cvt = use_facet<codecvt<wchar_t, char, mbstate_t> >(loc);
531 mbstate_t state;
532 memset(&state, 0, sizeof(mbstate_t));
533
534 codecvt_base::result res;
535
536 {
537 wchar_t wbuf[4096];
538 // Check we will have enough room for the generated wide string generated from the whole char buffer:
539 int len = cvt.length(state, cp936_str.data(), cp936_str.data() + cp936_str.size(), sizeof(wbuf) / sizeof(wchar_t));
540 CPPUNIT_ASSERT( cp936_str.size() == (size_t)len );
541
542 const char *from_next;
543 wchar_t *to_next;
544 res = cvt.in(state, cp936_str.data(), cp936_str.data() + cp936_str.size(), from_next,
545 wbuf, wbuf + sizeof(wbuf) / sizeof(wchar_t), to_next);
546 CPPUNIT_ASSERT( res == codecvt_base::ok );
547 CPPUNIT_ASSERT( from_next == cp936_str.data() + cp936_str.size() );
548 cp936_wstr.assign(wbuf, to_next);
549 }
550
551 {
552 const wchar_t *from_next;
553 char buf[4096];
554 char *to_next;
555 res = cvt.out(state, cp936_wstr.data(), cp936_wstr.data() + cp936_wstr.size(), from_next,
556 buf, buf + sizeof(buf), to_next);
557 CPPUNIT_ASSERT( res == codecvt_base::ok );
558 CPPUNIT_CHECK( string(buf, to_next) == cp936_str );
559 }
560 }
561 catch (const runtime_error&)
562 {
563 CPPUNIT_MESSAGE("Not enough platform localization support to check 936 code page encoding.");
564 }
565 try
566 {
567 const string utf8_str = "\xe4\xb8\xad\xe5\x9b\xbd\xe7\xa4\xbe\xe4\xbc\x9a\xe7\xa7\x91\xe5\xad\xa6\xe9\x99\xa2\xe5\x8f\x91\xe5\xb8\x83\x32\x30\x30\x38\xe5\xb9\xb4\xe3\x80\x8a\xe7\xbb\x8f\xe6\xb5\x8e\xe8\x93\x9d\xe7\x9a\xae\xe4\xb9\xa6\xe3\x80\x8b\xe6\x8c\x87\xe5\x87\xba\xef\xbc\x8c\x32\x30\x30\x37\xe5\xb9\xb4\xe4\xb8\xad\xe5\x9b\xbd\xe7\xbb\x8f\xe6\xb5\x8e\xe5\xa2\x9e\xe9\x95\xbf\xe7\x94\xb1\xe5\x81\x8f\xe5\xbf\xab\xe8\xbd\xac\xe5\x90\x91\xe8\xbf\x87\xe7\x83\xad\xe7\x9a\x84\xe8\xb6\x8b\xe5\x8a\xbf\xe6\x98\x8e\xe6\x98\xbe\xe9\xa2\x84\xe8\xae\xa1\xe5\x85\xa8\xe5\xb9\xb4\x47\x44\x50\xe5\xa2\x9e\xe9\x80\x9f\xe5\xb0\x86\xe8\xbe\xbe\x31\x31\x2e\x36\x25\xe3\x80\x82";
568 wstring utf8_wstr;
569 locale loc(locale::classic(), new codecvt_byname<wchar_t, char, mbstate_t>(".utf8"));
570 codecvt<wchar_t, char, mbstate_t> const& cvt = use_facet<codecvt<wchar_t, char, mbstate_t> >(loc);
571 mbstate_t state;
572 memset(&state, 0, sizeof(mbstate_t));
573
574 codecvt_base::result res;
575
576 {
577 wchar_t wbuf[4096];
578 // Check we will have enough room for the wide string generated from the whole char buffer:
579 int len = cvt.length(state, utf8_str.data(), utf8_str.data() + utf8_str.size(), sizeof(wbuf) / sizeof(wchar_t));
580 CPPUNIT_ASSERT( utf8_str.size() == (size_t)len );
581
582 const char *from_next;
583 wchar_t *to_next;
584 res = cvt.in(state, utf8_str.data(), utf8_str.data() + utf8_str.size(), from_next,
585 wbuf, wbuf + sizeof(wbuf) / sizeof(wchar_t), to_next);
586 CPPUNIT_ASSERT( res == codecvt_base::ok );
587 CPPUNIT_ASSERT( from_next == utf8_str.data() + utf8_str.size() );
588 utf8_wstr.assign(wbuf, to_next);
589
590 // Try to read one char after the other:
591 wchar_t wc;
592 const char* from = utf8_str.data();
593 const char* from_end = from + utf8_str.size();
594 from_next = utf8_str.data();
595 size_t length = 1;
596 size_t windex = 0;
597 while (from + length <= from_end) {
598 res = cvt.in(state, from, from + length, from_next,
599 &wc, &wc + 1, to_next);
600 switch (res) {
601 case codecvt_base::ok:
602 // reset length:
603 from = from_next;
604 length = 1;
605 CPPUNIT_ASSERT( wc == utf8_wstr[windex++] );
606 wc = 0;
607 break;
608 case codecvt_base::partial:
609 if (from_next == from)
610 // from_next hasn't move so we have to pass more chars
611 ++length;
612 else
613 // char between from and from_next has been eaten, we simply restart
614 // conversion from from_next:
615 from = from_next;
616 continue;
617 case codecvt_base::error:
618 case codecvt_base::noconv:
619 CPPUNIT_FAIL;
620 //break;
621 }
622 }
623 CPPUNIT_ASSERT( windex == utf8_wstr.size() );
624 }
625
626 {
627 const wchar_t *from_next;
628 char buf[4096];
629 char *to_next;
630 res = cvt.out(state, utf8_wstr.data(), utf8_wstr.data() + utf8_wstr.size(), from_next,
631 buf, buf + sizeof(buf), to_next);
632 CPPUNIT_ASSERT( res == codecvt_base::ok );
633 CPPUNIT_CHECK( string(buf, to_next) == utf8_str );
634 }
635
636 {
637 // Check that an obviously wrong UTF8 encoded string is correctly detected:
638 const string bad_utf8_str("\xdf\xdf\xdf\xdf\xdf");
639 wchar_t wc;
640 const char *from_next;
641 wchar_t *to_next;
642 res = cvt.in(state, bad_utf8_str.data(), bad_utf8_str.data() + bad_utf8_str.size(), from_next,
643 &wc, &wc + 1, to_next);
644 CPPUNIT_ASSERT( res == codecvt_base::error );
645 }
646 }
647 catch (const runtime_error&)
648 {
649 CPPUNIT_MESSAGE("Not enough platform localization support to check UTF8 encoding.");
650 }
651 #endif
652 }
653
654 #endif
655