7z アーカイブ形式のバイナリ データを書き込むにはどうすればよいですか?
質問
7z アーカイブ形式の形式の説明とソース コードを徹底的に調べてきましたが、有効なコンテナを作成するのにまだ苦労しています。空のコンテナを作成できると思います...とにかく、ここからが私のスタートです:
std::ofstream ofs(archivename.c_str(), std::ios::binary|std::ios::trunc);
Byte signature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
Byte major = 0;
Byte minor = 3;
ofs.write((const char*)signature, 6);
ofs.write((const char*)major, 1);
ofs.write((const char*)minor, 1);
UInt64 offset = 0;
UInt64 size = 0;
UInt32 crc = 0;
ofs.write((const char*)offset, 4);
ofs.write((const char*)size, 8);
ofs.write((const char*)crc, 8);
ofs.write((const char*)CrcCalc(0, 0), 8);
ofs.close();
私の主な問題は、std::ofstream::write() を理解していないことだと思います。Byte は「unsigned char」、UInt64 と UInt32 は両方とも「unsigned long」です。
更新0:誰もが指摘しているように、これをビッグエンディアンのマシンで実行すると問題になります。ここではそうではありません。Fredrik Janssen 氏によると、非配列のアドレスをキャストする必要があります。CrcCalc() は LZMA SDK の関数であることにも言及しておきます。& を追加すると少しは役に立ちますが、問題があるのは最初の unsigned char[6] です。
更新1:以下の空のアーカイブ ファイルを取得する作業コード。
static void SetUInt32(Byte *p, UInt32 d)
{
for (int i = 0; i < 4; i++, d >>= 8)
p[i] = (Byte)d;
}
static void SetUInt64(Byte *p, UInt64 d)
{
for (int i = 0; i < 8; i++, d >>= 8)
p[i] = (Byte)d;
}
void make_7z_archive()
{
CrcGenerateTable();
std::ofstream ofs(archivename.c_str(), std::ios::binary|std::ios::trunc);
Byte signature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
Byte major = 0;
Byte minor = 3;
ofs.write((const char*)signature, 6);
ofs.write((const char*)&major, 1);
ofs.write((const char*)&minor, 1);
UInt64 offset = 0;
UInt64 size = 0;
UInt32 crc = 0;
Byte buf[24];
SetUInt64(buf + 4, offset);
SetUInt64(buf + 12, size);
SetUInt32(buf + 20, crc);
SetUInt32(buf, CrcCalc(buf + 4, 20));
ofs.write((const char*)buf, 24);
ofs.close();
}
注記:CrcGenerateTable() と CrcCalc() は LZMA SDK からのものです。
解決
7z の形式はわかりませんが、オフセット、サイズ、および crc を書き留めると、これらはリトルエンディアン形式でファイルに書き込まれることに気付きました (リトルエンディアンの CPU を使用していると仮定します)。
編集:おそらくさらに悪いことに、メジャー、マイナー、オフセット、サイズ、CRC の前に & がありません。つまり、実際の値をポインタにキャストしています。
他のヒント
えー...私は混乱しています。それは SDK...あなたの投稿で言及されています...また、 7-zip ソースはオンラインです. 。こちらも参照 p7zip SourceForge で。p7zip のソースをざっと見たところ、「7z」で始まるファイルがたくさんあり、それがうまく機能しそうな気がします。
私自身は 7z 形式をプログラムで使用したことはありません (コマンドライン ユーティリティ/GUI を使用するだけです) が、なぜこれらの低レベルのものを SDK を使用せずに自分で処理する必要があるのでしょうか?(LGPL ライセンスによるものを除く)