Как мне записать двоичные данные для формата архива 7z? - PullRequest
3 голосов
/ 30 января 2009

Я пролил описание формата и исходный код для формата архива 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 (). Байт - это «unsigned char», UInt64 и UInt32 оба являются «unsigned long».

UPDATE0 : Как все указывают, было бы проблемой, если бы я запустил это на машине с прямым порядком байтов. Это не тот случай, здесь. Согласно Фредрику Янссену, я должен использовать адрес не массивов. Я должен также упомянуть, что CrcCalc () является функцией в LZMA SDK. Добавление & немного помогает, это первый неподписанный символ [6], у которого есть некоторые проблемы.

UPDATE1 : рабочий код для получения пустого файла архива ниже.

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.

Ответы [ 2 ]

2 голосов
/ 30 января 2009

не знаю формат 7z, но я замечаю, что когда вы записываете смещение, размер и crc, они будут записаны в файл в формате с прямым порядком байтов (я полагаю, у вас есть процесс с прямым порядком байтов).

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

0 голосов
/ 30 января 2009

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

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

...