encodedstream.h
Engine/source/persistence/rapidjson/encodedstream.h
Classes:
class
Input stream wrapper with dynamically bound encoding and automatic encoding detection.
class
Output stream wrapper with dynamically bound encoding and automatic encoding detection.
class
Input byte stream wrapper with a statically bound encoding.
class
Output byte stream wrapper with statically bound encoding.
Namespaces:
namespace
Public Defines
define
RAPIDJSON_ENCODINGS_FUNC(x) <Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
Detailed Description
Public Defines
RAPIDJSON_ENCODINGS_FUNC(x) <Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
1 2#ifndef RAPIDJSON_ENCODEDSTREAM_H_ 3#define RAPIDJSON_ENCODEDSTREAM_H_ 4 5#include "rapidjson.h" 6 7namespace rapidjson { 8 9//! Input byte stream wrapper with a statically bound encoding. 10/*! 11 \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. 12 \tparam InputByteStream Type of input byte stream. For example, FileReadStream. 13*/ 14template <typename Encoding, typename InputByteStream> 15class EncodedInputStream { 16 RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); 17public: 18 typedef typename Encoding::Ch Ch; 19 20 EncodedInputStream(InputByteStream& is) : is_(is) { 21 current_ = Encoding::TakeBOM(is_); 22 } 23 24 Ch Peek() const { return current_; } 25 Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; } 26 size_t Tell() const { return is_.Tell(); } 27 28 // Not implemented 29 void Put(Ch c) { RAPIDJSON_ASSERT(false); } 30 void Flush() { RAPIDJSON_ASSERT(false); } 31 Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 32 size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 33 34private: 35 // Prohibit assignment for VC C4512 warning 36 EncodedInputStream& operator=(const EncodedInputStream&); 37 38 InputByteStream& is_; 39 Ch current_; 40}; 41 42//! Output byte stream wrapper with statically bound encoding. 43/*! 44 \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. 45 \tparam InputByteStream Type of input byte stream. For example, FileWriteStream. 46*/ 47template <typename Encoding, typename OutputByteStream> 48class EncodedOutputStream { 49 RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); 50public: 51 typedef typename Encoding::Ch Ch; 52 53 EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { 54 if (putBOM) 55 Encoding::PutBOM(os_); 56 } 57 58 void Put(Ch c) { Encoding::Put(os_, c); } 59 void Flush() { os_.Flush(); } 60 61 // Not implemented 62 Ch Peek() const { RAPIDJSON_ASSERT(false); } 63 Ch Take() { RAPIDJSON_ASSERT(false); } 64 size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } 65 Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 66 size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 67 68private: 69 // Prohibit assignment for VC C4512 warning 70 EncodedOutputStream& operator=(const EncodedOutputStream&); 71 72 OutputByteStream& os_; 73}; 74 75#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x 76 77//! Input stream wrapper with dynamically bound encoding and automatic encoding detection. 78/*! 79 \tparam CharType Type of character for reading. 80 \tparam InputByteStream type of input byte stream to be wrapped. 81*/ 82template <typename CharType, typename InputByteStream> 83class AutoUTFInputStream { 84 RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); 85public: 86 typedef CharType Ch; 87 88 //! Constructor. 89 /*! 90 \param is input stream to be wrapped. 91 \param type UTF encoding type if it is not detected from the stream. 92 */ 93 AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) { 94 DetectType(); 95 static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) }; 96 takeFunc_ = f[type_]; 97 current_ = takeFunc_(*is_); 98 } 99 100 UTFType GetType() const { return type_; } 101 bool HasBOM() const { return hasBOM_; } 102 103 Ch Peek() const { return current_; } 104 Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; } 105 size_t Tell() const { return is_->Tell(); } 106 107 // Not implemented 108 void Put(Ch) { RAPIDJSON_ASSERT(false); } 109 void Flush() { RAPIDJSON_ASSERT(false); } 110 Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 111 size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 112 113private: 114 // Detect encoding type with BOM or RFC 4627 115 void DetectType() { 116 // BOM (Byte Order Mark): 117 // 00 00 FE FF UTF-32BE 118 // FF FE 00 00 UTF-32LE 119 // FE FF UTF-16BE 120 // FF FE UTF-16LE 121 // EF BB BF UTF-8 122 123 const unsigned char* c = (const unsigned char *)is_->Peek4(); 124 if (!c) 125 return; 126 127 unsigned bom = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24); 128 hasBOM_ = false; 129 if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } 130 else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } 131 else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); } 132 else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); } 133 else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); } 134 135 // RFC 4627: Section 3 136 // "Since the first two characters of a JSON text will always be ASCII 137 // characters [RFC0020], it is possible to determine whether an octet 138 // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking 139 // at the pattern of nulls in the first four octets." 140 // 00 00 00 xx UTF-32BE 141 // 00 xx 00 xx UTF-16BE 142 // xx 00 00 00 UTF-32LE 143 // xx 00 xx 00 UTF-16LE 144 // xx xx xx xx UTF-8 145 146 if (!hasBOM_) { 147 unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); 148 switch (pattern) { 149 case 0x08: type_ = kUTF32BE; break; 150 case 0x0A: type_ = kUTF16BE; break; 151 case 0x01: type_ = kUTF32LE; break; 152 case 0x05: type_ = kUTF16LE; break; 153 case 0x0F: type_ = kUTF8; break; 154 } 155 } 156 157 // RUntime check whether the size of character type is sufficient. It only perform checks with assertion. 158 switch (type_) { 159 case kUTF8: 160 // Do nothing 161 break; 162 case kUTF16LE: 163 case kUTF16BE: 164 RAPIDJSON_ASSERT(sizeof(Ch) >= 2); 165 break; 166 case kUTF32LE: 167 case kUTF32BE: 168 RAPIDJSON_ASSERT(sizeof(Ch) >= 4); 169 break; 170 } 171 } 172 173 typedef Ch (*TakeFunc)(InputByteStream& is); 174 InputByteStream* is_; 175 UTFType type_; 176 Ch current_; 177 TakeFunc takeFunc_; 178 bool hasBOM_; 179}; 180 181//! Output stream wrapper with dynamically bound encoding and automatic encoding detection. 182/*! 183 \tparam CharType Type of character for writing. 184 \tparam InputByteStream type of output byte stream to be wrapped. 185*/ 186template <typename CharType, typename OutputByteStream> 187class AutoUTFOutputStream { 188 RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); 189public: 190 typedef CharType Ch; 191 192 //! Constructor. 193 /*! 194 \param os output stream to be wrapped. 195 \param type UTF encoding type. 196 \param putBOM Whether to write BOM at the beginning of the stream. 197 */ 198 AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) { 199 // RUntime check whether the size of character type is sufficient. It only perform checks with assertion. 200 switch (type_) { 201 case kUTF16LE: 202 case kUTF16BE: 203 RAPIDJSON_ASSERT(sizeof(Ch) >= 2); 204 break; 205 case kUTF32LE: 206 case kUTF32BE: 207 RAPIDJSON_ASSERT(sizeof(Ch) >= 4); 208 break; 209 case kUTF8: 210 // Do nothing 211 break; 212 } 213 214 static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) }; 215 putFunc_ = f[type_]; 216 217 if (putBOM) 218 PutBOM(); 219 } 220 221 UTFType GetType() const { return type_; } 222 223 void Put(Ch c) { putFunc_(*os_, c); } 224 void Flush() { os_->Flush(); } 225 226 // Not implemented 227 Ch Peek() const { RAPIDJSON_ASSERT(false); } 228 Ch Take() { RAPIDJSON_ASSERT(false); } 229 size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } 230 Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 231 size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 232 233private: 234 void PutBOM() { 235 typedef void (*PutBOMFunc)(OutputByteStream&); 236 static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) }; 237 f[type_](*os_); 238 } 239 240 typedef void (*PutFunc)(OutputByteStream&, Ch); 241 242 OutputByteStream* os_; 243 UTFType type_; 244 PutFunc putFunc_; 245}; 246 247#undef RAPIDJSON_ENCODINGS_FUNC 248 249} // namespace rapidjson 250 251#endif // RAPIDJSON_FILESTREAM_H_ 252
