OSDN Git Service

2007-01-29 Benjamin Kosnik <bkoz@redhat.com>
[pf3gnuchains/gcc-fork.git] / libstdc++-v3 / include / ext / codecvt_specializations.h
1 // Locale support (codecvt) -*- C++ -*-
2
3 // Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
4 //  Free Software Foundation, Inc.
5 //
6 // This file is part of the GNU ISO C++ Library.  This library is free
7 // software; you can redistribute it and/or modify it under the
8 // terms of the GNU General Public License as published by the
9 // Free Software Foundation; either version 2, or (at your option)
10 // any later version.
11
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 // GNU General Public License for more details.
16
17 // You should have received a copy of the GNU General Public License along
18 // with this library; see the file COPYING.  If not, write to the Free
19 // Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20 // USA.
21
22 // As a special exception, you may use this file as part of a free software
23 // library without restriction.  Specifically, if other files instantiate
24 // templates or use macros or inline functions from this file, or you compile
25 // this file and link it with other files to produce an executable, this
26 // file does not by itself cause the resulting executable to be covered by
27 // the GNU General Public License.  This exception does not however
28 // invalidate any other reasons why the executable file might be covered by
29 // the GNU General Public License.
30
31 //
32 // ISO C++ 14882: 22.2.1.5 Template class codecvt
33 //
34
35 // Written by Benjamin Kosnik <bkoz@redhat.com>
36
37 /** @file ext/codecvt_specializations.h
38  *  This file is a GNU extension to the Standard C++ Library.
39  */
40
41 #ifndef _EXT_CODECVT_SPECIALIZATIONS_H
42 #define _EXT_CODECVT_SPECIALIZATIONS_H 1
43
44 #include <bits/c++config.h>
45 #include <locale>
46 #include <iconv.h>
47
48 _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
49
50   /// @brief  Extension to use icov for dealing with character encodings.
51   // This includes conversions and comparisons between various character
52   // sets.  This object encapsulates data that may need to be shared between
53   // char_traits, codecvt and ctype.
54   class encoding_state
55   {
56   public:
57     // Types: 
58     // NB: A conversion descriptor subsumes and enhances the
59     // functionality of a simple state type such as mbstate_t.
60     typedef iconv_t     descriptor_type;
61     
62   protected:
63     // Name of internal character set encoding.
64     std::string         _M_int_enc;
65
66     // Name of external character set encoding.
67     std::string         _M_ext_enc;
68
69     // Conversion descriptor between external encoding to internal encoding.
70     descriptor_type     _M_in_desc;
71
72     // Conversion descriptor between internal encoding to external encoding.
73     descriptor_type     _M_out_desc;
74
75     // The byte-order marker for the external encoding, if necessary.
76     int                 _M_ext_bom;
77
78     // The byte-order marker for the internal encoding, if necessary.
79     int                 _M_int_bom;
80
81     // Number of external bytes needed to construct one complete
82     // character in the internal encoding.
83     // NB: -1 indicates variable, or stateful, encodings.
84     int                 _M_bytes;
85
86   public:
87     explicit 
88     encoding_state() 
89     : _M_in_desc(0), _M_out_desc(0), _M_ext_bom(0), _M_int_bom(0), _M_bytes(0)
90     { }
91
92     explicit 
93     encoding_state(const char* __int, const char* __ext, 
94                    int __ibom = 0, int __ebom = 0, int __bytes = 1)
95     : _M_int_enc(__int), _M_ext_enc(__ext), _M_in_desc(0), _M_out_desc(0), 
96       _M_ext_bom(__ebom), _M_int_bom(__ibom), _M_bytes(__bytes)
97     { init(); }
98
99     // 21.1.2 traits typedefs
100     // p4
101     // typedef STATE_T state_type
102     // requires: state_type shall meet the requirements of
103     // CopyConstructible types (20.1.3)
104     // NB: This does not preseve the actual state of the conversion
105     // descriptor member, but it does duplicate the encoding
106     // information.
107     encoding_state(const encoding_state& __obj) : _M_in_desc(0), _M_out_desc(0)
108     { construct(__obj); }
109
110     // Need assignment operator as well.
111     encoding_state&
112     operator=(const encoding_state& __obj)
113     {
114       construct(__obj);
115       return *this;
116     }
117
118     ~encoding_state()
119     { destroy(); } 
120
121     bool
122     good() const throw()
123     { 
124       const descriptor_type __err = reinterpret_cast<iconv_t>(-1);
125       bool __test = _M_in_desc && _M_in_desc != __err; 
126       __test &=  _M_out_desc && _M_out_desc != __err;
127       return __test;
128     }
129     
130     int
131     character_ratio() const
132     { return _M_bytes; }
133
134     const std::string
135     internal_encoding() const
136     { return _M_int_enc; }
137
138     int 
139     internal_bom() const
140     { return _M_int_bom; }
141
142     const std::string
143     external_encoding() const
144     { return _M_ext_enc; }
145
146     int 
147     external_bom() const
148     { return _M_ext_bom; }
149
150     const descriptor_type&
151     in_descriptor() const
152     { return _M_in_desc; }
153
154     const descriptor_type&
155     out_descriptor() const
156     { return _M_out_desc; }
157
158   protected:
159     void
160     init()
161     {
162       const descriptor_type __err = reinterpret_cast<iconv_t>(-1);
163       const bool __have_encodings = _M_int_enc.size() && _M_ext_enc.size();
164       if (!_M_in_desc && __have_encodings)
165         {
166           _M_in_desc = iconv_open(_M_int_enc.c_str(), _M_ext_enc.c_str());
167           if (_M_in_desc == __err)
168             std::__throw_runtime_error(__N("encoding_state::_M_init "
169                                     "creating iconv input descriptor failed"));
170         }
171       if (!_M_out_desc && __have_encodings)
172         {
173           _M_out_desc = iconv_open(_M_ext_enc.c_str(), _M_int_enc.c_str());
174           if (_M_out_desc == __err)
175             std::__throw_runtime_error(__N("encoding_state::_M_init "
176                                   "creating iconv output descriptor failed"));
177         }
178     }
179
180     void
181     construct(const encoding_state& __obj)
182     {
183       destroy();
184       _M_int_enc = __obj._M_int_enc;
185       _M_ext_enc = __obj._M_ext_enc;
186       _M_ext_bom = __obj._M_ext_bom;
187       _M_int_bom = __obj._M_int_bom;
188       _M_bytes = __obj._M_bytes;
189       init();
190     }
191
192     void
193     destroy() throw()
194     {
195       const descriptor_type __err = reinterpret_cast<iconv_t>(-1);
196       if (_M_in_desc && _M_in_desc != __err) 
197         {
198           iconv_close(_M_in_desc);
199           _M_in_desc = 0;
200         }
201       if (_M_out_desc && _M_out_desc != __err) 
202         {
203           iconv_close(_M_out_desc);
204           _M_out_desc = 0;
205         }
206     }
207   };
208
209   /// @brief  encoding_char_traits.
210   // Custom traits type with encoding_state for the state type, and the
211   // associated fpos<encoding_state> for the position type, all other
212   // bits equivalent to the required char_traits instantiations.
213   template<typename _CharT>
214     struct encoding_char_traits : public std::char_traits<_CharT>
215     {
216       typedef encoding_state                            state_type;
217       typedef typename std::fpos<state_type>            pos_type;
218     };
219
220 _GLIBCXX_END_NAMESPACE
221
222
223 _GLIBCXX_BEGIN_NAMESPACE(std)
224
225   using __gnu_cxx::encoding_state;
226
227   /// @brief  codecvt<InternT, _ExternT, encoding_state> specialization.
228   // This partial specialization takes advantage of iconv to provide
229   // code conversions between a large number of character encodings.
230   template<typename _InternT, typename _ExternT>
231     class codecvt<_InternT, _ExternT, encoding_state>
232     : public __codecvt_abstract_base<_InternT, _ExternT, encoding_state>
233     {
234     public:      
235       // Types:
236       typedef codecvt_base::result                      result;
237       typedef _InternT                                  intern_type;
238       typedef _ExternT                                  extern_type;
239       typedef __gnu_cxx::encoding_state                 state_type;
240       typedef state_type::descriptor_type               descriptor_type;
241
242       // Data Members:
243       static locale::id                 id;
244
245       explicit 
246       codecvt(size_t __refs = 0)
247       : __codecvt_abstract_base<intern_type, extern_type, state_type>(__refs)
248       { }
249
250       explicit 
251       codecvt(state_type& __enc, size_t __refs = 0)
252       : __codecvt_abstract_base<intern_type, extern_type, state_type>(__refs)
253       { }
254
255      protected:
256       virtual 
257       ~codecvt() { }
258
259       virtual result
260       do_out(state_type& __state, const intern_type* __from, 
261              const intern_type* __from_end, const intern_type*& __from_next,
262              extern_type* __to, extern_type* __to_end,
263              extern_type*& __to_next) const;
264
265       virtual result
266       do_unshift(state_type& __state, extern_type* __to, 
267                  extern_type* __to_end, extern_type*& __to_next) const;
268
269       virtual result
270       do_in(state_type& __state, const extern_type* __from, 
271             const extern_type* __from_end, const extern_type*& __from_next,
272             intern_type* __to, intern_type* __to_end, 
273             intern_type*& __to_next) const;
274
275       virtual int 
276       do_encoding() const throw();
277
278       virtual bool 
279       do_always_noconv() const throw();
280
281       virtual int 
282       do_length(state_type&, const extern_type* __from, 
283                 const extern_type* __end, size_t __max) const;
284
285       virtual int 
286       do_max_length() const throw();
287     };
288
289   template<typename _InternT, typename _ExternT>
290     locale::id 
291     codecvt<_InternT, _ExternT, encoding_state>::id;
292
293   // This adaptor works around the signature problems of the second
294   // argument to iconv():  SUSv2 and others use 'const char**', but glibc 2.2
295   // uses 'char**', which matches the POSIX 1003.1-2001 standard.
296   // Using this adaptor, g++ will do the work for us.
297   template<typename _Tp>
298     inline size_t
299     __iconv_adaptor(size_t(*__func)(iconv_t, _Tp, size_t*, char**, size_t*),
300                     iconv_t __cd, char** __inbuf, size_t* __inbytes,
301                     char** __outbuf, size_t* __outbytes)
302     { return __func(__cd, (_Tp)__inbuf, __inbytes, __outbuf, __outbytes); }
303
304   template<typename _InternT, typename _ExternT>
305     codecvt_base::result
306     codecvt<_InternT, _ExternT, encoding_state>::
307     do_out(state_type& __state, const intern_type* __from, 
308            const intern_type* __from_end, const intern_type*& __from_next,
309            extern_type* __to, extern_type* __to_end,
310            extern_type*& __to_next) const
311     {
312       result __ret = codecvt_base::error;
313       if (__state.good())
314         {
315           const descriptor_type& __desc = __state.out_descriptor();
316           const size_t __fmultiple = sizeof(intern_type);
317           size_t __fbytes = __fmultiple * (__from_end - __from);
318           const size_t __tmultiple = sizeof(extern_type);
319           size_t __tbytes = __tmultiple * (__to_end - __to); 
320           
321           // Argument list for iconv specifies a byte sequence. Thus,
322           // all to/from arrays must be brutally casted to char*.
323           char* __cto = reinterpret_cast<char*>(__to);
324           char* __cfrom;
325           size_t __conv;
326
327           // Some encodings need a byte order marker as the first item
328           // in the byte stream, to designate endian-ness. The default
329           // value for the byte order marker is NULL, so if this is
330           // the case, it's not necessary and we can just go on our
331           // merry way.
332           int __int_bom = __state.internal_bom();
333           if (__int_bom)
334             {     
335               size_t __size = __from_end - __from;
336               intern_type* __cfixed = static_cast<intern_type*>
337                 (__builtin_alloca(sizeof(intern_type) * (__size + 1)));
338               __cfixed[0] = static_cast<intern_type>(__int_bom);
339               char_traits<intern_type>::copy(__cfixed + 1, __from, __size);
340               __cfrom = reinterpret_cast<char*>(__cfixed);
341               __conv = __iconv_adaptor(iconv, __desc, &__cfrom,
342                                         &__fbytes, &__cto, &__tbytes); 
343             }
344           else
345             {
346               intern_type* __cfixed = const_cast<intern_type*>(__from);
347               __cfrom = reinterpret_cast<char*>(__cfixed);
348               __conv = __iconv_adaptor(iconv, __desc, &__cfrom, &__fbytes, 
349                                        &__cto, &__tbytes); 
350             }
351
352           if (__conv != size_t(-1))
353             {
354               __from_next = reinterpret_cast<const intern_type*>(__cfrom);
355               __to_next = reinterpret_cast<extern_type*>(__cto);
356               __ret = codecvt_base::ok;
357             }
358           else 
359             {
360               if (__fbytes < __fmultiple * (__from_end - __from))
361                 {
362                   __from_next = reinterpret_cast<const intern_type*>(__cfrom);
363                   __to_next = reinterpret_cast<extern_type*>(__cto);
364                   __ret = codecvt_base::partial;
365                 }
366               else
367                 __ret = codecvt_base::error;
368             }
369         }
370       return __ret; 
371     }
372
373   template<typename _InternT, typename _ExternT>
374     codecvt_base::result
375     codecvt<_InternT, _ExternT, encoding_state>::
376     do_unshift(state_type& __state, extern_type* __to, 
377                extern_type* __to_end, extern_type*& __to_next) const
378     {
379       result __ret = codecvt_base::error;
380       if (__state.good())
381         {
382           const descriptor_type& __desc = __state.in_descriptor();
383           const size_t __tmultiple = sizeof(intern_type);
384           size_t __tlen = __tmultiple * (__to_end - __to); 
385           
386           // Argument list for iconv specifies a byte sequence. Thus,
387           // all to/from arrays must be brutally casted to char*.
388           char* __cto = reinterpret_cast<char*>(__to);
389           size_t __conv = __iconv_adaptor(iconv,__desc, NULL, NULL,
390                                           &__cto, &__tlen); 
391           
392           if (__conv != size_t(-1))
393             {
394               __to_next = reinterpret_cast<extern_type*>(__cto);
395               if (__tlen == __tmultiple * (__to_end - __to))
396                 __ret = codecvt_base::noconv;
397               else if (__tlen == 0)
398                 __ret = codecvt_base::ok;
399               else
400                 __ret = codecvt_base::partial;
401             }
402           else 
403             __ret = codecvt_base::error;
404         }
405       return __ret; 
406     }
407    
408   template<typename _InternT, typename _ExternT>
409     codecvt_base::result
410     codecvt<_InternT, _ExternT, encoding_state>::
411     do_in(state_type& __state, const extern_type* __from, 
412           const extern_type* __from_end, const extern_type*& __from_next,
413           intern_type* __to, intern_type* __to_end, 
414           intern_type*& __to_next) const
415     { 
416       result __ret = codecvt_base::error;
417       if (__state.good())
418         {
419           const descriptor_type& __desc = __state.in_descriptor();
420           const size_t __fmultiple = sizeof(extern_type);
421           size_t __flen = __fmultiple * (__from_end - __from);
422           const size_t __tmultiple = sizeof(intern_type);
423           size_t __tlen = __tmultiple * (__to_end - __to); 
424           
425           // Argument list for iconv specifies a byte sequence. Thus,
426           // all to/from arrays must be brutally casted to char*.
427           char* __cto = reinterpret_cast<char*>(__to);
428           char* __cfrom;
429           size_t __conv;
430
431           // Some encodings need a byte order marker as the first item
432           // in the byte stream, to designate endian-ness. The default
433           // value for the byte order marker is NULL, so if this is
434           // the case, it's not necessary and we can just go on our
435           // merry way.
436           int __ext_bom = __state.external_bom();
437           if (__ext_bom)
438             {     
439               size_t __size = __from_end - __from;
440               extern_type* __cfixed =  static_cast<extern_type*>
441                 (__builtin_alloca(sizeof(extern_type) * (__size + 1)));
442               __cfixed[0] = static_cast<extern_type>(__ext_bom);
443               char_traits<extern_type>::copy(__cfixed + 1, __from, __size);
444               __cfrom = reinterpret_cast<char*>(__cfixed);
445               __conv = __iconv_adaptor(iconv, __desc, &__cfrom,
446                                        &__flen, &__cto, &__tlen); 
447             }
448           else
449             {
450               extern_type* __cfixed = const_cast<extern_type*>(__from);
451               __cfrom = reinterpret_cast<char*>(__cfixed);
452               __conv = __iconv_adaptor(iconv, __desc, &__cfrom,
453                                        &__flen, &__cto, &__tlen); 
454             }
455
456           
457           if (__conv != size_t(-1))
458             {
459               __from_next = reinterpret_cast<const extern_type*>(__cfrom);
460               __to_next = reinterpret_cast<intern_type*>(__cto);
461               __ret = codecvt_base::ok;
462             }
463           else 
464             {
465               if (__flen < static_cast<size_t>(__from_end - __from))
466                 {
467                   __from_next = reinterpret_cast<const extern_type*>(__cfrom);
468                   __to_next = reinterpret_cast<intern_type*>(__cto);
469                   __ret = codecvt_base::partial;
470                 }
471               else
472                 __ret = codecvt_base::error;
473             }
474         }
475       return __ret; 
476     }
477   
478   template<typename _InternT, typename _ExternT>
479     int 
480     codecvt<_InternT, _ExternT, encoding_state>::
481     do_encoding() const throw()
482     {
483       int __ret = 0;
484       if (sizeof(_ExternT) <= sizeof(_InternT))
485         __ret = sizeof(_InternT) / sizeof(_ExternT);
486       return __ret; 
487     }
488   
489   template<typename _InternT, typename _ExternT>
490     bool 
491     codecvt<_InternT, _ExternT, encoding_state>::
492     do_always_noconv() const throw()
493     { return false; }
494   
495   template<typename _InternT, typename _ExternT>
496     int 
497     codecvt<_InternT, _ExternT, encoding_state>::
498     do_length(state_type&, const extern_type* __from, 
499               const extern_type* __end, size_t __max) const
500     { return std::min(__max, static_cast<size_t>(__end - __from)); }
501
502   // _GLIBCXX_RESOLVE_LIB_DEFECTS
503   // 74.  Garbled text for codecvt::do_max_length
504   template<typename _InternT, typename _ExternT>
505     int 
506     codecvt<_InternT, _ExternT, encoding_state>::
507     do_max_length() const throw()
508     { return 1; }
509
510 _GLIBCXX_END_NAMESPACE
511
512 #endif