## 19.4 例 2: 複数バイト文字コード変換の定義 (JIS <-> Unicode)

次に、状態依存のコード変換について説明します。先に説明したように、この型の変換は、日本語文字のJIS のような状態依存の複数バイト符号化と、 Unicode のようなワイド文字符号化の間で行います。一般に、外部デバイスは複数バイト符号化を使用し、内部処理ではワイド文字符号化を使用します。

状態依存のコード変換ファセットを実装し、使用するための手順は、次のとおりです。

1. 必要に応じて新しい変換状態型を定義します。
2. 必要に応じて新しい文字の特性型を定義します。または、新しい状態型で文字特性テンプレートのインスタンスを生成します。
3. コード変換ファセットを定義します。
4. 新しい文字の特性型を利用して、新しいストリーム型のインスタンスを生成します。
5. 新しいコード変換ファセットを持ったロケールに、ファイルストリームのバッファを組み込みます。

次に、以上の手順の詳細を説明します。

### 19.4.1 新しい変換状態型の定義

複数バイトシーケンスを、状態依存の複数バイト符号化で構文解析したり作成するには、コード変換ファセットで変換状態を管理する必要があります。この状態は、デフォルトでは `mbstate_t` 型であり、C ライブラリで定義する実装依存の状態型です。この型で変換状態を追跡するのに不充分な場合は、ユーザー定義の変換状態型を作成してください。以下のコードはその定義方法を示したものですが、新しい状態型には、次のメンバー関数が必要なので注意してください。

- コンストラクタ。引数 `0` には、変換状態の初期状態を表す変換状態オブジェクトを作成するという特別な意味があります。
- コピーコンストラクタと割り当て
- 等価と非等価の比較

次に、新しい変換状態型を示します。

>     class JISstate_t {
>     public:
>                        JISstate_t( int state=0 )
>                        : state_(state) { ; }

>                        JISstate_t(const JISstate_t& state)
>                        : state_(state.state_) { ; }

>                        JISstate_t& operator=(const JISstate_t& state)
>                         {
>                            if ( &state != this )
>                              state_= state.state_;
>                            return *this;
>                         }

>                        JISstate_t& operator=(const int state)
>                         {
>                            state_= state;
>                            return *this;
>                         }

>                        bool operator==(const JISstate_t& state) const
>                         {
>                            return ( state_ == state.state_ );
>                         }

>                        bool operator!=(const JISstate_t& state) const
>                         {
>                            return ( !(state_ == state.state_) );
>                         }

>     private:
>                        int state_;

>                      };

### 19.4.2 新しい文字特性型の定義

変換状態型は、 文字特性の一部です。そのため、新しい変換状態型では、新しい文字特性型が必要です。

標準以外で、移植性のないライブラリ機能を使用しない場合、新しい文字特性型を定義して、必要な型を定義しなおす必要があります。

>     struct JIS_char_traits: public char_traits<wchar_t>
>     {
>             typedef JISstate_t                state_type;
>             typedef fpos<state_type>          pos_type;
>             typedef wstreamoff                off_type;
>     };

### 19.4.3 コード変換ファセットの定義

最初の例と同様に、実際のコード変換ファセットを定義します。手順は、基本的に前と同様ですが、新しいコード変換型に新しいクラステンプレートを定義し、それを特殊化します。コードは次のようになります。

>     template <class internT, class externT, class stateT>
>     class UnicodeJISConversion
>     : public codecvt<internT, externT, stateT>
>     {
>     };

>     class UnicodeJISConversion<wchar_t, char, JISstate_t>
>     : public codecvt<wchar_t, char, JISstate_t>
>     {
>     protected:

>      result do_in(JISstate_t& state,
>                   const char*  from,
>                   const char*  from_end,
>                   const char*& from_next,
>                   wchar_t*     to,
>                   wchar_t*     to_limit,
>                   wchar_t*&    to_next) const;

>      result do_out(JISstate_t& state,
>                    const wchar_t*  from,
>                    const wchar_t*  from_end,
>                    const wchar_t*& from_next,
>                    char*           to,
>                    char*           to_limit,
>                    char*&          to_next) const;

>      bool do_always_noconv() const throw()
>      { return false; };

>      int do_encoding() const throw();
>      { return -1; }

>     };

この例では、関数 `do_encoding()` で コード変換が状態依存であることを表す -1 を返す必要があります。ここでも関数 `in()` と `out()` は、『標準 C++ クラスライブラリ・リファレンス』のクラス codecvt で説明しているエラー表示方式に沿って処理を行います。

非状態依存の変換を特徴付けているのは、`in()` と `out()` に対して変換状態引数を使用して、ファイルストリームバッファとコード変換ファセット間の通信に利用している点です。ファイルストリームバッファは、変換状態の作成、管理、削除を行います。最初に、ファイルストリームバッファでは、変換状態オブジェクトを作成します。これは、変換状態の初期状態を表し、それをコード変換ファセットに渡します。ファセットでは、実行する変換に合わせてそれを変更します。ファイルストリームバッファでは、続く 2 つのコード変換の間もそれを保存します。

### 19.4.4 新しいコード変換ファセットの使用

次に、新しいコード変換ファセットの使用方法の例を示します。

>     typedef basic_fstream<wchar_t,JIS_char_traits> JIS_fstream;   //1
>     JIS_fstream inout("/tmp/fil");
>     UnicodeJISConversion<wchar_t,char,JISstate_t> cvtfac;
>     locale cvtloc(locale(),&cvtfac);
>     inout.rdbuf()->pubimbue(cvtloc)                               //2
>     wcout << inout.rdbuf();                                       //3

//1 | Unicode-JIS コード変換では、デフォルトの型 `mbstate_t` ではない変換状態型を使用します。変換状態型は文字特性に含まれるので、新しいファイル型を作成する必要があります。`JIS_char_traits` の代わりに、文字特性テンプレートの特別な拡張機能を利用し、`char_traits<wchar_t,JISstate_t>` を使用しました。
//2 | ここで、ストリームバッファのロケールは、Unicode-JIS コード変換ファセットのある大域ロケールのコピーに置き換えられます。
//3 | JIS 符号化ファイル `"/tmp/fil"` が読み取られ、自動的に Unicode に変換され、`wcout` に書き込まれます。

Copyright (c) 1998, Rogue Wave Software, Inc.
このマニュアルに関する誤りのご指摘やご質問は、電子メールにてお送りください。

OEM リリース, 1998 年 6 月