Final refactoring of ZipHandler class.

This commit is contained in:
Stephen Anthony 2018-09-05 12:21:55 -02:30
parent cacb1e3341
commit ee643e818b
2 changed files with 138 additions and 61 deletions

View File

@ -393,6 +393,9 @@ void ZipHandler::ZipFile::decompress(BytePtr& out, uInt64 length)
case 14:
throw ZipError::LZMA_UNSUPPORTED; // FIXME - LZMA format not yet supported
default:
throw ZipError::UNSUPPORTED;
}
}
catch(const ZipError&)
@ -404,18 +407,27 @@ void ZipHandler::ZipFile::decompress(BytePtr& out, uInt64 length)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt64 ZipHandler::ZipFile::getCompressedDataOffset()
{
// Don't support a number of features
GeneralFlagReader const flags(myHeader.bitFlag);
if(myHeader.startDiskNumber != myEcd.diskNumber ||
myHeader.versionNeeded > 63 || flags.patchData() ||
flags.encrypted() || flags.strongEncryption())
throw ZipError::UNSUPPORTED;
// Read the fixed-sized part of the local file header
uInt64 read_length = 0;
bool success = readStream(myBuffer, myHeader.localHeaderOffset, 0x1e, read_length);
if(!success)
throw ZipError::FILE_ERROR;
else if(read_length != 0x1e)
else if(read_length != LocalFileHeaderReader::minimumLength())
throw ZipError::FILE_TRUNCATED;
// Compute the final offset
return myHeader.localHeaderOffset + 0x1e +
read_word(myBuffer.get() + 0x1a) +
read_word(myBuffer.get() + 0x1c);
LocalFileHeaderReader reader(&myBuffer[0]);
if(!reader.signatureCorrect())
throw ZipError::BAD_SIGNATURE;
return myHeader.localHeaderOffset + reader.totalLength();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -151,64 +151,145 @@ class ZipHandler
};
using ZipFilePtr = unique_ptr<ZipFile>;
class EcdReader
/** Classes to parse the ZIP metadata in an abstracted way */
class ReaderBase
{
public:
explicit EcdReader(const uInt8* const b) : myBuf(b) { }
protected:
explicit ReaderBase(const uInt8* const b) : myBuf(b) { }
uInt32 signature() const { return read_dword(myBuf + 0x00); }
uInt16 thisDiskNo() const { return read_word(myBuf + 0x04); }
uInt16 dirStartDisk() const { return read_word(myBuf + 0x06); }
uInt16 dirDiskEntries() const { return read_word(myBuf + 0x08); }
uInt16 dirTotalEntries() const { return read_word(myBuf + 0x0a); }
uInt32 dirSize() const { return read_dword(myBuf + 0x0c); }
uInt32 dirOffset() const { return read_dword(myBuf + 0x10); }
uInt16 commentLength() const { return read_word(myBuf + 0x14); }
string comment() const { return read_string(myBuf + 0x16, commentLength()); }
bool signatureCorrect() const { return signature() == 0x06054b50; }
size_t totalLength() const { return minimumLength() + commentLength(); }
static size_t minimumLength() { return 0x16; }
uInt8 read_byte(size_t offs) const
{
return myBuf[offs];
}
uInt16 read_word(size_t offs) const
{
return (uInt16(myBuf[offs + 1]) << 8) |
(uInt16(myBuf[offs + 0]) << 0);
}
uInt32 read_dword(std::size_t offs) const
{
return (uInt32(myBuf[offs + 3]) << 24) |
(uInt32(myBuf[offs + 2]) << 16) |
(uInt32(myBuf[offs + 1]) << 8) |
(uInt32(myBuf[offs + 0]) << 0);
}
uInt64 read_qword(size_t offs) const
{
return (uInt64(myBuf[offs + 7]) << 56) |
(uInt64(myBuf[offs + 6]) << 48) |
(uInt64(myBuf[offs + 5]) << 40) |
(uInt64(myBuf[offs + 4]) << 32) |
(uInt64(myBuf[offs + 3]) << 24) |
(uInt64(myBuf[offs + 2]) << 16) |
(uInt64(myBuf[offs + 1]) << 8) |
(uInt64(myBuf[offs + 0]) << 0);
}
string read_string(size_t offs, size_t len = string::npos) const
{
return string(reinterpret_cast<char const *>(myBuf + offs), len);
}
private:
const uInt8* const myBuf;
};
class CentralDirEntryReader
class LocalFileHeaderReader : public ReaderBase
{
public:
explicit CentralDirEntryReader(const uInt8* const b) : myBuf(b) { }
explicit LocalFileHeaderReader(const uInt8* const b) : ReaderBase(b) { }
uInt32 signature() const { return read_dword(myBuf + 0x00); }
uInt8 versionCreated() const { return myBuf[0x04]; }
uInt8 osCreated() const { return myBuf[0x05]; }
uInt8 versionNeeded() const { return myBuf[0x06]; }
uInt8 osNeeded() const { return myBuf[0x07]; }
uInt16 generalFlag() const { return read_word(myBuf + 0x08); }
uInt16 compressionMethod() const { return read_word(myBuf + 0x0a); }
uInt16 modifiedTime() const { return read_word(myBuf + 0x0c); }
uInt16 modifiedDate() const { return read_word(myBuf + 0x0e); }
uInt32 crc32() const { return read_dword(myBuf + 0x10); }
uInt32 compressedSize() const { return read_dword(myBuf + 0x14); }
uInt32 uncompressedSize() const { return read_dword(myBuf + 0x18); }
uInt16 filenameLength() const { return read_word(myBuf + 0x1c); }
uInt16 extraFieldLength() const { return read_word(myBuf + 0x1e); }
uInt16 fileCommentLength() const { return read_word(myBuf + 0x20); }
uInt16 startDisk() const { return read_word(myBuf + 0x22); }
uInt16 intFileAttr() const { return read_word(myBuf + 0x24); }
uInt32 extFileAttr() const { return read_dword(myBuf + 0x26); }
uInt32 headerOffset() const { return read_dword(myBuf + 0x2a); }
string filename() const { return read_string(myBuf + 0x2e, filenameLength()); }
string fileComment() const { return read_string(myBuf + 0x2e + filenameLength() + extraFieldLength(), fileCommentLength()); }
uInt32 signature() const { return read_dword(0x00); }
uInt8 versionNeeded() const { return read_byte(0x04); }
uInt8 osNeeded() const { return read_byte(0x05); }
uInt16 generalFlag() const { return read_word(0x06); }
uInt16 compressionMethod() const { return read_word(0x08); }
uInt16 modifiedTime() const { return read_word(0x0a); }
uInt16 modifiedDate() const { return read_word(0x0c); }
uInt32 crc32() const { return read_dword(0x0e); }
uInt32 compressedSize() const { return read_dword(0x12); }
uInt32 uncompressedSize() const { return read_dword(0x16); }
uInt16 filenameLength() const { return read_word(0x1a); }
uInt16 extraFieldLength() const { return read_word(0x1c); }
string filename() const { return read_string(0x1e, filenameLength()); }
bool signatureCorrect() const { return signature() == 0x04034b50; }
size_t totalLength() const { return minimumLength() + filenameLength() + extraFieldLength(); }
static size_t minimumLength() { return 0x1e; }
};
class CentralDirEntryReader : public ReaderBase
{
public:
explicit CentralDirEntryReader(const uInt8* const b) : ReaderBase(b) { }
uInt32 signature() const { return read_dword(0x00); }
uInt8 versionCreated() const { return read_byte(0x04); }
uInt8 osCreated() const { return read_byte(0x05); }
uInt8 versionNeeded() const { return read_byte(0x06); }
uInt8 osNeeded() const { return read_byte(0x07); }
uInt16 generalFlag() const { return read_word(0x08); }
uInt16 compressionMethod() const { return read_word(0x0a); }
uInt16 modifiedTime() const { return read_word(0x0c); }
uInt16 modifiedDate() const { return read_word(0x0e); }
uInt32 crc32() const { return read_dword(0x10); }
uInt32 compressedSize() const { return read_dword(0x14); }
uInt32 uncompressedSize() const { return read_dword(0x18); }
uInt16 filenameLength() const { return read_word(0x1c); }
uInt16 extraFieldLength() const { return read_word(0x1e); }
uInt16 fileCommentLength() const { return read_word(0x20); }
uInt16 startDisk() const { return read_word(0x22); }
uInt16 intFileAttr() const { return read_word(0x24); }
uInt32 extFileAttr() const { return read_dword(0x26); }
uInt32 headerOffset() const { return read_dword(0x2a); }
string filename() const { return read_string(0x2e, filenameLength()); }
string fileComment() const { return read_string(0x2e + filenameLength() + extraFieldLength(), fileCommentLength()); }
bool signatureCorrect() const { return signature() == 0x02014b50; }
size_t totalLength() const { return minimumLength() + filenameLength() + extraFieldLength() + fileCommentLength(); }
static size_t minimumLength() { return 0x2e; }
};
class EcdReader : public ReaderBase
{
public:
explicit EcdReader(const uInt8* const b) : ReaderBase(b) { }
uInt32 signature() const { return read_dword(0x00); }
uInt16 thisDiskNo() const { return read_word(0x04); }
uInt16 dirStartDisk() const { return read_word(0x06); }
uInt16 dirDiskEntries() const { return read_word(0x08); }
uInt16 dirTotalEntries() const { return read_word(0x0a); }
uInt32 dirSize() const { return read_dword(0x0c); }
uInt32 dirOffset() const { return read_dword(0x10); }
uInt16 commentLength() const { return read_word(0x14); }
string comment() const { return read_string(0x16, commentLength()); }
bool signatureCorrect() const { return signature() == 0x06054b50; }
size_t totalLength() const { return minimumLength() + commentLength(); }
static size_t minimumLength() { return 0x16; }
};
class GeneralFlagReader
{
public:
explicit GeneralFlagReader(uInt16 val) : myValue(val) { }
bool encrypted() const { return bool(myValue & 0x0001); }
bool implode8kDict() const { return bool(myValue & 0x0002); }
bool implode3Trees() const { return bool(myValue & 0x0004); }
uInt32 deflateOption() const { return uInt32((myValue >> 1) & 0x0003); }
bool lzmaEosMark() const { return bool(myValue & 0x0002); }
bool useDescriptor() const { return bool(myValue & 0x0008); }
bool patchData() const { return bool(myValue & 0x0020); }
bool strongEncryption() const { return bool(myValue & 0x0040); }
bool utf8Encoding() const { return bool(myValue & 0x0800); }
bool directoryEncryption() const { return bool(myValue & 0x2000); }
private:
const uInt8* const myBuf;
uInt16 myValue;
};
private:
@ -221,22 +302,6 @@ class ZipHandler
/** Close a ZIP file and add it to the cache */
void addToCache();
/** Convenience functions to read specific datatypes */
static inline uInt16 read_word(const uInt8* const buf)
{
uInt16 p0 = uInt16(buf[0]), p1 = uInt16(buf[1]);
return (p1 << 8) | p0;
}
static inline uInt32 read_dword(const uInt8* const buf)
{
return (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
}
static inline string read_string(const uInt8* const buf, size_t len = string::npos)
{
return (buf == nullptr || *buf == '\0') ? "" :
string(reinterpret_cast<const char*>(buf), len);
}
private:
static constexpr uInt32 DECOMPRESS_BUFSIZE = 16384;
static constexpr uInt32 CACHE_SIZE = 8; // number of open files to cache