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