## 19.2 例 1: 1 バイト文字変換の定義 (ASCII <-> EBCDIC)

ファイルストリームバッファとコード変換ファセットによる連携的な処理例として、EBCDIC で符号化されたテキストファイルを ASCII で符号化された文字ストリームに変換するための、コード変換ファセットの実装を紹介します。ASCII 文字と EBCDIC 文字の間の変換は、固定サイズの変換なので、文字はすべて 1 バイトで表します。そのため、変換は文字単位で行われます。

ASCII-EBCDIC コード変換ファセットを実装して使用するための手順は、次のとおりです。

1. 標準コード変換ファセット型 `codecvt` から、新しいファセット型を派生させます。
2. 文字型 `char` の新しいファセット型を特殊化します。
3. バッファで使用するメンバー関数を実装します。
4. ASCII-EBCDIC コード変換ファセットを持つロケールに、ファイルストリームのバッファを組み込みます。

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

### 19.2.1 新しいファセット型の派生

次に示すのは、新しいコード変換ファセット型 `AsciiEbcdicConversion` です。

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

文字型 `char` でクラステンプレートを特殊化するので、上記の型は空です。

### 19.2.2 新しいファセット型の特殊化とメンバー関数の実装

コード変換ファセットでは、2 つのメンバー関数 `in()` と `out()` を使用します。

- 関数 `in()` は、外部デバイスからの読み取り時の変換に使用します。
- 関数 `out()` は、外部デバイスへの書き込み時の変換に使用します。

ファイルストリームバッファで使用する、コード変換ファセットの他のメンバー関数は次のとおりです。

- 関数 `always_noconv()` は、ファセットで何も変換されない場合は、`true` を返します。外部と内部で符号化が同じ場合などには、ファイルストリームバッファによるコード変換ファセットをバイパスすることもできるためです。この例で使用するファセットは、変換をすることが明らかであり、バイパスはしないため、この例の `always_noconv()` では `false` が返ります。
- 関数 `encoding()` は、状態依存であるか、固定サイズであるかなど、変換型に関する情報を提供します。この例では、変換は固定サイズで行います。関数 `encoding()` は、内部文字のサイズを返します。ファイルバッファは内部で ASCII 符号化を使用するため、内部文字のサイズは 1 になります。

ファセットの公開メンバー関数は、いずれも個別に限定公開の仮想メンバー関数 `do_...()` を呼び出します。次に示すのは、特殊化したファセット型の宣言です。

>     class AsciiEbcdicConversion<char, char, mbstate_t>
>     : public codecvt<char, char, mbstate_t>
>     {
>     protected:

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

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

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

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

>     };

簡潔にするために、ここでは、Rogue Wave のファイルストリームバッファの実装に使用する関数だけを実装します。さらに応用範囲の広いコード変換ファセットが必要な場合は、`do_length()` と `do_max_length()` も実装してください。

関数 `do_in()` と `do_out()` の実装は簡単です。どちらの関数も、`[from,from_end)` の範囲の文字シーケンスを対応するシーケンス `[to,to_end)` に変換します。ポインタ `from_next` と `to_next` は、正しく変換された最後の文字より後の位置を示します。基本的に、これらの関数に与える情報や結果に制限はありません。ただし、ファイルストリームバッファとの通信を有効にするには、処理結果の成功や失敗を正しく伝える必要があります。

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

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

>     fstream inout("/tmp/fil");                                    //1
>     AsciiEbcdicConversion<char,char,mbstate_t> cvtfac;
>     locale cvtloc(locale(),&cvtfac);
>     inout.rdbuf()->pubimbue(cvtloc)                               //2
>     cout << inout.rdbuf();                                        //3

//1 | ファイルを作成すると、デフォルトロケールとして、現在の大域ロケールのスナップショットが設定されます。ストリームには 2 つのロケールオブジェクトがあり、1 つは数値項目の書式設定に使用し、もう 1 つはストリームのバッファによるコード変換に使用します。
//2 | ここで、ストリームバッファのロケールは、ASCII-EBCDIC コード変換ファセットを持つ大域ロケールのコピーに置き換えられます。
//3 | EBCDIC ファイル `"/tmp/fil"` の内容が読み取られ、ASCII に自動的に変換され、`cout` に書き込まれます。

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

OEM リリース, 1998 年 6 月