ECMA-404によると、

(序文)JSONテキストは、Unicodeコードポイントの列です。

それ以前のRFC4627には、次のように記されています。

(第3節)JSONテキストはUnicodeで符号化しなければなりません。既定のエンコーディングはUTF-8です。

(第6節)JSONはUTF-8、UTF-16、UTF-32で表現できます。UTF-8で記述する場合、JSONは8ビット互換です。UTF-16やUTF-32で記述する場合は、バイナリーのcontent-transfer-encodingを使わなければなりません。

RapidJSONはさまざまなエンコーディングに対応します。JSONのエンコーディングの妥当性を検証し、エンコーディング間でJSONを変換することもできます。これらの機能はすべて内部に実装されているため、外部ライブラリー(ICUなど)は不要です。

Unicode

Unicodeの公式サイトより:

Unicodeは、プラットフォーム、プログラム、言語を問わず、すべての文字に一意の番号を与えます。

この一意の番号をコードポイントと呼び、範囲は0x0から0x10FFFFです。

Unicode Transformation Format

Unicodeコードポイントを保存するエンコーディングは複数あります。これらをUnicode Transformation Format(UTF)と呼びます。RapidJSONは、広く使われる次のUTFに対応しています。

  • UTF-8:8ビットの可変長エンコーディング。コードポイントを1〜4バイトに対応付けます。
  • UTF-16:16ビットの可変長エンコーディング。コードポイントを1〜2個の16ビットコード単位(2〜4バイト)に対応付けます。
  • UTF-32:32ビットの固定長エンコーディング。コードポイントを1個の32ビットコード単位(4バイト)へ直接対応付けます。

UTF-16とUTF-32では、バイト順(エンディアン)が重要です。コンピューターのメモリー内では、そのコンピューターのバイト順で保存するのが一般的です。しかし、ファイルに保存したりネットワークで転送したりする場合は、バイト列の順序をリトルエンディアン(LE)かビッグエンディアン(BE)として明示する必要があります。

RapidJSONは、rapidjson/encodings.hの構造体を通じてこれらのエンコーディングを提供します。

namespace rapidjson {
template<typename CharType = char>
struct UTF8;
template<typename CharType = wchar_t>
struct UTF16;
template<typename CharType = wchar_t>
struct UTF16LE;
template<typename CharType = wchar_t>
struct UTF16BE;
template<typename CharType = unsigned>
struct UTF32;
template<typename CharType = unsigned>
struct UTF32LE;
template<typename CharType = unsigned>
struct UTF32BE;
} // namespace rapidjson
RapidJSONの主な名前空間
Definition rapidjson.h:374

メモリー内のテキスト処理には、通常UTF8、UTF16、UTF32を使います。入出力によるテキスト処理には、UTF8、UTF16LE、UTF16BE、UTF32LE、UTF32BEを使えます。

DOM形式のAPIを使う場合、GenericValue<Encoding>とGenericDocument<Encoding>のテンプレート引数Encodingは、メモリー内のJSON文字列を表現するエンコーディングを指定します。そのため、通常はこの引数にUTF8、UTF16、UTF32を使います。選択は、OSやアプリケーションで使用する他のライブラリーによって異なります。たとえば、Windows APIはUnicode文字をUTF-16で表現しますが、大半のLinuxディストリビューションやアプリケーションはUTF-8を好みます。

UTF-16のDOM宣言の例:

typedef GenericDocument<UTF16<> > WDocument;
typedef GenericValue<UTF16<> > WValue;

詳しい例は、DOMのエンコーディングの節を参照してください。

文字型

宣言で示したように、各エンコーディングにはテンプレート引数CharTypeがあります。少し紛らわしいのですが、各CharTypeが保存するのは文字(コードポイント)ではなく、コード単位です。前の節で述べたように、UTF-8では1つのコードポイントを1〜4個のコード単位へ符号化する場合があります。

UTF16(LE|BE)とUTF32(LE|BE)では、CharTypeはそれぞれ最低2バイト、4バイトの整数型でなければなりません。

C++11で導入されたchar16_tとchar32_tは、それぞれUTF16とUTF32に使えます。

AutoUTF

これまでのエンコーディングは、コンパイル時に静的に決まります。つまり、メモリーやストリームで使うエンコーディングを正確に知っている必要があります。しかし、異なるエンコーディングのファイルを読み書きし、実行時にエンコーディングを決める必要がある場合もあります。

AutoUTFは、この目的のために設計されたエンコーディングです。入出力ストリームに応じて、使用するエンコーディングを選択します。現時点では、EncodedInputStreamとEncodedOutputStreamとともに使う必要があります。

ASCII

JSON標準にはASCIIの記述がありませんが、UTF-8を扱えないアプリケーション向けに7ビットASCIIのJSONを出力したい場合があります。どのJSONでもエスケープ列\uXXXXでUnicode文字を表現できるため、JSONは常にASCIIで符号化できます。

UTF-8のDOMをASCIIで出力する例です。

using namespace rapidjson;
Document d; // UTF8<>
// ...
StringBuffer buffer;
d.Accept(writer);
std::cout << buffer.GetString();
bool Accept(Handler &handler) const
この値に対応するイベントをHandlerへ渡します。
Definition document.h:1768
JSONライター。
Definition writer.h:87
GenericStringBuffer< UTF8< char >, CrtAllocator > StringBuffer
UTF8エンコーディングの文字列バッファー。
Definition fwd.h:61
GenericDocument< UTF8<> > Document
UTF8エンコーディングのGenericDocument。
Definition document.h:2402

入力ストリームにもASCIIを使えます。入力ストリームに127を超える値のバイトがあると、kParseErrorStringInvalidEncodingエラーになります。

ASCIIはUnicodeコードポイントを表現できないため、メモリー内(DocumentのエンコーディングやReaderの変換先エンコーディング)では使用できません。

妥当性検証とエンコーディング変換

RapidJSONはJSONを解析するときに、入力JSONが指定したエンコーディングの妥当な列であるかどうかを検証できます。このオプションは、テンプレート引数parseFlagsにkParseValidateEncodingFlagを追加すると有効になります。

入力と出力のエンコーディングが異なる場合、ReaderとWriterは自動的にテキストのエンコーディングを変換します。この場合は入力列を必ず復号するので、kParseValidateEncodingFlagは不要です。復号できない列は必然的に不正な列です。

Transcoder

RapidJSONのエンコーディング関数はJSONの解析・生成用に設計されていますが、JSON以外の文字列のエンコーディング変換にも流用できます。

UTF-8からUTF-16へ文字列を変換する例です。

#include "rapidjson/encodings.h"
using namespace rapidjson;
const char* s = "..."; // UTF-8 string
StringStream source(s);
bool hasError = false;
while (source.Peek() != '\0')
if (!Transcoder<UTF8<>, UTF16<> >::Transcode(source, target)) {
hasError = true;
break;
}
if (!hasError) {
const wchar_t* t = target.GetString();
// ...
}
メモリー内の出力ストリームを表します。
Definition stringbuffer.h:41
GenericStringStream< UTF8< char > > StringStream
UTF8エンコーディングの文字列ストリーム。
Definition fwd.h:49
エンコーディング変換。
Definition encodings.h:658
UTF-16エンコーディング。
Definition encodings.h:269
UTF-8エンコーディング。
Definition encodings.h:96

AutoUTFと対応するストリームを使って、変換元・変換先のエンコーディングを実行時に設定することもできます。