文字列テーブルのデータ構造
文字列テーブルから文字列を取り出すときには対になるラベルを用います。
C++ の場合には enum を使って実現するのが効率が良いと思われます。
ラベル | 日本語 | 英語 |
---|---|---|
STR_HELLO | こんにちは。 | Hello. |
STR_BYE | さようなら。 | Good bye. |
このテーブルから
enum { STR_HELLO, //!< こんにちは。 STR_BYE //!< さようなら。 };
このような列挙の定義を生成することにします。
実際のデータ構造は、文字列データへのポインタ配列を使用します。
イメージ的には以下のようになります。
+--------------------+--- +--|文字列#0へのポインタ| | +--------------------+ 文字列ポインタ配列 +-|--|文字列#1へのポインタ| | | +--------------------+--- | +->|こんにちは。\0 | | +--------------------+ 文字列データブロック +--->|さようなら。\0 | +--------------------+---
この構造にヘッダ部分をくっつけて、文字列テーブルデータ構造を作ります。
ヘッダ部分には、文字列テーブルデータに関する情報、文字列データのサイズなどを含めます。
/* +--------------+ | StringTable | +--------------+ |ポインタ配列部| +--------------+ |文字列データ部| +--------------+ */ struct StringTable { char signature[4]; //!< 文字列テーブルデータをあらわす識別子 ulong version; //!< バージョンナンバー ulong indexOffset; //!< インデックス(ポインタ配列)のデータ先頭からのバイトオフセット ulong indexCount; //!< インデックスの要素数 ulong stringOffset; //!< 文字列データのデータ先頭からのバイトオフセット ulong stringDataSize; //!< 文字列データブロックのバイトサイズ };
識別子をつけておくと、読み込んだデータが処理対象として正しいかどうかのチェックが出来ます。
バージョンナンバーを用意することで、仕様変更があった場合に古いデータにも対応することが出来ます。
ポインタ配列部はデータの先頭から文字列データ部に含まれる各文字列データの先頭の文字までの
バイトオフセットの配列になります。
データ具体例は以下の通りです。
|<---- 32 byte ---->| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |S|T|B|L| 1| 24| 2| signature, version, indexOffset, indexCount, +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 32| 26| 32| 45| stringOffset, stringDataSize, 文字列 #0 オフセット、 文字列 #1 オフセット +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |こ |ん |に |ち |は |。 |0|さ |よ 文字列 #0, 文字列 #1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |う |な |ら |。 |0| | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
indexOffset, stringOffset, および各文字列オフセットは、ファイルからデータを読み込んで
StringTable のアドレスを加算して、キャストすることでポインタとして扱えます。
C++ ではなく C 風な使い方なのが少し気になりますが、この方が簡単・便利になります。
(もちろん、整数とポインタの間のキャストがうまく行く環境に限られます。)
キャストをこのデータを直接扱う部分に閉じ込めてやれば、他のソースはキレイな C++ の
コードを保つことが出来るということで手を打とうと思います。