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.
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.
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)
来源:https://stackoverflow.com/questions/496204/how-do-i-write-binary-data-for-7z-archive-format