All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
encodings.h
1 #ifndef RAPIDJSON_ENCODINGS_H_
2 #define RAPIDJSON_ENCODINGS_H_
3 
4 #include "rapidjson.h"
5 
6 #ifdef _MSC_VER
7 RAPIDJSON_DIAG_PUSH
8 RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
9 RAPIDJSON_DIAG_OFF(4702) // unreachable code
10 #elif defined(__GNUC__)
11 RAPIDJSON_DIAG_PUSH
12 RAPIDJSON_DIAG_OFF(effc++)
13 #endif
14 
15 namespace rapidjson {
16 
17 ///////////////////////////////////////////////////////////////////////////////
18 // Encoding
19 
20 /*! \class rapidjson::Encoding
21  \brief Concept for encoding of Unicode characters.
22 
23 \code
24 concept Encoding {
25  typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition.
26 
27  enum { supportUnicode = 1 }; // or 0 if not supporting unicode
28 
29  //! \brief Encode a Unicode codepoint to an output stream.
30  //! \param os Output stream.
31  //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
32  template<typename OutputStream>
33  static void Encode(OutputStream& os, unsigned codepoint);
34 
35  //! \brief Decode a Unicode codepoint from an input stream.
36  //! \param is Input stream.
37  //! \param codepoint Output of the unicode codepoint.
38  //! \return true if a valid codepoint can be decoded from the stream.
39  template <typename InputStream>
40  static bool Decode(InputStream& is, unsigned* codepoint);
41 
42  //! \brief Validate one Unicode codepoint from an encoded stream.
43  //! \param is Input stream to obtain codepoint.
44  //! \param os Output for copying one codepoint.
45  //! \return true if it is valid.
46  //! \note This function just validating and copying the codepoint without actually decode it.
47  template <typename InputStream, typename OutputStream>
48  static bool Validate(InputStream& is, OutputStream& os);
49 
50  // The following functions are deal with byte streams.
51 
52  //! Take a character from input byte stream, skip BOM if exist.
53  template <typename InputByteStream>
54  static CharType TakeBOM(InputByteStream& is);
55 
56  //! Take a character from input byte stream.
57  template <typename InputByteStream>
58  static Ch Take(InputByteStream& is);
59 
60  //! Put BOM to output byte stream.
61  template <typename OutputByteStream>
62  static void PutBOM(OutputByteStream& os);
63 
64  //! Put a character to output byte stream.
65  template <typename OutputByteStream>
66  static void Put(OutputByteStream& os, Ch c);
67 };
68 \endcode
69 */
70 
71 ///////////////////////////////////////////////////////////////////////////////
72 // UTF8
73 
74 //! UTF-8 encoding.
75 /*! http://en.wikipedia.org/wiki/UTF-8
76  http://tools.ietf.org/html/rfc3629
77  \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
78  \note implements Encoding concept
79 */
80 template<typename CharType = char>
81 struct UTF8 {
82  typedef CharType Ch;
83 
84  enum { supportUnicode = 1 };
85 
86  template<typename OutputStream>
87  static void Encode(OutputStream& os, unsigned codepoint) {
88  if (codepoint <= 0x7F)
89  os.Put(static_cast<Ch>(codepoint & 0xFF));
90  else if (codepoint <= 0x7FF) {
91  os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
92  os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
93  }
94  else if (codepoint <= 0xFFFF) {
95  os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
96  os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
97  os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
98  }
99  else {
100  RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
101  os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
102  os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
103  os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
104  os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
105  }
106  }
107 
108  template <typename InputStream>
109  static bool Decode(InputStream& is, unsigned* codepoint) {
110 #define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | ((unsigned char)c & 0x3Fu)
111 #define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0)
112 #define TAIL() COPY(); TRANS(0x70)
113  Ch c = is.Take();
114  if (!(c & 0x80)) {
115  *codepoint = (unsigned char)c;
116  return true;
117  }
118 
119  unsigned char type = GetRange((unsigned char)c);
120  *codepoint = (0xFF >> type) & (unsigned char)c;
121  bool result = true;
122  switch (type) {
123  case 2: TAIL(); return result;
124  case 3: TAIL(); TAIL(); return result;
125  case 4: COPY(); TRANS(0x50); TAIL(); return result;
126  case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
127  case 6: TAIL(); TAIL(); TAIL(); return result;
128  case 10: COPY(); TRANS(0x20); TAIL(); return result;
129  case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
130  default: return false;
131  }
132 #undef COPY
133 #undef TRANS
134 #undef TAIL
135  }
136 
137  template <typename InputStream, typename OutputStream>
138  static bool Validate(InputStream& is, OutputStream& os) {
139 #define COPY() os.Put(c = is.Take())
140 #define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0)
141 #define TAIL() COPY(); TRANS(0x70)
142  Ch c;
143  COPY();
144  if (!(c & 0x80))
145  return true;
146 
147  bool result = true;
148  switch (GetRange((unsigned char)c)) {
149  case 2: TAIL(); return result;
150  case 3: TAIL(); TAIL(); return result;
151  case 4: COPY(); TRANS(0x50); TAIL(); return result;
152  case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
153  case 6: TAIL(); TAIL(); TAIL(); return result;
154  case 10: COPY(); TRANS(0x20); TAIL(); return result;
155  case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
156  default: return false;
157  }
158 #undef COPY
159 #undef TRANS
160 #undef TAIL
161  }
162 
163  static unsigned char GetRange(unsigned char c) {
164  // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
165  // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
166  static const unsigned char type[] = {
167  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
168  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
169  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
170  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
171  0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
172  0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
173  0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
174  0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
175  8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
176  10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
177  };
178  return type[c];
179  }
180 
181  template <typename InputByteStream>
182  static CharType TakeBOM(InputByteStream& is) {
183  RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
184  Ch c = Take(is);
185  if ((unsigned char)c != 0xEFu) return c;
186  c = is.Take();
187  if ((unsigned char)c != 0xBBu) return c;
188  c = is.Take();
189  if ((unsigned char)c != 0xBFu) return c;
190  c = is.Take();
191  return c;
192  }
193 
194  template <typename InputByteStream>
195  static Ch Take(InputByteStream& is) {
196  RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
197  return is.Take();
198  }
199 
200  template <typename OutputByteStream>
201  static void PutBOM(OutputByteStream& os) {
202  RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
203  os.Put(0xEFu); os.Put(0xBBu); os.Put(0xBFu);
204  }
205 
206  template <typename OutputByteStream>
207  static void Put(OutputByteStream& os, Ch c) {
208  RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
209  os.Put(static_cast<typename OutputByteStream::Ch>(c));
210  }
211 };
212 
213 ///////////////////////////////////////////////////////////////////////////////
214 // UTF16
215 
216 //! UTF-16 encoding.
217 /*! http://en.wikipedia.org/wiki/UTF-16
218  http://tools.ietf.org/html/rfc2781
219  \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
220  \note implements Encoding concept
221 
222  \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
223  For streaming, use UTF16LE and UTF16BE, which handle endianness.
224 */
225 template<typename CharType = wchar_t>
226 struct UTF16 {
227  typedef CharType Ch;
228  RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
229 
230  enum { supportUnicode = 1 };
231 
232  template<typename OutputStream>
233  static void Encode(OutputStream& os, unsigned codepoint) {
234  RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
235  if (codepoint <= 0xFFFF) {
236  RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
237  os.Put(static_cast<typename OutputStream::Ch>(codepoint));
238  }
239  else {
240  RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
241  unsigned v = codepoint - 0x10000;
242  os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
243  os.Put((v & 0x3FF) | 0xDC00);
244  }
245  }
246 
247  template <typename InputStream>
248  static bool Decode(InputStream& is, unsigned* codepoint) {
249  RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
250  Ch c = is.Take();
251  if (c < 0xD800 || c > 0xDFFF) {
252  *codepoint = c;
253  return true;
254  }
255  else if (c <= 0xDBFF) {
256  *codepoint = (c & 0x3FF) << 10;
257  c = is.Take();
258  *codepoint |= (c & 0x3FF);
259  *codepoint += 0x10000;
260  return c >= 0xDC00 && c <= 0xDFFF;
261  }
262  return false;
263  }
264 
265  template <typename InputStream, typename OutputStream>
266  static bool Validate(InputStream& is, OutputStream& os) {
267  RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
268  RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
269  Ch c;
270  os.Put(c = is.Take());
271  if (c < 0xD800 || c > 0xDFFF)
272  return true;
273  else if (c <= 0xDBFF) {
274  os.Put(c = is.Take());
275  return c >= 0xDC00 && c <= 0xDFFF;
276  }
277  return false;
278  }
279 };
280 
281 //! UTF-16 little endian encoding.
282 template<typename CharType = wchar_t>
283 struct UTF16LE : UTF16<CharType> {
284  template <typename InputByteStream>
285  static CharType TakeBOM(InputByteStream& is) {
286  RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
287  CharType c = Take(is);
288  return (unsigned short)c == 0xFEFFu ? Take(is) : c;
289  }
290 
291  template <typename InputByteStream>
292  static CharType Take(InputByteStream& is) {
293  RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
294  CharType c = (unsigned char)is.Take();
295  c |= (unsigned char)is.Take() << 8;
296  return c;
297  }
298 
299  template <typename OutputByteStream>
300  static void PutBOM(OutputByteStream& os) {
301  RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
302  os.Put(0xFFu); os.Put(0xFEu);
303  }
304 
305  template <typename OutputByteStream>
306  static void Put(OutputByteStream& os, CharType c) {
307  RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
308  os.Put(c & 0xFFu);
309  os.Put((c >> 8) & 0xFFu);
310  }
311 };
312 
313 //! UTF-16 big endian encoding.
314 template<typename CharType = wchar_t>
315 struct UTF16BE : UTF16<CharType> {
316  template <typename InputByteStream>
317  static CharType TakeBOM(InputByteStream& is) {
318  RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
319  CharType c = Take(is);
320  return (unsigned short)c == 0xFEFFu ? Take(is) : c;
321  }
322 
323  template <typename InputByteStream>
324  static CharType Take(InputByteStream& is) {
325  RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
326  CharType c = (unsigned char)is.Take() << 8;
327  c |= (unsigned char)is.Take();
328  return c;
329  }
330 
331  template <typename OutputByteStream>
332  static void PutBOM(OutputByteStream& os) {
333  RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
334  os.Put(0xFEu); os.Put(0xFFu);
335  }
336 
337  template <typename OutputByteStream>
338  static void Put(OutputByteStream& os, CharType c) {
339  RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
340  os.Put((c >> 8) & 0xFFu);
341  os.Put(c & 0xFFu);
342  }
343 };
344 
345 ///////////////////////////////////////////////////////////////////////////////
346 // UTF32
347 
348 //! UTF-32 encoding.
349 /*! http://en.wikipedia.org/wiki/UTF-32
350  \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
351  \note implements Encoding concept
352 
353  \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
354  For streaming, use UTF32LE and UTF32BE, which handle endianness.
355 */
356 template<typename CharType = unsigned>
357 struct UTF32 {
358  typedef CharType Ch;
359  RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
360 
361  enum { supportUnicode = 1 };
362 
363  template<typename OutputStream>
364  static void Encode(OutputStream& os, unsigned codepoint) {
365  RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
366  RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
367  os.Put(codepoint);
368  }
369 
370  template <typename InputStream>
371  static bool Decode(InputStream& is, unsigned* codepoint) {
372  RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
373  Ch c = is.Take();
374  *codepoint = c;
375  return c <= 0x10FFFF;
376  }
377 
378  template <typename InputStream, typename OutputStream>
379  static bool Validate(InputStream& is, OutputStream& os) {
380  RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
381  Ch c;
382  os.Put(c = is.Take());
383  return c <= 0x10FFFF;
384  }
385 };
386 
387 //! UTF-32 little endian enocoding.
388 template<typename CharType = unsigned>
389 struct UTF32LE : UTF32<CharType> {
390  template <typename InputByteStream>
391  static CharType TakeBOM(InputByteStream& is) {
392  RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
393  CharType c = Take(is);
394  return (unsigned)c == 0x0000FEFFu ? Take(is) : c;
395  }
396 
397  template <typename InputByteStream>
398  static CharType Take(InputByteStream& is) {
399  RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
400  CharType c = (unsigned char)is.Take();
401  c |= (unsigned char)is.Take() << 8;
402  c |= (unsigned char)is.Take() << 16;
403  c |= (unsigned char)is.Take() << 24;
404  return c;
405  }
406 
407  template <typename OutputByteStream>
408  static void PutBOM(OutputByteStream& os) {
409  RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
410  os.Put(0xFFu); os.Put(0xFEu); os.Put(0x00u); os.Put(0x00u);
411  }
412 
413  template <typename OutputByteStream>
414  static void Put(OutputByteStream& os, CharType c) {
415  RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
416  os.Put(c & 0xFFu);
417  os.Put((c >> 8) & 0xFFu);
418  os.Put((c >> 16) & 0xFFu);
419  os.Put((c >> 24) & 0xFFu);
420  }
421 };
422 
423 //! UTF-32 big endian encoding.
424 template<typename CharType = unsigned>
425 struct UTF32BE : UTF32<CharType> {
426  template <typename InputByteStream>
427  static CharType TakeBOM(InputByteStream& is) {
428  RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
429  CharType c = Take(is);
430  return (unsigned)c == 0x0000FEFFu ? Take(is) : c;
431  }
432 
433  template <typename InputByteStream>
434  static CharType Take(InputByteStream& is) {
435  RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
436  CharType c = (unsigned char)is.Take() << 24;
437  c |= (unsigned char)is.Take() << 16;
438  c |= (unsigned char)is.Take() << 8;
439  c |= (unsigned char)is.Take();
440  return c;
441  }
442 
443  template <typename OutputByteStream>
444  static void PutBOM(OutputByteStream& os) {
445  RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
446  os.Put(0x00u); os.Put(0x00u); os.Put(0xFEu); os.Put(0xFFu);
447  }
448 
449  template <typename OutputByteStream>
450  static void Put(OutputByteStream& os, CharType c) {
451  RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
452  os.Put((c >> 24) & 0xFFu);
453  os.Put((c >> 16) & 0xFFu);
454  os.Put((c >> 8) & 0xFFu);
455  os.Put(c & 0xFFu);
456  }
457 };
458 
459 ///////////////////////////////////////////////////////////////////////////////
460 // ASCII
461 
462 //! ASCII encoding.
463 /*! http://en.wikipedia.org/wiki/ASCII
464  \tparam CharType Code unit for storing 7-bit ASCII data. Default is char.
465  \note implements Encoding concept
466 */
467 template<typename CharType = char>
468 struct ASCII {
469  typedef CharType Ch;
470 
471  enum { supportUnicode = 0 };
472 
473  template<typename OutputStream>
474  static void Encode(OutputStream& os, unsigned codepoint) {
475  RAPIDJSON_ASSERT(codepoint <= 0x7F);
476  os.Put(static_cast<Ch>(codepoint & 0xFF));
477  }
478 
479  template <typename InputStream>
480  static bool Decode(InputStream& is, unsigned* codepoint) {
481  unsigned char c = static_cast<unsigned char>(is.Take());
482  *codepoint = c;
483  return c <= 0X7F;
484  }
485 
486  template <typename InputStream, typename OutputStream>
487  static bool Validate(InputStream& is, OutputStream& os) {
488  unsigned char c = is.Take();
489  os.Put(c);
490  return c <= 0x7F;
491  }
492 
493  template <typename InputByteStream>
494  static CharType TakeBOM(InputByteStream& is) {
495  RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
496  Ch c = Take(is);
497  return c;
498  }
499 
500  template <typename InputByteStream>
501  static Ch Take(InputByteStream& is) {
502  RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
503  return is.Take();
504  }
505 
506  template <typename OutputByteStream>
507  static void PutBOM(OutputByteStream& os) {
508  RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
509  (void)os;
510  }
511 
512  template <typename OutputByteStream>
513  static void Put(OutputByteStream& os, Ch c) {
514  RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
515  os.Put(static_cast<typename OutputByteStream::Ch>(c));
516  }
517 };
518 
519 ///////////////////////////////////////////////////////////////////////////////
520 // AutoUTF
521 
522 //! Runtime-specified UTF encoding type of a stream.
523 enum UTFType {
524  kUTF8 = 0, //!< UTF-8.
525  kUTF16LE = 1, //!< UTF-16 little endian.
526  kUTF16BE = 2, //!< UTF-16 big endian.
527  kUTF32LE = 3, //!< UTF-32 little endian.
528  kUTF32BE = 4 //!< UTF-32 big endian.
529 };
530 
531 //! Dynamically select encoding according to stream's runtime-specified UTF encoding type.
532 /*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().
533 */
534 template<typename CharType>
535 struct AutoUTF {
536  typedef CharType Ch;
537 
538  enum { supportUnicode = 1 };
539 
540 #define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
541 
542  template<typename OutputStream>
543  RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) {
544  typedef void (*EncodeFunc)(OutputStream&, unsigned);
545  static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
546  (*f[os.GetType()])(os, codepoint);
547  }
548 
549  template <typename InputStream>
550  RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) {
551  typedef bool (*DecodeFunc)(InputStream&, unsigned*);
552  static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };
553  return (*f[is.GetType()])(is, codepoint);
554  }
555 
556  template <typename InputStream, typename OutputStream>
557  RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
558  typedef bool (*ValidateFunc)(InputStream&, OutputStream&);
559  static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };
560  return (*f[is.GetType()])(is, os);
561  }
562 
563 #undef RAPIDJSON_ENCODINGS_FUNC
564 };
565 
566 ///////////////////////////////////////////////////////////////////////////////
567 // Transcoder
568 
569 //! Encoding conversion.
570 template<typename SourceEncoding, typename TargetEncoding>
571 struct Transcoder {
572  //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
573  template<typename InputStream, typename OutputStream>
574  RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
575  unsigned codepoint;
576  if (!SourceEncoding::Decode(is, &codepoint))
577  return false;
578  TargetEncoding::Encode(os, codepoint);
579  return true;
580  }
581 
582  //! Validate one Unicode codepoint from an encoded stream.
583  template<typename InputStream, typename OutputStream>
584  RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
585  return Transcode(is, os); // Since source/target encoding is different, must transcode.
586  }
587 };
588 
589 //! Specialization of Transcoder with same source and target encoding.
590 template<typename Encoding>
592  template<typename InputStream, typename OutputStream>
593  RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
594  os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class.
595  return true;
596  }
597 
598  template<typename InputStream, typename OutputStream>
599  RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
600  return Encoding::Validate(is, os); // source/target encoding are the same
601  }
602 };
603 
604 } // namespace rapidjson
605 
606 #if defined(__GNUC__) || defined(_MSV_VER)
607 RAPIDJSON_DIAG_POP
608 #endif
609 
610 #endif // RAPIDJSON_ENCODINGS_H_