]> git.tdb.fi Git - libs/core.git/blob - source/stringcodec/codec.h
Add some missing includes
[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 = THROW_ON_ERROR;
43
44                 Encoder(ErrorMode em): err_mode(em==DEFAULT ? THROW_ON_ERROR : em) { }
45         public:
46                 virtual ~Encoder() = default;
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 = THROW_ON_ERROR;
94
95                 Decoder(ErrorMode em): err_mode(em==DEFAULT ? THROW_ON_ERROR : em) { }
96         public:
97                 virtual ~Decoder() = default;
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() = default;
135 public:
136         virtual ~Codec() = default;
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 = THROW_ON_ERROR;
166
167 protected:
168         StandardCodec(ErrorMode em): err_mode(em==DEFAULT ? THROW_ON_ERROR : em) { }
169
170         ErrorMode get_error_mode(ErrorMode em = DEFAULT) const
171         { return (em==DEFAULT ? err_mode : em); }
172
173 public:
174         virtual Encoder *create_encoder(ErrorMode em = DEFAULT) const
175         { return new typename C::Encoder(get_error_mode(em)); }
176
177         virtual Decoder *create_decoder(ErrorMode em = DEFAULT) const
178         { return new typename C::Decoder(get_error_mode(em)); }
179 };
180
181
182 /** Convenience function that decodes a string. */
183 template<typename C>
184 ustring decode(const std::string &s)
185 {
186         typename C::Decoder dec;
187         return dec.decode(s);
188 }
189
190 /** Convenience function that encodes a string. */
191 template<typename C>
192 std::string encode(const ustring &s)
193 {
194         typename C::Encoder enc;
195         return enc.encode(s);
196 }
197
198 /** Convenience function that transcodes a string from one codec to another. */
199 template<typename F, typename T>
200 std::string transcode(const std::string &s)
201 {
202         return encode<T>(decode<F>(s));
203 }
204
205 /** Creates a codec for an encoding by name.  The caller is responsible for
206 deleting the codec when it's no longer needed. */
207 Codec *create_codec(const std::string &);
208
209 /** Automatically detects the encoding of a string and creates a codec for it.
210 The codec must be deleted when it's no longer needed. */
211 Codec *detect_codec(const std::string &);
212
213 } // namespace StringCodec
214 } // namespace Msp
215
216 #endif