631 lines
23 KiB
C++
631 lines
23 KiB
C++
// Copyright (C) 2011 Milo Yip
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
// THE SOFTWARE.
|
|
|
|
#ifndef RAPIDJSON_ENCODINGS_H_
|
|
#define RAPIDJSON_ENCODINGS_H_
|
|
|
|
#include "rapidjson.h"
|
|
|
|
#ifdef _MSC_VER
|
|
RAPIDJSON_DIAG_PUSH
|
|
RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
|
|
RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
|
#elif defined(__GNUC__)
|
|
RAPIDJSON_DIAG_PUSH
|
|
RAPIDJSON_DIAG_OFF(effc++)
|
|
#endif
|
|
|
|
namespace rapidjson {
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Encoding
|
|
|
|
/*! \class rapidjson::Encoding
|
|
\brief Concept for encoding of Unicode characters.
|
|
|
|
\code
|
|
concept Encoding {
|
|
typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition.
|
|
|
|
enum { supportUnicode = 1 }; // or 0 if not supporting unicode
|
|
|
|
//! \brief Encode a Unicode codepoint to an output stream.
|
|
//! \param os Output stream.
|
|
//! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
|
|
template<typename OutputStream>
|
|
static void Encode(OutputStream& os, unsigned codepoint);
|
|
|
|
//! \brief Decode a Unicode codepoint from an input stream.
|
|
//! \param is Input stream.
|
|
//! \param codepoint Output of the unicode codepoint.
|
|
//! \return true if a valid codepoint can be decoded from the stream.
|
|
template <typename InputStream>
|
|
static bool Decode(InputStream& is, unsigned* codepoint);
|
|
|
|
//! \brief Validate one Unicode codepoint from an encoded stream.
|
|
//! \param is Input stream to obtain codepoint.
|
|
//! \param os Output for copying one codepoint.
|
|
//! \return true if it is valid.
|
|
//! \note This function just validating and copying the codepoint without actually decode it.
|
|
template <typename InputStream, typename OutputStream>
|
|
static bool Validate(InputStream& is, OutputStream& os);
|
|
|
|
// The following functions are deal with byte streams.
|
|
|
|
//! Take a character from input byte stream, skip BOM if exist.
|
|
template <typename InputByteStream>
|
|
static CharType TakeBOM(InputByteStream& is);
|
|
|
|
//! Take a character from input byte stream.
|
|
template <typename InputByteStream>
|
|
static Ch Take(InputByteStream& is);
|
|
|
|
//! Put BOM to output byte stream.
|
|
template <typename OutputByteStream>
|
|
static void PutBOM(OutputByteStream& os);
|
|
|
|
//! Put a character to output byte stream.
|
|
template <typename OutputByteStream>
|
|
static void Put(OutputByteStream& os, Ch c);
|
|
};
|
|
\endcode
|
|
*/
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// UTF8
|
|
|
|
//! UTF-8 encoding.
|
|
/*! http://en.wikipedia.org/wiki/UTF-8
|
|
http://tools.ietf.org/html/rfc3629
|
|
\tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
|
|
\note implements Encoding concept
|
|
*/
|
|
template<typename CharType = char>
|
|
struct UTF8 {
|
|
typedef CharType Ch;
|
|
|
|
enum { supportUnicode = 1 };
|
|
|
|
template<typename OutputStream>
|
|
static void Encode(OutputStream& os, unsigned codepoint) {
|
|
if (codepoint <= 0x7F)
|
|
os.Put(static_cast<Ch>(codepoint & 0xFF));
|
|
else if (codepoint <= 0x7FF) {
|
|
os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
|
|
os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
|
|
}
|
|
else if (codepoint <= 0xFFFF) {
|
|
os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
|
|
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
|
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
|
}
|
|
else {
|
|
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
|
os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
|
|
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
|
|
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
|
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
|
}
|
|
}
|
|
|
|
template <typename InputStream>
|
|
static bool Decode(InputStream& is, unsigned* codepoint) {
|
|
#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | ((unsigned char)c & 0x3Fu)
|
|
#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0)
|
|
#define TAIL() COPY(); TRANS(0x70)
|
|
Ch c = is.Take();
|
|
if (!(c & 0x80)) {
|
|
*codepoint = (unsigned char)c;
|
|
return true;
|
|
}
|
|
|
|
unsigned char type = GetRange((unsigned char)c);
|
|
*codepoint = (0xFF >> type) & (unsigned char)c;
|
|
bool result = true;
|
|
switch (type) {
|
|
case 2: TAIL(); return result;
|
|
case 3: TAIL(); TAIL(); return result;
|
|
case 4: COPY(); TRANS(0x50); TAIL(); return result;
|
|
case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
|
|
case 6: TAIL(); TAIL(); TAIL(); return result;
|
|
case 10: COPY(); TRANS(0x20); TAIL(); return result;
|
|
case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
|
|
default: return false;
|
|
}
|
|
#undef COPY
|
|
#undef TRANS
|
|
#undef TAIL
|
|
}
|
|
|
|
template <typename InputStream, typename OutputStream>
|
|
static bool Validate(InputStream& is, OutputStream& os) {
|
|
#define COPY() os.Put(c = is.Take())
|
|
#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0)
|
|
#define TAIL() COPY(); TRANS(0x70)
|
|
Ch c;
|
|
COPY();
|
|
if (!(c & 0x80))
|
|
return true;
|
|
|
|
bool result = true;
|
|
switch (GetRange((unsigned char)c)) {
|
|
case 2: TAIL(); return result;
|
|
case 3: TAIL(); TAIL(); return result;
|
|
case 4: COPY(); TRANS(0x50); TAIL(); return result;
|
|
case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
|
|
case 6: TAIL(); TAIL(); TAIL(); return result;
|
|
case 10: COPY(); TRANS(0x20); TAIL(); return result;
|
|
case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
|
|
default: return false;
|
|
}
|
|
#undef COPY
|
|
#undef TRANS
|
|
#undef TAIL
|
|
}
|
|
|
|
static unsigned char GetRange(unsigned char c) {
|
|
// Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
|
|
// With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
|
|
static const unsigned char type[] = {
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
|
|
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
|
|
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
|
|
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
|
|
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,
|
|
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,
|
|
};
|
|
return type[c];
|
|
}
|
|
|
|
template <typename InputByteStream>
|
|
static CharType TakeBOM(InputByteStream& is) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
|
Ch c = Take(is);
|
|
if ((unsigned char)c != 0xEFu) return c;
|
|
c = is.Take();
|
|
if ((unsigned char)c != 0xBBu) return c;
|
|
c = is.Take();
|
|
if ((unsigned char)c != 0xBFu) return c;
|
|
c = is.Take();
|
|
return c;
|
|
}
|
|
|
|
template <typename InputByteStream>
|
|
static Ch Take(InputByteStream& is) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
|
return is.Take();
|
|
}
|
|
|
|
template <typename OutputByteStream>
|
|
static void PutBOM(OutputByteStream& os) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
|
os.Put(0xEFu); os.Put(0xBBu); os.Put(0xBFu);
|
|
}
|
|
|
|
template <typename OutputByteStream>
|
|
static void Put(OutputByteStream& os, Ch c) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
|
os.Put(static_cast<typename OutputByteStream::Ch>(c));
|
|
}
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// UTF16
|
|
|
|
//! UTF-16 encoding.
|
|
/*! http://en.wikipedia.org/wiki/UTF-16
|
|
http://tools.ietf.org/html/rfc2781
|
|
\tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
|
|
\note implements Encoding concept
|
|
|
|
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
|
|
For streaming, use UTF16LE and UTF16BE, which handle endianness.
|
|
*/
|
|
template<typename CharType = wchar_t>
|
|
struct UTF16 {
|
|
typedef CharType Ch;
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
|
|
|
|
enum { supportUnicode = 1 };
|
|
|
|
template<typename OutputStream>
|
|
static void Encode(OutputStream& os, unsigned codepoint) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
|
if (codepoint <= 0xFFFF) {
|
|
RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
|
|
os.Put(static_cast<typename OutputStream::Ch>(codepoint));
|
|
}
|
|
else {
|
|
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
|
unsigned v = codepoint - 0x10000;
|
|
os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
|
|
os.Put((v & 0x3FF) | 0xDC00);
|
|
}
|
|
}
|
|
|
|
template <typename InputStream>
|
|
static bool Decode(InputStream& is, unsigned* codepoint) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
|
|
Ch c = is.Take();
|
|
if (c < 0xD800 || c > 0xDFFF) {
|
|
*codepoint = c;
|
|
return true;
|
|
}
|
|
else if (c <= 0xDBFF) {
|
|
*codepoint = (c & 0x3FF) << 10;
|
|
c = is.Take();
|
|
*codepoint |= (c & 0x3FF);
|
|
*codepoint += 0x10000;
|
|
return c >= 0xDC00 && c <= 0xDFFF;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
template <typename InputStream, typename OutputStream>
|
|
static bool Validate(InputStream& is, OutputStream& os) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
|
Ch c;
|
|
os.Put(c = is.Take());
|
|
if (c < 0xD800 || c > 0xDFFF)
|
|
return true;
|
|
else if (c <= 0xDBFF) {
|
|
os.Put(c = is.Take());
|
|
return c >= 0xDC00 && c <= 0xDFFF;
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
//! UTF-16 little endian encoding.
|
|
template<typename CharType = wchar_t>
|
|
struct UTF16LE : UTF16<CharType> {
|
|
template <typename InputByteStream>
|
|
static CharType TakeBOM(InputByteStream& is) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
|
CharType c = Take(is);
|
|
return (unsigned short)c == 0xFEFFu ? Take(is) : c;
|
|
}
|
|
|
|
template <typename InputByteStream>
|
|
static CharType Take(InputByteStream& is) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
|
CharType c = (unsigned char)is.Take();
|
|
c |= (unsigned char)is.Take() << 8;
|
|
return c;
|
|
}
|
|
|
|
template <typename OutputByteStream>
|
|
static void PutBOM(OutputByteStream& os) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
|
os.Put(0xFFu); os.Put(0xFEu);
|
|
}
|
|
|
|
template <typename OutputByteStream>
|
|
static void Put(OutputByteStream& os, CharType c) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
|
os.Put(c & 0xFFu);
|
|
os.Put((c >> 8) & 0xFFu);
|
|
}
|
|
};
|
|
|
|
//! UTF-16 big endian encoding.
|
|
template<typename CharType = wchar_t>
|
|
struct UTF16BE : UTF16<CharType> {
|
|
template <typename InputByteStream>
|
|
static CharType TakeBOM(InputByteStream& is) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
|
CharType c = Take(is);
|
|
return (unsigned short)c == 0xFEFFu ? Take(is) : c;
|
|
}
|
|
|
|
template <typename InputByteStream>
|
|
static CharType Take(InputByteStream& is) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
|
CharType c = (unsigned char)is.Take() << 8;
|
|
c |= (unsigned char)is.Take();
|
|
return c;
|
|
}
|
|
|
|
template <typename OutputByteStream>
|
|
static void PutBOM(OutputByteStream& os) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
|
os.Put(0xFEu); os.Put(0xFFu);
|
|
}
|
|
|
|
template <typename OutputByteStream>
|
|
static void Put(OutputByteStream& os, CharType c) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
|
os.Put((c >> 8) & 0xFFu);
|
|
os.Put(c & 0xFFu);
|
|
}
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// UTF32
|
|
|
|
//! UTF-32 encoding.
|
|
/*! http://en.wikipedia.org/wiki/UTF-32
|
|
\tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
|
|
\note implements Encoding concept
|
|
|
|
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
|
|
For streaming, use UTF32LE and UTF32BE, which handle endianness.
|
|
*/
|
|
template<typename CharType = unsigned>
|
|
struct UTF32 {
|
|
typedef CharType Ch;
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
|
|
|
|
enum { supportUnicode = 1 };
|
|
|
|
template<typename OutputStream>
|
|
static void Encode(OutputStream& os, unsigned codepoint) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
|
|
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
|
os.Put(codepoint);
|
|
}
|
|
|
|
template <typename InputStream>
|
|
static bool Decode(InputStream& is, unsigned* codepoint) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
|
|
Ch c = is.Take();
|
|
*codepoint = c;
|
|
return c <= 0x10FFFF;
|
|
}
|
|
|
|
template <typename InputStream, typename OutputStream>
|
|
static bool Validate(InputStream& is, OutputStream& os) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
|
|
Ch c;
|
|
os.Put(c = is.Take());
|
|
return c <= 0x10FFFF;
|
|
}
|
|
};
|
|
|
|
//! UTF-32 little endian enocoding.
|
|
template<typename CharType = unsigned>
|
|
struct UTF32LE : UTF32<CharType> {
|
|
template <typename InputByteStream>
|
|
static CharType TakeBOM(InputByteStream& is) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
|
CharType c = Take(is);
|
|
return (unsigned)c == 0x0000FEFFu ? Take(is) : c;
|
|
}
|
|
|
|
template <typename InputByteStream>
|
|
static CharType Take(InputByteStream& is) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
|
CharType c = (unsigned char)is.Take();
|
|
c |= (unsigned char)is.Take() << 8;
|
|
c |= (unsigned char)is.Take() << 16;
|
|
c |= (unsigned char)is.Take() << 24;
|
|
return c;
|
|
}
|
|
|
|
template <typename OutputByteStream>
|
|
static void PutBOM(OutputByteStream& os) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
|
os.Put(0xFFu); os.Put(0xFEu); os.Put(0x00u); os.Put(0x00u);
|
|
}
|
|
|
|
template <typename OutputByteStream>
|
|
static void Put(OutputByteStream& os, CharType c) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
|
os.Put(c & 0xFFu);
|
|
os.Put((c >> 8) & 0xFFu);
|
|
os.Put((c >> 16) & 0xFFu);
|
|
os.Put((c >> 24) & 0xFFu);
|
|
}
|
|
};
|
|
|
|
//! UTF-32 big endian encoding.
|
|
template<typename CharType = unsigned>
|
|
struct UTF32BE : UTF32<CharType> {
|
|
template <typename InputByteStream>
|
|
static CharType TakeBOM(InputByteStream& is) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
|
CharType c = Take(is);
|
|
return (unsigned)c == 0x0000FEFFu ? Take(is) : c;
|
|
}
|
|
|
|
template <typename InputByteStream>
|
|
static CharType Take(InputByteStream& is) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
|
CharType c = (unsigned char)is.Take() << 24;
|
|
c |= (unsigned char)is.Take() << 16;
|
|
c |= (unsigned char)is.Take() << 8;
|
|
c |= (unsigned char)is.Take();
|
|
return c;
|
|
}
|
|
|
|
template <typename OutputByteStream>
|
|
static void PutBOM(OutputByteStream& os) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
|
os.Put(0x00u); os.Put(0x00u); os.Put(0xFEu); os.Put(0xFFu);
|
|
}
|
|
|
|
template <typename OutputByteStream>
|
|
static void Put(OutputByteStream& os, CharType c) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
|
os.Put((c >> 24) & 0xFFu);
|
|
os.Put((c >> 16) & 0xFFu);
|
|
os.Put((c >> 8) & 0xFFu);
|
|
os.Put(c & 0xFFu);
|
|
}
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// ASCII
|
|
|
|
//! ASCII encoding.
|
|
/*! http://en.wikipedia.org/wiki/ASCII
|
|
\tparam CharType Code unit for storing 7-bit ASCII data. Default is char.
|
|
\note implements Encoding concept
|
|
*/
|
|
template<typename CharType = char>
|
|
struct ASCII {
|
|
typedef CharType Ch;
|
|
|
|
enum { supportUnicode = 0 };
|
|
|
|
template<typename OutputStream>
|
|
static void Encode(OutputStream& os, unsigned codepoint) {
|
|
RAPIDJSON_ASSERT(codepoint <= 0x7F);
|
|
os.Put(static_cast<Ch>(codepoint & 0xFF));
|
|
}
|
|
|
|
template <typename InputStream>
|
|
static bool Decode(InputStream& is, unsigned* codepoint) {
|
|
unsigned char c = static_cast<unsigned char>(is.Take());
|
|
*codepoint = c;
|
|
return c <= 0X7F;
|
|
}
|
|
|
|
template <typename InputStream, typename OutputStream>
|
|
static bool Validate(InputStream& is, OutputStream& os) {
|
|
unsigned char c = is.Take();
|
|
os.Put(c);
|
|
return c <= 0x7F;
|
|
}
|
|
|
|
template <typename InputByteStream>
|
|
static CharType TakeBOM(InputByteStream& is) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
|
Ch c = Take(is);
|
|
return c;
|
|
}
|
|
|
|
template <typename InputByteStream>
|
|
static Ch Take(InputByteStream& is) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
|
return is.Take();
|
|
}
|
|
|
|
template <typename OutputByteStream>
|
|
static void PutBOM(OutputByteStream& os) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
|
(void)os;
|
|
}
|
|
|
|
template <typename OutputByteStream>
|
|
static void Put(OutputByteStream& os, Ch c) {
|
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
|
os.Put(static_cast<typename OutputByteStream::Ch>(c));
|
|
}
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// AutoUTF
|
|
|
|
//! Runtime-specified UTF encoding type of a stream.
|
|
enum UTFType {
|
|
kUTF8 = 0, //!< UTF-8.
|
|
kUTF16LE = 1, //!< UTF-16 little endian.
|
|
kUTF16BE = 2, //!< UTF-16 big endian.
|
|
kUTF32LE = 3, //!< UTF-32 little endian.
|
|
kUTF32BE = 4 //!< UTF-32 big endian.
|
|
};
|
|
|
|
//! Dynamically select encoding according to stream's runtime-specified UTF encoding type.
|
|
/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().
|
|
*/
|
|
template<typename CharType>
|
|
struct AutoUTF {
|
|
typedef CharType Ch;
|
|
|
|
enum { supportUnicode = 1 };
|
|
|
|
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
|
|
|
|
template<typename OutputStream>
|
|
RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) {
|
|
typedef void (*EncodeFunc)(OutputStream&, unsigned);
|
|
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
|
|
(*f[os.GetType()])(os, codepoint);
|
|
}
|
|
|
|
template <typename InputStream>
|
|
RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) {
|
|
typedef bool (*DecodeFunc)(InputStream&, unsigned*);
|
|
static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };
|
|
return (*f[is.GetType()])(is, codepoint);
|
|
}
|
|
|
|
template <typename InputStream, typename OutputStream>
|
|
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
|
|
typedef bool (*ValidateFunc)(InputStream&, OutputStream&);
|
|
static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };
|
|
return (*f[is.GetType()])(is, os);
|
|
}
|
|
|
|
#undef RAPIDJSON_ENCODINGS_FUNC
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Transcoder
|
|
|
|
//! Encoding conversion.
|
|
template<typename SourceEncoding, typename TargetEncoding>
|
|
struct Transcoder {
|
|
//! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
|
|
template<typename InputStream, typename OutputStream>
|
|
RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
|
|
unsigned codepoint;
|
|
if (!SourceEncoding::Decode(is, &codepoint))
|
|
return false;
|
|
TargetEncoding::Encode(os, codepoint);
|
|
return true;
|
|
}
|
|
|
|
//! Validate one Unicode codepoint from an encoded stream.
|
|
template<typename InputStream, typename OutputStream>
|
|
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
|
|
return Transcode(is, os); // Since source/target encoding is different, must transcode.
|
|
}
|
|
};
|
|
|
|
//! Specialization of Transcoder with same source and target encoding.
|
|
template<typename Encoding>
|
|
struct Transcoder<Encoding, Encoding> {
|
|
template<typename InputStream, typename OutputStream>
|
|
RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
|
|
os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class.
|
|
return true;
|
|
}
|
|
|
|
template<typename InputStream, typename OutputStream>
|
|
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
|
|
return Encoding::Validate(is, os); // source/target encoding are the same
|
|
}
|
|
};
|
|
|
|
} // namespace rapidjson
|
|
|
|
#if defined(__GNUC__) || defined(_MSV_VER)
|
|
RAPIDJSON_DIAG_POP
|
|
#endif
|
|
|
|
#endif // RAPIDJSON_ENCODINGS_H_
|