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は、プラットフォーム、プログラム、言語を問わず、すべての文字に一意の番号を与えます。
この一意の番号をコードポイントと呼び、範囲は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の構造体を通じてこれらのエンコーディングを提供します。
メモリー内のテキスト処理には、通常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宣言の例:
詳しい例は、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で出力する例です。
入力ストリームにもASCIIを使えます。入力ストリームに127を超える値のバイトがあると、kParseErrorStringInvalidEncodingエラーになります。
ASCIIはUnicodeコードポイントを表現できないため、メモリー内(DocumentのエンコーディングやReaderの変換先エンコーディング)では使用できません。
妥当性検証とエンコーディング変換
RapidJSONはJSONを解析するときに、入力JSONが指定したエンコーディングの妥当な列であるかどうかを検証できます。このオプションは、テンプレート引数parseFlagsにkParseValidateEncodingFlagを追加すると有効になります。
入力と出力のエンコーディングが異なる場合、ReaderとWriterは自動的にテキストのエンコーディングを変換します。この場合は入力列を必ず復号するので、kParseValidateEncodingFlagは不要です。復号できない列は必然的に不正な列です。
Transcoder
RapidJSONのエンコーディング関数はJSONの解析・生成用に設計されていますが、JSON以外の文字列のエンコーディング変換にも流用できます。
UTF-8からUTF-16へ文字列を変換する例です。
AutoUTFと対応するストリームを使って、変換元・変換先のエンコーディングを実行時に設定することもできます。