1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
5 Notes on the codecvt implementation.
10 Notes on the codecvt implementation.
14 prepared by Benjamin Kosnik (bkoz@redhat.com) on August 28, 2000
21 The standard class codecvt attempts to address conversions between
22 different character encoding schemes. In particular, the standard
23 attempts to detail conversions between the implementation-defined wide
24 characters (hereafter referred to as wchar_t) and the standard type
25 char that is so beloved in classic "C" (which can now be referred to
26 as narrow characters.) This document attempts to describe how the GNU
27 libstdc++-v3 implementation deals with the conversion between wide and
28 narrow characters, and also presents a framework for dealing with the
29 huge number of other encodings that iconv can convert, including
30 Unicode and UTF8. Design issues and requirements are addressed, and
31 examples of correct usage for both the required specializations for
32 wide and narrow characters and the implementation-provided extended
33 functionality are given.
38 2. What the standard says
40 Around page 425 of the C++ Standard, this charming heading comes into view:
43 22.2.1.5 - Template class codecvt [lib.locale.codecvt]
46 The text around the codecvt definition gives some clues:
50 -1- The class codecvt<internT,externT,stateT> is for use when
51 converting from one codeset to another, such as from wide characters
52 to multibyte characters, between wide character encodings such as
58 Hmm. So, in some unspecified way, Unicode encodings and
59 translations between other character sets should be handled by this
65 -2- The stateT argument selects the pair of codesets being mapped between.
70 Ah ha! Another clue...
75 -3- The instantiations required in the Table ??
76 (lib.locale.category), namely codecvt<wchar_t,char,mbstate_t> and
77 codecvt<char,char,mbstate_t>, convert the implementation-defined
78 native character set. codecvt<char,char,mbstate_t> implements a
79 degenerate conversion; it does not convert at
80 all. codecvt<wchar_t,char,mbstate_t> converts between the native
81 character sets for tiny and wide characters. Instantiations on
82 mbstate_t perform conversion between encodings known to the library
83 implementor. Other encodings can be converted by specializing on a
84 user-defined stateT type. The stateT object can contain any state that
85 is useful to communicate to or from the specialized do_convert member.
90 At this point, a couple points become clear:
93 One: The standard clearly implies that attempts to add non-required
94 (yet useful and widely used) conversions need to do so through the
95 third template parameter, stateT.</p>
98 Two: The required conversions, by specifying mbstate_t as the third
99 template parameter, imply an implementation strategy that is mostly
100 (or wholly) based on the underlying C library, and the functions
101 mcsrtombs and wcsrtombs in particular.</p>
105 3. Some thoughts on what would be useful
107 Probably the most frequently asked question about code conversion is:
108 "So dudes, what's the deal with Unicode strings?" The dude part is
109 optional, but apparently the usefulness of Unicode strings is pretty
110 widely appreciated. Sadly, this specific encoding (And other useful
111 encodings like UTF8, UCS4, ISO 8859-10, etc etc etc) are not mentioned
115 In particular, the simple implementation detail of wchar_t's size
116 seems to repeatedly confound people. Many systems use a two byte,
117 unsigned integral type to represent wide characters, and use an
118 internal encoding of Unicode or UCS2. (See AIX, Microsoft NT, Java,
119 others.) Other systems, use a four byte, unsigned integral type to
120 represent wide characters, and use an internal encoding of
121 UCS4. (GNU/Linux systems using glibc, in particular.) The C
122 programming language (and thus C++) does not specify a specific size
123 for the type wchar_t.
126 Thus, portable C++ code cannot assume a byte size (or endianness) either.
129 Getting back to the frequently asked question: What about Unicode strings?
132 What magic spell will do this conversion?
135 A couple of comments:
139 The thought that all one needs to convert between two arbitrary
140 codesets is two types and some kind of state argument is
141 unfortunate. In particular, encodings may be stateless. The naming of
142 the third parameter as stateT is unfortunate, as what is really needed
143 is some kind of generalized type that accounts for the issues that
144 abstract encodings will need. The minimum information that is required
151 Identifiers for each of the codesets involved in the conversion. For
152 example, using the iconv family of functions from the Single Unix
153 Specification (what used to be called X/Open) hosted on the GNU/Linux
154 operating system allows bi-directional mapping between far more than
155 the following tantalizing possibilities:
158 (An edited list taken from <code>`iconv --list`</code> on a Red Hat 6.2/Intel system:
162 8859_1, 8859_9, 10646-1:1993, 10646-1:1993/UCS4, ARABIC, ARABIC7,
163 ASCII, EUC-CN, EUC-JP, EUC-KR, EUC-TW, GREEK-CCIcode, GREEK, GREEK7-OLD,
164 GREEK7, GREEK8, HEBREW, ISO-8859-1, ISO-8859-2, ISO-8859-3,
165 ISO-8859-4, ISO-8859-5, ISO-8859-6, ISO-8859-7, ISO-8859-8,
166 ISO-8859-9, ISO-8859-10, ISO-8859-11, ISO-8859-13, ISO-8859-14,
167 ISO-8859-15, ISO-10646, ISO-10646/UCS2, ISO-10646/UCS4,
168 ISO-10646/UTF-8, ISO-10646/UTF8, SHIFT-JIS, SHIFT_JIS, UCS-2, UCS-4,
169 UCS2, UCS4, UNICODE, UNICODEBIG, UNICODELIcodeLE, US-ASCII, US, UTF-8,
170 UTF-16, UTF8, UTF16).
175 For iconv-based implementations, string literals for each of the
176 encodings (ie. "UCS-2" and "UTF-8") are necessary,
178 non-iconv implementations a table of enumerated values or some other
179 mechanism may be required.
182 Maximum length of the identifying string literal.
185 Some encodings are require explicit endian-ness. As such, some kind
186 of endian marker or other byte-order marker will be necessary. See
187 "Footnotes for C/C++ developers" in Haible for more information on
188 UCS-2/Unicode endian issues. (Summary: big endian seems most likely,
189 however implementations, most notably Microsoft, vary.)
192 Types representing the conversion state, for conversions involving
193 the machinery in the "C" library, or the conversion descriptor, for
194 conversions using iconv (such as the type iconv_t.) Note that the
195 conversion descriptor encodes more information than a simple encoding
199 Conversion descriptors for both directions of encoding. (ie, both
200 UCS-2 to UTF-8 and UTF-8 to UCS-2.)
203 Something to indicate if the conversion requested if valid.
206 Something to represent if the conversion descriptors are valid.
209 Some way to enforce strict type checking on the internal and
210 external types. As part of this, the size of the internal and
211 external types will need to be known.
216 4. Problems with "C" code conversions : thread safety, global
217 locales, termination.
220 In addition, multi-threaded and multi-locale environments also impact
221 the design and requirements for code conversions. In particular, they
222 affect the required specialization codecvt<wchar_t, char, mbstate_t>
223 when implemented using standard "C" functions.
226 Three problems arise, one big, one of medium importance, and one small.
229 First, the small: mcsrtombs and wcsrtombs may not be multithread-safe
230 on all systems required by the GNU tools. For GNU/Linux and glibc,
231 this is not an issue.
234 Of medium concern, in the grand scope of things, is that the functions
235 used to implement this specialization work on null-terminated
236 strings. Buffers, especially file buffers, may not be null-terminated,
237 thus giving conversions that end prematurely or are otherwise
241 The last, and fundamental problem, is the assumption of a global
242 locale for all the "C" functions referenced above. For something like
243 C++ iostreams (where codecvt is explicitly used) the notion of
244 multiple locales is fundamental. In practice, most users may not run
245 into this limitation. However, as a quality of implementation issue,
246 the GNU C++ library would like to offer a solution that allows
247 multiple locales and or simultaneous usage with computationally
248 correct results. In short, libstdc++-v3 is trying to offer, as an
249 option, a high-quality implementation, damn the additional complexity!
252 For the required specialization codecvt<wchar_t, char, mbstate_t> ,
253 conversions are made between the internal character set (always UCS4
254 on GNU/Linux) and whatever the currently selected locale for the
255 LC_CTYPE category implements.
261 The two required specializations are implemented as follows:
265 codecvt<char, char, mbstate_t>
268 This is a degenerate (ie, does nothing) specialization. Implementing
269 this was a piece of cake.
273 codecvt<char, wchar_t, mbstate_t>
276 This specialization, by specifying all the template parameters, pretty
277 much ties the hands of implementors. As such, the implementation is
278 straightforward, involving mcsrtombs for the conversions between char
279 to wchar_t and wcsrtombs for conversions between wchar_t and char.
282 Neither of these two required specializations deals with Unicode
283 characters. As such, libstdc++-v3 implements a partial specialization
284 of the codecvt class with and iconv wrapper class, __enc_traits as the
285 third template parameter.
288 This implementation should be standards conformant. First of all, the
289 standard explicitly points out that instantiations on the third
290 template parameter, stateT, are the proper way to implement
291 non-required conversions. Second of all, the standard says (in Chapter
292 17) that partial specializations of required classes are a-ok. Third
293 of all, the requirements for the stateT type elsewhere in the standard
294 (see 21.1.2 traits typedefs) only indicate that this type be copy
298 As such, the type __enc_traits is defined as a non-templatized, POD
299 type to be used as the third type of a codecvt instantiation. This
300 type is just a wrapper class for iconv, and provides an easy interface
301 to iconv functionality.
304 There are two constructors for __enc_traits:
308 __enc_traits() : __in_desc(0), __out_desc(0)
311 This default constructor sets the internal encoding to some default
312 (currently UCS4) and the external encoding to whatever is returned by
313 nl_langinfo(CODESET).
317 __enc_traits(const char* __int, const char* __ext)
320 This constructor takes as parameters string literals that indicate the
321 desired internal and external encoding. There are no defaults for
325 One of the issues with iconv is that the string literals identifying
326 conversions are not standardized. Because of this, the thought of
327 mandating and or enforcing some set of pre-determined valid
328 identifiers seems iffy: thus, a more practical (and non-migraine
329 inducing) strategy was implemented: end-users can specify any string
330 (subject to a pre-determined length qualifier, currently 32 bytes) for
331 encodings. It is up to the user to make sure that these strings are
332 valid on the target system.
340 Strangely enough, this member function attempts to open conversion
341 descriptors for a given __enc_traits object. If the conversion
342 descriptors are not valid, the conversion descriptors returned will
343 not be valid and the resulting calls to the codecvt conversion
344 functions will return error.
352 Provides a way to see if the given __enc_traits object has been
353 properly initialized. If the string literals describing the desired
354 internal and external encoding are not valid, initialization will
355 fail, and this will return false. If the internal and external
356 encodings are valid, but iconv_open could not allocate conversion
357 descriptors, this will also return false. Otherwise, the object is
358 ready to convert and will return true.
362 __enc_traits(const __enc_traits&)
365 As iconv allocates memory and sets up conversion descriptors, the copy
366 constructor can only copy the member data pertaining to the internal
367 and external code conversions, and not the conversion descriptors
371 Definitions for all the required codecvt member functions are provided
372 for this specialization, and usage of codecvt<internal character type,
373 external character type, __enc_traits> is consistent with other
383 a. conversions involving string literals
386 typedef codecvt_base::result result;
387 typedef unsigned short unicode_t;
388 typedef unicode_t int_type;
389 typedef char ext_type;
390 typedef __enc_traits enc_type;
391 typedef codecvt<int_type, ext_type, enc_type> unicode_codecvt;
393 const ext_type* e_lit = "black pearl jasmine tea";
394 int size = strlen(e_lit);
395 int_type i_lit_base[24] =
396 { 25088, 27648, 24832, 25344, 27392, 8192, 28672, 25856, 24832, 29184,
397 27648, 8192, 27136, 24832, 29440, 27904, 26880, 28160, 25856, 8192, 29696,
400 const int_type* i_lit = i_lit_base;
401 const ext_type* efrom_next;
402 const int_type* ifrom_next;
403 ext_type* e_arr = new ext_type[size + 1];
405 int_type* i_arr = new int_type[size + 1];
408 // construct a locale object with the specialized facet.
409 locale loc(locale::classic(), new unicode_codecvt);
410 // sanity check the constructed locale has the specialized facet.
411 VERIFY( has_facet<unicode_codecvt>(loc) );
412 const unicode_codecvt& cvt = use_facet<unicode_codecvt>(loc);
413 // convert between const char* and unicode strings
414 unicode_codecvt::state_type state01("UNICODE", "ISO_8859-1");
415 initialize_state(state01);
416 result r1 = cvt.in(state01, e_lit, e_lit + size, efrom_next,
417 i_arr, i_arr + size, ito_next);
418 VERIFY( r1 == codecvt_base::ok );
419 VERIFY( !int_traits::compare(i_arr, i_lit, size) );
420 VERIFY( efrom_next == e_lit + size );
421 VERIFY( ito_next == i_arr + size );
424 b. conversions involving std::string
426 c. conversions involving std::filebuf and std::ostream
429 More information can be found in the following testcases:
431 <li> testsuite/22_locale/codecvt_char_char.cc
432 <li> testsuite/22_locale/codecvt_unicode_wchar_t.cc
433 <li> testsuite/22_locale/codecvt_unicode_char.cc
434 <li> testsuite/22_locale/codecvt_wchar_t_char.cc
443 a. things that are sketchy, or remain unimplemented:
444 do_encoding, max_length and length member functions
445 are only weakly implemented. I have no idea how to do
446 this correctly, and in a generic manner. Nathan?
449 b. conversions involving std::string
453 how should operators != and == work for string of
454 different/same encoding?
457 what is equal? A byte by byte comparison or an
458 encoding then byte comparison?
461 conversions between narrow, wide, and unicode strings
464 c. conversions involving std::filebuf and std::ostream
467 how to initialize the state object in a
468 standards-conformant manner?
471 how to synchronize the "C" and "C++"
472 conversion information?
475 wchar_t/char internal buffers and conversions between
476 internal/external buffers?
484 Ulrich Drepper for the iconv suggestions and patient answering of
485 late-night questions, Jason Merrill for the template partial
486 specialization hints, language clarification, and wchar_t fixes.
490 9. Bibliography / Referenced Documents
493 Drepper, Ulrich, GNU libc (glibc) 2.2 manual. In particular, Chapters "6. Character Set Handling" and "7 Locales and Internationalization"
496 Drepper, Ulrich, Numerous, late-night email correspondence
499 Feather, Clive, "A brief description of Normative Addendum 1," in particular the parts on Extended Character Sets
500 http://www.lysator.liu.se/c/na1.html
503 Haible, Bruno, "The Unicode HOWTO" v0.18, 4 August 2000
504 ftp://ftp.ilog.fr/pub/Users/haible/utf8/Unicode-HOWTO.html
507 ISO/IEC 14882:1998 Programming languages - C++
510 ISO/IEC 9899:1999 Programming languages - C
513 Khun, Markus, "UTF-8 and Unicode FAQ for Unix/Linux"
514 http://www.cl.cam.ac.uk/~mgk25/unicode.html
517 Langer, Angelika and Klaus Kreft, Standard C++ IOStreams and Locales, Advanced Programmer's Guide and Reference, Addison Wesley Longman, Inc. 2000
520 Stroustrup, Bjarne, Appendix D, The C++ Programming Language, Special Edition, Addison Wesley, Inc. 2000
523 System Interface Definitions, Issue 6 (IEEE Std. 1003.1-200x)
524 The Open Group/The Institute of Electrical and Electronics Engineers, Inc.
525 http://www.opennc.org/austin/docreg.html