Description

This is not a "port" of some other existing implementation, everything has been written from scratch
(althought some code was actually inspired by existing public domain projects) and it's all pure C++/Qt.
Please note that this is not a complete stand-alone library, it's just a bunch of classes.
You will have to add them to your project and modify them to best fit your needs.

It supports basic features like file extraction and compression (with optional password encryption) and
archive comments.
There are methods to extract single files or the whole archive and methods to compress the contents of a whole directory.
Nevertheless, it should be quite trivial to add other features. The public API only has a few methods because this is what
I was looking for. This does not mean you can't write a few more lines of code (it really shouldn't take more than a few
lines!) to add more features.

The classes are great if you only need to use the PKZIP format for loading/saving your application's data.
Just remember that you will need to customize a few parts of the code, i.e. to add your own password
retrieval method.

Requirements

Features

Fast (but less robust with corrupt archives) parsing of the ZIP file format.

Traditional PKWARE password encryption (strong encryption as introduced by PKZip versions 5.0 and later is NOT available).

Support for archive comments.

Optional namespace and shared lib support (see below).

Time zone support (see below).

Missing features and restrictions

Needs to be modified to fit into an existing project (i.e.: you might need to add your own password handling routine).

Weak support of corrupt archives (althought some files could be extracted even if the archive is corrupted).

No support for filesystem specific features like unix symbolic links.

No support for spanned archives.

No support for strong encryption or features introduced after PKZIP version 2.0 (see the PKWARE specs for details).

Namespace support

If you need the classes to be inside a namespace, simply define OSDAB_NAMESPACE in the project file. The classes will then be in a Osdab::Zip namespace.

Building as a shared library (.DLL / .so / .dylib)

There are two ways to achieve this.

The easiest and cleanest way is to edit the zipglobal.h file and remove the "#ifndef OSDAB_ZIP_LIB" block.

The other way consists in #defining OSDAB_ZIP_LIB in both the project you create for the shared zip library and in the projects linking the library.
An example in the "Example.SharedLib" directory contains such a sample build.

Time zones

Time zone support is implemented only on Windows and Unix compatible systems.

It can be disabled by defining OSDAB_ZIP_NO_UTC in the project file.

The currentUtcOffset() method in zipglobal.cpp is where the current UTC offset is calculated. Qt has no proper time zone support (Qt 4.7.x) so the code relies on gmtime and localtime.

A last tip: zlib's inflateInit() and deflateInit() methods check if the library's major version is the same as the
version in the header file you include. You can do this test when your application starts thus notifying
an error before the user starts working! Here is some trivial example code:

Technical details

zlib linking

Linking the zlib library is not really required as it is statically linked into the Qt libraries.
Qt's QtCore library exports all the zlib functions, so you only need to let your INCLUDEPATH point
to the zlib.h and zconf.h header files. Anyway, if you want to use a specific version of the zlib
library you will need to link against it as usual.

The Bitter Bitty flag

The first versions of the UnZip class used to first parse the local header records to retrieve the archive contents.
However this introduced some problems with entries that have the third general purpose bit flag set.
The original purpose of this flag is to allow to write the CRC32, compressed and uncompressed size after the compressed
data in a so-called "data descriptor" record. This was necessary because some devices (maybe some ice-age tape drive)
might not be able to seek back and set the three fields in the local header record.
Locating the data descriptor is however a big issue since we need to skip the compressed data without knowing its length.
And btw.: the data descriptor has an OPTIONAL signature.

One day one of you guys out there realized that the class failed in parsing OpenOffice archives (plain PKZIP 2.0 zip files!).
After a short coffeine powered debug session, I realized that the problem was related to my beloved 3rd general purpose
bit flag (friends call him Bitty, but his full name is Bitter Bitty - ok, I will quit it with these poor geek jokes).
OpenOffice sets the Bitty flag for empty files (or under some other circumstance.. I can't remember now) but the
routine I wrote to locate the data descriptor was slow and buggy (very slow; and very buggy).

This was a good reason for me to write the whole archive parsing routines back from scratch.
The latest versions start parsing the central directory records (at the end of the zip file) instead of parsing the
local header entries. This allows me to always retrieve CRC32, compressed and uncompressed size, besides of the
offset of the local header entry for each file.
I suppose most zip routines use this second approach (at least some open source ones do) as it is quite faster.
However, this means that incomplete zip files (files with a corrupted or missing end) won't be parsed, because
I didn't add any routines to handle these files by attempting to parse the local header.

Btw. the local headers are still read to do some basic redundancy checks and detect if the values in the central directory
differ from the ones in the local header.

Encrypted archives

About encrypted archives: only the last byte in the decrypted encryption header is used for testing the password as
to PKZip version 2.0 and later. Earlier versions used the last two bytes and it seems that many zip implementations
still use two bytes (at least when writing the encryption header). The Zip class still writes the last two bytes for
testing the password at extraction time (using part of the file modification time as we don't know the CRC yet).