如何写入 7z 存档格式的二进制数据?

发布于 2024-07-13 17:12:01 字数 1857 浏览 4 评论 0原文

我一直在研究 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() 的理解。 字节是一个“无符号字符”,UInt64 & UInt32 都是“unsigned long”。

UPDATE0:正如每个人都指出的那样,如果我在大端机器上运行它,就会出现问题。 这里的情况并非如此。 根据 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。

I've been pouring over the format description and source code for the 7z archive format, but I'm still having trouble writing a valid container. I assume I can create an empty container... anyway here's my start:

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();

I think my main problem is a lack of understanding of std::ofstream::write(). Byte is an 'unsigned char', UInt64 & UInt32 are both 'unsigned long'.

UPDATE0: As everyone points out, it'd be a problem if I ran this on a big-endian machine. That's not the case here. Per Fredrik Janssen, I should be casting the address of the non-arrays. I should also mention that CrcCalc() is a function in the LZMA SDK. Adding & helps a bit, it's that first unsigned char[6] that's having some problems.

UPDATE1: Working code to get an empty archive file below.

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();
}

NOTE: CrcGenerateTable() and CrcCalc() are from the LZMA SDK.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

岁月静好 2024-07-20 17:12:01

不知道 7z 的格式,但我注意到当你写下偏移量、大小和 crc 时,这些将以小端格式写入文件(我假设你有一个小端 CPU)。

编辑:可能更糟糕的是,您错过了 & 在major、minor、offset、size 和crc 之前,即您将实际值转换为指针。

don't know the format of 7z, but I notice when you write down offset, size and crc that these will be written to the file in little-endian format (I assume you have a little-endian CPU).

Edit: An probably worse, you are missing the & before major, minor, offset, size and crc, i.e. you are casting the actual values to a pointer.

酷到爆炸 2024-07-20 17:12:01

呃……我很困惑。 它有一个 SDK...您在帖子中提到...还有7-zip 源在线。 另请参阅 SourceForge 上的 p7zip。 我只是浏览了 p7zip 的源代码,有一堆以“7z”开头的文件,看起来它们可以解决这个问题。

我自己没有以编程方式使用过 7z 格式(只是通过命令行 util/GUI),但是为什么您需要自己处理这些低级事务而不是通过 SDK? (除了 LGPL 许可之外)

Uh... I'm confused. It has an SDK... which you mention in your post... also the 7-zip sources are online. see also p7zip on SourceForge. I just glanced at the sources for p7zip and there are a bunch of files that start with "7z" that look like they would do the trick.

I haven't used the 7z format programattically myself (just through the command-line util / GUI) but why would you need to handle those low-level things yourself rather than through the SDK? (other than because of the LGPL licensing)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文