バイナリ ファイルの一種であるterminfoデータベース ファイルの解析を検討しています。そのストレージ形式について自分で読んで、私が直面している問題を確認できます。
マニュアルは言う -
ヘッダー セクションは、ファイルを開始します。このセクションには、以下で説明する形式の 6 つの短整数が含まれます。これらの整数は
(1) マジックナンバー (8 進数の 0432);
...
...
short 整数は、2 つの 8 ビット バイトに格納されます。最初のバイトには値の最下位 8 ビットが含まれ、2 番目のバイトには最上位 8 ビットが含まれます。(したがって、表される値は 256*秒 + 最初です。) 値 -1 は 2 バイト 0377、0377 で表されます。その他の負の値は不正です。通常、この値は、対応する機能がこの端末にないことを意味します。これがハードウェアに対応していないマシンは、整数を 2 バイトとして読み取り、リトルエンディアン値を計算する必要があります。
このタイプの入力を解析する際の最初の問題は、サイズが 8 ビットに固定されることです。そのため、サイズが正確に 8 ビットであることが保証されないため、単純な古い char は使用できません。だから私は「固定幅の整数型
int8_t
」を探していましたが、再び白黒を選択するかuint8_t
、「実装が型を直接サポートする場合にのみ提供される」と明確に述べているジレマに直面しました。では、タイプが十分に移植可能になるようにするには、何を選択すればよいでしょうか。2 番目の問題は
buffer.readInt16LE()
、リトル エンディアン形式で 16 バイトのデータを読み取る可能性のある C++ 標準ライブラリのメソッドがないことです。では、移植可能で安全な方法でこの機能を再度実装するにはどうすればよいでしょうか。
私はすでにchar
データ型でそれを読み取ろうとしましたが、間違いなく私のマシンでガベージが生成されます。infocmp
適切な入力は、コマンド (例: - )で読み取ることができます$ infocmp xterm
。
#include <fstream>
#include <iostream>
#include <vector>
int main()
{
std::ifstream db(
"/usr/share/terminfo/g/gnome", std::ios::binary | std::ios::ate);
std::vector<unsigned char> buffer;
if (db) {
auto size = db.tellg();
buffer.resize(size);
db.seekg(0, std::ios::beg);
db.read(reinterpret_cast<char*>(&buffer.front()), size);
}
std::cout << "\n";
}
$1 = std::vector of length 3069, capacity 3069 = {26 '\032', 1 '\001', 21 '\025',
0 '\000', 38 '&', 0 '\000', 16 '\020', 0 '\000', 157 '\235', 1 '\001',
193 '\301', 4 '\004', 103 'g', 110 'n', 111 'o', 109 'm', 101 'e', 124 '|',
71 'G', 78 'N', 79 'O', 77 'M', 69 'E', 32 ' ', 84 'T', 101 'e', 114 'r',
109 'm', 105 'i', 110 'n', 97 'a', 108 'l', 0 '\000', 0 '\000', 1 '\001',
0 '\000', 0 '\000', 1 '\001', 0 '\000', 0 '\000', 0 '\000', 0 '\000',
0 '\000', 0 '\000', 0 '\000', 0 '\000', 1 '\001', 1 '\001', 0 '\000',
....
....