1 // Tencent is pleased to support the open source community by making RapidJSON available.
3 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
5 // Licensed under the MIT License (the "License"); you may not use this file except
6 // in compliance with the License. You may obtain a copy of the License at
8 // http://opensource.org/licenses/MIT
10 // Unless required by applicable law or agreed to in writing, software distributed
11 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 // specific language governing permissions and limitations under the License.
15 #ifndef RAPIDJSON_ENCODEDSTREAM_H_
16 #define RAPIDJSON_ENCODEDSTREAM_H_
19 #include "memorystream.h"
23 RAPIDJSON_DIAG_OFF(effc
++)
28 RAPIDJSON_DIAG_OFF(padded
)
31 RAPIDJSON_NAMESPACE_BEGIN
33 //! Input byte stream wrapper with a statically bound encoding.
35 \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
36 \tparam InputByteStream Type of input byte stream. For example, FileReadStream.
38 template <typename Encoding
, typename InputByteStream
>
39 class EncodedInputStream
{
40 RAPIDJSON_STATIC_ASSERT(sizeof(typename
InputByteStream::Ch
) == 1);
42 typedef typename
Encoding::Ch Ch
;
44 EncodedInputStream(InputByteStream
& is
) : is_(is
) {
45 current_
= Encoding::TakeBOM(is_
);
48 Ch
Peek() const { return current_
; }
49 Ch
Take() { Ch c
= current_
; current_
= Encoding::Take(is_
); return c
; }
50 size_t Tell() const { return is_
.Tell(); }
53 void Put(Ch
) { RAPIDJSON_ASSERT(false); }
54 void Flush() { RAPIDJSON_ASSERT(false); }
55 Ch
* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
56 size_t PutEnd(Ch
*) { RAPIDJSON_ASSERT(false); return 0; }
59 EncodedInputStream(const EncodedInputStream
&);
60 EncodedInputStream
& operator=(const EncodedInputStream
&);
66 //! Specialized for UTF8 MemoryStream.
68 class EncodedInputStream
<UTF8
<>, MemoryStream
> {
70 typedef UTF8
<>::Ch Ch
;
72 EncodedInputStream(MemoryStream
& is
) : is_(is
) {
73 if (static_cast<unsigned char>(is_
.Peek()) == 0xEFu
) is_
.Take();
74 if (static_cast<unsigned char>(is_
.Peek()) == 0xBBu
) is_
.Take();
75 if (static_cast<unsigned char>(is_
.Peek()) == 0xBFu
) is_
.Take();
77 Ch
Peek() const { return is_
.Peek(); }
78 Ch
Take() { return is_
.Take(); }
79 size_t Tell() const { return is_
.Tell(); }
84 Ch
* PutBegin() { return 0; }
85 size_t PutEnd(Ch
*) { return 0; }
90 EncodedInputStream(const EncodedInputStream
&);
91 EncodedInputStream
& operator=(const EncodedInputStream
&);
94 //! Output byte stream wrapper with statically bound encoding.
96 \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
97 \tparam OutputByteStream Type of input byte stream. For example, FileWriteStream.
99 template <typename Encoding
, typename OutputByteStream
>
100 class EncodedOutputStream
{
101 RAPIDJSON_STATIC_ASSERT(sizeof(typename
OutputByteStream::Ch
) == 1);
103 typedef typename
Encoding::Ch Ch
;
105 EncodedOutputStream(OutputByteStream
& os
, bool putBOM
= true) : os_(os
) {
107 Encoding::PutBOM(os_
);
110 void Put(Ch c
) { Encoding::Put(os_
, c
); }
111 void Flush() { os_
.Flush(); }
114 Ch
Peek() const { RAPIDJSON_ASSERT(false); return 0;}
115 Ch
Take() { RAPIDJSON_ASSERT(false); return 0;}
116 size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
117 Ch
* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
118 size_t PutEnd(Ch
*) { RAPIDJSON_ASSERT(false); return 0; }
121 EncodedOutputStream(const EncodedOutputStream
&);
122 EncodedOutputStream
& operator=(const EncodedOutputStream
&);
124 OutputByteStream
& os_
;
127 #define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
129 //! Input stream wrapper with dynamically bound encoding and automatic encoding detection.
131 \tparam CharType Type of character for reading.
132 \tparam InputByteStream type of input byte stream to be wrapped.
134 template <typename CharType
, typename InputByteStream
>
135 class AutoUTFInputStream
{
136 RAPIDJSON_STATIC_ASSERT(sizeof(typename
InputByteStream::Ch
) == 1);
142 \param is input stream to be wrapped.
143 \param type UTF encoding type if it is not detected from the stream.
145 AutoUTFInputStream(InputByteStream
& is
, UTFType type
= kUTF8
) : is_(&is
), type_(type
), hasBOM_(false) {
146 RAPIDJSON_ASSERT(type
>= kUTF8
&& type
<= kUTF32BE
);
148 static const TakeFunc f
[] = { RAPIDJSON_ENCODINGS_FUNC(Take
) };
149 takeFunc_
= f
[type_
];
150 current_
= takeFunc_(*is_
);
153 UTFType
GetType() const { return type_
; }
154 bool HasBOM() const { return hasBOM_
; }
156 Ch
Peek() const { return current_
; }
157 Ch
Take() { Ch c
= current_
; current_
= takeFunc_(*is_
); return c
; }
158 size_t Tell() const { return is_
->Tell(); }
161 void Put(Ch
) { RAPIDJSON_ASSERT(false); }
162 void Flush() { RAPIDJSON_ASSERT(false); }
163 Ch
* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
164 size_t PutEnd(Ch
*) { RAPIDJSON_ASSERT(false); return 0; }
167 AutoUTFInputStream(const AutoUTFInputStream
&);
168 AutoUTFInputStream
& operator=(const AutoUTFInputStream
&);
170 // Detect encoding type with BOM or RFC 4627
172 // BOM (Byte Order Mark):
173 // 00 00 FE FF UTF-32BE
174 // FF FE 00 00 UTF-32LE
179 const unsigned char* c
= reinterpret_cast<const unsigned char *>(is_
->Peek4());
183 unsigned bom
= static_cast<unsigned>(c
[0] | (c
[1] << 8) | (c
[2] << 16) | (c
[3] << 24));
185 if (bom
== 0xFFFE0000) { type_
= kUTF32BE
; hasBOM_
= true; is_
->Take(); is_
->Take(); is_
->Take(); is_
->Take(); }
186 else if (bom
== 0x0000FEFF) { type_
= kUTF32LE
; hasBOM_
= true; is_
->Take(); is_
->Take(); is_
->Take(); is_
->Take(); }
187 else if ((bom
& 0xFFFF) == 0xFFFE) { type_
= kUTF16BE
; hasBOM_
= true; is_
->Take(); is_
->Take(); }
188 else if ((bom
& 0xFFFF) == 0xFEFF) { type_
= kUTF16LE
; hasBOM_
= true; is_
->Take(); is_
->Take(); }
189 else if ((bom
& 0xFFFFFF) == 0xBFBBEF) { type_
= kUTF8
; hasBOM_
= true; is_
->Take(); is_
->Take(); is_
->Take(); }
191 // RFC 4627: Section 3
192 // "Since the first two characters of a JSON text will always be ASCII
193 // characters [RFC0020], it is possible to determine whether an octet
194 // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
195 // at the pattern of nulls in the first four octets."
196 // 00 00 00 xx UTF-32BE
197 // 00 xx 00 xx UTF-16BE
198 // xx 00 00 00 UTF-32LE
199 // xx 00 xx 00 UTF-16LE
203 unsigned pattern
= (c
[0] ? 1 : 0) | (c
[1] ? 2 : 0) | (c
[2] ? 4 : 0) | (c
[3] ? 8 : 0);
205 case 0x08: type_
= kUTF32BE
; break;
206 case 0x0A: type_
= kUTF16BE
; break;
207 case 0x01: type_
= kUTF32LE
; break;
208 case 0x05: type_
= kUTF16LE
; break;
209 case 0x0F: type_
= kUTF8
; break;
210 default: break; // Use type defined by user.
214 // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
215 if (type_
== kUTF16LE
|| type_
== kUTF16BE
) RAPIDJSON_ASSERT(sizeof(Ch
) >= 2);
216 if (type_
== kUTF32LE
|| type_
== kUTF32BE
) RAPIDJSON_ASSERT(sizeof(Ch
) >= 4);
219 typedef Ch (*TakeFunc
)(InputByteStream
& is
);
220 InputByteStream
* is_
;
227 //! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
229 \tparam CharType Type of character for writing.
230 \tparam OutputByteStream type of output byte stream to be wrapped.
232 template <typename CharType
, typename OutputByteStream
>
233 class AutoUTFOutputStream
{
234 RAPIDJSON_STATIC_ASSERT(sizeof(typename
OutputByteStream::Ch
) == 1);
240 \param os output stream to be wrapped.
241 \param type UTF encoding type.
242 \param putBOM Whether to write BOM at the beginning of the stream.
244 AutoUTFOutputStream(OutputByteStream
& os
, UTFType type
, bool putBOM
) : os_(&os
), type_(type
) {
245 RAPIDJSON_ASSERT(type
>= kUTF8
&& type
<= kUTF32BE
);
247 // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
248 if (type_
== kUTF16LE
|| type_
== kUTF16BE
) RAPIDJSON_ASSERT(sizeof(Ch
) >= 2);
249 if (type_
== kUTF32LE
|| type_
== kUTF32BE
) RAPIDJSON_ASSERT(sizeof(Ch
) >= 4);
251 static const PutFunc f
[] = { RAPIDJSON_ENCODINGS_FUNC(Put
) };
258 UTFType
GetType() const { return type_
; }
260 void Put(Ch c
) { putFunc_(*os_
, c
); }
261 void Flush() { os_
->Flush(); }
264 Ch
Peek() const { RAPIDJSON_ASSERT(false); return 0;}
265 Ch
Take() { RAPIDJSON_ASSERT(false); return 0;}
266 size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
267 Ch
* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
268 size_t PutEnd(Ch
*) { RAPIDJSON_ASSERT(false); return 0; }
271 AutoUTFOutputStream(const AutoUTFOutputStream
&);
272 AutoUTFOutputStream
& operator=(const AutoUTFOutputStream
&);
275 typedef void (*PutBOMFunc
)(OutputByteStream
&);
276 static const PutBOMFunc f
[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM
) };
280 typedef void (*PutFunc
)(OutputByteStream
&, Ch
);
282 OutputByteStream
* os_
;
287 #undef RAPIDJSON_ENCODINGS_FUNC
289 RAPIDJSON_NAMESPACE_END
299 #endif // RAPIDJSON_FILESTREAM_H_