1 /*
2 
3   character conversion (user locale <-> latin1)
4 
5   copyright (c) 2005, 2006 squell <squell@alumina.nl>
6 
7   use, modification, copying and distribution of this software is permitted
8   under the conditions described in the file 'COPYING'.
9 
10   Usage:
11 
12   The cvtstring class encapsulates an encoding-neutral string. Uses templates
13   heavily for avoiding compile dependencies and using the C++ type system
14   itself for specifying conversions. A limited string interface is provided
15   for constructing, but not editing strings.
16 
17   Example:
18 
19   std::puts( conv<latin1>("ISO 8859-1 text").str<local>().c_str() );
20 
21 */
22 
23 #ifndef __ZF_CHARCONV_HPP
24 #define __ZF_CHARCONV_HPP
25 
26 #include <cstddef>
27 #include <string>
28 
29   /* most older gcc's don't define wstring, but I only need it as a
30      simple and adequate container, and it works just fine. */
31 
32 #if (__DJGPP__) || (__CYGWIN__) || (__GNUC__ == 2)
33 namespace std {
34     typedef basic_string<wchar_t> wstring;
35 }
36 #endif
37 
38 namespace charset {
39     template<class Encoding = void> class conv;
40 
41   /*
42       Making the default template the base class for non default templates
43       solves the problem of dynamically specifying conversions, removes
44       the need for a template conversion constructor, and moves error messages
45       from the linking stage to the compiler stage.
46   */
47 
48     template<> class conv<void> {
49     protected:
50         typedef std::wstring data;
51         static const int cellsize = sizeof(wchar_t) / sizeof(data::value_type);
52 
53         data internal;
conv(const data & s)54         explicit conv(const data& s) : internal(s) { }
55     public:
conv(const conv<> & other)56         conv(const conv<>& other) : internal(other.internal) { }
conv(void)57         conv(void)                : internal()               { }
58 
59       // some familiar functions
empty()60         bool empty() const          { return internal.empty(); }
clear()61         void clear()                { internal.erase(); }
swap(conv<> & other)62         void swap(conv<>& other)    { internal.swap(other.internal); }
63 
64         void reserve(std::size_t req = 0)
65                                     { internal.reserve(req * cellsize); }
66         conv<>& operator+=
67           (wchar_t c)               { return internal.append((data::value_type*)&c, cellsize), *this; }
68         conv<>& operator+=
69           (const conv<>& rhs)       { return (internal+=rhs.internal), *this; }
70 
length()71         std::size_t length() const  { return internal.length() / cellsize; }
72 
73         conv<> substr(std::size_t pos = 0, std::size_t n = std::size_t(-1))
74         { return conv<>(internal.substr(pos*cellsize, n*cellsize)); }
75 
76         template<class E>
77           std::basic_string<typename conv<E>::char_type>
str()78                    str()   const    { return conv<E>(*this); }
79 
80       // outside operations
81         friend conv<> operator+ (const conv<>& lhs, const conv<>& rhs) { return conv<>(lhs.internal + rhs.internal); }
82         friend bool operator==(const conv<>& lhs, const conv<>& rhs) { return lhs.internal == rhs.internal; }
83         friend bool operator!=(const conv<>& lhs, const conv<>& rhs) { return lhs.internal != rhs.internal; }
84         friend bool operator< (const conv<>& lhs, const conv<>& rhs) { return lhs.internal <  rhs.internal; }
85         friend bool operator<=(const conv<>& lhs, const conv<>& rhs) { return lhs.internal <= rhs.internal; }
86         friend bool operator> (const conv<>& lhs, const conv<>& rhs) { return lhs.internal >  rhs.internal; }
87         friend bool operator>=(const conv<>& lhs, const conv<>& rhs) { return lhs.internal >= rhs.internal; }
88     };
89 
90   /*
91       Any parameterization simply is a different "face" of the same class.
92   */
93 
94     template<class Encoding> class conv : public conv<> {
95     public:
conv(const std::string & s)96         conv(const std::string& s)         : conv<>(decode(s.data(), s.size())) { }
conv(const char * p,std::size_t l)97         conv(const char* p, std::size_t l) : conv<>(decode(p,l)) { }
conv(const char * p)98         conv(const char* p)                : conv<>((conv)std::string(p)) { }
conv(const conv<> & other)99         conv(const conv<>& other)          : conv<>(other) { }
conv(void)100         conv(void)                         : conv<>() { }
101 
string()102         operator std::string() const
103         { return encode(internal.data(), internal.size()/cellsize); }
104 
105         template<class E>     // some compilers dont like using conv<>::str?
106           std::basic_string<typename conv<E>::char_type>
str()107                    str()   const    { return conv<>::str<E>(); }
108 
109         typedef char char_type;
110     public:           // too many compilers crap on template friend templates
111         static conv<>::data decode(const char*, std::size_t);
112         static std::string  encode(const void*, std::size_t);
113     };
114 
115   /*
116       Direct wide char interface
117   */
118 
119     template<> class conv<wchar_t> : public conv<> {
120     public:
conv(const std::wstring & s)121         conv(const std::wstring& s)           : conv<>(s) { }
conv(const wchar_t * p,std::size_t l)122         conv(const wchar_t* p, std::size_t l) : conv<>(std::wstring(p,l)) { }
conv(const wchar_t * p)123         conv(const wchar_t* p)                : conv<>(p) { }
conv(const conv<> & other)124         conv(const conv<>& other)             : conv<>(other) { }
conv(void)125         conv(void)                            : conv<>() { }
conv(std::size_t n,wchar_t c)126         conv(std::size_t n, wchar_t c)        : conv<>(std::wstring(n,c)) { }
127 
wstring()128         operator std::wstring () const { return internal; }
129 
130         template<class E>
131           std::basic_string<typename conv<E>::char_type>
str()132                    str()   const    { return conv<>::str<E>(); }
133 
134         typedef wchar_t char_type;
135     };
136 
137   /*
138       Convenient function
139   */
140 
141     template<class In, class Out>
recode(std::basic_string<typename In::char_type> str)142     inline std::basic_string<typename Out::char_type> recode(std::basic_string<typename In::char_type> str)
143     {
144         return (conv<Out>) (conv<In>) str;
145     }
146 
147   /*
148       Predefined charsets, explicit specialization prototypes
149   */
150 
151     typedef char local;
152     struct latin1;
153 
154     template<> conv<>::data conv<local >::decode(const char*, std::size_t);
155     template<> std::string  conv<local >::encode(const void*, std::size_t);
156 
157     template<> conv<>::data conv<latin1>::decode(const char*, std::size_t);
158     template<> std::string  conv<latin1>::encode(const void*, std::size_t);
159 }
160 
161 #endif
162 
163