]> git.tdb.fi Git - libs/core.git/blob - source/stringcodec/codec.h
Let the base classes decide the default error mode
[libs/core.git] / source / stringcodec / codec.h
1 #ifndef MSP_STRINGCODEC_CODEC_H_
2 #define MSP_STRINGCODEC_CODEC_H_
3
4 #include <string>
5 #include "except.h"
6 #include "ustring.h"
7
8 namespace Msp {
9 namespace StringCodec {
10
11 enum ErrorMode
12 {
13         DEFAULT,
14         THROW_ON_ERROR,
15         IGNORE_ERRORS,
16         TRANSLITERATE
17 };
18
19
20 /**
21 Base class for string codecs.  Use one of the derived classes or the function
22 create_codec to create a specific codec.
23
24 Unicode strings are represented as ustrings.  An std::string is considered to
25 be an encoded sequence of bytes.  A codec is able to determine if an encoded
26 string could be decoded with it.
27 */
28 class Codec
29 {
30 public:
31         /**
32         Base class for string encoder.
33
34         Each codec class should contain an Encoder class derived from this.  The
35         encode_char and transliterate functions must be overloaded.  Some encoders
36         may find it useful or necessary to implement some other functions too
37         (particularly sync and reset for stateful codecs).
38         */
39         class Encoder
40         {
41         protected:
42                 ErrorMode err_mode;
43
44                 Encoder(ErrorMode em): err_mode(em==DEFAULT ? THROW_ON_ERROR : em) { }
45         public:
46                 virtual ~Encoder() { }
47
48                 /** Encodes a single unicode character.  If the character can't be
49                 represented in this encoding, error() should be called. */
50                 virtual void encode_char(unichar ch, std::string &buf) = 0;
51
52                 /** Encodes a unicode string.  This is equivalent to calling encode_char
53                 for each character in the string with the same buffer. */
54                 virtual void encode(const ustring &str, std::string &buf);
55
56                 std::string encode(const ustring &);
57
58                 /** Procuces a sequence of bytes that will bring the encoder back to the
59                 initial state. */
60                 virtual void sync(std::string &buf) { (void)buf; }
61
62                 /** Resets the encoder to the initial state without producing output. */
63                 virtual void reset() { }
64
65         protected:
66                 /** Handles an error depending on the error mode.
67
68                 THROW_ON_ERROR: throws err
69                 IGNORE_ERRORS: does nothing
70                 TRANSLITERATE: calls transliterate(ch, buf) */
71                 template<typename E>
72                 void error(unichar ch, std::string &buf, const E &err)
73                 {
74                         if(err_mode==TRANSLITERATE)
75                                 transliterate(ch, buf);
76                         else if(err_mode!=IGNORE_ERRORS)
77                                 throw err;
78                 }
79
80                 /** Attempts to produce an alternative encoding for a unicode character.
81                 Typically this includes dropping accent marks or romanizing letters. */
82                 virtual void transliterate(unichar ch, std::string &buf) = 0;
83         };
84
85         /**
86         Base class for string decoder.
87
88         Each codec class should contain an Decoder class derived from this.
89         */
90         class Decoder
91         {
92         protected:
93                 ErrorMode err_mode;
94
95                 Decoder(ErrorMode em): err_mode(em==DEFAULT ? THROW_ON_ERROR : em) { }
96         public:
97                 virtual ~Decoder() { }
98
99                 /** Decodes a single character from a string.  The iterator is advanced
100                 to the next character.  For stateful codecs, -1 may be returned if a
101                 state change sequence was decoded but no character followed it.  If
102                 invalid input is encountered, the error() function should be called and
103                 the iterator advanced only if it doesn't throw. */
104                 virtual unichar decode_char(const std::string &str, std::string::const_iterator &i) = 0;
105
106                 /** Decodes a string. */
107                 virtual void decode(const std::string &str, ustring &buf);
108
109                 ustring decode(const std::string &);
110
111                 /** Resets the decoder to the initial state. */
112                 virtual void reset() { }
113
114         protected:
115                 /** Handles an error depending on the error mode.  The return value is
116                 suitable for returning from decode_char.
117                 
118                 THROW_ON_ERROR: throws err
119                 IGNORE_ERRORS: returns -1
120                 TRANSLITERATE: return 0xFFFD */
121                 template<typename E>
122                 unichar error(const E &err)
123                 {
124                         if(err_mode==TRANSLITERATE)
125                                 return 0xFFFD;
126                         else if(err_mode==IGNORE_ERRORS)
127                                 return -1;
128                         else
129                                 throw err;
130                 }
131         };
132
133 protected:
134         Codec() { }
135 public:
136         virtual ~Codec() { }
137
138         /** Returns the name of the encoding handled by this codec. */
139         virtual const char *get_name() const = 0;
140
141         /** Creates an encoder for this codec. */
142         virtual Encoder *create_encoder(ErrorMode err_mode = DEFAULT) const = 0;
143
144         /** Creates a decoder for this codec. */
145         virtual Decoder *create_decoder(ErrorMode err_mode = DEFAULT) const = 0;
146
147         /** Determines whether the given string can be successfully decoded with
148         this codec.  Note that this function returning true does not guarantee that
149         the string was actually encoded with this codec.  In particular, many 8-bit
150         encodings are indistinguishable. */
151         virtual bool detect(const std::string &) const;
152 };
153
154 typedef Codec::Encoder Encoder;
155 typedef Codec::Decoder Decoder;
156
157
158 /**
159 A helper class to provide some common functionality.
160 */
161 template<typename C>
162 class StandardCodec: public Codec
163 {
164 private:
165         ErrorMode err_mode;
166
167 protected:
168         StandardCodec(ErrorMode em): err_mode(em==DEFAULT ? THROW_ON_ERROR : em) { }
169
170 public:
171         virtual Encoder *create_encoder(ErrorMode em = DEFAULT) const
172         { return new typename C::Encoder(em==DEFAULT ? err_mode : em); }
173
174         virtual Decoder *create_decoder(ErrorMode em = DEFAULT) const
175         { return new typename C::Decoder(em==DEFAULT ? err_mode : em); }
176 };
177
178
179 /** Convenience function that decodes a string. */
180 template<typename C>
181 ustring decode(const std::string &s)
182 {
183         typename C::Decoder dec;
184         return dec.decode(s);
185 }
186
187 /** Convenience function that encodes a string. */
188 template<typename C>
189 std::string encode(const ustring &s)
190 {
191         typename C::Encoder enc;
192         return enc.encode(s);
193 }
194
195 /** Convenience function that transcodes a string from one codec to another. */
196 template<typename F, typename T>
197 std::string transcode(const std::string &s)
198 {
199         return encode<T>(decode<F>(s));
200 }
201
202 /** Creates a codec for an encoding by name.  The caller is responsible for
203 deleting the codec when it's no longer needed. */
204 Codec *create_codec(const std::string &);
205
206 /** Automatically detects the encoding of a string and creates a codec for it.
207 The codec must be deleted when it's no longer needed. */
208 Codec *detect_codec(const std::string &);
209
210 } // namespace StringCodec
211 } // namespace Msp
212
213 #endif