Skip to content

AlexanderBagel/FWZip

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

66 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FWZip версия 2.0.5 - (от 26 ноября 2024 года)
Автор: Александр (Rouse_) Багель
Авторский сайт: http://rouse.drkb.ru
Авторский блог: http://alexander-bagel.blogspot.ru/
Стабильная версия FWZip: http://rouse.drkb.ru/components.php#fwzip
Репозиторий с последней версией FWZip: https://github.com/AlexanderBagel/FWZip
mailto: [email protected]

0. В качестве вступления:

  В последнее время по работе я часто начал сталкиваться с задачами требующими работу с архивами. 
  Формат архива для решения задач был выбран самый распространенный - ZIP и я начал искать уже реализованные сторонние классы для работы с архивами в этом формате.
  Изначально требования были просты: мне требовался компонент (набор классов) который не тянул бы за собой сторонние библиотеки.
  Таких компонентов нашлось достаточно много. 
  Но потом задачи стали усложнятся и соответственно требования к компонентам изменились.
  Через какое-то время мне нужен был компонент умеющий паковать и распаковывать файлы больших размеров.
  Еще через какое-то время потребовалось чтобы при этом он не отьедал почти всю память у приложения.  
  В конце концов мне потребовалось что бы он умел работать с зашифрованными архивами,
  плюс до кучи (т.к. работать приходится в основном с XML - т.е. текстом) чтобы он поддерживал алгоритм сжатия PPMD.
  В итоге у меня остался один более-менее приемлимый вариант, но стоящий 400 долларов и не умеющий PPMD (sic).
  Пришлось делать все самому (правда PPMD не добавлен так как оказался не нужным)...
  
1. Возможности библиотеки:

  Набор классов FWZip предназначен для создания и распаковки ZIP архивов с методами сжатия Store и Deflate.
  
  В данный момент поддерживаются следующие расширенные элементы спецификации:
    - поддержка ZIP64 расширения
    - поддержка DataDescryptors
    - поддержка криптографии по методу PKWARE
    - поддержка расширенного блока данных с NTFS аттрибутами
    - поддержка UTF8 кодировки в именах файлов
    - поддержка длинных путей и имен файлов под NTFS (до 65535 символов)
    - поддержка многотомных архивов

  Не поддерживаемые элементы спецификации (реализации части из них я не смог встретить ни в одном архиваторе):
    - не поддерживаются следующие алгоритмы сжатия Shrunk, ReducedХ, Imploded, TCA, Deflate64, PKWAREхх, BZIP2
    - не поддерживаются методы усиленной криптографии
    - не поддерживается шифрование CentralDirectory

  Вкратце - все что может сделать WinRar при создании ZIP архива, данный набор классов умеет.
  
  Поддерживаются Delphi версий от седьмой и до Delphi 11 Alexandria включительно (как 32-бита, так и 64).
  Включая работу в составе FireMonkey приложения (iOS/Android сборки не поддерживаются).
  Начиная с версии 2.0 добавлена поддержка кроссплатформенного FreePascal + Lazarus. Работоспособность проверена на Ubuntu 22.4 x64. MacOS пока не поддерживается (но обьектные файлы включены).
  
  ВАЖНО!!!
  Файлы фреймворка сохранены в формате UTF-8, для корректной работы под устаревшими версиями Delphi (например седьмой версии) потребуется подключить файлы из папки .\delphi7\ 
  
  ВАЖНО!!!
  При использовании данной библиотеки в составе Delphi 2007 и ниже могут быть проблемы с распаковкой данных в связи с тем
  что с этими версиями Delphi поставляется устаревший вариант ZLib. Его крайне желательно обновить.
  Читайте инструкцию в пункте 11.
  
  Установка:
  Delphi - распаковать архив, указать путь к папке с исходным кодом фреймворка в настройках IDE или проекта.
  Lazarus - распаковать архив, открыть и скомпилировать пакет FWZipLCL. Подключить пакет к проекту. Установка пакета в IDE не требуется.
  
2. Список изменений:

  2.0.5 (от 26 ноября 2024 года):
    - Исправлена ошибка добавления пустых файлов при вызове TFWZipWriterItem.ChangeDataStream().

  2.0.4 (от 19 марта 2024 года):
    - Пересобраны объектные файлы для Lazarus. Старый вариант был не совместим со статически линкуемой libcairo.so
    - Добавлен пакет FWZipLCL для более удобной работы с фреймворком под Lazarus.
    - Исправлена ошибка получения атрибутов папки под Linux.

  2.0.3 (от 27 января 2024 года):
    - Отключена реакция на Z_BUF_ERROR, которую может выдать zlib новых версий при подготовке первого кадра при сжатии. Огромное спасибо Артёму Измайлову за найденую ошибку.

  2.0.2
    - Добавлена поддержка длинных сетевых путей
    - В TFWZipModifier добавлена возможность изменения имени добавляемого из архива элемента

  2.0.1 (от 1 сентября 2023 года):
    - Исправлена критическая ошибка в TFWAbstractMultiStream.StartNewVolume
    - Поправлены warning выдаваемые в trunc версии FPC
    - Исправлено неверное преобразование в OEM строку при рассчете длины текста под Delphi 7. Огромное спасибо Игорю Скрипнику за найденую ошибку.
    - Добавлена проверка AES шифрования выставленная через метод компрессии, в обход шестого бита GPBF. Огромное спасибо avp011 за найденую ошибку.
    - Добавлены два сугубо утилитарных метода из оригинального ZLib. ZCompress и ZDecompress
    - Исправлена небольшая ошибка в ExctractZIPDemo1
    - Исправлена ошибка работы с длинными именами, префикс добавляется только по необходимости, исправлено создание папок в случае полностью отсутствующего длинного пути.

  2.0 (от 11 июля 2023 года):
  
    - Добавлена поддержка Linux посредством совместимости с FreePascal + Lazarus, тесты работоспособности производились на Ubuntu 22.4 x64
    - Огромное спасибо "Александру В" ака @CynicRus за помощь в сборке обьектников под FPC (включая Mach-O), Ренату Сулейманову, Сергею Пархоменко и Boris Usievich за тестирование.
    - По предложению Сергея Есепчука добавлены методы ReadersCount и перекрытый AddZipFile, а так-же свойство Reader в класс TFWZipModifier.
    - Расширен демопример "Demos\Modify ZIP\Replace data in ZIP", добавлена демонстрация работы с внешним ридером.
    - Фикс ошибки при распаковке файлов нулевой длины, проявившейся в результате правок под Delphi 11 Alexandria
    - По предложению Артема Измайлова в классы TFWZipReader и TFWZipWriter добавлена функция Find() 
    - Исправлена некорректная работа с флагом UseUTF8String при записи общего коментария к архиву (добавленого в версии 1.1.1). Коментарий не поддерживает кодировку ввиду отсутствия GeneralPurposeBitFlag и идет всегда в OEM.

  1.1.1 (от 12 ноября 2021 года):
  
    - Исправлена ошибка финализации многотомного архива. Большое спасибо Владиславу Нечепоренко за обнаружение данной ошибки.
    - Исправлена неверная трактовка параметра NewFileName в методе TFWZipReaderItem.Extract. Большое спасибо Артуру Алееву за обнаружение данной ошибки.
    - Неверно генерировалось локальное время файла добавленного из стрима.
    - Добавлена глобальная переменная UseLongNamePrefix управляющая поддержкой длинных путей.
    - Отключено избыточное поднятие исключения при создании архива в Delphi 11 Alexandria, связанное с изменениями в методе TStream.CopyFrom. Большое спасибо Сергею Ecепчуку за обнаружение данной проблемы.	
    - При добавлении глобального коментария не учитывался флаг UseUTF8String.	

  1.1.0 (от 23 мая 2020 года):
  
    ВАЖНО!!!
    Произошли изменения в наименованиях некоторых ранее не используемых полей структур TEndOfCentralDir, TZip64EOFCentralDirectoryLocator и TZip64EOFCentralDirectoryRecord.
    Могут потребоваться правки в проектах, использующих данные поля в своих целях.

    ВАЖНО!!!
    Файлы фреймворка сохранены в формате UTF-8, для корректной работы под устаревшими версиями Delphi (например седьмой версии) потребуется подключить файлы из папки .\AnsiFiles\	

    - Добавлена поддержка многотомных архивов. Введены классы TFWAbstractMultiStream и реализация наследника от него для работы с локальными файлами TFWFileMultiStream.
    - Добавлены примеры работы с многотомными архивами (создание/чтение/модификация). См. папку .\Demos\MultyPart ZIP\
    - Добавлен проект юнит-тестирования всех модулей фреймворка FWZipTests а так-же проект тестирования. См. папку .\.UnitTest\
    - Изменено поведение параметра Mask в методе TFWZipWriter.AddFolder. Теперь список масок можно перечислять через точку с запятой. За поиск в подпапках отвечает параметр SubFolders.
    - Исправлена ошибка возникающая при повторном создании архива с предыдущей неудачной сборки (не скидывался флаг ExceptOnWrite отвечающий за сборку в CentralDirectory).
    - Исправлена ошибка контроля размера блока ExData для каждой записи.
    - Исправлена ошибка при получения контрольной суммы с папки при назначеном пароле.	

  1.0.12 (от 20 декабря 2019 года):
  
    - Добавлен метод TFWZipWriter.InsertStream
    - Расширен метод TFWZipWriter.AddStream, добавлено свойство TStreamOwnership позволяющее более удобно контролировать жизненный цикл вшнешних данных.
    - Добавлен расширенный конструктор в TZDecompressionStream позволяющий автоматически разрушать переданный для распаковки стрим
    - Добавлен новый класс TFWZipItemItemUnpackedStream для работы с незапакованными и незашифрованными данными
    - Добавлен метод TFWZipReaderItem.CreateDecompressionStream для работы с блоком данных извне
    - Добавлена поддержка длинных путей и имен файлов	

  1.0.11 (от 31 августа 2015 года):
  
    - Добавлен класс TFWZipModifier, позволяющий производить любые изменения архива "на лету" и не требующий перепаковки данных.
    - Небольшие изменения в классе FWZipReader, неверно читался пустой архив, из-за некоретного детектирования END_OF_CENTRAL_DIR_SIGNATURE	
    - Исправлена небольшая ошибка при проверке архива в случае если проверялся большой файл (неверно рассчитывались проценты)
    - Поправлен неверный режим создания TFileStream в процедуре TFWZipReader.LoadFromFile  
    Реализовано предложение от Максима Буянова:
    - К классу TFWZipReader добавлено свойство DefaultDuplicateAction, позволяющее назначить действие по умолчанию при обнаружении дубликатов распаковываемых файлов.  
    Исправлены ошибки обнаруженные Максимом Минеевым и реализовано новое предложение:
    - Исправлена ошибка рабты с граничными значениями MAXDWORD при которых не всегда правильно принималось решение о использовании ZIP64
    - В LocalDirectory теперь пишется информация о ZIP64 (ибо некоторые архиваторы почему-то не хотят ее читать из CentralDirectory)
    - Добавлен перекрытый метод Extract к классу TFWZipReaderItem позволяющий изменять имя распаковываемого файла
    Исправлена ошибка найденная Дмитрием Мозулёвым:
    - При использовании UTF8 происходил RangeCheckError в процедуре TFWZipReaderItem.InitFromStream при проверке имени файла на принадлежность директории.

  1.0.10 (от 6 ноября 2013 года):
  
    - В класс TFWZipReaderItem добавлено свойство ItemIndex
    - Добавлен новый класс исключения EZipReaderRead, поднимающийся при ошибках чтения архива
    - Добавлен новый класс исключения EZipWriterWrite, поднимающийся при ошибках создания архива
    - Во всех исключениях модуля FWZipReader и частично FWZipWriter предоставляется более подробная информация об ошибке.
    - свойство TrimPackedStreamSize является устаревшим и работает только при включенной директиве USE_AUTOGENERATED_ZLIB_HEADER
    Реализован набор предложений от Владислава Нечепоренко:	
    - время модификации файлов пишется с учетом таймзоны
    - в класс TFWZipReader добавлена процедура проверки архива Check (производит эмуляцию распаковки без реального извлечения данных)
    - для возможности работы с элементом архива до того момента пока он не залочен, добавлены два состояния прогреса psStart и psEnd генерируемый классом TFWZipReader (см. тип TProgressState). 
    - создание архива переведено на использование deflateInit2_ (см. примечение ВАЖНО!!!)
    - убраны очепятки и неиспользуемые переменные
    Исправлена ошибка присланная Максимом Буяновым связанная с тем что FWZip не мог распаковать некоторые архивы созданные в 7Zip, а именно ZLib не мог распаковать такой архив с использованием автогенерируемого заголовка и вызовом функции inflateInit_. Правильный вариант заключается в отключении автогенерируемого заголовка и переходу на вызов функции inflateInit2_.
    - устаревший код, приводящий к данной ошибке убран под директиву USE_AUTOGENERATED_ZLIB_HEADER, большое спасибо Владиславу Нечепоренко за помощь в исправлении данной ошибки.
    ВАЖНО!!!
    Использование нового функционала при стандартном модуле ZLib возможно только начиная с Delphi 2009 и выше. Для более старых версий Delphi автоматически будет включена директива USE_AUTOGENERATED_ZLIB_HEADER, переводящая на старый вариант сжатия/распаковки. Если требуется наличие нового функционала необходимо к FWZip подключить библиотеку ZLibEx (плюс включить директиву USE_ZLIB_EX), либо воспользоваться реализацией через библиотеку обьявлением директивы USE_ZLIB_DLL.	

  1.0.9 (от 20 июля 2013 года):
  
    - обновлен текст спецификации в разделе документации (текущая поддерживаемая 6.3)  
    - некоторые свойства архива вынесены в protected поле для возможности анализа архива (см. демо ZipAnalizer)
    - добавлен вывод состояния прогресса TProgressState в обработчики событий OnProgress
    Исправлены ошибки обнаруженные Дмитрием Головачевым:
    - добавлена поддержка спецификации PKWARE версии 6.3 в части работы с архивами более 4 гигабайт. (в частности 7Zip слишком требователем к структуре Zip64EndOfCentralDir и требует размер параметра SizeOfZip64EOFCentralDirectoryRecord декрементированный на 12 байт, в отличие от других архиваторов WinRar/PkZip/WinZip)
    - метод AddFolder теперь возвращает правильное количество добавленных файлов с учетом файлов в подпапках

  1.0.8 (от 14 июня 2013 года):
  
    - код протестирован на совместимость с 64 битным режимом компиляции под Delphi XE3.
    - изменен алгоритм поиска сигнатуры END_OF_CENTRAL_DIR_SIGNATURE, убран избыточный реаллок.
    Реализован набор предложений от Владислава Нечепоренко:
    - добавлена поддержка строк в кодировке UTF8. Для этого в классе FWZipWriter добавлен флаг UseUTF8String, этот-же флаг добавлен к классу TFWZipWriterItem для более тонкой настройки параметров.
      класс FWZipReader корректно распознает такие строки и преоборазовывает их в OEM формат при открытии архива.
    - добавлена поддержка ZLibEx, старые версии которой используются в составе Delphi. 
      использование данной библиотеки является рекомендованной при ошибках распаковки. (см. описание в пункте 11)
    - добавлен файл fwzip.inc в котором можно глобально менять настройки библиотеки	 

  1.0.7 (от 10 июня 2013 года):
  
    - исправлена критическая ошибка в модуле FWZipReader приводящая к разрушению памяти приложения при открытии специальным образом сформированных файлов.
      Спасибо Олегу Егорову ака 'Ega23' за детектирование данной ошибки.

  1.0.6 (от 14 февраля 2013 года):
  
    - добавлено свойство TrimPackedStreamSize к классу TFWZipWriter, отсекующее лишний мусор в конце ZLib стрима. 
      По умолчанию данное свойство включено.
      Если данное свойство отключено, созданный архив не сможет распаковаться при помощи библиотеки ICSharpCode.SharpZipLibrary, проверяющей валидность размеров стримов.
    - Исправлена некорректная запись поля VersionNeededToExtract.
      Спасибо Гигорию Поверенному ака 'Grighome' за детектирование вышеперечисленных ошибок.
    - добавлен метод AddEmptyFolder для добавления пустых папок.
    - добавлено свойство AlwaysAddEmptyFolder. Если оно включено, добавление записи о папке происходит всегда перед добавлением информации об ее элементах.
    - исправлена ошибка алгоритма поиска сигнатуры END_OF_CENTRAL_DIR_SIGNATURE. 
      В случае если последним элементом архива был незапакованый ZIP архив, то был большой шанс неверного определения позиции данной сигнатуры.
      Спасибо Владимиру Симашко за детектирование данной ошибки.

  1.0.5 (от 2 октября 2012 года):
  
    - расширены параметры методов TFWZipReader.LoadFromFile и TFWZipReader.LoadFromStream. 
      Добавлены два параметра позволяющие указывать оффсеты на начало и конец архива в файле или стриме с данными. (Например с целью пропустить SFX стаб).

  1.0.4 (от 21 февраля 2012 года):
  
    - добавлена overload процедура ExtractAll к классу TFWZipReader. Данная процедура принимает дополнительный параметр ExtractMask, 
      указывающий маску, по которой будет происходить отбор файлов для извлечения. (см. демо ExctractZIPDemo1)
    - добавлена процедура AddFilesAndFolders к классу TFWZipWriter. (см. демо CreateZIPDemo1)
    - исправлены ошибки найденные v1ctar, за что ему огромное спасибо.
    - Добавлены новые типы исключений: EZipReader, EZipReaderItem, EZipWriter и EZipWriterItem.

  1.0.3 (от 29 июня 2011 года):
  
    - для тех, кто испытывает сложности с распаковкой архивов созданных сторонними архиваторами при ипользовании Delphi версии 2009 и ниже, функционал zlib вынесен в отдельную библиотеку. 
      (см. описание в пункте 9) или узнайте о возможности использования альтернативного варианта ZLib описанном в пункте 10.
    - исправлено неверное определение размера свободного места на диске в процедуре ExtractAll (не учитывался относительный и UNC пути). Спасибо Павлу Лобачу за детектирование данной ошибки.
    - исправлен порядок выставления атрибутов файла и времени при распаковке (если в артибутах присутствовал флаг FILE_ATTRIBUTE_READONLY, то выставление даты файла возвращало ошибку)
    - добавлено событие OnDuplicate, возникающее при попытке распаковки уже существующего на диске файла
    - реализованы предложения от Антона ака Fr0sT (отдельный респект за подробный анализ кода), а именно:
    - исправлены очепятки в наименовании некоторых свойств и внутренних переменных.
    - добавлен дополнительный перекрытый конструктор к классу TFWZipWriter, позволяющий выставить сжатие по умолчанию.
    - добавлена дополнительная перекрытая функция AddFolder с меньшим количеством параметров.
    - в событие TZipProgressEvent добавлена переменная Cancel позволяющая пользователю прервать процесс создания/распаковки архива.
    - добавлена обработка исключительных ситуаций при создании архива (см. демо BuildWithException)	

  1.0.2 (от 4 апреля 2011 года):
  
    - исправлена ошибка извлечения данных сохраненных без сжатия (Z_NO_COMPRESSION). 
      Не выставлялся результат erDone в случае упешного извлечения. 
      Спасибо Роману Игнатьеву ака "Romkin", обнаружевшему данную ошибку.
    - исправлена не совсем корректная обработка исключения EZDecompressionError в процедуре ExtractToStream.
    - добавлен дополнительный результат erWrongCRC32 к типу TExtractResult.
      Он выставляется в случае если параметр CheckCRC32 функции ExtractToStream был выстален в False и контрольная сумма извлеченного файла не совпала с оригинальной.
    - обработчик исключения EZDecompressionError изменен на EZLibError. 
      Спасибо Александру Басову ака "@!!ex" за детект данного глюка.	
      
  1.0.1 (от 4 марта 2011 года):
  
    - поправлены некоторые глюки. 
      Спасибо ребятам с форума www.delphimaster.ru 
      (Дмитрий Тимохов, Riply, И. Павел, clickmaker, Гость, Думкин, Dennis I. Komarov, han_malign, brother, Sergey Masloff, antonn)
    - убрана проверка на уникальность имен в архиве
    - добавлена проверка на длину пути
    - убрана критическая секция в классе TFWZipReader. Т.к. паралельная распаковка в текущем варианте всеравно не возможна, то смысла морозить потоки я не вижу.
    - структура TFWZipWriterItem переделана в виде класса, как следствие убрана функция ReplaceItem
    - к классам TFWZipReaderItem и TFWZipWriterItem добавлено свойство Tag
    - исправлена ошибка деления на ноль в обработчике OnProgress возникающая при попытка сжать файл нулевого размера.
    - добавлена работа с блоком ExData каждого элемента (см. демо UseExDataBlob)	  

  1.0 (от 22 февраля 2011 года): 
  
    - первичный релиз

3. Описание файлов:

  - .\FWZipConsts.pas - Типы и константы используемые для работы с ZIP архивами
  - .\FWZipCrc32.pas - Набор функций для рассчета контрольной суммы блока данных  
  - .\FWZipCrypt.pas - Реализация криптографии по методу PKWARE
  - .\FWZipModifier.pas - Класс для модификации ранее созданных ZIP архивов без перепаковки неизмененных данных.
  - .\FWZipReader.pas - Набор классов для распаковки ZIP архива  
  - .\FWZipStream.pas - Вспомогательный стрим для поддержки шифрования на лету и усеченного заголовка ZLib  
  - .\FWZipWriter.pas - Класс для создания ZIP архива
  - .\FWZipLCL.lpk - Пакет для Lazarus
  - .\FWZipLCL.pas - Содержимое пакета для Lazarus
  - .\FWZipZLib.pas - Базовые стримы сжатия и распаковки. Вынесено из ZLibEx в отдельный модуль для совместимости со старыми версиями Delphi
  - .\FWZipZLibFPC.pas - Линковка ZLib для Free Pascal
  - .\FWZipTests.pas - Класс для тестирования фреймворка 
  - .\FWZipUtils.pas - Набор платформозависимых методов  
  - .\fwzip.inc - Директивы глобального изменения настроек библиотеки 
  
  - .\delphi7\ - копии файлов корневой директории в Win1251 кодировке для старых версий Delphi включя демонстрационные примеры
  - .\Demos\ - папки с демонстрационными примерами
  - .\Demos\FWZipDemos.bpg - ProjectGroup со всеми демопримерами для Delphi7
  - .\Demos\FWZipDemos.groupproj - ProjectGroup со всеми демопримерами для Delphi 2007 и выше
  - .\Demos\Create ZIP 1\CreateZIPDemo1.dpr - Демонстрация создания архива используя различные варианты добавления данных
  - .\Demos\Create ZIP 2\CreateZIPDemo2.dpr - Демонстрация создания архива и изменения добавленных записей
  - .\Demos\Extract ZIP 1\ExctractZIPDemo1.dpr - Демонстрация распаковки архива.
  - .\Demos\Extract ZIP 2\ExctractZIPDemo2.dpr - Демонстрация распаковки зашифрованного архива.
  - .\Demos\Modify ZIP\ - папки с примерами модификации архивов без их перепаковки
  - .\Demos\Modify ZIP\Merge two ZIP\MergeZip.dpr - пример обьединения данных из нескольких архивов в один
  - .\Demos\Modify ZIP\Replace data in ZIP\ReplaceZipItemData.dpr - пример изменения части данных в архиве не требующий перепаковки неизмененных данных.
  - .\Demos\Modify ZIP\Split ZIP\SplitZip.dpr - пример разбития архива на несколько частей.
  - .\Demos\MultyPart ZIP\ - папки с примерами работы с многотомными архивами.
  - .\Demos\MultyPart ZIP\Create MultiPart ZIP\ - пример создания многотомного архива.
  - .\Demos\MultyPart ZIP\Modify MultiPart Zip\ - пример модификации многотомного архива.
  - .\Demos\MultyPart ZIP\Read MultiPart ZIP\ - пример чтения многотомного архива.
  - .\Demos\Use ZIP ExData\UseExDataBlob.dpr - Демонстрация работы с блоком ExData каждого элемента архива.
  - .\Demos\Test Build With Exception\BuildWithException.dpr - Демонстрация обработки исключительных ситуаций при создании архива.
  - .\Demos\PerfomanceTest\ - папка с проектом тестировщика производительности.
  - .\Demos\DemoResults\ - папка создается при работе демонстрационных примеров.
  - .\Demos\ZipAnalizer\ - папка с проектом анализатора ZIP архивов с использованием FWZipReader
  - .\Demos\ZipAnalizer2\ - папка с проектом анализатора ZIP архивов с использованием сканирования сигнатур
  
  - .\fpc_lib\* - папка с скомпилированными обьектниками zlib-1.2.13 для линковки в FPC/Lazarus
  
  - .\.UnitTest\* - папка с проектом юнит тестов всех классов фреймворка
  
  - .\Doc\* - документация, на основании которой велась разработка данного набора классов.    
  
  модули для обратной совместимости:
  - .\zlib_external.pas - Юнит для подключения внешней библиотеки (см. описание в пункте 9) - устарел
  - .\zlib_dll\ - папка с проектом внешней библиотеки
  - .\zlib_dll\zlib_d2010.dpr - проект внешней библиотеки
  - .\zlib_dll\zlib_d2010.dll - скомпилированная библиотека  
  
4. Создание архива:

Для создания архива применяется класс TFWZipWriter.
Порядок действий:
  - создать TFWZipWriter
  - при помощи методов AddStream/AddFiles/AddFolder указать содержимое будующего архива.
  - выполнить тонкую настройку каждого элемента при помощи изменения свойств класса TFWZipWriterItem
  - при необходимости удалить лишние элементы вызовом метода DeleteItem или Clear
  - установить коментарий к архиву
  - по необходимости назначить обработчики OnException, OnProgress и OnSaveExData
  - вызвать метод BuildZip	
  - проанализировать результат вызова метода BuildZip
  - разрушить TFWZipWriter
  
4.1 - Модификация архива

Для модификации архива применяется класс TFWZipModifier, являющийся наследником TFWZipWriter.
Порядок действий аналогичен созданию архива, за исключением наличия двух дополнительных методов:
  - AddZipFile - добавляем уже существующий архив из которого будут браться данные не требующие перепаковки
  - AddFromZip - добавляет данные из существующего архива в текущий (скажем аналог AddStream)

Смотрите примеры в папке .\Demos\Modify ZIP\
  
5. Распаковка архива:

Для распаковки архива применяется класс TFWZipReader
Порядок действий:
  - создать TFWZipReader
  - открыть архив вызовом методов LoadFromFile/LoadFromStream
  - при желании выполнить проверку целостности архива вызовом метода Check
  - по необходимости назначить обработчик OnProgress
  - автоматическая распаковка всего архива:
    - если архив зашифрован, то передать список паролей свойству PasswordList или назначить обработчик OnPassword
    - если предполагается работа с блоком ExData назначить обработчик OnLoadExData
    - по необходимости назначить обработчик OnExeption. В нем вы будете принимать решение, продолжать распаковку архива при исключении или прервать.
    - вызвать метод ExtractAll
  - ручная распаковка поэлементно:
    - выбрать необходимый элемент архива при помощи TFWZipReader.Item[Index] и вызвать метод Extract/ExtractToStream
    - если предполагается работа с блоком ExData назначить обработчик OnLoadExData выбранному элементу
    - если Extract/ExtractToStream вернул erNeedPassword, повторить вызов метода при этом указав верный пароль
  - разрушить TFWZipReader
  
6. Планируемые расширения классов:

В ближайшем будующем планируется добавить поддержку NTFS стримов (ExDataTag = $0E, в принципе вы и сами можете ее добаить работая с обработчиками блока ExData вынесенными наружу).
Так-же планируется поддержка X.509 сертификатов и следующих методов сжатия (BZIP2, LZMA, PPMD). 
Но, т.к. данный набор классов пишется под себя, то данные расширения будут добавлены только по мере их необходимости в моей основной работе.

7. Производительность:

  - перед созданием архива резервируется память под CentralDirectory = SizeOf(TCentralDirectoryFileHeaderEx) * количество элементов архива.
  - средний объем используемой памяти при сжатии 400кб, в пиках до полумегобайта.
  - средний объем используемой памяти при распаковке 100Кб, в пиках до 160кб.
  Тестирование производилось из рассчета сжатия файла с диска напрямую в архив, и извлечение напрямую из архива в файл на диске. 
  При использовании промежуточных стримов - размер памяти естественно увеличится.
  
  Результаты нагрузочных тестов (уровень сжатия clDefault):
  
  - сжималось 3 файла по 3 6 и 9 гигабайт:
    (тестировалось использование ZIP64 расширения из-за превышения по размеру элементов)
    - размер CentralDirectory: 378 байт
    - количество элементов: 3
    - общий обьем данных: 18,989,302,272 байт (~17 гигабайт)
    - время сжатия: 30 минут
    - средний расход памяти при сжатии: 396,085 байт
    - пиковый расход памяти при сжатии: 396,099 байт
    - время распаковки: 15 минут
    - средний расход памяти при распаковке: 170,413 байт
    - пиковый расход памяти при распаковке: 170,420 байт

  - сжималась папка Program Files со старого диска с установленной Windows XP, все элементы шифровались паролем "qwe":
    (тестировалось использование ZIP64 расширения из-за превышения по кол-ву элементов + использование дескрипторов)	
    - размер CentralDirectory: 11,264,400 байт (~10 мегабайт)
    - количество элементов: 89,400 
    - общий обьем данных: 43,748,481,918 байт (~40 гигабайт)
    - время сжатия: 1 час 56 минут
    - средний расход памяти при сжатии: 403,953 байт
    - пиковый расход памяти при сжатии: 413,636 байт
    - время распаковки: 40 минут
    - средний расход памяти при распаковке: 158,419 байт
    - пиковый расход памяти при распаковке:	172,628 байт

8. Технические нюансы:

При формировании архива блок ExData (за исключением ZIP64) не пишется в LocalDirectory (по спецификации его наличие там не обязательно, хотя он и может там присутствовать). 
Т.к. этот-же блок присутствует в CentralDirectory, то я посчитал не оптимальным увеличивать размер архива излишним дубляжом информации.

При шифровании файлов в архиве желательно включать DataDescryptors для каждого зашифрованного элемента (состояние данного флага по умолчанию указывается в конструкторе класса TFWZipWriter).
Дело в том, что при шифровании необходимо сгенерировать заголовок инициализации ключа, в создании которого принимает контрольная сумма файла или (при включенных DataDescryptors) время модицикации файла.
Если не указать DataDescryptors то придется зачитывать файл два раза. Первый раз перед генерацией криптозаголовка для получения CRC32, второй раз уже непосредственно при упаковке файла. Таким образом время формирования зашифрованного архива с отключенными DataDescryptors в два раза больше чем с включенными. Сама-же контрольная сумма рассчитается в любом случае на лету при сжатии данных.

Если шифрование не используется, то DataDescryptors желательно отключить, с целью экономии 20 байт на каждый элемент архива.

Сохранение сжатого файла в архив сделано немного не оптимально.
По условию при сжатии методом Deflate, реализуемым ZLib-ом нужно отсекать ZLibHeader размером в два байта.
Я не стал излишне заморачиваться и сделал следующим образом, сначала пишем весь сжатый стрим по его оффсету минус 2 байта, а потом пишем поверх имя файла (ну или EncryptedFileHeader) затирая эти два байта.
Исправить можно немного переписав TFWZipItemStream, но чес слово, лениво сильно :) 
Кто хочет - пусть сделает.

При создании многотомных архивов следует учитывать нюансы сторонних распаковщиков. В частности WinRar не умеет работать с многотомным архивом в том случае, если CentralDirectory находится не на том-же томе архива, что и запись EndOfCentralDir (самый последний том архива). Поэтому такие архивы (как правило с большим количеством элементов не помещающихся целиком в последний том архива) WinRar открыть не сможет.

Что касается 7Zip, на тестах было выявлено - если занизить размер тома до 100 байт, то 7Zip сможет прочитать только те файлы, которые попали в первый том, с которого начинается CentralDirectory,
хотя при увеличении размера, вроде бы как читает весь архив целиком.

При создании многотомного архива производилась проверка работоспособности фреймворка на размере тома в 100 байт. Однако, согласно спецификации, минимальное значение тома должно быть MAXWORD, поэтому было поставлено искусственное ограничение на значение данного параметра в конструкторе TFWFileMultiStream.CreateWrite.
При реализации собственных наследников от TFWAbstractMultiStream можете указывать требуемые вам значения.

9. Использование внешней библиотеки (устарело, см. пункт 11)

При использовании FWZip в версиях Delphi ниже 2010 Александр Басов ака "@!!ex" обнаружил ошибку.
Некоторые архивы, созданные сторонними архиваторами, не рапаковывались. Вызвано это было тем, что старые версии Delphi используют устаревший код ZLib, который не позволял произвести корректную распаковку сжатого стрима. При сборке под Delphi 2010 и выше, данная ошибка изчезала.
Т.к. код ZLib вкомпилен в zlib.dcu, а сами DCU разных версий не совместимы между собой, то пришлось написать отдельную библиотеку, экпортирующую следующие функции в том виде, в котором они реализованы в 2010-ой дельфи:

    - deflateInit_
    - DeflateInit2_
    - deflate
    - deflateEnd
    - inflateInit_
    - inflateInit2_
    - inflate
    - inflateEnd
    - inflateReset
    - adler32

Для использования данной библиотеки, необходимо обьявить глобальную директиву USE_ZLIB_DLL и тогда, вместо стантартного юнита ZLib, поставляемого с Delphi, FWZip будет использовать юнит ZLib_external, который будет производить вызов данных функций не из zlib.dcu, а из библиотеки.

10. Использование ZLib поставляемой с Indy (устарело, см. пункт 11)

Еще один вариант замены устаревшей ZLib предложил Павел Лобач. 
1. Необходимо скачать и установить самую последнюю версию Indy по следующей ссылке: ftp://indy.fulgan.com/ZIP/ 
На конец февраля 2012-го года прямая ссылка была следующей: ftp://indy.fulgan.com/ZIP/Indy10_4736.zip
2. Прописать путь к папке с ZLib (.\Lib\Protocols\ZLib\)
3. Сделать этот путь самым первым в настройках проекта (или в настройках IDE, смотря как вы его подключили)

11. Использование ZLibEx (рекомендованный вариант)

Наиболее правильный вариант решения проблем с ошибками распаковок архивов, собранных с использованием более новых версий ZLib предложил Владислав Нечепоренко.
1. Необходимо скачать и установить самую последнюю версию ZLibEx по следующей ссылке: http://www.base2ti.com/
2. Выполнить установку в соответствии с рекомендациями в разделе "installation" из файла Readme.txt
3. Раскомментировать директиву USE_ZLIB_EX в файле настроек fwzip.inc

About

Набор классов для архивирования.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published