Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
wcodecvt.cpp
Go to the documentation of this file.
1
29#define _RWSTD_LIB_SRC
30
31#include <rw/_defs.h>
32
33
34// working around a Compaq C++ bug (see PR #26778)
35#if __DECCXX_VER >= 60300000 && __DECCXX_VER < 60400000
36
37# include <stdarg.h>
38_USING (std::va_list);
39
40// override autoconfigured macro whose value is incorrect
41// if <unistd.h> is #included before <iconv.h>
42# include <unistd.h>
43# define _RWSTD_NO_ICONV_CONST_CHAR
44
45#endif // Compaq C++ 6.3
46
47#include <wchar.h>
48#include <limits.h>
49#include <locale.h>
50#include <stdlib.h> // for MB_CUR_MAX, mblen(), mbtowc()
51#include <string.h> // for memcmp()
52#include <errno.h>
53
54#if defined (__SUNPRO_CC) && __SUNPRO_CC <= 0x540 \
55 && (defined (__SunOS_5_8) || defined (__SunOS_5_9))
56 // working around SunOS/SunPro header dependencies (see PR #26255)
57# undef _TIME_T
58#endif // SunPro <= 5.4 && SunOS 5.{8,9}
59
60#include <loc/_codecvt.h>
61#include <loc/_locale.h>
62#include <loc/_localedef.h>
63
64#include <rw/_traits.h> // for _RWSTD_WCSLEN()
65
66#include "iso2022.h"
67#include "setlocale.h"
68#include "use_facet.h"
69
70
71// declare mbrlen() if it's not declared in the system headers
72// but is known to be defined in the libc binary
73#if defined (_RWSTD_NO_MBRLEN) && !defined (_RWSTD_NO_MBRLEN_IN_LIBC)
74
75# undef _RWSTD_NO_MBRLEN
76
77extern "C" size_t
78mbrlen (const char*, size_t, _RWSTD_MBSTATE_T*) _LIBC_THROWS();
79
80#endif // _RWSTD_NO_MBRLEN && !_RWSTD_NO_MBRLEN_IN_LIBC
81
82
83// declare mblen() if it's not declared in the system headers
84// but is known to be defined in the libc binary
85#if defined (_RWSTD_NO_MBLEN) && !defined (_RWSTD_NO_MBLEN_IN_LIBC)
86
87# undef _RWSTD_NO_MBLEN
88
89extern "C" int
90mblen (const char*, size_t) _LIBC_THROWS();
91
92#endif // _RWSTD_NO_MBLEN && !_RWSTD_NO_MBLEN_IN_LIBC
93
94
95// declare mbtowc() if it's not declared in the system headers
96// but is known to be defined in the libc binary
97#if defined (_RWSTD_NO_MBTOWC) && !defined (_RWSTD_NO_MBTOWC_IN_LIBC)
98
99# undef _RWSTD_NO_MBTOWC
100
101extern "C" int
102mbtowc (wchar_t*, const char*, size_t) _LIBC_THROWS();
103
104#endif // _RWSTD_NO_MBTOWC && !_RWSTD_NO_MBTOWC_IN_LIBC
105
106
107// declare wcsrtombs() if it's not declared in the system headers
108// but is known to be defined in the libc binary
109#if defined (_RWSTD_NO_WCSRTOMBS) && !defined (_RWSTD_NO_WCSRTOMBS_IN_LIBC)
110
111# undef _RWSTD_NO_WCSRTOMBS
112
113extern "C" size_t
114wcsrtombs (char*, const wchar_t**, size_t, _RWSTD_MBSTATE_T*) _LIBC_THROWS();
115
116#endif // _RWSTD_NO_WCSRTOMBS && !_RWSTD_NO_WCSRTOMBS_IN_LIBC
117
118
119// declare wcrtomb() if it's not declared in the system headers
120// but is known to be defined in the libc binary
121#if defined (_RWSTD_NO_WCRTOMB) && !defined (_RWSTD_NO_WCRTOMB_IN_LIBC)
122
123# undef _RWSTD_NO_WCRTOMB
124
125extern "C" size_t
126wcrtomb (char*, wchar_t, _RWSTD_MBSTATE_T*) _LIBC_THROWS();
127
128#endif // _RWSTD_NO_WCRTOMB && !_RWSTD_NO_WCRTOMB_IN_LIBC
129
130
131// declare wctomb() if it's not declared in the system headers
132// but is known to be defined in the libc binary
133#if defined (_RWSTD_NO_WCTOMB) && !defined (_RWSTD_NO_WCTOMB_IN_LIBC)
134
135# undef _RWSTD_NO_WCTOMB
136
137extern "C" {
138
140wctomb (char*, wchar_t) _LIBC_THROWS();
141
142} // extern "C"
143
144#endif // _RWSTD_NO_WCTOMB && !_RWSTD_NO_WCTOMB_IN_LIBC
145
146
147// utf8 encoding maximum size
148#undef _UTF8_MB_CUR_MAX
149#define _UTF8_MB_CUR_MAX 6
150
151
152enum {
153 // mask to retrieve ISO-2022 encoding type
155
156 // UCS-4 or UCS-2 (wchar_t width) encoding type
157 __rw_ucs_be = 0x000010, // big-endian word and byte order
158 __rw_ucs_le = 0x000040, // little-endian word and byte order
159 __rw_ucs = 0x0000f0, // platform-endianness
160
161 // UCS-4 encoding type
162 __rw_ucs4_be = 0x000100, // big-endian word and byte order
163 __rw_ucs4_be_le = 0x000200, // big-endian word, little-endian byte order
164 __rw_ucs4_le = 0x000400, // little-endian word and byte order
165 __rw_ucs4_le_be = 0x000800, // little-endian word, big-endian byte order
166 __rw_ucs4 = 0x000f00, // platform-endianness
167
168 // UCS-2 encoding type
169 __rw_ucs2_be = 0x001000, // big-endian word and byte order
170 __rw_ucs2_le = 0x004000, // little-endian word and byte order
171 __rw_ucs2 = 0x00f000, // platform-endianness
172
173 // UTF encoding type
174 __rw_utf8 = 0x010000, // UTF-8
175 __rw_utf16_be = 0x020000, // UTF-16, big-endian byte order
176 __rw_utf16_le = 0x040000, // UTF-16, little-endian byte order
177 __rw_utf16 = 0x060000, // UTF-16, platform endianness
178
179 __rw_strict = 0x100000, // do strict UCS validation
180
181 __rw_use_libc = 0x200000, // always use libc locale
182
183 // mask to retrieve UCS encoding type
188
189 // mask to retrieve UTF encoding type
192
193#define ISO2022_TYPE(x) ((x) & __rw_2022_mask)
194
195// helper macros to retrieve the type of an UCS and UTF encoding
196#define UCS_TYPE(x) ((x) & __rw_ucs_mask)
197#define UTF_TYPE(x) ((x) & __rw_utf_mask)
198
199#define IS_UCS(x) (UCS_TYPE (x) == __rw_ucs)
200#define IS_UCS_BE(x) (UCS_TYPE (x) == __rw_ucs_be)
201#define IS_UCS_LE(x) (UCS_TYPE (x) == __rw_ucs_le)
202#define IS_UCS_BE_LE(x) (UCS_TYPE (x) == __rw_ucs_be_le)
203#define IS_UCS_LE_BE(x) (UCS_TYPE (x) == __rw_ucs_le_be)
204
205#define IS_UTF8(x) (UCS_TYPE (x) == __rw_utf8)
206#define IS_UTF16(x) (UCS_TYPE (x) == __rw_utf16)
207#define IS_UTF16_BE(x) (UCS_TYPE (x) == __rw_utf16_be)
208#define IS_UTF16_LE(x) (UCS_TYPE (x) == __rw_utf16_le)
209
210// evaluates to 1 if the facet should use the libc locale, 0 otherwise
211#define USE_LIBC(impl, x) \
212 ((!(impl) || ((x) & __rw_use_libc)) && !(UCS_TYPE (x) || UTF_TYPE (x)))
213
214
215// _RWSTD_MBSTATE_T macro might expand to char* (on AIX)
217
218
220
221
222static const struct {
223 const char *mod;
224 int flags;
225} __rw_ucsmods[] = {
226 { "UCS", __rw_ucs },
227 { "UCS-4", __rw_ucs4 },
228 { "UCS-2", __rw_ucs2 },
229 { "UCS-4-BE", __rw_ucs4_be },
230 { "UCS-4-LE", __rw_ucs4_le },
231 { "UCS-2-BE", __rw_ucs2_be },
232 { "UCS-2-LE", __rw_ucs2_le },
233 { "UCS-4-BE-LE", __rw_ucs4_be_le },
234 { "UCS-4-LE-BE", __rw_ucs4_le_be },
235 { "UCS-BE", __rw_ucs_be },
236 { "UCS-LE", __rw_ucs_le }
237};
238
239static const size_t
240__rw_n_ucsmods = sizeof __rw_ucsmods / sizeof *__rw_ucsmods;
241
242
243static inline int
244__rw_mbsinit (const StateT *psrc)
245{
246#ifndef _RWSTD_NO_MBSINIT
247
248 return mbsinit (psrc);
249
250#else // if defined (_RWSTD_NO_MBSINIT)
251
252 // commented out to work around an HP aCC 1.21 bug
253 /* static */ const StateT state = StateT ();
254 return !psrc || 0 == memcmp (psrc, &state, sizeof state);
255
256#endif // _RWSTD_NO_MBSINIT
257
258}
259
260
261#undef min
262#define min(a, b) ((a) < (b) ? (a) : (b))
263#undef max
264#define max(a,b) ((a) > (b)) ? (a) : (b)
265
266
267#ifndef _RWSTD_NO_WCHAR_T
268
269// behaves just like mbrlen(), except that if the character pointed to
270// by `str' is the NUL character and `emax' is non-zero, the function
271// returns 1
272static inline size_t
273__rw_libc_mbrlen (_RWSTD_MBSTATE_T &state,
274 const char *str,
275 size_t emax)
276{
277 _RWSTD_ASSERT (0 != str);
278
279 if ('\0' == *str)
280 return 0 < emax;
281
282#ifndef _RWSTD_NO_MBRLEN
283
284 // `emax' is the maximum number of elements of type char in `str'
285 return mbrlen (str, emax, &state);
286
287#elif !defined (_RWSTD_NO_MBLEN)
288
289 _RWSTD_UNUSED (state);
290
291 return mblen (str, emax);
292
293#else // if defined (_RWSTD_NO_MBLEN)
294
295 _RWSTD_UNUSED (state);
296
297 // this is bogus but it's the best we can do given the absence
298 // of libc support for this functionality (more likely than not,
299 // this code will never end up getting executed because we'll
300 // never get this far)
301 const char *next = str;
302
303 for (; *next && emax; ++next, --emax);
304
305 return next - str;
306
307#endif // _RWSTD_NO_MBRLEN
308
309}
310
311
312// does a simple transliteration of the UTF-8 encoded character string
313static unsigned int
314__rw_xlit (const _RW::__rw_codecvt_t* impl,
315 const char *utf8s, size_t sz)
316{
317 const unsigned int* const ptbls = impl->get_xliteration_tab ();
318
319 unsigned int index = 0;
320
321 for (const unsigned int* ptbl = ptbls; sz; --sz, ++utf8s) {
322
323 typedef unsigned char UChar;
324
325 index = ptbl [UChar (*utf8s)];
326
327 if (_RWSTD_UINT_MAX == index)
328 // transliteration not provided for this character
329 return 0;
330
331 if (index & 0x80000000) {
332 ptbl = ptbls + 256 * index;
333 }
334 else {
335 // utf-8 string representation should end here
336 _RWSTD_ASSERT (0 == sz);
337 }
338 }
339
340 return index & 0x80000000 ? 0 : index;
341}
342
343
344static _STD::codecvt_base::result
345__rw_libc_do_in (_RWSTD_MBSTATE_T &state,
346 const char *from,
347 const char *from_end,
348 const char* &from_next,
349 wchar_t *to,
350 wchar_t *to_limit,
351 wchar_t* &to_next)
352{
353 _RWSTD_ASSERT (from <= from_end);
354 _RWSTD_ASSERT (to <= to_limit);
355
356 _STD::codecvt_base::result res = _STD::codecvt_base::ok;
357
358 // compute the length of the source sequence in bytes and
359 // the size of the destination buffer in wide characters
360 size_t src_len = from_end - from;
361 size_t dst_size = to_limit - to;
362
363 // set the initial values to the source and destination pointers
364 const char* psrc = from;
365 wchar_t* pdst = to;
366
367 while (dst_size && src_len) {
368
369 // the number of bytes that form the next multibyte character
370 size_t nbytes;
371
372#ifndef _RWSTD_NO_MBRTOWC
373 nbytes = mbrtowc (pdst, psrc, src_len, &state);
374#elif !defined (_RWSTD_NO_MBTOWC)
375 nbytes = mbtowc (pdst, psrc, src_len);
376#else
377 nbytes = _RWSTD_SIZE_MAX;
378#endif
379
380 // -1 indicates an invalid sequence (i.e., error)
381 if (nbytes == size_t (-1)) {
382 res = _STD::codecvt_base::error;
383 break;
384 }
385
386 // -2 indicates an ambiguous but valid subsequence
387 // (i.e., ok)
388 if (nbytes == size_t (-2))
389 break;
390
391 // 0 indicates the NUL character (skip over it)
392 if (nbytes == 0)
393 ++nbytes;
394
395 // > 0 indicates the number of bytes in the successfully
396 // converted multibyte character
397 psrc += nbytes;
398 src_len -= nbytes;
399 ++pdst;
400 --dst_size;
401 }
402
403 // adjust "next" pointers
404 from_next = psrc;
405 to_next = pdst;
406
407 // if the conversion has exhausted all space in the destination
408 // range AND there are more COMPLETE characters in the source
409 // range then we have a "partial" conversion
410 if (res == _STD::codecvt_base::ok && src_len && !dst_size) {
411 _RWSTD_MBSTATE_T tmp_state = state;
412 size_t tmp = __rw_libc_mbrlen (tmp_state, psrc, src_len);
413 if (tmp < size_t (-2))
414 res = _STD::codecvt_base::partial;
415 }
416
417 return res;
418}
419
420
421static _STD::codecvt_base::result
422__rw_libc_do_out (_RWSTD_MBSTATE_T &state,
423 const wchar_t *from,
424 const wchar_t *from_end,
425 const wchar_t* &from_next,
426 char *to,
427 char *to_limit,
428 char* &to_next)
429{
430 _RWSTD_ASSERT (from <= from_end);
431 _RWSTD_ASSERT (to <= to_limit);
432
433 // verify that both ranges are valid
434 _RWSTD_ASSERT (from && from_end || !from && !from_end);
435 _RWSTD_ASSERT (to && to_limit || !to && !to_limit);
436
437 // set the (possibly uninitialized) next pointers
438 // to point to the beginning of each sequence
439 from_next = from;
440 to_next = to;
441
442 // save the value of MB_CUR_MAX and avoid repeatedly using
443 // the macro for efficiency (it may expand to a function call)
444 const size_t mb_cur_max = size_t (MB_CUR_MAX);
445
446 // the result of conversion
447 _STD::codecvt_base::result res = _STD::codecvt_base::ok;
448
449 // the size of the available space in the destination range
450 size_t dst_free = size_t (to_limit - to_next);
451
452 // small temporary buffer used when the space in the destination
453 // buffer is less than MB_CUR_MAX
454 char buff [_RWSTD_MB_LEN_MAX];
455
456 // convert the source sequence one character at a time
457 for ( ; from_next < from_end; ++from_next) {
458
459 // since there is no guarantee that the converted internal
460 // character would fit in the remaining space in the
461 // destination buffer, use the small local buffer if
462 // the remaining space is less that the longest external
463 // multibyte character (i.e., MB_CUR_MAX)
464 char* const tmpdst = dst_free < mb_cur_max ? buff : to_next;
465
466 // save the state in case it's changed but the converted
467 // character doesn't fit in the destination buffer
468 const _RWSTD_MBSTATE_T save_state = state;
469
470 // the number of bytes in the resulting multibyte character
471 // sequence, not including the terminating NUL
472 size_t dst_len = 0;
473
474#ifndef _RWSTD_NO_WCRTOMB
475
476 // convert the next source character (note that it would be
477 // unsafe to use wcsrtombs() since the source sequence may
478 // not be NUL terminated)
479 dst_len = wcrtomb (tmpdst, *from_next, &state);
480
481#elif !defined (_RWSTD_NO_WCTOMB)
482
483 _RWSTD_UNUSED (state);
484 dst_len = wctomb (tmpdst, *from_next);
485
486#else // error
487
488 _RWSTD_UNUSED (state);
489 dst_len = _RWSTD_SIZE_MAX;
490
491#endif // _RWSTD_NO_WCRTOMB, _RWSTD_NO_WCTOMB
492
493 // -1 is returned as an indication of an illegal sequence
494 if (_RWSTD_SIZE_MAX == dst_len) {
495 res = _STD::codecvt_base::error;
496 break;
497 }
498
499 // if the multibyte sequence is the NUL character
500 // adjust the result by one (i.e., the length of
501 // the multibyte NUL character)
502 if (0 == dst_len)
503 ++dst_len;
504
505 // if the remaining space in the destination sequence
506 // is less than MB_CUR_MAX, check to see if the multibyte
507 // character will fit in there
508 if (dst_free < mb_cur_max) {
509 if (dst_free < dst_len) {
510 // the source character converted to a multibyte
511 // character whose length in bytes is greater than
512 // the available space in the destination sequence
513
514 // restore the state to the value prior to the last
515 // conversion and return partial
516 state = save_state;
517 res = _STD::codecvt_base::partial;
518 break;
519 }
520
521 // the destination sequence has sufficient space
522 // for the multibyte character
523 memcpy (to_next, buff, dst_len);
524 }
525
526 // advance the destination next pointer one past the end
527 // of the multibyte character and decrement the size of
528 // of the available space in the destination sequence
529 to_next += dst_len;
530 dst_free -= dst_len;
531 }
532
533 return res;
534}
535
536
537static _STD::codecvt_base::result
538__rw_libc_do_unshift (_RWSTD_MBSTATE_T& state, char*& to_next, char* to_limit)
539{
540 // save current state
541 _RWSTD_MBSTATE_T tmp_state = state;
542
543 // use libc locale to obtain the shift sequence
544 char tmp [_RWSTD_MB_LEN_MAX];
545
546 size_t ret;
547
548#ifndef _RWSTD_NO_WCRTOMB
549 ret = wcrtomb (tmp, wchar_t (0), &state);
550#elif !defined (_RWSTD_NO_WCTOMB)
551 ret = wctomb (tmp, wchar_t (0));
552#else
553 ret = _RWSTD_SIZE_MAX;
554#endif
555
556 if (_RWSTD_SIZE_MAX == ret)
557 return _STD::codecvt_base::error;
558
559 if (ret > size_t (to_limit - to_next)) {
560 // restore the state and return partial
561 state = tmp_state;
562 return _STD::codecvt_base::partial;
563 }
564
565 // copy the shift sequence
566 memcpy (to_next, tmp, ret);
567 to_next += ret;
568 return _STD::codecvt_base::ok;
569}
570
571
572// checks a UTF-8 sequence representing a single character
573// for validity by performing a number of computationally
574// relatively expensive tests; used only in strict mode
575static bool
576__rw_utf8validate (const char* from, size_t nbytes)
577{
578 _RWSTD_ASSERT (0 != from);
579 _RWSTD_ASSERT (1 < nbytes && 7 > nbytes);
580
581 const unsigned char* const byte =
582 _RWSTD_REINTERPRET_CAST (const unsigned char*, from);
583
584 // check for overlong sequences with the bit pattern shown below
585
586 // 2 bytes: 1100 000x (10xx xxxx)
587 if (2 == nbytes && (byte [0] & 0xfeU) == 0xfeU)
588 return false;
589
590 // 3 bytes: 1110 0000 100x xxxx (10xx xxxx)
591 if (3 == nbytes) {
592
593 // first detect and reject all overlong sequences
594 if (0xe0U == byte [0] && (byte [1] & 0xe0U) == 0x80U)
595 return false;
596
597 // detect and reject UTF-16 surrogate pairs, i.e., UCS characters
598 // in the range [U+D800, U+DFFF] (i.e., inclusive of both ends),
599 // i.e., "\xed\xa0\x80" through "\xed\xbf\xbf", as well as U+FFFE
600 // and U+FFFF, i.e., "\xef\xbf\xbe" and "\xef\xbf\xbf"
601 if (0xedU == byte [0]) {
602 if (byte [1] >= 0xa0)
603 return false;
604 }
605 else if ( 0xefU == byte [0] && 0xbfU == byte [1]
606 && 0xbeU <= byte [2] && 0xbfU >= byte [2])
607 return false;
608 }
609
610 // 4 bytes: 1111 0000 1000 xxxx (10xx xxxx 10xx xxxx)
611 if (4 == nbytes && 0xf0U == byte [0] && (byte [1] & 0xf0U) == 0x80U)
612 return false;
613
614 // 5 bytes: 11111 000 1000 0xxx (10xxx xxx 10xx xxxx 10xx xxxx)
615 if (5 == nbytes && 0xf8U == byte [0] && (byte [1] & 0xf8U) == 0x80U)
616 return false;
617
618 // 6 bytes: 1111 1100 1000 00xx (10xx xxxx 10xx xxxx 10xxx xxx 10xxx xxx)
619 if (6 == nbytes && 0xfcU == byte [0] && (byte [1] & 0xfcU) == 0x80U)
620 return false;
621
622 for (size_t i = 1; i < nbytes; ++i) {
623 if ((byte [i] & ~0x3fU) != 0x80U)
624 return false; // invalid byte
625 }
626
627 return true;
628}
629
630
631static _STD::codecvt_base::result
632__rw_libstd_do_in (const char *from_end,
633 const char *&from_next,
634 wchar_t *to_limit,
635 wchar_t *&to_next,
636 int flags,
637 const _RW::__rw_codecvt_t *impl)
638{
639 // use UCS as the internal encoding if `impl' is 0
640 // (i.e., if the codecvt database is not available)
641 if (!impl && !UCS_TYPE (flags))
642 flags |= __rw_ucs;
643
644 const bool use_ucs = 0 != UCS_TYPE (flags);
645 const bool strict_utf = 0 != (flags & __rw_strict);
646
647 _STD::codecvt_base::result res;
648
649 for (const unsigned* const tab = impl ? impl->n_to_w_tab () : 0; ; ) {
650
651 if (from_next == from_end) {
652 res = _STD::codecvt_base::ok;
653 break;
654 }
655
656 if (to_next == to_limit) {
657 res = _STD::codecvt_base::partial;
658 break;
659 }
660
661 const char* from = from_next;
662
663 wchar_t wchar;
664
665 if (impl) {
666
667 // compute the offset of the multibyte character into
668 // one of the tables (UCS or wchar_t) where the value
669 // of the internal character corresponding to the
670 // multibyte character is stored
671 const unsigned off = __rw_mbtowco (tab, from, from_end);
672
673 if (_RWSTD_UINT_MAX == off) {
674 // the source sequence forms neither a valid multibyte
675 // character, nor is it an initial subsequence of one
676 res = _STD::codecvt_base::error;
677 break;
678 }
679
680 if (from == from_next) {
681 // the source sequence forms an incomplete initial
682 // subsequence of a valid multibyte character
683 res = _STD::codecvt_base::partial;
684 break;
685 }
686
687 wchar = use_ucs ? impl->get_ucs4_at_offset (off)
688 : impl->get_internal_at_offset (off);
689 }
690 else {
691 // use an algorithmic transformation from UTF-8 to UCS-4
692 _RWSTD_INT32_T wi;
693
694 const char* tmp = __rw_utf8toucs4 (&wi, from, from_end);
695
696 if (strict_utf && tmp) {
697
698 // perform additional expensive UTF-8 validation
699 const size_t utf_len = tmp - from;
700
701 if (utf_len > 1 && !__rw_utf8validate (from, utf_len))
702 tmp = 0;
703 }
704
705 from = tmp;
706
707 if (!from) {
708 // the source sequence forms neither a valid UTF-8
709 // character, nor is it an initial subsequence of one
710 res = _STD::codecvt_base::error;
711 break;
712 }
713
714 if (from_next == from) {
715 // the source sequence forms an incomplete initial
716 // subsequence of a valid UTF-8 character
717 res = _STD::codecvt_base::partial;
718 break;
719 }
720
721 wchar = wchar_t (wi);
722 }
723
724 from_next = from;
725 *to_next++ = wchar;
726 }
727
728 return res;
729}
730
731
732static _STD::codecvt_base::result
733__rw_libstd_do_out (const wchar_t *from,
734 const wchar_t *from_end,
735 const wchar_t *&from_next,
736 char *to,
737 char *to_limit,
738 char *&to_next,
739 int flags,
740 const _RW::__rw_codecvt_t *impl)
741{
742 // final result of the transformation
743 _STD::codecvt_base::result res = _STD::codecvt_base::ok;
744
745 const bool use_ucs = IS_UCS (flags);
746
747 // utf8 temporary buffer
748 char utfbuf [_UTF8_MB_CUR_MAX + 1];
749
750 const unsigned int* const tbl =
751 impl ? use_ucs ? impl->utf8_to_ext_tab () : impl->w_to_n_tab () : 0;
752
753 for (from_next = from, to_next = to; from_next != from_end; ++from_next) {
754
755 if (to_next == to_limit) {
756 res = _STD::codecvt_base::partial;
757 break;
758 }
759
760 if (flags & __rw_strict) {
761
762 // in strict mode check wide character for validity
763 // (i.e., diagnose surrogate pairs as illegal)
764
765 typedef _RWSTD_UWCHAR_INT_T WIntT;
766
767 // convert wchar_t to the unsigned form of its underlying
768 // integer type that's safe in arithmetic comaprisons and
769 // doesn't generate signed/unsigned compiler warnings
770 const WIntT wi = _RWSTD_STATIC_CAST (WIntT, *from_next);
771
772 if ( WIntT (0xd800U) <= wi && wi <= WIntT (0xdfffU)
773 || WIntT (0xfffeU) <= wi && wi <= WIntT (0xffffU)) {
774 res = _STD::codecvt_base::error;
775 break;
776 }
777 }
778
779 // compute the number of bytes available in the destination sequence
780 const size_t bytes_avail = to_limit - to_next;
781
782 size_t utf8_len;
783
784 if (impl) {
785
786 // encode the wide character value in UTF-8 as if it was UCS
787 utf8_len = __rw_itoutf8 (*from_next, utfbuf);
788
789 // convert the UTF-8 encoded wchar_t value into
790 // into the external representation
791 const char* utf = utfbuf;
792 unsigned off = __rw_mbtowco (tbl, utf, utf + utf8_len);
793
794 // FIXME: block below has been disabled but is being compiled
795 // to avoid syntax regressions; it might produce "unreachable
796 // code" warnings with some compilers
797 if (0 /* disbled */ && _RWSTD_UINT_MAX == off) {
798 // try transliteration
799 off = __rw_xlit (impl, utfbuf, utf8_len);
800 if (0 == off) {
801 res = _STD::codecvt_base::error;
802 break;
803 }
804 }
805
806 if (_RWSTD_UINT_MAX == off) {
807 // the sequence does not form a valid character
808 res = _STD::codecvt_base::error;
809 break;
810 }
811
812 if (utf == utfbuf) {
813 // the next multibyte character position was incomplete
814 res = _STD::codecvt_base::ok;
815 break;
816 }
817
818 // get the UTF-8 sequence corresponding to the wide character
819 utf = _RWSTD_REINTERPRET_CAST (const char*, impl + 1) + off;
820
821 // check that there's enough space in the destination sequence
822 utf8_len = *utf ? strlen (utf) : 1;
823 if (bytes_avail < utf8_len) {
824 res = _STD::codecvt_base::partial;
825 break;
826 }
827
828 // copy the UTF-8 sequence into the destination sequence
829 memcpy (to_next, utf, utf8_len);
830 }
831 else {
832
833 // codeset is UTF-8
834 // external encoding is UTF-8, so no lookup is necessary
835
836 // encode the wide char in the destination buffer if it fits
837
838 if (bytes_avail < _UTF8_MB_CUR_MAX) {
839 utf8_len = __rw_itoutf8 (*from_next, utfbuf);
840
841 if (bytes_avail < utf8_len) {
842 res = _STD::codecvt_base::partial;
843 break;
844 }
845
846 // move from temporary buffer to destination buffer
847 memcpy (to_next, utfbuf, utf8_len);
848 }
849 else
850 utf8_len = __rw_itoutf8 (*from_next, to_next);
851 }
852
853 to_next += utf8_len;
854 }
855
856 return res;
857}
858
859
860// implements do_length() on top of libc mbrlen()
861static size_t
862__rw_libc_do_length (_RWSTD_MBSTATE_T &state,
863 const char *from,
864 const char *from_end,
865 size_t imax)
866{
867 const char* const from_begin = from;
868
869 for ( ; imax && from < from_end; --imax) {
870
871 // compute the maximum length (in bytes) of the multibyte
872 // character sequence starting at `from'
873 size_t nbytes = from_end - from;
874 if (_RWSTD_MB_LEN_MAX < nbytes)
875 nbytes = _RWSTD_MB_LEN_MAX;
876
877 // get the number of bytes used to encode the next multibyte
878 // character (including NUL), or -1 if the sequence at `from'
879 // does not form a valid multibyte character (and -2 if it's
880 // an incomplete subsequence of a valid multibyte character)
881 nbytes = __rw_libc_mbrlen (state, from, nbytes);
882
883 // stop when an invalid or incomplete character is encountered
884 if (nbytes >= size_t (-2))
885 break;
886
887 from += nbytes;
888 }
889
890 // return the number of bytes (extern_type characters) in the sequence
891 return from - from_begin;
892}
893
894
895// implements do_length() for UTF-8@UCS
896static size_t
897__rw_utf8_do_length (const char *from,
898 const char *from_end,
899 size_t imax,
900 int flags)
901{
902 _RWSTD_ASSERT (from <= from_end);
903
904 const bool strict_utf = 0 != (flags & __rw_strict);
905
906 const char *from_next = from;
907
908 // count successive utf8 characters - this is a UTF-8 encoding
909 for ( ; imax && from_next < from_end; --imax) {
910
911 // use an algorithmic transformation from UTF-8 to UCS-4
912 _RWSTD_INT32_T wi;
913
914 const char* const next = __rw_utf8toucs4 (&wi, from_next, from_end);
915
916 // stop if the character is either invalid or incomplete
917 if (!next || next == from_next)
918 break;
919
920 _RWSTD_ASSERT (from_next <= next);
921 _RWSTD_ASSERT (next <= from_end);
922
923 // perform additional expensive UTF-8 validation in strict mode
924 const size_t utf_len = next - from_next;
925
926 if ( strict_utf
927 && utf_len > 1 && !__rw_utf8validate (from_next, utf_len))
928 break;
929
930 from_next = next;
931 }
932
933 // return the number of extern characters
934 return from_next - from;
935}
936
937
938// 22.2.1.5.2 [lib.locale.codecvt.virtuals]
939// including the resolution of lwg issue 305
940//
941// -9- Preconditions: (from<=from_end) well-defined and true; state
942// initialized, if at the beginning of a sequence, or else equal
943// to the result of converting the preceding characters in the
944// sequence.
945//
946// -9a- Effects: The effect on the state argument is "as if" it called
947// do_in(state, from, from_end, from, to, to+max, to) for to pointing
948// to a buffer of at least max elements.
949//
950// -10- Returns: (from_next-from) where from_next is the largest value
951// in the range [from,from_end] such that the sequence of values
952// in the range [from,from_next) represents max or fewer valid
953// complete characters of type internT. The instantiation
954// codecvt<char, char, mbstate_t> returns the lesser of max
955// and (from_end-from).
956
957// Note that the function returns the number of externT characters
958// (i.e., those of type char for the required instantiations).
959
960static size_t
961__rw_libstd_do_length (const char* from,
962 const char* from_end,
963 size_t imax,
964 int flags,
965 const _RW::__rw_codecvt_t* impl)
966{
967 // use UCS as the internal encoding if `impl' is 0
968 // (i.e., if the codecvt database is not available)
969 if (!impl && !UCS_TYPE (flags))
970 flags |= __rw_ucs;
971
972 const bool use_ucs = 0 != UCS_TYPE (flags);
973
974 if (impl) {
975
976 const char* from_next = from;
977
978 const unsigned char* const limit =
979 _RWSTD_REINTERPRET_CAST (const unsigned char*, from_end);
980
981 const unsigned int* const tbls =
982 use_ucs ? impl->utf8_to_ext_tab () : impl->n_to_w_tab ();
983
984 _RWSTD_ASSERT (tbls);
985
986 // `imax' is the maximum number of intern_type characters
987 for ( ; imax && from_next < from_end; --imax) {
988
989 const unsigned char* next =
990 _RWSTD_REINTERPRET_CAST (const unsigned char*, from_next);
991
992 for (const unsigned* tbl = tbls; tbl [*next] & 0x80000000; ) {
993
994 // check if the extern character is valid
995 if (_RWSTD_UINT_MAX == tbl [*next])
996 return from_next - from;
997
998 // the value here is the table index
999 const unsigned index = tbl [*next] & 0x7fffffff;
1000 tbl = tbls + 256 * index;
1001
1002 ++next;
1003
1004 if (next == limit)
1005 return from_next - from;
1006 }
1007
1008 from_next = _RWSTD_REINTERPRET_CAST (const char*, next + 1);
1009 }
1010
1011 // return the number of extern characters
1012 return from_next - from;
1013 }
1014
1015 return __rw_utf8_do_length (from, from_end, imax, flags);
1016}
1017
1018} // namespace __rw
1019
1020
1022
1023
1024_RW::__rw_facet_id codecvt<wchar_t, char, _RWSTD_MBSTATE_T>::id;
1025
1026
1027/* explicit */ codecvt<wchar_t, char, _RWSTD_MBSTATE_T>::
1028codecvt (size_t __ref /* = 0 */)
1029 : _RW::__rw_facet (__ref)
1030{
1031 // no-op
1032}
1033
1034
1035// outlined to avoid generating a vtable in each translation unit
1036// that uses the class
1037/* virtual */ codecvt<wchar_t, char, _RWSTD_MBSTATE_T>::
1038~codecvt ()
1039{
1040 // no-op
1041}
1042
1043
1044/* virtual */ bool
1045codecvt<wchar_t, char, _RWSTD_MBSTATE_T>::
1046do_always_noconv () const _THROWS (())
1047{
1048 return false; // conversion always necessary
1049}
1050
1051
1052/* virtual */ int
1053codecvt<wchar_t, char, _RWSTD_MBSTATE_T>::
1054do_encoding () const _THROWS (())
1055{
1056 // 22.2.1.5.2 p6 1(ext.) <=> 1(int.)
1057 return 1;
1058}
1059
1060
1061/* virtual */ int
1062codecvt<wchar_t, char, _RWSTD_MBSTATE_T>::
1063do_max_length () const _THROWS (())
1064{
1065 return 1;
1066}
1067
1068
1069/* virtual */ codecvt_base::result
1070codecvt<wchar_t, char, _RWSTD_MBSTATE_T>::
1071do_out (state_type &state,
1072 const intern_type *from,
1073 const intern_type *from_end,
1074 const intern_type *&from_next,
1075 extern_type *to,
1076 extern_type *to_end,
1077 extern_type *&to_next) const
1078{
1079 // 22.2.1.5.2, p1 - preconditions
1080 _RWSTD_ASSERT (from <= from_end);
1081 _RWSTD_ASSERT (to <= to_end);
1082
1083 // verify that both ranges are valid
1084 _RWSTD_ASSERT (from && from_end || !from && !from_end);
1085 _RWSTD_ASSERT (to && to_end || !to && !to_end);
1086
1087 // next pointers must always be set before returning, even on error
1088 from_next = from;
1089 to_next = to;
1090
1091#ifdef _RWSTDDEBUG
1092
1093 // verify that the conversion state is valid
1094 const int mbstate_valid = _RW::__rw_mbsinit (&state);
1095
1096 _RWSTD_ASSERT (0 != mbstate_valid);
1097
1098#else // if !defined (_RWSTDDEBUG)
1099
1100 _RWSTD_UNUSED (state);
1101
1102#endif // _RWSTDDEBUG
1103
1104 // copy internal sequence to external
1105 for (; from_next != from_end && to_next != to_end; ++from_next, ++to_next)
1106 // prevent conversion problems due to char signedness
1107 *to_next = _RWSTD_STATIC_CAST (unsigned char, *from_next);
1108
1109 // Table 53, and lwg issue 382: do_out() returns partial
1110 // if not all source characters could be converted (e.g.,
1111 // because the destination range is full)
1112 return from_next == from_end ? ok : partial;
1113}
1114
1115
1116/* virtual */ codecvt_base::result
1117codecvt<wchar_t, char, _RWSTD_MBSTATE_T>::
1118do_in (state_type &state,
1119 const extern_type *from,
1120 const extern_type *from_end,
1121 const extern_type *&from_next,
1122 intern_type *to,
1123 intern_type *to_end,
1124 intern_type *&to_next) const
1125{
1126 // 22.2.1.5.2, p1 - preconditions
1127 _RWSTD_ASSERT (from <= from_end);
1128 _RWSTD_ASSERT (to <= to_end);
1129
1130 // verify that both ranges are valid
1131 _RWSTD_ASSERT (from && from_end || !from && !from_end);
1132 _RWSTD_ASSERT (to && to_end || !to && !to_end);
1133
1134 // next pointers must always be set before returning, even on error
1135 from_next = from;
1136 to_next = to;
1137
1138 const int mbstate_valid = _RW::__rw_mbsinit (&state);
1139
1140 _RWSTD_ASSERT (0 != mbstate_valid);
1141 if (!mbstate_valid)
1142 return error;
1143
1144 // copy external sequence to internal
1145 for (; from_next != from_end && to_next != to_end;
1146 ++from_next, ++to_next) {
1147 // prevent conversion problems due to char signedness
1148 *to_next = _RWSTD_STATIC_CAST (unsigned char, *from_next);
1149 }
1150
1151 return from_next == from_end ? ok : partial;
1152}
1153
1154
1155/* virtual */ codecvt_base::result
1156codecvt<wchar_t, char, _RWSTD_MBSTATE_T>::
1157do_unshift (state_type &state,
1158 extern_type *to,
1159 extern_type *to_end,
1160 extern_type *&to_next) const
1161{
1162 // verify that the range is valid
1163 _RWSTD_ASSERT (to <= to_end);
1164 _RWSTD_ASSERT (to && to_end || !to && !to_end);
1165
1166 _RWSTD_UNUSED (to_end);
1167
1168 // next pointer must always be set before returning, even on error
1169 to_next = to;
1170
1171 const int mbstate_valid = _RW::__rw_mbsinit (&state);
1172
1173 _RWSTD_ASSERT (0 != mbstate_valid);
1174 if (!mbstate_valid)
1175 return error;
1176
1177 return noconv;
1178}
1179
1180
1181/* virtual */ int
1182codecvt<wchar_t, char, _RWSTD_MBSTATE_T>::
1183do_length (state_type &state,
1184 const extern_type *from,
1185 const extern_type *from_end,
1186 size_t imax) const
1187{
1188 // 22.2.1.5.2, p9 - preconditions
1189 _RWSTD_ASSERT (from <= from_end);
1190
1191 // verify that the range is valid
1192 _RWSTD_ASSERT (from && from_end || !from && !from_end);
1193
1194 const int mbstate_valid = _RW::__rw_mbsinit (&state);
1195
1196 _RWSTD_ASSERT (0 != mbstate_valid);
1197 if (!mbstate_valid)
1198 return 0;
1199
1200 // 22.2.1.5.2, p10
1201 const size_t len = from_end - from;
1202 return int (len < imax ? len : imax);
1203}
1204
1205
1206// codecvt_byname <wchar,char> specialization
1207codecvt_byname<wchar_t, char, _RWSTD_MBSTATE_T>::
1208codecvt_byname (const char *name, size_t ref)
1209 : codecvt<wchar_t, char, _RWSTD_MBSTATE_T>(ref)
1210{
1211 _C_flags = _RW::__rw_encoding_from_name (name);
1212
1213#if 0
1214
1215 // FIXME: reliably detect whether the encoding is really stateless
1216 // when `name' refers to a libc locale name
1217
1218 if (_RW::stateless == (_C_flags & 0xf)) {
1219 const _RW::__rw_setlocale clocale (_C_name, LC_CTYPE);
1220
1221 _C_flags = mbtowc (0, 0, 0) ? _RW::stateful : _RW::stateless;
1222 }
1223
1224#endif // 0/1
1225
1226 char locale_name [256];
1227
1228 // look for the `@' name modifier in the locale name
1229 const char* mod = strchr (name, '@');
1230 if (mod) {
1231
1232 const char* const mod_nam = mod + 1;
1233 const size_t mod_len = strlen (mod_nam);
1234
1235 // search for one of the known modifiers
1236 if (mod_len > 2 && !memcmp (mod_nam, "UCS", 3)) {
1237
1238 int flags = 0;
1239
1240 for (size_t i = 0; i != _RW::__rw_n_ucsmods; ++i) {
1241 if (!strcmp (_RW::__rw_ucsmods [i].mod, mod_nam)) {
1242 flags = _RW::__rw_ucsmods [i].flags;
1243 break;
1244 }
1245 }
1246
1247 if (flags)
1248 _C_flags |= flags;
1249 else
1250 mod = 0;
1251 }
1252 else
1253 mod = 0; // not a "@UCS-" modifier
1254 }
1255
1256 if (mod) {
1257 _RWSTD_ASSERT (long (mod - name) < long (sizeof locale_name));
1258
1259 memcpy (locale_name, name, mod - name);
1260 locale_name [mod - name] = '\0';
1261 name = locale_name;
1262 }
1263
1264 // handle the special names: UTF-8, UTF-16, UTF-16-BE, UTF-16-LE,
1265 // denoting an external UTF encoding with strict validation rules
1266 // but slower processing, and their relaxed but faster equivalents,
1267 // utf-8, utf-16, utf-16-be, utf-16-le
1268 const size_t name_len = strlen (name);
1269
1270 if (4 < name_len) {
1271
1272 // check whether the UTF- prefix is in lowercase or capital letters
1273 const bool pfx_low = !memcmp (name, "utf-", 4);
1274 const bool pfx_cap = !pfx_low && !memcmp (name, "UTF-", 4);
1275
1276 int flags = 0;
1277
1278 if (pfx_low || pfx_cap) {
1279
1280 if (5 == name_len && '8' == name [4])
1281 flags = __rw_utf8;
1282 else if (!strcmp (name + 4, "16"))
1283 flags = __rw_utf16;
1284 else if (pfx_low) {
1285 if (!strcmp (name + 4, "16-BE"))
1287 else if (!strcmp (name + 4, "16-LE"))
1289 }
1290 else if (pfx_cap) {
1291 if (!strcmp (name + 4, "16-BE"))
1293 else if (!strcmp (name + 4, "16-LE"))
1295 }
1296 }
1297
1298 if (flags) {
1299 _C_flags |= flags;
1300
1301 if (pfx_cap)
1302 _C_flags |= __rw_strict ;
1303
1304 *locale_name = '\0';
1305 name = locale_name;
1306 }
1307 }
1308
1309 if ( this->_C_opts & this->_C_use_libc
1310 && !UCS_TYPE (_C_flags) && !UTF_TYPE (_C_flags))
1311 _C_flags |= __rw_use_libc;
1312
1313 this->_C_set_name (name, _C_namebuf, sizeof _C_namebuf);
1314}
1315
1316
1317// outlined to avoid generating a vtable in each translation unit
1318// that uses the class
1319/* virtual */ codecvt_byname<wchar_t, char, _RWSTD_MBSTATE_T>::~
1320codecvt_byname ()
1321{
1322 // no-op
1323}
1324
1325
1326/* virtual */ codecvt_base::result
1327codecvt_byname<wchar_t, char, _RWSTD_MBSTATE_T>::
1328do_in (state_type& state,
1329 const extern_type* from,
1330 const extern_type* from_end,
1331 const extern_type*& from_next,
1332 intern_type* to,
1333 intern_type* to_limit,
1334 intern_type*& to_next) const
1335{
1336 // 22.2.1.5.2 p1
1337 _RWSTD_ASSERT (from <= from_end);
1338 _RWSTD_ASSERT (to <= to_limit);
1339
1340 // verify that both ranges are valid
1341 _RWSTD_ASSERT (from && from_end || !from && !from_end);
1342 _RWSTD_ASSERT (to && to_limit || !to && !to_limit);
1343
1344 // the standard does not specify the value of
1345 // *next pointers at entry;
1346 from_next = from;
1347 to_next = to;
1348
1349 // do_in result
1350 result res = error;
1351
1352 // test the type of the encoding that the facet is interpreting
1353 switch (ISO2022_TYPE (_C_flags)) {
1354
1355 case _RW::stateless: {
1356
1357 // obtain the mapping of the database file
1358 const _RW::__rw_codecvt_t* const impl =
1359 _RWSTD_STATIC_CAST (const _RW::__rw_codecvt_t*, this->_C_data ());
1360
1361 if (USE_LIBC (impl, _C_flags)) {
1362 // use libc locale
1363 const _RW::__rw_setlocale clocale (_C_name, LC_CTYPE);
1364
1365#ifndef _RWSTD_NO_MBTOWC
1366
1367 // verify that either the encoding is stateful
1368 // or the state is in its initial shift state
1369 const bool mbstate_valid =
1370 mbtowc (0, 0, 0) || _RW::__rw_mbsinit (&state);
1371
1372 _RWSTD_ASSERT (mbstate_valid);
1373 _RWSTD_UNUSED (mbstate_valid);
1374
1375#endif // _RWSTD_NO_MBTOWC
1376
1377 res = _RW::__rw_libc_do_in (state,
1378 from, from_end, from_next,
1379 to, to_limit, to_next);
1380 }
1381 else {
1382
1383 // verify that the state is in its initial shift state
1384 const int mbstate_valid = _RW::__rw_mbsinit (&state);
1385 _RWSTD_ASSERT (mbstate_valid);
1386
1387 _RWSTD_UNUSED (mbstate_valid);
1388
1389 res = _RW::__rw_libstd_do_in (from_end, from_next,
1390 to_limit, to_next,
1391 _C_flags, impl);
1392 }
1393 break;
1394 }
1395
1396 case _RW::iso2022_jp:
1397 res = _RW::__rw_iso2022jp_do_in (state, from_next, from_end,
1398 to_next, to_limit);
1399 break;
1400
1401 case _RW::iso2022_jp2:
1402 res = _RW::__rw_iso2022jp2_do_in (state, from_next, from_end,
1403 to_next, to_limit);
1404 break;
1405
1406 case _RW::iso2022_kr:
1407 case _RW::iso2022_cn:
1408 default:
1409 break;
1410 };
1411
1412 return res;
1413}
1414
1415
1416/* virtual */ codecvt_base::result
1417codecvt_byname<wchar_t, char, _RWSTD_MBSTATE_T>::
1418do_out (state_type &state,
1419 const intern_type *from,
1420 const intern_type *from_end,
1421 const intern_type *&from_next,
1422 extern_type *to,
1423 extern_type *to_limit,
1424 extern_type *&to_next) const
1425{
1426 // 22.2.1.5.2 p1
1427 _RWSTD_ASSERT (from <= from_end);
1428 _RWSTD_ASSERT (to <= to_limit);
1429
1430 // verify that both ranges are valid
1431 _RWSTD_ASSERT (from && from_end || !from && !from_end);
1432 _RWSTD_ASSERT (to && to_limit || !to && !to_limit);
1433
1434 // the standard does not specify the value of the next pointers on entry
1435 from_next = from;
1436 to_next = to;
1437
1438 // conversion result
1439 codecvt_base::result res = codecvt_base::error;
1440
1441 // test the type of the encoding that the facet is interpreting
1442 switch (ISO2022_TYPE (_C_flags)) {
1443
1444 case _RW::stateless: {
1445
1446 // obtain the mapping of the database file
1447 const _RW::__rw_codecvt_t* impl =
1448 _RWSTD_STATIC_CAST(const _RW::__rw_codecvt_t*, this->_C_data ());
1449
1450 if (USE_LIBC (impl, _C_flags)) {
1451 // use libc locale
1452 const _RW::__rw_setlocale clocale (_C_name, LC_CTYPE);
1453
1454#ifndef _RWSTD_NO_MBTOWC
1455
1456 // verify that either the encoding is stateful
1457 // or the state is in its initial shift state
1458 const bool mbstate_valid =
1459 mbtowc (0, 0, 0) || _RW::__rw_mbsinit (&state);
1460
1461 _RWSTD_ASSERT (mbstate_valid);
1462 _RWSTD_UNUSED (mbstate_valid);
1463
1464#endif // _RWSTD_NO_MBTOWC
1465
1466 res = _RW::__rw_libc_do_out (state, from, from_end, from_next,
1467 to, to_limit, to_next);
1468 }
1469 else {
1470 // verify that the state is in its initial shift state
1471 const int mbstate_valid = _RW::__rw_mbsinit (&state);
1472 _RWSTD_ASSERT (mbstate_valid);
1473
1474 _RWSTD_UNUSED (mbstate_valid);
1475
1476 // use own implementation
1477 res = _RW::__rw_libstd_do_out (from, from_end, from_next,
1478 to, to_limit, to_next,
1479 _C_flags, impl);
1480 }
1481 break;
1482 }
1483 case _RW::iso2022_jp:
1484 res = _RW::__rw_iso2022jp_do_out (state, from_next, from_end,
1485 to_next, to_limit);
1486 break;
1487 case _RW::iso2022_jp2:
1488 res = _RW::__rw_iso2022jp2_do_out (state, from_next, from_end,
1489 to_next, to_limit);
1490 break;
1491 case _RW::iso2022_kr:
1492 case _RW::iso2022_cn:
1493 default:
1494 break;
1495 };
1496
1497 return res;
1498}
1499
1500
1501/* virtual */ codecvt_base::result
1502codecvt_byname<wchar_t, char, _RWSTD_MBSTATE_T>::
1503do_unshift (state_type& state,
1504 extern_type* to,
1505 extern_type* to_limit,
1506 extern_type*& to_next) const
1507{
1508 // verify that the range is valid
1509 _RWSTD_ASSERT (to <= to_limit);
1510 _RWSTD_ASSERT (to && to_limit || !to && !to_limit);
1511
1512 // the standard does not specify the value of
1513 // to_next pointer at entry;
1514 to_next = to;
1515
1516 // do_unshift result
1517 codecvt_base::result res = codecvt_base::error;
1518
1519 // test the type of the encoding that the facet is interpreting
1520 switch (ISO2022_TYPE (_C_flags)) {
1521
1522 case _RW::stateless:
1523
1524 if (USE_LIBC (_C_impdata, _C_flags)) {
1525
1526 const _RW::__rw_setlocale clocale (_C_name, LC_CTYPE);
1527
1528 if (mbtowc (0, 0, 0) == 0) {
1529 // verify that the state is in its initial shift state
1530 const int mbstate_valid = _RW::__rw_mbsinit (&state);
1531 _RWSTD_ASSERT (mbstate_valid);
1532
1533 res = mbstate_valid ? noconv : error;
1534 }
1535 else
1536 res = _RW::__rw_libc_do_unshift (state, to_next, to_limit);
1537 }
1538 else {
1539 // use our own implementation
1540
1541 // verify that the state is in its initial shift state
1542 const int mbstate_valid = _RW::__rw_mbsinit (&state);
1543 _RWSTD_ASSERT (mbstate_valid);
1544
1545 res = mbstate_valid ? noconv : error;
1546 }
1547 break;
1548
1549 case _RW::iso2022_jp:
1550 res = _RW::__rw_iso2022jp_do_unshift (state, to_next, to_limit);
1551 break;
1552 case _RW::iso2022_jp2:
1553 res = _RW::__rw_iso2022jp2_do_unshift (state, to_next, to_limit);
1554 break;
1555 case _RW::iso2022_kr:
1556 case _RW::iso2022_cn:
1557 default:
1558 break;
1559 };
1560
1561 return res;
1562}
1563
1564
1565/* virtual */ int
1566codecvt_byname<wchar_t, char, _RWSTD_MBSTATE_T>::
1567do_length (state_type& state,
1568 const extern_type *from,
1569 const extern_type *from_end,
1570 size_t cmax) const
1571{
1572 // 22.2.1.5.2 p1
1573 _RWSTD_ASSERT (from <= from_end);
1574
1575 // verify that the range is valid
1576 _RWSTD_ASSERT (from && from_end || !from && !from_end);
1577
1578 size_t len = 0;
1579
1580 // test the type of the encoding that the facet is interpreting
1581 switch (ISO2022_TYPE (_C_flags)) {
1582
1583 case _RW::stateless: {
1584
1585 // obtain the mapping of the database file
1586 const _RW::__rw_codecvt_t* impl =
1587 _RWSTD_STATIC_CAST(const _RW::__rw_codecvt_t*, this->_C_data ());
1588
1589 if (USE_LIBC (impl, _C_flags)) {
1590 // use libc locale
1591 const _RW::__rw_setlocale clocale (this->_C_name, LC_CTYPE);
1592
1593#ifndef _RWSTD_NO_MBTOWC
1594
1595 // verify that either the encoding is stateful
1596 // or the state is in its initial shift state
1597 const bool mbstate_valid =
1598 mbtowc (0, 0, 0) || _RW::__rw_mbsinit (&state);
1599
1600 _RWSTD_ASSERT (mbstate_valid);
1601 _RWSTD_UNUSED (mbstate_valid);
1602
1603#endif // _RWSTD_NO_MBTOWC
1604
1605 len = _RW::__rw_libc_do_length (state, from, from_end, cmax);
1606 }
1607 else {
1608 // verify that the state is in its initial shift state
1609 const int mbstate_valid = _RW::__rw_mbsinit (&state);
1610 _RWSTD_ASSERT (mbstate_valid);
1611
1612 _RWSTD_UNUSED (mbstate_valid);
1613
1614 len = _RW::__rw_libstd_do_length (from, from_end,
1615 cmax, _C_flags, impl);
1616 }
1617 break;
1618 }
1619 case _RW::iso2022_jp:
1620 len = _RW::__rw_iso2022jp_do_length (state, from, from_end, cmax);
1621 break;
1622 case _RW::iso2022_jp2:
1623 len = _RW::__rw_iso2022jp2_do_length (state, from, from_end, cmax);
1624 break;
1625 case _RW::iso2022_kr:
1626 case _RW::iso2022_cn:
1627 default:
1628 break;
1629 };
1630
1631 return int (len);
1632}
1633
1634
1635/* virtual */ int
1636codecvt_byname<wchar_t, char, _RWSTD_MBSTATE_T>::
1637do_encoding () const _THROWS (())
1638{
1639
1640 // -7- Returns: -1 if the encoding of the extern_type sequence is
1641 // state-dependent; else the constant number of extern_type
1642 // characters needed to produce an internal character;
1643 // or 0 if this number is not a constant 227).
1644 // _____________
1645 // Footnote 227: If encoding() yields -1, then more than max_length()
1646 // extern_type elements may be consumed when producing a single internT
1647 // character, and additional extern_type elements may appear at the end
1648 // of a sequence after those that yield the final intern_type character.
1649
1650 int enc = 0; // variable-width stateless encoding
1651
1652 // test the type of the encoding that the facet is interpreting
1653 switch (ISO2022_TYPE (_C_flags)) {
1654
1655 case _RW::stateless: {
1656 // obtain the database file mapping
1657 const _RW::__rw_codecvt_t* impl =
1658 _RWSTD_STATIC_CAST(const _RW::__rw_codecvt_t*, this->_C_data ());
1659
1660 if (USE_LIBC (impl, _C_flags)) {
1661 // 7.20.7.2 of C99: if first arg is 0, mbtowc() returns non-zero
1662 // or 0 whether or not the encoding is stateful or stateless
1663 const _RW::__rw_setlocale clocale (_C_name, LC_CTYPE);
1664
1665 if (mbtowc (0, 0, 0)) {
1666 // in a stateful encoding, the number of extern_type
1667 // elements required to produce a single intern_type
1668 // character is indeterminate
1669 enc = -1;
1670 }
1671 else {
1672 // in a stateless encoding, the number of extern_type
1673 // elements required to produce a single intern_type
1674 // character is guaranteed to be 1 only when MB_CUR_MAX
1675 // is also 1, otherwise it's most likely to be variable
1676 // (e.g., EUC, UTF-8, etc.)
1677 if (1 == MB_CUR_MAX)
1678 enc = 1;
1679 }
1680 }
1681 else {
1682 // use own implementation
1683 // 22.2.1.5.2 p6
1684 if (impl)
1685 enc = 1 < impl->mb_cur_max ? 0 : 1;
1686 else
1687 enc = 0;
1688 }
1689
1690 break;
1691 }
1692 case _RW::iso2022_jp:
1693 enc = _RW::__rw_iso2022jp_do_encoding ();
1694 break;
1695 case _RW::iso2022_jp2:
1696 enc = _RW::__rw_iso2022jp2_do_encoding ();
1697 break;
1698 case _RW::iso2022_kr:
1699 case _RW::iso2022_cn:
1700 default:
1701 break;
1702 };
1703
1704 return enc;
1705}
1706
1707
1708/* virtual */ int
1709codecvt_byname<wchar_t, char, _RWSTD_MBSTATE_T>::
1710do_max_length () const _THROWS (())
1711{
1712 // returns the max value do_length (s, from, from_end, 1) can return
1713 // for any valid range [from, from_end) - see LWG issue 74 (a DR)
1714 size_t max_len = 0;
1715
1716 // test the type of the encoding that the facet is interpreting
1717 switch (ISO2022_TYPE (_C_flags)) {
1718
1719 case _RW::stateless: {
1720 // obtain the database file mapping
1721 const _RW::__rw_codecvt_t* impl =
1722 _RWSTD_STATIC_CAST(const _RW::__rw_codecvt_t*, this->_C_data ());
1723
1724 if (USE_LIBC (impl, _C_flags)) {
1725 // use libc locale
1726 const _RW::__rw_setlocale clocale (_C_name, LC_CTYPE);
1727
1728 max_len = size_t (MB_CUR_MAX);
1729 }
1730 else {
1731 // use own implementation
1732 if (IS_UTF8 (_C_flags))
1733 max_len = _UTF8_MB_CUR_MAX;
1734 else if (impl)
1735 max_len = size_t (impl->mb_cur_max);
1736 }
1737 break;
1738 }
1739 case _RW::iso2022_jp:
1740 max_len = _RW::__rw_iso2022jp_do_max_length ();
1741 break;
1742 case _RW::iso2022_jp2:
1743 max_len = _RW::__rw_iso2022jp2_do_max_length ();
1744 break;
1745 case _RW::iso2022_kr:
1746 case _RW::iso2022_cn:
1747 default:
1748 break;
1749 };
1750
1751 return int (max_len);
1752}
1753
1754#endif // _RWSTD_NO_WCHAR_T
1755
1756} // namespace std
1757
1758
1759#ifndef _RWSTD_NO_WCHAR_T
1760
1761# define TARGS_W <wchar_t, char, _RWSTD_MBSTATE_T>
1762
1763_RWSTD_DEFINE_FACET_FACTORY (static, codecvt, TARGS_W, wcodecvt);
1765
1766#endif // _RWSTD_NO_WCHAR_T
#define i
Definition 17.names.cpp:126
#define res
Definition 17.names.cpp:531
#define index
Definition 17.names.cpp:482
#define off
Definition 17.names.cpp:507
#define sz
Definition 17.names.cpp:550
#define tmp
Definition 17.names.cpp:553
#define len
Definition 17.names.cpp:488
volatile int result
#define flags
#define _THROWS()
#define LC_CTYPE
unsigned short wchar_t
#define _RWSTD_DLLIMPORT
Definition _config.h:391
#define MB_CUR_MAX
#define _RWSTD_REINTERPRET_CAST(T, x)
Definition _defs.h:535
#define _RWSTD_UNUSED(arg)
Definition _defs.h:972
#define _RWSTD_STATIC_CAST(T, x)
Definition _defs.h:534
#define _LIBC_THROWS()
Definition _defs.h:1152
#define _RWSTD_NAMESPACE(name)
Definition _defs.h:567
#define _RWSTD_UWCHAR_INT_T
Definition _defs.h:1287
#define _RWSTD_ASSERT(ignore)
Definition _defs.h:1108
#define _USING(name)
Definition _defs.h:568
#define _RWSTD_MBSTATE_T
Definition _mbstate.h:199
const char * name
Definition codecvt1.cpp:72
const char * str
Definition exec.cpp:170
Definition json.h:5363
_RWSTD_MBSTATE_T StateT
Definition codecvt.cpp:68
unsigned char UChar
Definition collate.cpp:122
#define _RWSTD_SPECIALIZE_USE_FACET(fid)
Definition use_facet.h:129
#define _RWSTD_DEFINE_FACET_FACTORY(Linkage, Facet, TArgs, fid)
Definition use_facet.h:52
#define IS_UCS(x)
Definition wcodecvt.cpp:199
#define ISO2022_TYPE(x)
Definition wcodecvt.cpp:193
_RWSTD_MBSTATE_T StateT
Definition wcodecvt.cpp:216
#define UCS_TYPE(x)
Definition wcodecvt.cpp:196
#define UTF_TYPE(x)
Definition wcodecvt.cpp:197
#define TARGS_W
#define USE_LIBC(impl, x)
Definition wcodecvt.cpp:211
#define IS_UTF8(x)
Definition wcodecvt.cpp:205
#define _UTF8_MB_CUR_MAX
Definition wcodecvt.cpp:149
@ __rw_ucs
Definition wcodecvt.cpp:159
@ __rw_utf16_le
Definition wcodecvt.cpp:176
@ __rw_utf_mask
Definition wcodecvt.cpp:190
@ __rw_ucs4
Definition wcodecvt.cpp:166
@ __rw_strict
Definition wcodecvt.cpp:179
@ __rw_ucs2
Definition wcodecvt.cpp:171
@ __rw_ucs2_le
Definition wcodecvt.cpp:170
@ __rw_ucs2_be
Definition wcodecvt.cpp:169
@ __rw_ucs4_le
Definition wcodecvt.cpp:164
@ __rw_utf8
Definition wcodecvt.cpp:174
@ __rw_use_libc
Definition wcodecvt.cpp:181
@ __rw_ucs4_be
Definition wcodecvt.cpp:162
@ __rw_utf16_be
Definition wcodecvt.cpp:175
@ __rw_2022_mask
Definition wcodecvt.cpp:154
@ __rw_ucs4_le_be
Definition wcodecvt.cpp:165
@ __rw_ucs_be
Definition wcodecvt.cpp:157
@ __rw_ucs4_be_le
Definition wcodecvt.cpp:163
@ __rw_utf16
Definition wcodecvt.cpp:177
@ __rw_ucs_le
Definition wcodecvt.cpp:158
@ __rw_ucs_mask
Definition wcodecvt.cpp:184