Как мне записать двоичные данные для формата архива 7z?

StackOverflow https://stackoverflow.com/questions/496204

  •  20-08-2019
  •  | 
  •  

Вопрос

Я перечитал описание формата и исходный код для формата архива 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:Как все отмечают, было бы проблемой, если бы я запустил это на машине большого размера.Здесь дело обстоит не так.Согласно Фредрику Янссену, я должен приводить адреса не-массивов.Я должен также упомянуть, что CrcCalc() - это функция в LZMA SDK.Добавление & немного помогает, это тот первый неподписанный символ [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, они будут записаны в файл в формате little-endian (я предполагаю, что у вас процессор little-endian).

Редактировать:Возможно, что еще хуже, вам не хватает & перед major, minor, offset, size и crc, т. е.вы приводите фактические значения к указателю.

Другие советы

Эээ...Я в замешательстве.В нем есть SDK - пакет...о котором вы упоминаете в своем посте...также в 7-zip-исходники находятся в Сети.смотрите также p7zip - файл на SourceForge.Я только что просмотрел исходные тексты для p7zip, и там есть куча файлов, начинающихся с "7z", которые выглядят так, как будто они справятся с задачей.

Я сам программно не использовал формат 7z (только через утилиту командной строки / GUI), но почему вам нужно обрабатывать эти низкоуровневые вещи самостоятельно, а не через SDK?(кроме как из-за лицензирования LGPL)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top