Поэтому для Qt написано много пакетов для работы с архивами.
Я лично предпочитаю The OSDaB Project.
http://code.google.com/p/osdab/source/browse/trunk/OSDaB-Zip
Meet a couple of pure-Qt/C++ classes capable of handling PKZIP 2.0 compatible zip archives.
Чтобы им пользоваться Qt должна быть собрана с поддержкой zlib. Само использование крайне легко, в примерах все описано.
Я же расскажу о неком досадном баге в этом пакете.
Я не буду углубляться в формат zip файла, он довольно сложен, главное вот это
Файл ZIP определяется наличием центрального каталога, который расположен в конце файла. В каталоге хранится список имен записей (файлов или каталогов), которые хранятся в файле ZIP, наряду с другими метаданными о входе и смещении в файле ZIP, указывающими на фактическое расположение сжатых данных.Проблема в том, что OSDaB считает что центральный каталог начинается начинается с минус 22 байта от конца архива. Т.е. он отступает 22 байта от конца файла архива и ищет там начало секции Центрального Каталога. Секция ЦК начинается с байт PK56. Так вот если он ее там не найдет, то начинается двигаться в начало файла но с шагом кратным 22. Для большинства архивов это работает. По ходу работы пришлось столкнуться с архивами у которых ЦК начинается вовсле не с -22 байта, а с 18 или 21. Поэтому проект пришлось подправить чтобы начинал поиск секции ЦК с 18 и шагал по 1 байту в начало. Это понижает скорость работы архиватора, но по крайней мере нужные мне архивы стали нормально читаться.
Правки, которые пришлось сделать, располагаются в файле unzip.cpp
Магический параметр UNZIP_EOCD_SIZE установлен равным 18
В функции
UnZip::ErrorCode UnzipPrivate::seekToCentralDirectory()
закоментарена строчка //offset -= UNZIP_EOCD_SIZE;
чтобы шаг был 1 байт. Кроме тогоoffset -= 1 /*UNZIP_EOCD_SIZE*/;
И ввел дополнительную проверкуif (offset > length)
offset = getSULong((const unsigned char*) buffer1, UNZIP_EOCD_OFF_CDOFF + 4);
Определив функцию getSULong
quint32 UnzipPrivate::getSULong(const unsigned char* data, quint32 offset) const
{
quint32 res = (quint32) data[offset];
res |= (((quint32)data[offset+1]) << 8);
return res;
}
* This source code was highlighted with Source Code Highlighter.
Комментариев нет:
Отправить комментарий