diff --git a/README.md b/README.md
index 09cdf84..25a57d4 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,69 @@
# JarUnPacker
+#### Версия: 2023.01.31
+#### Автор: Александр Бабаев
-Проект Lazarus для распаковки / упаковки JAR файлов
\ No newline at end of file
+## Описание
+Проект Lazarus для распаковки / упаковки JAR файлов. Может распаковать jar файл, составив список, и упаковать jar файл по списку.
+
+## Лицензия
+
+### Определения
+
+**JarUnPacker** (далее «_программа_» или «_продукт_») - программа и её исходный код, на которое распространяется данное соглашение.
+
+**Конечный пользователь** (далее «_вы_» или «_пользователь_») - лицо и/или организация, которое(-ая) использует программу.
+
+**Автор** - человек, написавший программу.
+
+### ОГРАНИЧЕНИЯ
+
+В некоторых государствах (районах, областях, штатах) не позволяется ограничение или исключение ответственности за непредвиденный ущерб. Если ваша страна (район, область, штат) не подразумевает ограничение или исключение ответственности за непредвиденный ущерб, то данное соглашение не может применяться к вам. В этом случае откажитесь от использования продукта.
+
+В некоторых государствах (районах, областях, штатах) не позволяется исключение подразумеваемых гарантий. Если ваша страна (район, область, штат) не подразумевает исключение подразумеваемых гарантий, то данное соглашение не может применяться к вам. В этом случае откажитесь от использования продукта.
+
+### ПРЕДМЕТ СОГЛАШЕНИЯ
+
+Данное соглашение заключается между автором и пользователем и определяет отношения между ними, возникающие при загрузке и использовании программы.
+
+### ЛИЦЕНЗИЯ
+
+Файл распространяется по принципу «**AS-IS**» («**КАК ЕСТЬ**»). Администрация не несет **НИКАКОЙ ОТВЕТСТВЕННОСТИ** в случае нанесения данной программой физического, материального или любого другого вреда вам и вашему компьютеру. Вы на свой страх и риск загружаете программу. Администрация не несёт никакой ответственности за ошибки, неисправности (и т.п.), нанесенные программой вашему компьютеру.
+
+Вы можете использовать данную программу на свое усмотрение, а также копировать и распространять со ссылкой на автора и сайт "https://babaev-an.ru/". Вам запрещается копировать, распространять продукт без ссылки на автора и указанный ранее сайт. Вам запрещается копирование и использование программы, если устанавливаемая вами копия файла не имеет ссылки на автора и указанный ранее сайт.
+
+ЕСЛИ ВЫ ЗАГРУЖАЕТЕ, КОПИРУЕТЕ ФАЙЛ ИЛИ ИСПОЛЬЗУЕТЕ ЕГО КАКИМ-ЛИБО ДРУГИМ СПОСОБОМ, ЭТИМ ВЫ ПОДТВЕРЖДАЕТЕ СВОЕ СОГЛАСИЕ СОБЛЮДАТЬ УСЛОВИЯ ДАННОГО ЛИЦЕНЗИОННОГО СОГЛАШЕНИЯ С КОНЕЧНЫМ ПОЛЬЗОВАТЕЛЕМ. ЕСЛИ ВЫ НЕ СОГЛАСНЫ, НЕ УСТАНАВЛИВАЙТЕ, НЕ КОПИРУЙТЕ И НЕ ИСПОЛЬЗУЙТЕ ФАЙЛ.
+
+### АВТОРСКОЕ ПРАВО
+
+Авторское право на все копии файла принадлежат его автору и защищено законодательством РФ и ряда других стран.
+
+### ОГРАНИЧЕННАЯ ГАРАНТИЯ И ПРАВОВАЯ ОГОВОРКА
+
+Вам не дается никаких гарантий. Все ваши возможные требования, притязания и претензии (в том числе и по качеству) будут **НЕПРИЗНАННЫ**.
+
+### ОГРАНИЧЕНИЕ ОТВЕТСТВЕННОСТИ
+
+Вам не дается никаких обязательств. Все ваши возможные требования будут **НЕПРИЗНАННЫ**.
+
+### Область использования
+Программу можно использовать в коммерческой и не коммерческой деятельности.
+
+## Использование
+
+Для распаковки jar архива передайте селудующие параметры:
+* `extract="Имя_JAR_файла"` - инициализация распаковки и задание файла для распаковки.
+* `target="Имя_папки"` - папка извлечения.
+* `listFile="Имя_файла_списка"` - имя файла для списка распакованных файлов.
+Рассмотрим пример: вам надо распаковать файл `C:\demo\demo.jar` в папку `C:\extract_to\` и сохранить список распакованных файлов в файл `C:\demo\list.txt`
+```
+ jarunpacker.exe /extract="C:\demo\demo.jar" /target="C:\extract_to\" /listFile="C:\demo\list.txt"
+```
+
+Для упаковки jar архива передайте селудующие параметры:
+* `compress="Имя_JAR_файла"` - инициализация упаковки и задание файла jar.
+* `from="Имя_папки"` - папка с файлами.
+* `filesList="Имя_файла_списка"` - имя файла для списка файлов для упаковки.
+Рассмотрим пример: вам надо упаковать в файл `C:\demo\demo.jar` из папки `C:\extract_to\` по списку файлов из файла `C:\demo\list.txt`
+```
+ jarunpacker.exe /compress="C:\demo\demo.jar" /from="C:\extract_to\" /filesList="C:\demo\list.txt"
+```
\ No newline at end of file
diff --git a/prereq/ANB ST CP/anbstcp.lpk b/prereq/ANB ST CP/anbstcp.lpk
new file mode 100644
index 0000000..98a223c
--- /dev/null
+++ b/prereq/ANB ST CP/anbstcp.lpk
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ExternHelp Items="Count"/>
+
+
+
diff --git a/prereq/ANB ST CP/anbstcp.pas b/prereq/ANB ST CP/anbstcp.pas
new file mode 100644
index 0000000..76318d1
--- /dev/null
+++ b/prereq/ANB ST CP/anbstcp.pas
@@ -0,0 +1,22 @@
+{ This file was automatically created by Lazarus. Do not edit!
+ This source is only used to compile and install the package.
+ }
+
+unit ANBSTCP;
+
+{$warn 5023 off : no warning about unused units}
+interface
+
+uses
+ ANBFormatString, ParamsMngr, SimplyINI, VCLEx, ANBInputBox, VersionControl,
+ SimplyJSON, FileUtilsEx, GraphicsEx, MsgBoxes, LazarusPackageIntf;
+
+implementation
+
+procedure Register;
+begin
+end;
+
+initialization
+ RegisterPackage('ANBSTCP', @Register);
+end.
diff --git a/prereq/ANB ST CP/data/ANBFormatString.pas b/prereq/ANB ST CP/data/ANBFormatString.pas
new file mode 100644
index 0000000..1b75a17
--- /dev/null
+++ b/prereq/ANB ST CP/data/ANBFormatString.pas
@@ -0,0 +1,72 @@
+unit ANBFormatString;
+{$MODE Delphi}
+{$codepage UTF8}
+interface
+uses StrUtils, SysUtils, VCLEx;
+{stdcalls}
+function FormatStr(const AFrmtdStr: String; const AArgs, AArgsValues: array of String): String; STDCALL;
+function FormatStrW(const AFrmtdStr: WideString; const AArgs, AArgsValues: array of WideString): WideString; STDCALL;
+implementation
+function SearchAndReplaceStr(const AStr, ASearchStr, AReplaceStr: String): String;
+var CurrDelim, NextDelim: IntEx;
+ ElemName, s: String;
+begin
+s:= '';
+CurrDelim:= 1;
+repeat
+ NextDelim:= PosEx(ASearchStr, AStr, CurrDelim);
+ if NextDelim = 0 then
+ NextDelim:= Length(AStr) + 1;
+ ElemName:= Copy(AStr, CurrDelim, NextDelim - CurrDelim);
+ if not (NextDelim > Length(AStr)) then
+ s:= s + ElemName + AReplaceStr
+ else
+ s:= s + ElemName;
+ CurrDelim:= NextDelim + Length(ASearchStr);
+ until CurrDelim > Length(AStr);
+Result:= s;
+end;
+{Only for Windows}
+function SearchAndReplaceStrW(const AStr, ASearchStr, AReplaceStr: WideString): WideString;
+var CurrDelim, NextDelim: IntEx;
+ ElemName, s: WideString;
+begin
+s:= '';
+CurrDelim:= 1;
+repeat
+ NextDelim:= PosEx(ASearchStr, AStr, CurrDelim);
+ if NextDelim = 0 then
+ NextDelim:= Length(AStr) + 1;
+ ElemName:= Copy(AStr, CurrDelim, NextDelim - CurrDelim);
+ if not (NextDelim > Length(AStr)) then
+ s:= s + ElemName + AReplaceStr
+ else
+ s:= s + ElemName;
+ CurrDelim:= NextDelim + Length(ASearchStr);
+ until CurrDelim > Length(AStr);
+Result:= s;
+end;
+function FormatStr(const AFrmtdStr: string; const AArgs, AArgsValues: array of String): String;
+var i: IntEx;
+ s: String;
+begin
+s:= AFrmtdStr;
+if High(AArgs) <> High(AArgsValues) then
+ raise Exception.Create('Array of arguments not equal array of its values!');
+for i:= 0 to High(AArgs) do
+ s:= SearchAndReplaceStr(s, AArgs[i], AArgsValues[i]);
+Result:= s;
+end;
+{Only for Windows}
+function FormatStrW(const AFrmtdStr: WideString; const AArgs, AArgsValues: array of WideString): WideString;
+var i: IntEx;
+ s: WideString;
+begin
+s:= AFrmtdStr;
+if High(AArgs) <> High(AArgsValues) then
+ raise Exception.Create('Array of arguments not equal array of its values!');
+for i:= 0 to High(AArgs) do
+ s:= SearchAndReplaceStrW(s, AArgs[i], AArgsValues[i]);
+Result:= s;
+end;
+end.
diff --git a/prereq/ANB ST CP/data/ANBInputBox.pas b/prereq/ANB ST CP/data/ANBInputBox.pas
new file mode 100644
index 0000000..0a05c60
--- /dev/null
+++ b/prereq/ANB ST CP/data/ANBInputBox.pas
@@ -0,0 +1,401 @@
+unit ANBInputBox;
+{$MODE Delphi}
+{$codepage UTF8}
+interface
+uses LCLIntf, LCLType, SysUtils, Graphics, Controls, Forms, StdCtrls, Classes, Types, MaskEdit, Spin, VCLEx;
+function ShowInputBox (const ACaption, APrompt, ADefault: String; var isAccept: Boolean): String; OVERLOAD; STDCALL;
+function ShowInputBox (const ACaption, APrompt, ADefault: String; const ABtnCaptions: array of String; var isAccept: Boolean): String; OVERLOAD; STDCALL;
+function ShowInputBox (const ACaption, APrompt, ADefault: String; const ABtnCaptions: array of String; const AMaxLength: IntEx; var isAccept: Boolean): String; OVERLOAD; STDCALL;
+function ShowPasswordInputBox (const ACaption, APrompt, ADefault, APassword: String; var isAccept, isPasswordConfirmed: Boolean; const APasswordChar: Char = '*'): String; OVERLOAD; STDCALL;
+function ShowPasswordInputBox (const ACaption, APrompt, ADefault, APassword: String; var isAccept, isPasswordConfirmed: Boolean; const ABtnCaptions: array of String; const APasswordChar: Char = '*'): String; OVERLOAD; STDCALL;
+function ShowComboBox (const ACaption, APrompt: String; var Items: TStringList; const ADefaultIndex: IntEx; var isAccept: Boolean): IntEx; OVERLOAD; STDCALL;
+function ShowComboBox (const ACaption, APrompt: String; var Items: TStringList; const ADefaultIndex: IntEx; const ABtnsCaption: array of String; var isAccept: Boolean): IntEx; OVERLOAD; STDCALL;
+function ShowMaskedBox (const ACaption, APrompt, AMask, ADefault: String; const isIgnoreMask: Boolean; var isAccept: Boolean): String; OVERLOAD; STDCALL;
+function ShowMaskedBox (const ACaption, APrompt, AMask, ADefault: String; const isIgnoreMask: Boolean; const ABtnCaptions: array of String; const AMaxLength: IntEx; var isAccept: Boolean): String; OVERLOAD; STDCALL;
+function ShowSpinedBox (const ACaption, APrompt: String; const ADefault: IntEx; var isAccept: Boolean): IntEx; STDCALL; OVERLOAD;
+function ShowSpinedBox (const ACaption, APrompt: String; const ADefault, AMinValue, AMaxValue: IntEx; const ABtnCaptions: array of String; var isAccept: Boolean): IntEx; STDCALL; OVERLOAD;
+const OkBtnDefCaption: String = '&Ok';
+ CancelBtnDefCaption: String = 'C&ancel';
+implementation
+function MyGetAveCharSize(Canvas: TCanvas): TPoint;
+var I: IntEx;
+ Buffer: array[0..51] of Char;
+begin
+with Result do
+ begin
+ x:= 0;
+ y:= 0;
+ end;
+for I:= 0 to 25 do
+ Buffer[I]:= Chr(I + Ord('A'));
+for I:= 0 to 25 do
+ Buffer[I + 26]:= Chr(I + Ord('a'));
+GetTextExtentPoint(Canvas.Handle, Buffer, 52, TSize(Result));
+Result.X:= Result.X div 52;
+end;
+function MyInputQuery(const ACaption, APrompt: String; var Value: String; var APasswordConfirmed: Boolean; const APassword: Boolean; const ANeedPassword: String; const APasswordChar: Char; const AMaxLength: IntEx; const ABtnsCaption: array of String): Boolean;
+var Form: TForm;
+ Prompt: TLabel;
+ Edit: TEdit;
+ DialogUnits: TPoint;
+ ButtonTop, ButtonWidth, ButtonHeight: IntEx;
+begin
+Result:= false;
+Form:= TForm.Create(Application);
+with Form do
+ try
+ Canvas.Font:= Font;
+ DialogUnits:= MyGetAveCharSize(Canvas);
+ BorderStyle:= bsDialog;
+ Caption:= ACaption;
+ ClientWidth:= MulDiv(180, DialogUnits.X, 4);
+ Position:= poScreenCenter;
+ Color:= clBtnFace;
+ Prompt:= TLabel.Create(Form);
+ with Prompt do
+ begin
+ Parent:= Form;
+ Caption:= APrompt;
+ Left:= MulDiv(8, DialogUnits.X, 4);
+ Top:= MulDiv(8, DialogUnits.Y, 8);
+ Constraints.MaxWidth:= MulDiv(164, DialogUnits.X, 4);
+ WordWrap:= True;
+ end;
+ Edit:= TEdit.Create(Form);
+ with Edit do
+ begin
+ Parent:= Form;
+ Left:= Prompt.Left;
+ Top:= Prompt.Top + Prompt.Height + 5;
+ Width:= MulDiv(164, DialogUnits.X, 4);
+ MaxLength:= AMaxLength;
+ if APassword then
+ PasswordChar:= APasswordChar;
+ Text:= Value;
+ SelectAll;
+ end;
+ ButtonTop:= Edit.Top + Edit.Height + 15;
+ ButtonWidth:= MulDiv(50, DialogUnits.X, 4);
+ ButtonHeight:= MulDiv(14, DialogUnits.Y, 8);
+ with TButton.Create(Form) do
+ begin
+ Parent:= Form;
+ Caption:= ABtnsCaption[0];
+ ModalResult:= mrOk;
+ Cursor:= crHandPoint;
+ Default:= True;
+ SetBounds(MulDiv(38, DialogUnits.X, 4), ButtonTop, ButtonWidth, ButtonHeight);
+ end;
+ with TButton.Create(Form) do
+ begin
+ Parent:= Form;
+ Caption:= ABtnsCaption[1];
+ ModalResult:= mrCancel;
+ Cursor:= crHandPoint;
+ Cancel:= True;
+ SetBounds(MulDiv(92, DialogUnits.X, 4), Edit.Top + Edit.Height + 15, ButtonWidth, ButtonHeight);
+ Form.ClientHeight:= Top + Height + 13;
+ end;
+ if ShowModal = mrOk then
+ begin
+ Value:= Edit.Text;
+ if APassword then
+ if Value = ANeedPassword then
+ APasswordConfirmed:= true
+ else
+ APasswordConfirmed:= false;
+ Result:= True;
+ end;
+ finally
+ Form.Free;
+ end;
+end;
+function MyInputComboQuery(const ACaption, APrompt: String; const Values: TStringList; const DefIndex: IntEx; var SelectedIndex: IntEx; const ABtnsCaption: array of String): Boolean;
+var Form: TForm;
+ Prompt: TLabel;
+ Combo: TComboBox;
+ DialogUnits: TPoint;
+ ButtonTop, ButtonWidth, ButtonHeight: IntEx;
+begin
+Result:= false;
+Form:= TForm.Create(Application);
+with Form do
+ try
+ Canvas.Font:= Font;
+ DialogUnits:= MyGetAveCharSize(Canvas);
+ BorderStyle:= bsDialog;
+ Caption:= ACaption;
+ ClientWidth:= MulDiv(180, DialogUnits.X, 4);
+ Position:= poScreenCenter;
+ Color:= clBtnFace;
+ Prompt:= TLabel.Create(Form);
+ with Prompt do
+ begin
+ Parent:= Form;
+ Caption:= APrompt;
+ Left:= MulDiv(8, DialogUnits.X, 4);
+ Top:= MulDiv(8, DialogUnits.Y, 8);
+ Constraints.MaxWidth:= MulDiv(164, DialogUnits.X, 4);
+ WordWrap:= True;
+ end;
+ Combo:= TComboBox.Create(Form);
+ with Combo do
+ begin
+ Parent:= Form;
+ Left:= Prompt.Left;
+ Top:= Prompt.Top + Prompt.Height + 5;
+ Width:= MulDiv(164, DialogUnits.X, 4);
+ Style:= csDropDownList;
+ Items.Assign(Values);
+ if DefIndex <= Items.Count - 1 then
+ ItemIndex:= DefIndex
+ else
+ ItemIndex:= -1;
+ end;
+ ButtonTop:= Combo.Top + Combo.Height + 15;
+ ButtonWidth:= MulDiv(50, DialogUnits.X, 4);
+ ButtonHeight:= MulDiv(14, DialogUnits.Y, 8);
+ with TButton.Create(Form) do
+ begin
+ Parent:= Form;
+ Caption:= ABtnsCaption[0];
+ ModalResult:= mrOk;
+ Cursor:= crHandPoint;
+ Default:= True;
+ SetBounds(MulDiv(38, DialogUnits.X, 4), ButtonTop, ButtonWidth, ButtonHeight);
+ end;
+ with TButton.Create(Form) do
+ begin
+ Parent:= Form;
+ Caption:= ABtnsCaption[1];
+ ModalResult:= mrCancel;
+ Cursor:= crHandPoint;
+ Cancel:= True;
+ SetBounds(MulDiv(92, DialogUnits.X, 4), Combo.Top + Combo.Height + 15, ButtonWidth, ButtonHeight);
+ Form.ClientHeight:= Top + Height + 13;
+ end;
+ if ShowModal = mrOk then
+ begin
+ SelectedIndex:= Combo.ItemIndex;
+ Result:= True;
+ end;
+ finally
+ Form.Free;
+ end;
+end;
+function MyInputMaskQuery(const ACaption, APrompt, AMask: String; var Value: String; const isIgnoreMask: Boolean; const AMaxLength: IntEx; const ABtnsCaption: array of String): Boolean;
+var Form: TForm;
+ Prompt: TLabel;
+ Edit: TMaskEdit;
+ DialogUnits: TPoint;
+ ButtonTop, ButtonWidth, ButtonHeight: IntEx;
+begin
+Result:= false;
+Form:= TForm.Create(Application);
+with Form do
+ try
+ Canvas.Font:= Font;
+ DialogUnits:= MyGetAveCharSize(Canvas);
+ BorderStyle:= bsDialog;
+ Caption:= ACaption;
+ ClientWidth:= MulDiv(180, DialogUnits.X, 4);
+ Position:= poScreenCenter;
+ Color:= clBtnFace;
+ Prompt:= TLabel.Create(Form);
+ with Prompt do
+ begin
+ Parent:= Form;
+ Caption:= APrompt;
+ Left:= MulDiv(8, DialogUnits.X, 4);
+ Top:= MulDiv(8, DialogUnits.Y, 8);
+ Constraints.MaxWidth:= MulDiv(164, DialogUnits.X, 4);
+ WordWrap:= True;
+ end;
+ Edit:= TMaskEdit.Create(Form);
+ with Edit do
+ begin
+ Parent:= Form;
+ Left:= Prompt.Left;
+ Top:= Prompt.Top + Prompt.Height + 5;
+ Width:= MulDiv(164, DialogUnits.X, 4);
+ MaxLength:= AMaxLength;
+ EditMask:= AMask;
+ if isIgnoreMask then
+ Text:= Value
+ else
+ EditText:= Value;
+ ValidateEdit;
+ end;
+ ButtonTop:= Edit.Top + Edit.Height + 15;
+ ButtonWidth:= MulDiv(50, DialogUnits.X, 4);
+ ButtonHeight:= MulDiv(14, DialogUnits.Y, 8);
+ with TButton.Create(Form) do
+ begin
+ Parent:= Form;
+ Caption:= ABtnsCaption[0];
+ ModalResult:= mrOk;
+ Cursor:= crHandPoint;
+ Default:= True;
+ SetBounds(MulDiv(38, DialogUnits.X, 4), ButtonTop, ButtonWidth, ButtonHeight);
+ end;
+ with TButton.Create(Form) do
+ begin
+ Parent:= Form;
+ Caption:= ABtnsCaption[1];
+ ModalResult:= mrCancel;
+ Cursor:= crHandPoint;
+ Cancel:= True;
+ SetBounds(MulDiv(92, DialogUnits.X, 4), Edit.Top + Edit.Height + 15, ButtonWidth, ButtonHeight);
+ Form.ClientHeight:= Top + Height + 13;
+ end;
+ if ShowModal = mrOk then
+ begin
+ if isIgnoreMask then
+ Value:= Edit.Text
+ else
+ Value:= Edit.EditText;
+ Result:= True;
+ end;
+ finally
+ Form.Free;
+ end;
+end;
+function MyInputSpinQuery(const ACaption, APrompt: String; var _Value: IntEx; const AMinValue, AMaxValue: IntEx; const ABtnsCaption: array of String): Boolean;
+var Form: TForm;
+ Prompt: TLabel;
+ Edit: TSpinEdit;
+ DialogUnits: TPoint;
+ ButtonTop, ButtonWidth, ButtonHeight: IntEx;
+begin
+Result:= False;
+Form:= TForm.Create(Application);
+with Form do
+ try
+ Canvas.Font:= Font;
+ DialogUnits:= MyGetAveCharSize(Canvas);
+ BorderStyle:= bsDialog;
+ Caption:= ACaption;
+ ClientWidth:= MulDiv(180, DialogUnits.X, 4);
+ Position:= poScreenCenter;
+ Color:= clBtnFace;
+ Prompt:= TLabel.Create(Form);
+ with Prompt do
+ begin
+ Parent:= Form;
+ Caption:= APrompt;
+ Left:= MulDiv(8, DialogUnits.X, 4);
+ Top:= MulDiv(8, DialogUnits.Y, 8);
+ Constraints.MaxWidth:= MulDiv(164, DialogUnits.X, 4);
+ WordWrap:= True;
+ end;
+ Edit:= TSpinEdit.Create(Form);
+ with Edit do
+ begin
+ Parent:= Form;
+ Left:= Prompt.Left;
+ Top:= Prompt.Top + Prompt.Height + 5;
+ Width:= MulDiv(164, DialogUnits.X, 4);
+ MinValue:= Integer(AMinValue);
+ MaxValue:= Integer(AMaxValue);
+ if _Value < AMinValue then
+ Value:= AMinValue
+ else
+ if _Value > AMaxValue then
+ Value:= AMaxValue
+ else
+ Value:= _Value;
+ SelectAll;
+ end;
+ ButtonTop:= Edit.Top + Edit.Height + 15;
+ ButtonWidth:= MulDiv(50, DialogUnits.X, 4);
+ ButtonHeight:= MulDiv(14, DialogUnits.Y, 8);
+ with TButton.Create(Form) do
+ begin
+ Parent:= Form;
+ Caption:= ABtnsCaption[0];
+ ModalResult:= mrOk;
+ Cursor:= crHandPoint;
+ Default:= True;
+ SetBounds(MulDiv(38, DialogUnits.X, 4), ButtonTop, ButtonWidth, ButtonHeight);
+ end;
+ with TButton.Create(Form) do
+ begin
+ Parent:= Form;
+ Caption:= ABtnsCaption[1];
+ ModalResult:= mrCancel;
+ Cursor:= crHandPoint;
+ Cancel:= True;
+ SetBounds(MulDiv(92, DialogUnits.X, 4), Edit.Top + Edit.Height + 15, ButtonWidth, ButtonHeight);
+ Form.ClientHeight:= Top + Height + 13;
+ end;
+ if ShowModal = mrOk then
+ begin
+ _Value:= Edit.Value;
+ Result:= True;
+ end;
+ finally
+ Form.Free;
+ end;
+end;
+function ShowInputBox (const ACaption, APrompt, ADefault: String; var isAccept: Boolean): String;
+var Pasw: boolean;
+begin
+Result:= ADefault;
+Pasw:= False;
+isAccept:= MyInputQuery(ACaption, APrompt, Result, Pasw, False, '', '*', 0, [OkBtnDefCaption, CancelBtnDefCaption]);
+end;
+function ShowInputBox (const ACaption, APrompt, ADefault: String; const ABtnCaptions: array of String; var isAccept: Boolean): String;
+var Pasw: boolean;
+begin
+Result:= ADefault;
+Pasw:= False;
+isAccept:= MyInputQuery(ACaption, APrompt, Result, Pasw, False, '', '*', 0, ABtnCaptions);
+end;
+function ShowInputBox (const ACaption, APrompt, ADefault: String; const ABtnCaptions: array of String; const AMaxLength: IntEx; var isAccept: Boolean): String;
+var Pasw: boolean;
+begin
+Result:= ADefault;
+Pasw:= False;
+isAccept:= MyInputQuery(ACaption, APrompt, Result, Pasw, false, '', '*', AMaxLength, ABtnCaptions);
+end;
+function ShowPasswordInputBox (const ACaption, APrompt, ADefault, APassword: String; var isAccept, isPasswordConfirmed: Boolean; const APasswordChar: Char = '*'): String;
+begin
+Result:= ADefault;
+isAccept:= MyInputQuery(ACaption, APrompt, Result, isPasswordConfirmed, True, APassword, APasswordChar, 0, [OkBtnDefCaption, CancelBtnDefCaption]);
+end;
+function ShowPasswordInputBox (const ACaption, APrompt, ADefault, APassword: String; var isAccept, isPasswordConfirmed: Boolean; const ABtnCaptions: array of String; const APasswordChar: Char = '*'): String;
+begin
+Result:= ADefault;
+isAccept:= MyInputQuery(ACaption, APrompt, Result, isPasswordConfirmed, True, APassword, APasswordChar, 0, ABtnCaptions);
+end;
+function ShowComboBox (const ACaption, APrompt: string; var Items: TStringList; const ADefaultIndex: IntEx; var isAccept: boolean): IntEx;
+begin
+Result:= ADefaultIndex;
+isAccept:= MyInputComboQuery(ACaption, APrompt, Items, Result, Result, [OkBtnDefCaption, CancelBtnDefCaption]);
+end;
+function ShowComboBox (const ACaption, APrompt: String; var Items: TStringList; const ADefaultIndex: IntEx; const ABtnsCaption: array of String; var isAccept: Boolean): IntEx;
+begin
+Result:= ADefaultIndex;
+isAccept:= MyInputComboQuery(ACaption, APrompt, Items, Result, Result, ABtnsCaption);
+end;
+function ShowMaskedBox (const ACaption, APrompt, AMask, ADefault: String; const isIgnoreMask: Boolean; var isAccept: Boolean): String;
+begin
+Result:= ADefault;
+isAccept:= MyInputMaskQuery(ACaption, APrompt, AMask, Result, isIgnoreMask, 0, [OkBtnDefCaption, CancelBtnDefCaption]);
+end;
+function ShowMaskedBox (const ACaption, APrompt, AMask, ADefault: String; const isIgnoreMask: Boolean; const ABtnCaptions: array of String; const AMaxLength: IntEx; var isAccept: Boolean): String;
+begin
+Result:= ADefault;
+isAccept:= MyInputMaskQuery(ACaption, APrompt, AMask, Result, isIgnoreMask, AMaxLength, ABtnCaptions);
+end;
+function ShowSpinedBox (const ACaption, APrompt: String; const ADefault: IntEx; var isAccept: Boolean): IntEx;
+begin
+Result:= ADefault;
+isAccept:= MyInputSpinQuery(ACaption, APrompt, Result, 0, 100, [OkBtnDefCaption, CancelBtnDefCaption]);
+end;
+function ShowSpinedBox (const ACaption, APrompt: String; const ADefault, AMinValue, AMaxValue: IntEx; const ABtnCaptions: array of String; var isAccept: Boolean): IntEx;
+begin
+Result:= ADefault;
+isAccept:= MyInputSpinQuery(ACaption, APrompt, Result, AMinValue, AMaxValue, ABtnCaptions);
+end;
+end.
diff --git a/prereq/ANB ST CP/data/ANBRegComp.pas b/prereq/ANB ST CP/data/ANBRegComp.pas
new file mode 100644
index 0000000..7db929b
--- /dev/null
+++ b/prereq/ANB ST CP/data/ANBRegComp.pas
@@ -0,0 +1,12 @@
+unit ANBRegComp;
+{$mode delphi}
+{$codepage UTF8}
+interface
+uses Classes, SysUtils, SkinButton;
+procedure Register;
+implementation
+procedure Register;
+begin
+RegisterComponents('ANB Components', [TSkinBtn]);
+end;
+end.
diff --git a/prereq/ANB ST CP/data/FileUtilsEx.pas b/prereq/ANB ST CP/data/FileUtilsEx.pas
new file mode 100644
index 0000000..4346c44
--- /dev/null
+++ b/prereq/ANB ST CP/data/FileUtilsEx.pas
@@ -0,0 +1,169 @@
+//version 0.31 beta
+unit FileUtilsEx;
+{$MODE Delphi}
+{$codepage UTF8}
+interface
+uses windows, sysutils, ShellApi, Classes;
+type TExePlatform = (expUnknown, exp32Bit, exp64Bit, expOther);
+//stdcalls
+function FileVersion (AFileName: String): String;
+function FileSize2Str (const AFileSize: Int64; AStringNames: Array of String; const ADecimalPlaces: Byte): String; Stdcall; Overload;
+function FileSize2Str (const AFileSize: Int64; AStringNames: Array of String): String; Stdcall; Overload;
+function FileSize2Str (const AFileSize: Int64; const ADecimalPlaces: Byte): String; Overload;
+function FileSize2Str (const AFileSize: Int64): String; Overload;
+function FileAccessDateToDateTime (FileTime: TFILETIME): TDateTime; Stdcall;
+function RenameDir (const DirName, NewName: String): Boolean; STDCALL;
+function GetEXEPlatform (const AFileName: String): TExePlatform; STDCALL;
+implementation
+const AFileSizeNames: Array[0..4] of String = ('Byte', 'KB', 'MB', 'GB', 'TB');
+//Getting version of the file
+function FileVersion (AFileName: String): String;
+var szName: array[0..255] of Char;
+ P: Pointer;
+ Value: Pointer;
+ Len: UINT;
+ GetTranslationString: String;
+ FFileName: PChar;
+ FValid:boolean;
+ FSize: DWORD;
+ FHandle: DWORD;
+ FBuffer: PChar;
+begin
+try
+ FFileName:= StrPCopy(StrAlloc(Length(AFileName) + 1), AFileName);
+ FValid:= False;
+ FSize:= GetFileVersionInfoSize(FFileName, FHandle);
+ if FSize > 0 then
+ try
+ GetMem(FBuffer, FSize);
+ FValid:= GetFileVersionInfo(FFileName, FHandle, FSize, FBuffer);
+ except
+ FValid:= False;
+ raise;
+ end;
+ Result:= '';
+ if FValid then
+ VerQueryValue(FBuffer, '\VarFileInfo\Translation', P, Len)
+ else
+ P:= nil;
+ if P <> nil then
+ GetTranslationString:= IntToHex(MakeLong(HiWord(Longint(P^)), LoWord(Longint(P^))), 8);
+ if FValid then
+ begin
+ StrPCopy(szName, '\StringFileInfo\' + GetTranslationString + '\FileVersion');
+ if VerQueryValue(FBuffer, szName, Value, Len) then
+ Result:= StrPas(PChar(Value));
+ end;
+ finally
+ try
+ if FBuffer <> nil then
+ FreeMem(FBuffer, FSize);
+ except
+ end;
+ try
+ StrDispose(FFileName);
+ except
+ end;
+ end;
+end;
+//FileSize2Str
+function FileSize2Str (const AFileSize: Int64; AStringNames: Array of String; const ADecimalPlaces: Byte): String; Overload;
+ function FrmtSize (const ASize, ADelim: Int64; const ADP: Byte): String;
+ var VDelim: Int64;
+ Indx: Byte;
+ begin
+ VDelim:= 1;
+ for Indx:= 0 to ADP do
+ VDelim:= VDelim*10;
+ Result:= FloatToStr(round((ASize*VDelim)/ADelim)/VDelim);
+ end;
+const AFrmtsStr: String = '%s %s';
+begin
+//Bytes
+if AFileSize < 1024 then
+ Result:= Format(AFrmtsStr, [IntToStr(AFileSize), AStringNames[0]]);
+//KiloBytes
+if (AFileSize >= 1024) and (AFileSize < 1048576) then
+ Result:= Format(AFrmtsStr, [FrmtSize(AFileSize, 1024, ADecimalPlaces), AStringNames[1]]);
+//MegaBytes
+if (AFileSize >= 1048576) and (AFileSize < 1073741824) then
+ Result:= Format(AFrmtsStr, [FrmtSize(AFileSize, 1048576, ADecimalPlaces), AStringNames[2]]);
+//GigaBytes
+if (AFileSize >= 1073741824) and (AFileSize < 1099511627776) then
+ Result:= Format(AFrmtsStr, [FrmtSize(AFileSize, 1073741824, ADecimalPlaces), AStringNames[3]]);
+//TeraBytes
+if (AFileSize >= 1099511627776) then
+ Result:= Format(AFrmtsStr, [FrmtSize(AFileSize, 1073741824, ADecimalPlaces), AStringNames[4]]);
+end;
+function FileSize2Str (const AFileSize: Int64; AStringNames: Array of String): String; Overload;
+begin
+Result:= FileSize2Str(AFileSize, AStringNames, 2);
+end;
+function FileSize2Str (const AFileSize: Int64; const ADecimalPlaces: Byte): String; Overload;
+begin
+Result:= FileSize2Str(AFileSize, AFileSizeNames, ADecimalPlaces);
+end;
+function FileSize2Str (const AFileSize: Int64): String; Overload;
+begin
+Result:= FileSize2Str(AFileSize, AFileSizeNames, 2);
+end;
+//FileAccessDateToDateTime
+//Author: Дураг (http://www.sql.ru/forum/memberinfo.aspx?mid=32731) from http://www.sql.ru/forum/259218/kak-poluchit-datu-i-vremya-sozdaniya-fayla
+function FileAccessDateToDateTime (FileTime: TFILETIME): TDateTime;
+var LocalTime: TFILETIME;
+ DOSFileTime: DWORD;
+begin
+FileTimeToLocalFileTime(FileTime, LocalTime);
+FileTimeToDosDateTime(LocalTime, LongRec(DOSFileTime).Hi, LongRec(DOSFileTime).Lo);
+Result:= FileDateToDateTime(DOSFileTime);
+end;
+//RenameDir
+function RenameDir (const DirName, NewName: String): Boolean;
+var shellinfo: TSHFILEOPSTRUCT;
+ DirFrom, DirTo: String;
+begin
+DirFrom:= DirName;
+DirTo:= NewName;
+with shellinfo do
+ begin
+ Wnd:= 0;
+ wFunc:= FO_RENAME;
+ pFrom:= PChar(DirFrom);
+ pTo:= PChar(DirTo);
+ fFlags:= FOF_FILESONLY or FOF_ALLOWUNDO or FOF_SILENT or FOF_NOCONFIRMATION;
+ end;
+SHFileOperation(shellinfo);
+Result:= DirectoryExists(NewName);
+end;
+//GetEXEPlatform
+//Author Dmitry Arefiev (http://www.sql.ru/forum/808857/kak-opredelit-razryadnost-prilozheniya)
+function GetEXEPlatform (const AFileName: String): TExePlatform;
+var oFS: TFileStream;
+ iPeOffset: Integer;
+ iPeHead: LongWord;
+ iMachineType: Word;
+begin
+Result:= expUnknown;
+try
+ oFS:= TFileStream.Create(AFileName, fmOpenRead or fmShareDenyNone);
+ try
+ oFS.Seek($3C, soFromBeginning);
+ oFS.Read(iPeOffset, SizeOf(iPeOffset));
+ oFS.Seek(iPeOffset, soFromBeginning);
+ oFS.Read(iPeHead, SizeOf(iPeHead));
+ if iPeHead <> $00004550 then
+ Exit;
+ oFS.Read(iMachineType, SizeOf(iMachineType));
+ case iMachineType of
+ $8664, $0200: Result:= exp64Bit;
+ $014C: Result:= exp32Bit;
+ else
+ Result:= expOther;
+ end;
+ finally
+ oFS.Free;
+ end;
+ except
+ end;
+end;
+end.
diff --git a/prereq/ANB ST CP/data/GraphicsEx.pas b/prereq/ANB ST CP/data/GraphicsEx.pas
new file mode 100644
index 0000000..c2e249c
--- /dev/null
+++ b/prereq/ANB ST CP/data/GraphicsEx.pas
@@ -0,0 +1,28 @@
+unit GraphicsEx;
+//version 0.1
+{$MODE Delphi}
+{$codepage UTF8}
+interface
+uses Classes, SysUtils, Graphics;
+type TRGBByte = 0..255;
+ TRGBColor = record
+ R, G, B: TRGBByte;
+ end;
+//stdcalls
+function RGB2Color (const ARGB: TRGBColor): TColor;
+function Color2RGB (const AColor: TColor): TRGBColor;
+implementation
+function RGB2Color (const ARGB: TRGBColor): TColor;
+begin
+Result:= RGBToColor(ARGB.R, ARGB.G, ARGB.B);
+end;
+function Color2RGB (const AColor: TColor): TRGBColor;
+//from http://www.delphisources.ru/pages/faq/base/rgb_tcolor.html
+var Color: LongInt;
+begin
+Color:= ColorToRGB(AColor);
+Result.R:= Color;
+Result.G:= Color shr 8;
+Result.B:= Color shr 16;
+end;
+end.
diff --git a/prereq/ANB ST CP/data/MsgBoxes.pas b/prereq/ANB ST CP/data/MsgBoxes.pas
new file mode 100644
index 0000000..25c3029
--- /dev/null
+++ b/prereq/ANB ST CP/data/MsgBoxes.pas
@@ -0,0 +1,25 @@
+unit MsgBoxes;
+{$mode delphi}
+{$codepage UTF8}
+interface
+uses Classes, SysUtils, Forms;
+{dialog types for Linux capatability}
+const DLG_ASTERISK = $40;
+ DLG_EXCLAMATION = $30;
+ DLG_WARNING = $30;
+ DLG_ERROR = $10;
+ DLG_QUESTION = $20;
+{stdcalls}
+function ShowMessageBox (const AText, ATitle: String; const AMessageType: LongInt = 0): Integer; STDCALL;
+function ShowMessageBoxA (const AText: String; const AMessageType: LongInt = 0): Integer; STDCALL;
+implementation
+//Sample Windows MessageDialogs
+function ShowMessageBox (const AText, ATitle: String; const AMessageType: LongInt = 0): Integer;
+begin
+Result:= Application.MessageBox(PChar(AText), PChar(ATitle), AMessageType);
+end;
+function ShowMessageBoxA (const AText: String; const AMessageType: LongInt = 0): Integer;
+begin
+Result:= Application.MessageBox(PChar(AText), PChar(Application.Title), AMessageType);
+end;
+end.
diff --git a/prereq/ANB ST CP/data/ParamsMngr.pas b/prereq/ANB ST CP/data/ParamsMngr.pas
new file mode 100644
index 0000000..2173dc4
--- /dev/null
+++ b/prereq/ANB ST CP/data/ParamsMngr.pas
@@ -0,0 +1,96 @@
+unit ParamsMngr;
+{$MODE Delphi}
+{$codepage UTF8}
+interface
+uses StrUtils, VCLEx;
+{stdcalls}
+function HasParam (const AParams: String; const AParam: Char): Boolean; OVERLOAD; STDCALL;
+function HasParam (const AParams: String; const AParam: String): Boolean; OVERLOAD; STDCALL;
+function HasParam (const AParam: String): Boolean; OVERLOAD; STDCALL;
+function GetParamValue (const AParams: String; const AParam: Char): String; OVERLOAD; STDCALL;
+function GetParamValue (const AParams: String; const AParam: String): String; OVERLOAD; STDCALL;
+function GetParamValue (const AParam: string): string; overload; stdcall;
+function StartParams: String; STDCALL;
+implementation
+function HasParam (const AParams: String; const AParam: Char): Boolean;
+begin
+Result:= False;
+if AParams <> '' then
+ if Pos('/' + AParam, AParams) > 0 then
+ Result:= True;
+end;
+function HasParam (const AParams: String; const AParam: String): Boolean;
+var PS: IntEx;
+ NextChr: Char;
+begin
+Result:= False;
+if AParams <> '' then
+ begin
+ PS:= Pos('/' + AParam, AParams);
+ if PS > 0 then
+ begin
+ NextChr:= AParams[PS + Length(AParam) + 1];
+ if (NextChr = '=') or (NextChr = '#') then
+ Result:= True;
+ end;
+ end;
+end;
+function HasParam (const AParam: String): Boolean;
+begin
+Result:= HasParam(StartParams, AParam);
+end;
+function GetParamValue (const AParams: String; const AParam: Char): String;
+var i, j, k: IntEx;
+begin
+Result:= '';
+i:= 0;
+j:= 0;
+k:= 0;
+if AParams <> '' then
+ begin
+ i:= Pos('/' + AParam, AParams);
+ if (i > 0) and (AParams[i+2] = '=') then
+ j:= i+3;
+ if j > 0 then
+ begin
+ k:= PosEx('#', AParams, j);
+ if k = 0 then
+ k:= Length(AParams) + 1;
+ Result:= Copy(AParams, j, k-j);
+ end;
+ end;
+end;
+function GetParamValue (const AParams: String; const AParam: String): String;
+var i, j, k: IntEx;
+begin
+Result:= '';
+i:= 0;
+j:= 0;
+k:= 0;
+if AParams <> '' then
+ begin
+ i:= Pos('/' + AParam, AParams);
+ if (i > 0) and (AParams[i + Length(AParam) + 1] = '=') then
+ j:= i + Length(AParam) + 2;
+ if j > 0 then
+ begin
+ k:= PosEx('#', AParams, j);
+ if k = 0 then
+ k:= Length(AParams) + 1;
+ Result:= Copy(AParams, j, k-j);
+ end;
+ end;
+end;
+function GetParamValue (const AParam: String): String;
+begin
+Result:= GetParamValue(StartParams, AParam);
+end;
+function StartParams: String;
+var i: IntEx;
+begin
+Result:= '';
+if Paramcount > 0 then
+ for i:= 1 to Paramcount do
+ Result:= Result + ParamStr(i) + '#';
+end;
+end.
diff --git a/prereq/ANB ST CP/data/SimplyINI.pas b/prereq/ANB ST CP/data/SimplyINI.pas
new file mode 100644
index 0000000..1856aa7
--- /dev/null
+++ b/prereq/ANB ST CP/data/SimplyINI.pas
@@ -0,0 +1,132 @@
+unit SimplyINI;
+{$MODE Delphi}
+{$codepage UTF8}
+interface
+uses SysUtils, Classes, IniFiles;
+//stdcalls
+function INIReadString (const ASection, AKey, ADefault, AFileName: string): string; stdcall;
+function INIReadInteger (const ASection, AKey: string; const ADefault: Int64; const AFileName: string): Int64; stdcall;
+function INIReadBoolean (const ASection, AKey: string; const ADefault: boolean; const AFileName: string): boolean; stdcall;
+procedure INIWriteString (const ASection, AKey, AValue, AFileName: string); stdcall;
+procedure INIWriteInteger (const ASection, AKey: string; const AValue: Int64; const AFileName: string); stdcall;
+procedure INIWriteBoolean (const ASection, AKey: string; const AValue: boolean; const AFileName: string); stdcall;
+procedure INIDeleteKey (const ASection, AKey, AFileName: string); stdcall;
+procedure INIDeleteSection (const ASection, AFileName: string); stdcall;
+function INISectionExists (const ASection, AFileName: string): boolean; stdcall;
+procedure INIReadSections (const AFileName: string; VStrings: TStrings); stdcall;
+procedure INIReadSection (const ASection, AFileName: string; VStrings: TStrings); stdcall;
+implementation
+//Read functions
+function INIReadString (const ASection, AKey, ADefault, AFileName: string): string;
+var INI: TIniFile;
+begin
+INI:= TIniFile.Create(AFileName);
+try
+ Result:= INI.ReadString(ASection, AKey, ADefault);
+ finally
+ INI.Free;
+ end;
+end;
+function INIReadInteger (const ASection, AKey: string; const ADefault: Int64; const AFileName: string): Int64;
+var INI: TIniFile;
+begin
+INI:= TIniFile.Create(AFileName);
+try
+ Result:= INI.ReadInteger(ASection, AKey, ADefault);
+ finally
+ INI.Free;
+ end;
+end;
+function INIReadBoolean (const ASection, AKey: string; const ADefault: boolean; const AFileName: string): boolean;
+var INI: TIniFile;
+begin
+INI:= TIniFile.Create(AFileName);
+try
+ Result:= INI.ReadBool(ASection, AKey, ADefault);
+ finally
+ INI.Free;
+ end;
+end;
+//Write procedures
+procedure INIWriteString (const ASection, AKey, AValue, AFileName: string);
+var INI: TIniFile;
+begin
+INI:= TIniFile.Create(AFileName);
+try
+ INI.WriteString(ASection, AKey, AValue);
+ finally
+ INI.Free;
+ end;
+end;
+procedure INIWriteInteger (const ASection, AKey: string; const AValue: Int64; const AFileName: string);
+var INI: TIniFile;
+begin
+INI:= TIniFile.Create(AFileName);
+try
+ INI.WriteInt64(ASection, AKey, AValue);
+ finally
+ INI.Free;
+ end;
+end;
+procedure INIWriteBoolean (const ASection, AKey: string; const AValue: boolean; const AFileName: string);
+var INI: TIniFile;
+begin
+INI:= TIniFile.Create(AFileName);
+try
+ INI.WriteBool(ASection, AKey, AValue);
+ finally
+ INI.Free;
+ end;
+end;
+//Delete function
+procedure INIDeleteKey (const ASection, AKey, AFileName: string);
+var INI: TIniFile;
+begin
+INI:= TIniFile.Create(AFileName);
+try
+ INI.DeleteKey(ASection, AKey);
+ finally
+ INI.Free;
+ end;
+end;
+procedure INIDeleteSection (const ASection, AFileName: string);
+var INI: TIniFile;
+begin
+INI:= TIniFile.Create(AFileName);
+try
+ INI.EraseSection(ASection);
+ finally
+ INI.Free;
+ end;
+end;
+function INISectionExists (const ASection, AFileName: string): boolean;
+var INI: TIniFile;
+begin
+INI:= TIniFile.Create(AFileName);
+try
+ Result:= INI.SectionExists(ASection);
+ finally
+ INI.Free;
+ end;
+end;
+procedure INIReadSections (const AFileName: string; VStrings: TStrings);
+var INI: TIniFile;
+begin
+INI:= TIniFile.Create(AFileName);
+try
+ INI.ReadSections(VStrings);
+ finally
+ INI.Free;
+ end;
+end;
+procedure INIReadSection (const ASection, AFileName: string; VStrings: TStrings);
+var INI: TIniFile;
+begin
+INI:= TIniFile.Create(AFileName);
+try
+ INI.ReadSection(ASection, VStrings);
+ finally
+ INI.Free;
+ end;
+end;
+end.
diff --git a/prereq/ANB ST CP/data/SimplyJSON.pas b/prereq/ANB ST CP/data/SimplyJSON.pas
new file mode 100644
index 0000000..89d64cd
--- /dev/null
+++ b/prereq/ANB ST CP/data/SimplyJSON.pas
@@ -0,0 +1,325 @@
+unit SimplyJSON;
+{$MODE Delphi}
+{$codepage UTF8}
+{*************************************************************************************************************************************
+ SimplyJSON
+ Модуль для парсинга JSON файлов (используется TJSONConfig).
+ Авторские права (c) 2016 - 2019, Александр Бабаев.
+История изменений:
+1.3 (01.05.2019) Переработан алгоритм открытия / парсинга JSON файлов при чтении, изменена функция JSReadFont
+1.2 (09.05.2017) Добавлены функции чтения/записи шрифтов.
+*************************************************************************************************************************************}
+interface
+uses Classes, SysUtils, Graphics, GraphicsEx, LazUTF8Classes, LazFileUtils, fpjson, jsonparser, jsonConf,
+ ANBFormatString;
+//stdcalls
+function JSReadString (const AKey, ADefault: UnicodeString; const AFileName: String): UnicodeString; STDCALL; OVERLOAD;
+function JSReadString (const AKey, ADefault, AFileName: String): String; STDCALL; OVERLOAD;
+function JSReadInteger (const AKey: UnicodeString; const ADefault: Int64; const AFileName: String): Int64; STDCALL; OVERLOAD;
+function JSReadInteger (const AKey: String; const ADefault: Int64; const AFileName: String): Int64; STDCALL; OVERLOAD;
+function JSReadBoolean (const AKey: UnicodeString; const ADefault: Boolean; const AFileName: String): Boolean; STDCALL; OVERLOAD;
+function JSReadBoolean (const AKey: String; const ADefault: Boolean; const AFileName: String): Boolean; STDCALL; OVERLOAD;
+function JSReadRGBColor (const AKey: UnicodeString; const ADefault: TRGBColor; const AFileName: String): TRGBColor; STDCALL; OVERLOAD;
+function JSReadRGBColor (const AKey: String; const ADefault: TRGBColor; const AFileName: String): TRGBColor; STDCALL; OVERLOAD;
+procedure JSReadFont (const AKey: UnicodeString; var Font: TFont; const AFileName: String); STDCALL; OVERLOAD;
+procedure JSReadFont (const AKey: String; var Font: TFont; const AFileName: String); STDCALL; OVERLOAD;
+procedure JSWriteString (const AKey, AValue: UnicodeString; const AFileName: String); STDCALL; OVERLOAD;
+procedure JSWriteString (const AKey, AValue, AFileName: String); STDCALL; OVERLOAD;
+procedure JSWriteInteger (const AKey: UnicodeString; const AValue: Int64; const AFileName: String); STDCALL; OVERLOAD;
+procedure JSWriteInteger (const AKey: String; const AValue: Int64; const AFileName: String); STDCALL; OVERLOAD;
+procedure JSWriteBoolean (const AKey: UnicodeString; const AValue: Boolean; const AFileName: String); STDCALL; OVERLOAD;
+procedure JSWriteBoolean (const AKey: String; const AValue: Boolean; const AFileName: String); STDCALL; OVERLOAD;
+procedure JSWriteRGBColor (const AKey: UnicodeString; const AValue: TRGBColor; const AFileName: String); STDCALL; OVERLOAD;
+procedure JSWriteRGBColor (const AKey: String; const AValue: TRGBColor; const AFileName: String); STDCALL; OVERLOAD;
+procedure JSWriteFont (const AKey: UnicodeString; const AValue: TFont; const AFileName: String); STDCALL; OVERLOAD;
+procedure JSWriteFont (const AKey: String; const AValue: TFont; const AFileName: String); STDCALL; OVERLOAD;
+procedure JSDeleteKey (const AKey: UnicodeString; const AFileName: String); STDCALL; OVERLOAD;
+procedure JSDeleteKey (const AKey, AFileName: String); STDCALL; OVERLOAD;
+procedure JSReadSubKeys (const AKey: UnicodeString; SubkeyList: TStrings; const AFileName: String); STDCALL; OVERLOAD;
+procedure JSReadSubKeys (const AKey: String; SubkeyList: TStrings; const AFileName: String); STDCALL; OVERLOAD;
+implementation
+//Support functions
+procedure GetJSData (const AFileName: String; var JSData: TJSONData);
+var FS: TFileStreamUTF8;
+ SL: TStringListUTF8;
+begin
+if not FileExistsUTF8(AFileName) then
+ begin
+ FS:= TFileStreamUTF8.Create(AFileName, fmOpenWrite);
+ SL:= TStringListUTF8.Create;
+ SL.Text:= '{}';
+ SL.SaveToStream(FS);
+ SL.Free;
+ FS.Free;
+ end;
+FS:= TFileStreamUTF8.Create(AFileName, fmOpenRead or fmShareDenyNone);
+JSData:= GetJSON(FS, True);
+FS.Free;
+end;
+function FrmtKey (const AKey: UnicodeString): UnicodeString;
+var KeyM: UnicodeString;
+begin
+Result:= AKey;
+//Для совместимости с SimplyJSON 1.0 - 1.2 и операциями записи
+KeyM:= AKey;
+if KeyM[1] = '/' then
+ Delete(KeyM, 1, 1);
+Result:= UnicodeString(FormatStr(KeyM, ['/'], ['.']));
+end;
+//Read functions
+function JSReadString (const AKey, ADefault: UnicodeString; const AFileName: String): UnicodeString; OVERLOAD;
+var JD: TJSONData;
+begin
+GetJSData(AFileName, JD);
+try
+ Result:= JD.FindPath(FrmtKey(AKey)).AsUnicodeString;
+ except
+ Result:= ADefault;
+ end;
+JD.Free;
+end;
+function JSReadString (const AKey, ADefault, AFileName: String): String; OVERLOAD;
+var Key, Def, Res: UnicodeString;
+begin
+Key:= UnicodeString(AKey);
+Def:= UnicodeString(ADefault);
+Res:= JSReadString(Key, Def, AFileName);
+Result:= String(Res);
+end;
+function JSReadInteger (const AKey: UnicodeString; const ADefault: Int64; const AFileName: String): Int64; OVERLOAD;
+var JD: TJSONData;
+begin
+GetJSData(AFileName, JD);
+try
+ Result:= JD.FindPath(FrmtKey(AKey)).AsInt64;
+ except
+ Result:= ADefault;
+ end;
+JD.Free;
+end;
+function JSReadInteger (const AKey: String; const ADefault: Int64; const AFileName: String): Int64; OVERLOAD;
+var Key: UnicodeString;
+begin
+Key:= UnicodeString(AKey);
+Result:= JSReadInteger(Key, ADefault, AFileName);
+end;
+function JSReadBoolean (const AKey: UnicodeString; const ADefault: Boolean; const AFileName: String): Boolean; OVERLOAD;
+var JD: TJSONData;
+begin
+GetJSData(AFileName, JD);
+try
+ Result:= JD.FindPath(FrmtKey(AKey)).AsBoolean;
+ except
+ Result:= ADefault;
+ end;
+JD.Free;
+end;
+function JSReadBoolean (const AKey: String; const ADefault: Boolean; const AFileName: String): Boolean; OVERLOAD;
+var Key: UnicodeString;
+begin
+Key:= UnicodeString(AKey);
+Result:= JSReadBoolean(Key, ADefault, AFileName);
+end;
+function JSReadRGBColor (const AKey: UnicodeString; const ADefault: TRGBColor; const AFileName: String): TRGBColor; OVERLOAD;
+var JD: TJSONData;
+ KeyM: UnicodeString;
+begin
+GetJSData(AFileName, JD);
+KeyM:= FrmtKey(AKey);
+try
+ Result.R:= JD.FindPath(KeyM + '.r').AsInteger;
+ Result.G:= JD.FindPath(KeyM + '.g').AsInteger;
+ Result.B:= JD.FindPath(KeyM + '.b').AsInteger;
+ except
+ Result:= ADefault;
+ end;
+JD.Free;
+end;
+function JSReadRGBColor (const AKey: String; const ADefault: TRGBColor; const AFileName: String): TRGBColor; OVERLOAD;
+var Key: UnicodeString;
+begin
+Key:= UnicodeString(AKey);
+Result:= JSReadRGBColor(Key, ADefault, AFileName);
+end;
+procedure JSReadFont (const AKey: UnicodeString; var Font: TFont; const AFileName: String);
+var JD: TJSONData;
+ FStyle: TFontStyles;
+ KeyM: UnicodeString;
+begin
+GetJSData(AFileName, JD);
+KeyM:= FrmtKey(AKey);
+try
+ Font.CharSet:= TFontCharSet(JD.FindPath(KeyM + '.charset').AsInteger);
+ Font.Color:= StringToColor(JD.FindPath(KeyM + '.color').AsString);
+ Font.Height:= JD.FindPath(KeyM + '.height').AsInteger;
+ Font.Name:= JD.FindPath(KeyM + '.name').AsString;
+ Font.Orientation:= JD.FindPath(KeyM + '.orientation').AsInteger;
+ Font.Pitch:= TFontPitch(JD.FindPath(KeyM + '.pitch').AsInteger);
+ Font.Quality:= TFontQuality(JD.FindPath(KeyM + '.quality').AsInteger);
+ Font.Size:= JD.FindPath(KeyM + '.size').AsInteger;
+ FStyle:= [];
+ if (JD.FindPath(KeyM + '.style.bold').AsBoolean) then
+ FStyle:= FStyle + [fsBold];
+ if (JD.FindPath(KeyM + '.style.italic').AsBoolean) then
+ FStyle:= FStyle + [fsItalic];
+ if (JD.FindPath(KeyM + '.style.underline').AsBoolean) then
+ FStyle:= FStyle + [fsUnderline];
+ if (JD.FindPath(KeyM + '.style.strikeout').AsBoolean) then
+ FStyle:= FStyle + [fsStrikeOut];
+ Font.Style:= FStyle;
+ except
+ end;
+JD.Free;
+end;
+procedure JSReadFont (const AKey: String; var Font: TFont; const AFileName: String);
+var Key: UnicodeString;
+begin
+Key:= UnicodeString(AKey);
+JSReadFont(Key, Font, AFileName);
+end;
+//Write procedures
+procedure JSWriteString (const AKey, AValue: UnicodeString; const AFileName: String); OVERLOAD;
+var JSConf: TJSONConfig;
+begin
+JSConf:= TJSONConfig.Create(Nil);
+with JSConf do
+ begin
+ Filename:= AFileName;
+ Formatted:= True;
+ SetValue(AKey, AValue);
+ Flush;
+ Free;
+ end;
+end;
+procedure JSWriteString (const AKey, AValue, AFileName: String); OVERLOAD;
+var Key, Val: UnicodeString;
+begin
+Key:= UnicodeString(AKey);
+Val:= UnicodeString(AValue);
+JSWriteString(Key, Val, AFileName);
+end;
+procedure JSWriteInteger (const AKey: UnicodeString; const AValue: Int64; const AFileName: String); OVERLOAD;
+var JSConf: TJSONConfig;
+begin
+JSConf:= TJSONConfig.Create(Nil);
+with JSConf do
+ begin
+ Filename:= AFileName;
+ Formatted:= True;
+ SetValue(AKey, AValue);
+ Free;
+ end;
+end;
+procedure JSWriteInteger (const AKey: String; const AValue: Int64; const AFileName: String); OVERLOAD;
+var Key: UnicodeString;
+begin
+Key:= UnicodeString(AKey);
+JSWriteInteger(Key, AValue, AFileName);
+end;
+procedure JSWriteBoolean (const AKey: UnicodeString; const AValue: Boolean; const AFileName: String); OVERLOAD;
+var JSConf: TJSONConfig;
+begin
+JSConf:= TJSONConfig.Create(Nil);
+with JSConf do
+ begin
+ Filename:= AFileName;
+ Formatted:= True;
+ SetValue(AKey, AValue);
+ Free;
+ end;
+end;
+procedure JSWriteBoolean (const AKey: String; const AValue: Boolean; const AFileName: String); OVERLOAD;
+var Key: UnicodeString;
+begin
+Key:= UnicodeString(AKey);
+JSWriteBoolean(Key, AValue, AFileName);
+end;
+procedure JSWriteRGBColor (const AKey: UnicodeString; const AValue: TRGBColor; const AFileName: String); OVERLOAD;
+var JSConf: TJSONConfig;
+begin
+JSConf:= TJSONConfig.Create(Nil);
+with JSConf do
+ begin
+ Filename:= AFileName;
+ Formatted:= True;
+ SetValue(AKey + '/r', AValue.R);
+ SetValue(AKey + '/g', AValue.G);
+ SetValue(AKey + '/b', AValue.B);
+ Free;
+ end;
+end;
+procedure JSWriteRGBColor (const AKey: String; const AValue: TRGBColor; const AFileName: String); OVERLOAD;
+var Key: UnicodeString;
+begin
+Key:= UnicodeString(AKey);
+JSWriteRGBColor(Key, AValue, AFileName);
+end;
+procedure JSWriteFont (const AKey: UnicodeString; const AValue: TFont; const AFileName: String); OVERLOAD;
+var JSConf: TJSONConfig;
+begin
+JSConf:= TJSONConfig.Create(Nil);
+with JSConf do
+ begin
+ Filename:= AFileName;
+ Formatted:= True;
+ SetValue(AKey + '/charset', Integer(AValue.CharSet));
+ SetValue(AKey + '/color', ColorToString(AValue.Color));
+ SetValue(AKey + '/height', AValue.Height);
+ SetValue(AKey + '/name', AValue.Name);
+ SetValue(AKey + '/orientation', AValue.Orientation);
+ SetValue(AKey + '/pitch', Integer(AValue.Pitch));
+ SetValue(AKey + '/quality', Integer(AValue.Quality));
+ SetValue(AKey + '/size', AValue.Size);
+ SetValue(AKey + '/style/bold', (fsBold in AValue.Style));
+ SetValue(AKey + '/style/italic', (fsItalic in AValue.Style));
+ SetValue(AKey + '/style/underline', (fsUnderline in AValue.Style));
+ SetValue(AKey + '/style/strikeout', (fsStrikeOut in AValue.Style));
+ Free;
+ end;
+end;
+procedure JSWriteFont (const AKey: String; const AValue: TFont; const AFileName: String); OVERLOAD;
+var Key: UnicodeString;
+begin
+Key:= UnicodeString(AKey);
+JSWriteFont(Key, AValue, AFileName);
+end;
+//Delete function
+procedure JSDeleteKey (const AKey: UnicodeString; const AFileName: String); OVERLOAD;
+var JSConf: TJSONConfig;
+begin
+JSConf:= TJSONConfig.Create(Nil);
+with JSConf do
+ begin
+ Filename:= AFileName;
+ Formatted:= True;
+ DeletePath(AKey);
+ Free;
+ end;
+end;
+procedure JSDeleteKey (const AKey, AFileName: String); OVERLOAD;
+var Key: UnicodeString;
+begin
+Key:= UnicodeString(AKey);
+JSDeleteKey(Key, AFileName);
+end;
+//Read subkeys
+procedure JSReadSubKeys (const AKey: UnicodeString; SubkeyList: TStrings; const AFileName: String); OVERLOAD;
+var JSConf: TJSONConfig;
+begin
+JSConf:= TJSONConfig.Create(Nil);
+with JSConf do
+ begin
+ Filename:= AFileName;
+ Formatted:= True;
+ SubkeyList.Clear;
+ EnumSubKeys(AKey, SubkeyList);
+ Free;
+ end;
+end;
+procedure JSReadSubKeys (const AKey: String; SubkeyList: TStrings; const AFileName: String); OVERLOAD;
+var Key: UnicodeString;
+begin
+Key:= UnicodeString(AKey);
+JSReadSubKeys(Key, SubkeyList, AFileName);
+end;
+end.
diff --git a/prereq/ANB ST CP/data/SkinButton.pas b/prereq/ANB ST CP/data/SkinButton.pas
new file mode 100644
index 0000000..83e7926
--- /dev/null
+++ b/prereq/ANB ST CP/data/SkinButton.pas
@@ -0,0 +1,61 @@
+unit SkinButton;
+{$mode delphi}
+{$codepage UTF8}
+interface
+uses Classes, SysUtils, Buttons, Graphics, Controls;
+type TSkinBtn = class(TSpeedButton)
+ private
+ FNormalColor, FHighlightColor, FClickColor: TColor;
+ FTransparent: Boolean;
+ FOnMouseDown: TMouseEvent;
+ FOnMouseEnter, FOnMouseLeave: TNotifyEvent;
+ protected
+ procedure POnMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+ procedure POnMouseEnter(Sender: TObject);
+ procedure POnMouseLeave(Sender: TObject);
+ public
+ constructor Create(AOwner: TComponent);
+ destructor Destroy;
+ published
+ property Transparent: Boolean read FTransparent;
+ property NormalColor: TColor read FNormalColor write FNormalColor;
+ property OnHighlightColor: TColor read FHighlightColor write FHighlightColor;
+ property OnClickColor: TColor read FClickColor write FClickColor;
+ property OnMouseDown: TMouseEvent read FOnMouseDown;
+ property OnMouseEnter: TNotifyEvent read FOnMouseEnter;
+ property OnMouseLeave: TNotifyEvent read FOnMouseLeave;
+ end;
+implementation
+constructor TSkinBtn.Create(AOwner: TComponent);
+begin
+inherited Create(AOwner);
+FNormalColor:= clWhite;
+FHighlightColor:= FNormalColor;
+FClickColor:= FNormalColor;
+FTransparent:= False;
+inherited Transparent:= FTransparent;
+inherited OnMouseEnter:= POnMouseEnter;
+inherited OnMouseDown:= POnMouseDown;
+inherited OnMouseLeave:= POnMouseLeave;
+end;
+destructor TSkinBtn.Destroy;
+begin
+inherited Destroy;
+end;
+procedure TSkinBtn.POnMouseEnter(Sender: TObject);
+begin
+(Sender as TSkinBtn).Color:= FHighlightColor;
+inherited OnMouseEnter(Sender);
+end;
+procedure TSkinBtn.POnMouseLeave(Sender: TObject);
+begin
+(Sender as TSkinBtn).Color:= FNormalColor;
+inherited OnMouseLeave(Sender);
+end;
+procedure TSkinBtn.POnMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+begin
+if Button = mbLeft then
+ (Sender as TSkinBtn).Color:= FClickColor;
+inherited OnMouseDown(Sender, Button, Shift, X, Y);
+end;
+end.
diff --git a/prereq/ANB ST CP/data/VCLEx.pas b/prereq/ANB ST CP/data/VCLEx.pas
new file mode 100644
index 0000000..7318555
--- /dev/null
+++ b/prereq/ANB ST CP/data/VCLEx.pas
@@ -0,0 +1,249 @@
+unit VCLEx;
+{$MODE Delphi}
+{$codepage UTF8}
+interface
+uses ShellApi, windows, sysutils, strutils, LazFileUtils, LazUTF8;
+type IntEx = {$IFDEF Win64}Int64{$ELSE}Integer{$ENDIF};
+ TWaitEvent = procedure;
+ TOSPlatform = (ospUnknown, ospWin32, ospWin64);
+ TPrivilegeState = (psError, psLimitedUser, psAdmin);
+ Percent = 0..100;
+ TRandomRange = (rrUpperCasesLetters, rrLowerCasesLetters, rrNumbers, rrStandartSymbols);
+ TRandomRanges = set of TRandomRange;
+//stdcalls
+function IntToBool (const AInt: IntEx): Boolean; STDCALL;
+function BoolToInt (const ABool: Boolean): IntEx; STDCALL;
+function CopyDirectory (const AFromDir, AToDir: String; const AFlags: Word = FOF_FILESONLY): Boolean; STDCALL;
+function MoveDirectory (const AFromDir, AToDir: String; const AFlags: Word = FOF_FILESONLY): Boolean; STDCALL;
+function DelDirectory (const ADir: String; const AFlags: Word = FOF_SILENT or FOF_NOCONFIRMATION): Boolean; STDCALL;
+procedure WaitEx (const AMs: Int64; OnWait: TWaitEvent); STDCALL;
+procedure Wait (const AMs: Int64); STDCALL;
+function GetBuildPlatform: TOSPlatform; STDCALL;
+function GetWindowsUserPrivilege: TPrivilegeState; STDCALL;
+function ExtractUpDir(const ADir: String; var VSuccess: Boolean): String; STDCALL;
+function GetAnyFileType (const AFileName: UTF8String): UTF8String; STDCALL;
+function FileSizeToStr (const AFS: Int64; const AScaleCaptions: array of String): String; OVERLOAD; STDCALL;
+function FileSizeToStr (const AFS: Int64): String; OVERLOAD; STDCALL;
+function GetRandomString (const sLength: Integer; const ARange: TRandomRanges = [rrUpperCasesLetters, rrLowerCasesLetters]; const AIncludedSymbols: String = ''; const AExcludedSymbols: String = ''): String; STDCALL;
+implementation
+function IntToBool (const AInt: IntEx): Boolean;
+begin
+if AInt >= 0 then
+ Result:= True
+ else
+ Result:= False;
+end;
+function BoolToInt (const ABool: Boolean): IntEx;
+begin
+if ABool then
+ Result:= 1
+ else
+ Result:= -1;
+end;
+//from http://www.delphiworld.narod.ru/base/copy_del_move_dir.html
+function CopyDirectory (const AFromDir, AToDir: String; const AFlags: Word = FOF_FILESONLY): Boolean;
+var fos: TSHFileOpStruct;
+begin
+with fos do
+ begin
+ wFunc:= FO_COPY;
+ fFlags:= AFlags;
+ pFrom:= PChar(AFromDir + #0);
+ pTo:= PChar(AToDir);
+ end;
+Result:= (0 = SHFileOperation(fos));
+end;
+function MoveDirectory (const AFromDir, AToDir: String; const AFlags: Word = FOF_FILESONLY): Boolean;
+var fos: TSHFileOpStruct;
+begin
+with fos do
+ begin
+ wFunc:= FO_MOVE;
+ fFlags:= AFlags;
+ pFrom:= PChar(AFromDir + #0);
+ pTo:= PChar(AToDir);
+ end;
+Result:= (0 = SHFileOperation(fos));
+end;
+function DelDirectory (const ADir: String; const AFlags: Word = FOF_SILENT or FOF_NOCONFIRMATION): Boolean;
+var
+ fos: TSHFileOpStruct;
+begin
+with fos do
+ begin
+ wFunc:= FO_DELETE;
+ fFlags:= AFlags;
+ pFrom:= PChar(ADir + #0);
+ end;
+Result:= (0 = SHFileOperation(fos));
+end;
+//---
+procedure WaitEx (const AMs: Int64; OnWait: TWaitEvent);
+var STime: Int64;
+begin
+STime:= GetTickCount64;
+repeat
+ OnWait;
+ until (GetTickCount64 - STime) = AMs;
+end;
+procedure Wait (const AMs: Int64);
+ procedure MyWait;
+ begin
+ end;
+begin
+WaitEx(AMs, @MyWait);
+end;
+//GetBuildPlatform
+function GetBuildPlatform: TOSPlatform;
+begin
+Result:= ospUnknown;
+if LowerCase({$I %FPCTARGETOS%}) = 'win32' then
+ Result:= ospWin32;
+if LowerCase({$I %FPCTARGETOS%}) = 'win64' then
+ Result:= ospWin64;
+end;
+//GetWindowsUserPrivilege
+function GetWindowsUserPrivilege: TPrivilegeState;
+const SECURITY_NT_AUTHORITY: TSIDIdentifierAuthority = (Value: (0, 0, 0, 0, 0, 5));
+ SECURITY_BUILTIN_DOMAIN_RID = $00000020;
+ DOMAIN_ALIAS_RID_ADMINS = $00000220;
+ SECURITY_MANDATORY_HIGH_RID = $00003000;
+ TokenIntegrityLevel = 25;
+var hAccessToken: THandle;
+ ptgGroups: PTokenGroups;
+ dwInfoBufferSize: DWORD;
+ psidAdministrators: PSID;
+ I: Integer;
+ SubAuthority: DWORD;
+begin
+Result:= psError;
+if Win32Platform <> VER_PLATFORM_WIN32_NT then
+ Exit;
+if not OpenThreadToken(GetCurrentThread, TOKEN_QUERY, True, hAccessToken) then
+ if not OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, hAccessToken) then
+ Exit;
+try
+ GetMem(ptgGroups, 1024);
+ try
+ if Win32MajorVersion < 6 then
+ begin
+ if not GetTokenInformation(hAccessToken, TokenGroups, ptgGroups, 1024, dwInfoBufferSize) then
+ Exit;
+ AllocateAndInitializeSid(SECURITY_NT_AUTHORITY, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, psidAdministrators);
+ try
+ Result:= psLimitedUser;
+ for I:= 0 to ptgGroups.GroupCount - 1 do
+ if EqualSid(psidAdministrators, ptgGroups.Groups[I].Sid) then
+ begin
+ Result:= psAdmin;
+ Break;
+ end;
+ finally
+ FreeSid(psidAdministrators);
+ end;
+ end
+ else
+ begin
+ if GetTokenInformation(hAccessToken, TTokenInformationClass(TokenIntegrityLevel), ptgGroups, 1024, dwInfoBufferSize) and IsValidSid(PSIDAndAttributes(ptgGroups)^.Sid) then
+ begin
+ Result:= psLimitedUser;
+ SubAuthority:= GetSidSubAuthorityCount(PSIDAndAttributes(ptgGroups)^.Sid)^ - 1;
+ if GetSidSubAuthority(PSIDAndAttributes(ptgGroups)^.Sid, SubAuthority)^ >= SECURITY_MANDATORY_HIGH_RID then
+ Result:= psAdmin;
+ end;
+ end;
+ finally
+ FreeMem(ptgGroups);
+ end;
+ finally
+ CloseHandle(hAccessToken);
+ end;
+end;
+function ExtractUpDir (const ADir: String; var VSuccess: Boolean): String;
+var CurrDelim, NextDelim: Integer;
+ s, Str: String;
+begin
+Str:= ExcludeTrailingBackslash(ADir);
+if Length(ADir) < 4 then
+ begin
+ VSuccess:= false;
+ Result:= ADir;
+ Exit;
+ end;
+s:= '';
+CurrDelim:= 1;
+repeat
+ NextDelim:= PosEx('\', Str, CurrDelim);
+ if NextDelim = 0 then
+ NextDelim:= Length(Str) + 1;
+ if NextDelim < Length(Str) then
+ s:= s + Copy(Str, CurrDelim, NextDelim - CurrDelim) + '\';
+ CurrDelim:= NextDelim + 1;
+ until (CurrDelim > Length(Str));
+VSuccess:= DirectoryExistsUTF8(s);
+Result:= s;
+end;
+function GetAnyFileType (const AFileName: UTF8String): UTF8String;
+var FileInfo: TSHFILEINFO;
+begin
+Result:= '';
+FillChar(FileInfo, SizeOf(FileInfo), 0);
+if (SHGetFileInfo(PChar(ExtractFileExt(AFileName)), FILE_ATTRIBUTE_NORMAL, FileInfo, SizeOf(FileInfo), SHGFI_TYPENAME or SHGFI_USEFILEATTRIBUTES) <> 0) then
+ Result:= AnsiToUtf8(FileInfo.szTypeName);
+end;
+function FileSizeToStr (const AFS: Int64; const AScaleCaptions: array of String): String;
+var ARSize: Real;
+begin
+if AFS < 1024 then
+ begin
+ Result:= Format('%d ' + AScaleCaptions[0], [AFS]);
+ Exit;
+ end;
+if AFS < 1048576 then
+ begin
+ ARSize:= Round((AFS / 1024)*100)/100;
+ Result:= FloatToStr(ARSize) + ' ' + AScaleCaptions[1];
+ Exit;
+ end;
+if AFS < 1073741824 then
+ begin
+ ARSize:= Round((AFS / 1048576)*100)/100;
+ Result:= FloatToStr(ARSize) + ' ' + AScaleCaptions[2];
+ Exit;
+ end;
+ARSize:= Round((AFS / 1073741824)*100)/100;
+Result:= FloatToStr(ARSize) + ' ' + AScaleCaptions[3];
+end;
+function FileSizeToStr (const AFS: Int64): String;
+begin
+Result:= FileSizeToStr(AFS, ['Byte', 'KB', 'MB', 'GB']);
+end;
+function GetRandomString (const sLength: Integer; const ARange: TRandomRanges = [rrUpperCasesLetters, rrLowerCasesLetters]; const AIncludedSymbols: String = ''; const AExcludedSymbols: String = ''): String;
+const UpperCaseChars = 'ABCDEFGHIKLMNOPQRSTUVWXYZ';
+ LowerCaseChars = 'abcdefghiklmnopqrstuvwxyz';
+ NumbersChars = '0123456789';
+ SymbolsChars = '!"#$%&''()*+,-.:;<=>?@\]^_`{|}~';
+var i, j: Integer;
+ Chars: String;
+begin
+SetLength (Result, sLength);
+Chars:= AIncludedSymbols;
+if rrUpperCasesLetters in ARange then
+ Chars:= Chars + UpperCaseChars;
+if rrLowerCasesLetters in ARange then
+ Chars:= Chars + LowerCaseChars;
+if rrNumbers in ARange then
+ Chars:= Chars + NumbersChars;
+if rrStandartSymbols in ARange then
+ Chars:= Chars + SymbolsChars;
+if Length(AExcludedSymbols) > 0 then
+ for i:= 1 to Length(AExcludedSymbols) do
+ begin
+ j:= Pos(AExcludedSymbols[i], Chars);
+ if j > 0 then
+ Delete(Chars, j, 1);
+ end;
+for i:= 1 to sLength do
+ Result[i]:= Chars[Random(Length(Chars))+1];
+end;
+end.
diff --git a/prereq/ANB ST CP/data/VersionControl.pas b/prereq/ANB ST CP/data/VersionControl.pas
new file mode 100644
index 0000000..04abe61
--- /dev/null
+++ b/prereq/ANB ST CP/data/VersionControl.pas
@@ -0,0 +1,145 @@
+unit VersionControl;
+{$MODE Delphi}
+{$codepage UTF8}
+interface
+uses LCLIntf, LCLType, LMessages, SysUtils, StrUtils, Forms, Classes,
+ {$IFDEF WINDOWS}PJVersionInfo{$ENDIF};
+type TSmallVersionInfo = record
+ sviMajor, sviMinor: int64;
+ end;
+type TVersionInfo = record
+ viMajor, viMinor, viRelease, viBuild: integer;
+ end;
+function SmallVersionInfoToStr (const Value: TSmallVersionInfo): string; stdcall;
+function VersionInfoToStr (const Value: TVersionInfo): string; stdcall;
+function VersionInfoToSmallVersionInfo (const Value: TVersionInfo): TSmallVersionInfo; stdcall;
+function SmallVersionInfoToVersionInfo (const Value: TSmallVersionInfo; const ANilValue: integer = 0): TVersionInfo; stdcall;
+function StrToVersionInfo (const AString: string): TVersionInfo; stdcall;
+function StrToSmallVersionInfo (const AString: string): TSmallVersionInfo; stdcall;
+function CompareVersionInfo (const AVersionInfo1, AVersionInfo2: TVersionInfo): integer; stdcall;
+function CompareSmallVersionInfo (const ASmallVersionInfo1, ASmallVersionInfo2: TSmallVersionInfo): integer; stdcall;
+{$IFDEF WINDOWS}function GetApplicationVersionInfoStr (const AFileName, AVersionSTR: string): string; STDCALL;{$ENDIF}
+const NilVersionInfo: TVersionInfo = (viMajor: 0; viMinor: 0; viRelease: 0; viBuild: 0);
+ NilSmallVersionInfo: TSmallVersionInfo = (sviMajor: 0; sviMinor: 0);
+implementation
+function SmallVersionInfoToStr (const Value: TSmallVersionInfo): string;
+const Mask: string = '%d.%d';
+begin
+Result:= Format(Mask, [Value.sviMajor, Value.sviMinor]);
+end;
+function VersionInfoToStr (const Value: TVersionInfo): string;
+const Mask: string = '%d.%d.%d.%d';
+begin
+Result:= Format(Mask, [Value.viMajor, Value.viMinor, Value.viRelease, Value.viBuild]);
+end;
+function VersionInfoToSmallVersionInfo (const Value: TVersionInfo): TSmallVersionInfo;
+begin
+Result.sviMajor:= Value.viMajor;
+Result.sviMinor:= Value.viMinor;
+end;
+function SmallVersionInfoToVersionInfo (const Value: TSmallVersionInfo; const ANilValue: integer = 0): TVersionInfo;
+begin
+Result.viMajor:= Value.sviMajor;
+Result.viMinor:= Value.sviMinor;
+Result.viRelease:= ANilValue;
+Result.viBuild:= ANilValue;
+end;
+function StrToVersionInfo (const AString: string): TVersionInfo;
+var stringver: string;
+ CurrDelim, NextDelim, CurrIndex: Integer;
+ StrArray: array [1..4] of string;
+begin
+stringver:= AString;
+CurrDelim:= 1;
+CurrIndex:= 1;
+repeat
+ NextDelim:= PosEx('.', stringver, CurrDelim);
+ if NextDelim = 0 then
+ NextDelim:= Length(stringver) + 1;
+ StrArray[CurrIndex]:= Copy(stringver, CurrDelim, NextDelim - CurrDelim);
+ CurrDelim:= NextDelim + 1;
+ CurrIndex:= CurrIndex + 1;
+ until CurrDelim > Length(stringver);
+Result.viMajor:= StrToInt(StrArray[1]);
+Result.viMinor:= StrToInt(StrArray[2]);
+Result.viRelease:= StrToInt(StrArray[3]);
+Result.viBuild:= StrToInt(StrArray[4]);
+end;
+function StrToSmallVersionInfo (const AString: string): TSmallVersionInfo;
+var stringver: string;
+ CurrDelim, NextDelim: Integer;
+ StrArray: array [1..2] of string;
+begin
+stringver:= AString;
+NextDelim:= PosEx('.', stringver, 1);
+if NextDelim = 0 then
+ begin
+ StrArray[1]:= stringver;
+ Exit;
+ end;
+StrArray[1]:= Copy(stringver, 1, NextDelim - 1);
+CurrDelim:= NextDelim + 1;
+NextDelim:= PosEx('.', stringver, CurrDelim);
+if NextDelim = 0 then
+ NextDelim:= Length(stringver) + 1;
+StrArray[2]:= Copy(stringver, CurrDelim, NextDelim - CurrDelim);
+Result.sviMajor:= StrToInt(StrArray[1]);
+Result.sviMinor:= StrToInt(StrArray[2]);
+end;
+function CompareVersionInfo (const AVersionInfo1, AVersionInfo2: TVersionInfo): integer;
+//Result:
+// 0 - AVersionInfo1 = AVersionInfo2
+// -1 - AVersionInfo1 > AVersionInfo2
+// 1 - AVersionInfo1 < AVersionInfo2
+begin
+//by default this versions are equal
+Result:= 0;
+//equal
+if ((AVersionInfo1.viMajor = AVersionInfo2.viMajor) and
+ (AVersionInfo1.viMinor = AVersionInfo2.viMinor) and
+ (AVersionInfo1.viRelease = AVersionInfo2.viRelease) and
+ (AVersionInfo1.viBuild = AVersionInfo2.viBuild)) then
+ Result:= 0;
+//more
+if ((AVersionInfo1.viMajor > AVersionInfo2.viMajor) or
+ ((AVersionInfo1.viMajor = AVersionInfo2.viMajor) and
+ (AVersionInfo1.viMinor > AVersionInfo2.viMinor)) or
+ ((AVersionInfo1.viMajor = AVersionInfo2.viMajor) and
+ (AVersionInfo1.viMinor = AVersionInfo2.viMinor) and
+ (AVersionInfo1.viRelease > AVersionInfo2.viRelease)) or
+ ((AVersionInfo1.viMajor = AVersionInfo2.viMajor) and
+ (AVersionInfo1.viMinor = AVersionInfo2.viMinor) and
+ (AVersionInfo1.viRelease = AVersionInfo2.viRelease) and
+ (AVersionInfo1.viBuild > AVersionInfo2.viBuild))) then
+ Result:= -1;
+//less
+if ((AVersionInfo1.viMajor < AVersionInfo2.viMajor) or
+ ((AVersionInfo1.viMajor = AVersionInfo2.viMajor) and
+ (AVersionInfo1.viMinor < AVersionInfo2.viMinor)) or
+ ((AVersionInfo1.viMajor = AVersionInfo2.viMajor) and
+ (AVersionInfo1.viMinor = AVersionInfo2.viMinor) and
+ (AVersionInfo1.viRelease < AVersionInfo2.viRelease)) or
+ ((AVersionInfo1.viMajor = AVersionInfo2.viMajor) and
+ (AVersionInfo1.viMinor = AVersionInfo2.viMinor) and
+ (AVersionInfo1.viRelease = AVersionInfo2.viRelease) and
+ (AVersionInfo1.viBuild < AVersionInfo2.viBuild))) then
+ Result:= 1;
+end;
+function CompareSmallVersionInfo (const ASmallVersionInfo1, ASmallVersionInfo2: TSmallVersionInfo): integer;
+var AVI1, AVI2: TVersionInfo;
+begin
+AVI1:= SmallVersionInfoToVersionInfo(ASmallVersionInfo1);
+AVI2:= SmallVersionInfoToVersionInfo(ASmallVersionInfo2);
+Result:= CompareVersionInfo(AVI1, AVI2);
+end;
+{$IFDEF WINDOWS}
+function GetApplicationVersionInfoStr (const AFileName, AVersionSTR: string): string;
+var VIC: TPJVersionInfo;
+begin
+VIC:= TPJVersionInfo.Create(nil);
+VIC.FileName:= AFileName;
+Result:= VIC.StringFileInfo[AVersionSTR];
+VIC.Free;
+end;
+{$ENDIF WINDOWS}
+end.
diff --git a/prereq/dd-verinfo/ChangeLog.txt b/prereq/dd-verinfo/ChangeLog.txt
new file mode 100644
index 0000000..e98d8d2
--- /dev/null
+++ b/prereq/dd-verinfo/ChangeLog.txt
@@ -0,0 +1,93 @@
+; ------------------------------------------------------------------------------
+; This Source Code Form is subject to the terms of the Mozilla Public License,
+; v. 2.0. If a copy of the MPL was not distributed with this file, You can
+; obtain one at http://mozilla.org/MPL/2.0/
+;
+; Copyright (C) 2013, Peter Johnson (www.delphidabbler.com).
+;
+; $Rev: 1132 $
+; $Date: 2013-01-14 03:31:09 +0000 (Mon, 14 Jan 2013) $
+;
+; Change Log for Version Information Component
+; ------------------------------------------------------------------------------
+
+Release v3.3.1 of 14 January 2013
++ Unit names are now qualified with namespace name on Delphi XE2 and later.
++ Changes to demo projects:
+ - Font and appearance of some controls changed.
+ - Controls are now themed.
+ - All form files now in text format.
+ - Forms are no longer scaled.
+ - 1st demo program's main window now resizes.
+ - 2nd demo dialogues' "help" buttona now display online examples instead of help file topics.
+ - Demos now need Delphi 7 as a minimum.
+ - New project configurations files.
++ Component source license changed to Mozilla Public License v2.0. (Demos now placed in public domain).
++ MPL text file and documentation wiki shortcut have had names changed.
++ WinHelp help file regenerated with updated copyright date.
++ Documentation revised.
+
+Release v3.3 of 03 November 2010
++ Added operator overloads to TPJVersionNumber record when compiled with Delphi 2006 and later to:
+ - Support equality tests using =, <>, <, <=, > and >= operators.
+ - Support implicit casting to a string which formats the version number as a dotted quad (issue #12: http://code.google.com/p/ddab-lib/issues/detail?id=12).
++ Added new helper functions primarily for use with Delphi 2005 and earlier:
+ - CompareVerNums - compares two version number records.
+ - VerNumToStr - formats a version number as a dotted quad.
++ Updated TPJVersionNumber topic in help file re changes.
++ Updated HTML documentation.
+
+Release v3.2 of 09 November 2009
++ Changed method used to get character set descriptions. These are now obtained from operating system where possible instead of from hard-wired values.
++ Added compiler directive to switch off unsafe code warnings on compilers that support the directive.
++ Added copy of Mozilla Public License.
++ Corrected error in help file.
++ Modified Demo 2 to enable it to compile on Delphi 2 and 3.
++ Updated documentation and included shortcut file that links to component Wiki.
+
+Release v3.1.1 of 11 December 2005
++ Changed component to Mozilla public license.
++ Fixed minor bug in VIDemo project.
++ Revised HelpEgs demo project to access related help file topics.
++ Updated help file to make examples available from component's main page.
++ Updated HTML documentation.
+
+Release v3.1 of 07 September 2003
++ Fixed to be compatible with C++ Builder - direct access to fields of TVSFixedFileInfo in property declarations were replaced by calls to an indexed property getter function.
+
+Release v3.0.1 of 08 July 2003
++ Changed component palette from PJSoft to DelphiDabbler.
++ Updated HTML documentation.
++ Changed copyright message in help file.
+
+Release v3.0 of 17 February 2002
++ Added ability to access all "translations" stored in a file's version information, rather than just first one. This has been done so that code using earlier versions of this component should continue to work unchanged.
++ Added new property to expose fixed file information record.
++ Added new "string array" property to give access to string information by name: this property can access any custom string information if the name is known.
++ Added properties to return number of "translations" and to select index of "translation" to be used.
++ Added properties to return language and character set codes in addition to descriptive strings.
++ All string info, language and character set properties now return values from the currently selected translation (which defaults to the first translation maintaining backward compatibilty).
++ Empty FileName property now accesses name of host application per command line rather than using Application.ExeName.
++ CharSet property now returns '' for unknown value rather than 'Unknown'.
++ Renamed TVersionNumber record to TPJVersionNumber.
++ Replaced Tvs_FixedFileInfo record with use of Windows unit defined type TVSFixedFileInfo.
++ Renamed unit to PJVersionInfo.
++ Changed component palette from "PJ Stuff" to "PJSoft".
++ Added two demo programs, one is a sample version information reading program and the other implements examples from the help file.
+
+Release v2.1 of 28 November 1999
++ Changed unit name from VerInfo to VInfo to allow component to install under Delphi 3 & 4 (VerInfo clashes with an existing unit in these versions).
++ Removed superfluous conditional compilation directives.
++ Updated HTML documentation to separate 16 bit from 32 bit version, to to include installation notes for Delphi 3/4 and to include update history.
+
+Release v2.0.1 of 08 July 1999
++ Changed palette where component installs to "PJ Stuff" from "Own".
++ Added HTML documentation (shared documentation with Release 1.0.1).
++ Included 16 bit Version Information Component release v1.0.1
+
+Un-released v2.0 of 06 December 1998
++ Forked development - 32 bit development (this fork) began with v2.0 while the 16 bit version continued with v1.0.1
++ Revised for use with Win32 - not backwards compatible with v1.0
+
+Un-released v1.0 of 26 April 1998
++ Original version - 16 bit only.
diff --git a/prereq/dd-verinfo/Documentation.URL b/prereq/dd-verinfo/Documentation.URL
new file mode 100644
index 0000000..966215c
--- /dev/null
+++ b/prereq/dd-verinfo/Documentation.URL
@@ -0,0 +1,3 @@
+[InternetShortcut]
+URL=http://www.delphidabbler.com/url/verinfo-docs
+
diff --git a/prereq/dd-verinfo/MPL-2.txt b/prereq/dd-verinfo/MPL-2.txt
new file mode 100644
index 0000000..fa0086a
--- /dev/null
+++ b/prereq/dd-verinfo/MPL-2.txt
@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+ means each individual or legal entity that creates, contributes to
+ the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+ means the combination of the Contributions of others (if any) used
+ by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+ means Source Code Form to which the initial Contributor has attached
+ the notice in Exhibit A, the Executable Form of such Source Code
+ Form, and Modifications of such Source Code Form, in each case
+ including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ (a) that the initial Contributor has attached the notice described
+ in Exhibit B to the Covered Software; or
+
+ (b) that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the
+ terms of a Secondary License.
+
+1.6. "Executable Form"
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+ means a work that combines Covered Software with other material, in
+ a separate file or files, that is not Covered Software.
+
+1.8. "License"
+ means this document.
+
+1.9. "Licensable"
+ means having the right to grant, to the maximum extent possible,
+ whether at the time of the initial grant or subsequently, any and
+ all of the rights conveyed by this License.
+
+1.10. "Modifications"
+ means any of the following:
+
+ (a) any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered
+ Software; or
+
+ (b) any new file in Source Code Form that contains any Covered
+ Software.
+
+1.11. "Patent Claims" of a Contributor
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the
+ License, by the making, using, selling, offering for sale, having
+ made, import, or transfer of either its Contributions or its
+ Contributor Version.
+
+1.12. "Secondary License"
+ means either the GNU General Public License, Version 2.0, the GNU
+ Lesser General Public License, Version 2.1, the GNU Affero General
+ Public License, Version 3.0, or any later versions of those
+ licenses.
+
+1.13. "Source Code Form"
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, "control" means (a) the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or (b) ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+ for sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+ or
+
+(b) for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+ Form, as described in Section 3.1, and You must inform recipients of
+ the Executable Form how they can obtain a copy of such Source Code
+ Form by reasonable means in a timely manner, at a charge no more
+ than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter
+ the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+* *
+* 6. Disclaimer of Warranty *
+* ------------------------- *
+* *
+* Covered Software is provided under this License on an "as is" *
+* basis, without warranty of any kind, either expressed, implied, or *
+* statutory, including, without limitation, warranties that the *
+* Covered Software is free of defects, merchantable, fit for a *
+* particular purpose or non-infringing. The entire risk as to the *
+* quality and performance of the Covered Software is with You. *
+* Should any Covered Software prove defective in any respect, You *
+* (not any Contributor) assume the cost of any necessary servicing, *
+* repair, or correction. This disclaimer of warranty constitutes an *
+* essential part of this License. No use of any Covered Software is *
+* authorized under this License except under this disclaimer. *
+* *
+************************************************************************
+
+************************************************************************
+* *
+* 7. Limitation of Liability *
+* -------------------------- *
+* *
+* Under no circumstances and under no legal theory, whether tort *
+* (including negligence), contract, or otherwise, shall any *
+* Contributor, or anyone who distributes Covered Software as *
+* permitted above, be liable to You for any direct, indirect, *
+* special, incidental, or consequential damages of any character *
+* including, without limitation, damages for lost profits, loss of *
+* goodwill, work stoppage, computer failure or malfunction, or any *
+* and all other commercial damages or losses, even if such party *
+* shall have been informed of the possibility of such damages. This *
+* limitation of liability shall not apply to liability for death or *
+* personal injury resulting from such party's negligence to the *
+* extent applicable law prohibits such limitation. Some *
+* jurisdictions do not allow the exclusion or limitation of *
+* incidental or consequential damages, so this exclusion and *
+* limitation may not apply to You. *
+* *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+ This Source Code Form is subject to the terms of the Mozilla Public
+ License, v. 2.0. If a copy of the MPL was not distributed with this
+ file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+ This Source Code Form is "Incompatible With Secondary Licenses", as
+ defined by the Mozilla Public License, v. 2.0.
\ No newline at end of file
diff --git a/prereq/dd-verinfo/PJVersionInfo.als b/prereq/dd-verinfo/PJVersionInfo.als
new file mode 100644
index 0000000..65b45a2
--- /dev/null
+++ b/prereq/dd-verinfo/PJVersionInfo.als
@@ -0,0 +1,94 @@
+charset
+charset_property
+charsetcode
+charsetcode_property
+comments
+comments_property
+companyname
+companyname_property
+currenttranslation
+currenttranslation_property
+filedescription
+filedescription_property
+fileflags
+fileflags_property
+fileflagsmask
+fileflagsmask_property
+filename
+filename_property
+fileos
+fileos_property
+filesubtype
+filesubtype_property
+filetype
+filetype_property
+fileversion
+fileversion_property
+fileversionnumber
+fileversionnumber_property
+fixedfileinfo
+fixedfileinfo_property
+haveinfo
+haveinfo_property
+internalname
+internalname_property
+language
+language_property
+languagecode
+languagecode_property
+legalcopyright
+legalcopyright_property
+legaltrademarks
+legaltrademarks_property
+numtranslations
+numtranslations_property
+originalfilename
+originalfilename_property
+privatebuild
+privatebuild_property
+productname
+productname_property
+productversion
+productversion_property
+productversionnumber
+productversionnumber_property
+specialbuild
+specialbuild_property
+stringfileinfo
+stringfileinfo_property
+tpjversioninfo
+tpjversioninfo_charset
+tpjversioninfo_charsetcode
+tpjversioninfo_comments
+tpjversioninfo_companyname
+tpjversioninfo_currenttranslation
+tpjversioninfo_example1
+tpjversioninfo_example2
+tpjversioninfo_example3
+tpjversioninfo_example4
+tpjversioninfo_filedescription
+tpjversioninfo_fileflags
+tpjversioninfo_fileflagsmask
+tpjversioninfo_filename
+tpjversioninfo_fileos
+tpjversioninfo_filesubtype
+tpjversioninfo_filetype
+tpjversioninfo_fileversion
+tpjversioninfo_fileversionnumber
+tpjversioninfo_fixedfileinfo
+tpjversioninfo_haveinfo
+tpjversioninfo_internalname
+tpjversioninfo_language
+tpjversioninfo_languagecode
+tpjversioninfo_legalcopyright
+tpjversioninfo_legaltrademarks
+tpjversioninfo_numtranslations
+tpjversioninfo_object
+tpjversioninfo_originalfilename
+tpjversioninfo_privatebuild
+tpjversioninfo_productname
+tpjversioninfo_productversion
+tpjversioninfo_productversionnumber
+tpjversioninfo_specialbuild
+tpjversioninfo_stringfileinfo
+tpjversionnumber
diff --git a/prereq/dd-verinfo/PJVersionInfo.dcr b/prereq/dd-verinfo/PJVersionInfo.dcr
new file mode 100644
index 0000000..d729cae
Binary files /dev/null and b/prereq/dd-verinfo/PJVersionInfo.dcr differ
diff --git a/prereq/dd-verinfo/PJVersionInfo.hlp b/prereq/dd-verinfo/PJVersionInfo.hlp
new file mode 100644
index 0000000..dfe3ed2
Binary files /dev/null and b/prereq/dd-verinfo/PJVersionInfo.hlp differ
diff --git a/prereq/dd-verinfo/PJVersionInfo.pas b/prereq/dd-verinfo/PJVersionInfo.pas
new file mode 100644
index 0000000..9c2e57f
--- /dev/null
+++ b/prereq/dd-verinfo/PJVersionInfo.pas
@@ -0,0 +1,926 @@
+{
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at http://mozilla.org/MPL/2.0/
+ *
+ * Copyright (C) 1998-2013, Peter Johnson (www.delphidabbler.com).
+ *
+ * $Rev: 1110 $
+ * $Date: 2013-01-13 23:26:17 +0000 (Sun, 13 Jan 2013) $
+ *
+ * Version Information Component. The component reads version information from
+ * executable files.
+}
+
+
+unit PJVersionInfo;
+
+// Determine if certain features are supported by compiler
+// * Supports_Assert - Defined if assertions supported (all compilers
+// except Delphi 2).
+// * Supports_ResourceString - Defined if resourcestring keyword supported (all
+// compilers except Delphi 2).
+// * Supports_AdvancedRecords - Defined if advanced records with record methods,
+// operator overloads etc. supported (Delphi 2006
+// and later).
+// * Supports_RTLNameSpaces - Defined if Delphi RTL / VCL unit references
+// should be qualified with namespaces.
+{$DEFINE Supports_Assert}
+{$DEFINE Supports_ResourceString}
+{$UNDEF Supports_AdvancedRecords}
+{$UNDEF Supports_RTLNameSpaces}
+{$IFDEF VER90} // Delphi 2
+ {$UNDEF Supports_Assert}
+ {$UNDEF Supports_ResourceString}
+{$ENDIF}
+// Switch off unsafe code warnings if switch supported
+{$IFDEF CONDITIONALEXPRESSIONS}
+ {$IF CompilerVersion >= 15.0} // >= Delphi 7
+ {$WARN UNSAFE_CODE OFF}
+ {$IFEND}
+ {$IF CompilerVersion >= 18.0} // >= Delphi 2006
+ {$DEFINE Supports_AdvancedRecords}
+ {$IFEND}
+ {$IF CompilerVersion >= 23.0} // Delphi XE2
+ {$DEFINE Supports_RTLNameSpaces}
+ {$IFEND}
+{$ENDIF}
+
+interface
+
+
+uses
+ // Delphi
+ {$IFDEF Supports_RTLNameSpaces}
+ Winapi.Windows, System.Classes;
+ {$ELSE}
+ Windows, Classes;
+ {$ENDIF}
+
+
+type
+
+ {
+ TPJVersionNumber:
+ Record that encapsulates version numbers.
+ }
+ TPJVersionNumber = record
+ V1: Word; // Major version number
+ V2: Word; // Minor version number
+ V3: Word; // Revision version number
+ V4: Word; // Build number
+ {$IFDEF Supports_AdvancedRecords}
+ class operator Implicit(Ver: TPJVersionNumber): string;
+ {Operator overload that performs implicit conversion of TPJVersionNumber
+ to string as dotted quad.
+ @param Ver [in] Version number to be converted.
+ @return Version number as dotted quad.
+ }
+ class operator LessThanOrEqual(Ver1, Ver2: TPJVersionNumber): Boolean;
+ {Operator overload that compares two version numbers to check if first is
+ less than or equal to the second.
+ @param Ver1 [in] First version number.
+ @param Ver2 [in] Second version number.
+ @return True if Ver1 <= Ver2, False otherwise.
+ }
+ class operator LessThan(Ver1, Ver2: TPJVersionNumber): Boolean;
+ {Operator overload that compares two version numbers to check if first is
+ less than second.
+ @param Ver1 [in] First version number.
+ @param Ver2 [in] Second version number.
+ @return True if Ver1 < Ver2, False otherwise.
+ }
+ class operator GreaterThan(Ver1, Ver2: TPJVersionNumber): Boolean;
+ {Operator overload that compares two version numbers to check if first is
+ greater than second.
+ @param Ver1 [in] First version number.
+ @param Ver2 [in] Second version number.
+ @return True if Ver1 > Ver2, False otherwise.
+ }
+ class operator GreaterThanOrEqual(Ver1, Ver2: TPJVersionNumber): Boolean;
+ {Operator overload that compares two version numbers to check if first is
+ greater than or equal to the second.
+ @param Ver1 [in] First version number.
+ @param Ver2 [in] Second version number.
+ @return True if Ver1 >= Ver2, False otherwise.
+ }
+ class operator Equal(Ver1, Ver2: TPJVersionNumber): Boolean;
+ {Operator overload that compares two version numbers to check for
+ equality.
+ @param Ver1 [in] First version number.
+ @param Ver2 [in] Second version number.
+ @return True if Ver1 = Ver2, False otherwise.
+ }
+ class operator NotEqual(Ver1, Ver2: TPJVersionNumber): Boolean;
+ {Operator overload that compares two version numbers to check for
+ inequality.
+ @param Ver1 [in] First version number.
+ @param Ver2 [in] Second version number.
+ @return True if Ver1 <> Ver2, False otherwise.
+ }
+ {$ENDIF}
+ end;
+
+ {
+ TPJVersionInfo:
+ Component that accesses the version information embedded in an executable
+ file and exposes the information as properties. Supports multi-lingual
+ version iformation resources.
+ }
+ TPJVersionInfo = class(TComponent)
+ private // properties
+ fFileName: string;
+ fHaveInfo: Boolean;
+ fNumTranslations: Integer;
+ fCurrentTranslation: Integer;
+ fFixedFileInfo: TVSFixedFileInfo;
+ procedure SetFileName(AName: string);
+ function GetProductVersionNumber: TPJVersionNumber;
+ function GetFileVersionNumber: TPJVersionNumber;
+ function GetLanguage: string;
+ function GetCharSet: string;
+ function GetCharSetCode: WORD;
+ function GetLanguageCode: WORD;
+ function GetCurrentTranslation: Integer;
+ procedure SetCurrentTranslation(const Value: Integer);
+ function GetStringFileInfo(const Name: string): string;
+ function GetStringFileInfoByIdx(Index: Integer): string;
+ function GetFixedFileInfoItemByIdx(Index: Integer): DWORD;
+ private
+ fPInfoBuffer: PChar; // Pointer to info buffer
+ fPTransBuffer: Pointer; // Pointer to translation buffer
+ procedure GetInfoBuffer(Len: DWORD);
+ {Creates an info buffer of required size.
+ @param Len [in] Required buffer size in characters.
+ }
+ procedure GetTransBuffer(Len: UINT);
+ {Creates a translation table buffer of required size.
+ @param Required buffer size in bytes.
+ }
+ function GetTransStr: string;
+ {Encodes information about the current translation in a string.
+ @return Required translation information.
+ }
+ protected
+ procedure ClearProperties; virtual;
+ {Forces properties to return cleared values.
+ }
+ procedure ReadVersionInfo; virtual;
+ {Reads version info from file named by FileName property.
+ }
+ public
+ constructor Create(AOwner: TComponent); override;
+ {Object constructor. Sets default values.
+ @param AOwner [in] Component that owns this one. May be nil.
+ }
+ destructor Destroy; override;
+ {Object destructor. Frees allocated memory.
+ }
+ property HaveInfo: Boolean
+ read fHaveInfo;
+ {Property true if file version info for the file named by the FileName
+ property has been successfully read}
+ property FixedFileInfo: TVSFixedFileInfo
+ read fFixedFileInfo;
+ {Exposes the whole fixed file info record. Following properties expose
+ the various fields of it}
+ property FileVersionNumber: TPJVersionNumber
+ read GetFileVersionNumber;
+ {Version number of file in numeric format. From fixed file info}
+ property ProductVersionNumber: TPJVersionNumber
+ read GetProductVersionNumber;
+ {Version number of product in numeric format. From fixed file info}
+ property FileOS: DWORD index 0
+ read GetFixedFileInfoItemByIdx;
+ {Code describing operating system to be used by file, From fixed file
+ info}
+ property FileType: DWORD index 1
+ read GetFixedFileInfoItemByIdx;
+ {Code descibing type of file. From fixed file info}
+ property FileSubType: DWORD index 2
+ read GetFixedFileInfoItemByIdx;
+ {Code describing sub-type of file - only used for certain values of
+ FileType property. From fixed file info}
+ property FileFlagsMask: DWORD index 3
+ read GetFixedFileInfoItemByIdx;
+ {Code describing which FileFlags are valid. From fixed file info}
+ property FileFlags: DWORD index 4
+ read GetFixedFileInfoItemByIdx;
+ {Flags describing file state. From fixed file info}
+ property Comments: string index 0
+ read GetStringFileInfoByIdx;
+ {String file info property giving user defined comments in current
+ translation}
+ property CompanyName: string index 1
+ read GetStringFileInfoByIdx;
+ {String file info property giving name of company in current translation}
+ property FileDescription: string index 2
+ read GetStringFileInfoByIdx;
+ {String file info property giving description of file in current
+ translation}
+ property FileVersion: string index 3
+ read GetStringFileInfoByIdx;
+ {String file info property giving version number of file in string format
+ in current translation}
+ property InternalName: string index 4
+ read GetStringFileInfoByIdx;
+ {String file info property giving internal name of file in current
+ translation}
+ property LegalCopyright: string index 5
+ read GetStringFileInfoByIdx;
+ {String file info property giving copyright message in current
+ translation}
+ property LegalTrademarks: string index 6
+ read GetStringFileInfoByIdx;
+ {String file info property giving trademark info in current translation}
+ property OriginalFileName: string index 7
+ read GetStringFileInfoByIdx;
+ {String file info property giving original name of file in current
+ translation}
+ property PrivateBuild: string index 8
+ read GetStringFileInfoByIdx;
+ {String file info property giving information about a private build of
+ file in current translation}
+ property ProductName: string index 9
+ read GetStringFileInfoByIdx;
+ {String file info property giving name of product in current translation}
+ property ProductVersion: string index 10
+ read GetStringFileInfoByIdx;
+ {String file info property giving version number of product in string
+ format in current translation}
+ property SpecialBuild: string index 11
+ read GetStringFileInfoByIdx;
+ {String file info property giving information about a special build of
+ file in current translation}
+ property StringFileInfo[const Name: string]: string
+ read GetStringFileInfo;
+ {Value of named string file info item in current translation. This
+ property can access both standard and custom string info}
+ property Language: string
+ read GetLanguage;
+ {Name of language in use in current translation}
+ property CharSet: string
+ read GetCharSet;
+ {Name of character set in use in current translation}
+ property LanguageCode: WORD
+ read GetLanguageCode;
+ {Code of laguage in use in current translation}
+ property CharSetCode: WORD
+ read GetCharSetCode;
+ {Code of character set in use in current translation}
+ property NumTranslations: Integer
+ read fNumTranslations;
+ {The number of difference translations (ie languages and char sets) in
+ the version information}
+ property CurrentTranslation: Integer
+ read GetCurrentTranslation write SetCurrentTranslation;
+ {Zero-based index of the current translation: this is 0 when a file is
+ first accessed. Set to a value in range 0..NumTranslations-1 to access
+ other translations. All string info, language and char set properties
+ return information for the current translation}
+ published
+ property FileName: string read fFileName write SetFileName;
+ {Name of file containing version information. If set to '' (default) the
+ version information comes from the containing executable file}
+ end;
+
+function VerNumToStr(const Ver: TPJVersionNumber): string;
+ {Converts a version number to its string representation as a dotted quad.
+ @param Ver [in] Version number to be converted.
+ @return Version number as dotted quad.
+ }
+
+function CompareVerNums(const Ver1, Ver2: TPJVersionNumber): Integer;
+ {Compares two version numbers and returns a value indicating if the first is
+ less than, equal to or greater than the second.
+ @param Ver1 [in] First version number to compare.
+ @param Ver2 [in] Second version number to compare.
+ @return 0 if Ver1 = Ver2, -ve if Ver1 < Ver2, +ve if Ver1 > Ver2.
+ }
+
+procedure Register;
+ {Registers this component.
+ }
+
+
+implementation
+
+
+uses
+ {$IFDEF Supports_RTLNameSpaces}
+ System.SysUtils;
+ {$ELSE}
+ // Delphi
+ SysUtils;
+ {$ENDIF}
+
+
+procedure Register;
+ {Registers this component.
+ }
+begin
+ RegisterComponents('DelphiDabbler', [TPJVersionInfo]);
+end;
+
+type
+ // ANSI version of CPINFOEX: provides information about a code page
+ _cpinfoexA = packed record
+ MaxCharSize: UINT;
+ {max length in bytes of a character in the code page}
+ DefaultChar: array[0..MAX_DEFAULTCHAR-1] of Byte;
+ {default character used to translate strings to the specific code page}
+ LeadByte: array[0..MAX_LEADBYTES-1] of Byte;
+ {fixed-length array of lead byte ranges: all elements null if none}
+ UnicodeDefaultChar: WideChar;
+ {unicode default char used in translations from the specific code page}
+ CodePage: UINT;
+ {code page value}
+ CodePageName: array[0..MAX_PATH-1] of AnsiChar;
+ {full localised name of the code page}
+ end;
+ CPINFOEXA = _cpinfoexA;
+ PCPInfoExA = ^CPINFOEXA;
+ TCPInfoExA = CPINFOEXA;
+
+ // Unicode version of CPINFOEX: provides information about a code page
+ _cpinfoexW = packed record
+ MaxCharSize: UINT;
+ {max length in bytes of a character in the code page}
+ DefaultChar: array[0..MAX_DEFAULTCHAR-1] of Byte;
+ {default character used to translate strings to the specific code page}
+ LeadByte: array[0..MAX_LEADBYTES-1] of Byte;
+ {fixed-length array of lead byte ranges: all elements null if none}
+ UnicodeDefaultChar: WideChar;
+ {unicode default char used in translations from the specific code page}
+ CodePage: UINT;
+ {code page value}
+ CodePageName: array[0..MAX_PATH-1] of WideChar;
+ {full localised name of the code page}
+ end;
+ CPINFOEXW = _cpinfoexW;
+ PCPInfoExW = ^CPINFOEXW;
+ TCPInfoExW = CPINFOEXW;
+
+ // Set TCPInfoEx etc to required ANSI or Unicode version of structure
+ {$IFDEF UNICODE}
+ TCPInfoEx = TCPInfoExW;
+ PCPInfoEx = PCPInfoExW;
+ {$ELSE}
+ TCPInfoEx = TCPInfoExA;
+ PCPInfoEx = PCPInfoExA;
+ {$ENDIF}
+ CPINFOEX = TCPInfoEx;
+
+var
+ // Pointer to Windows API GetCPInfoEx function if it exists or to GetCPInfoAlt
+ // otherwise
+ GetCPInfoExFn: function (CodePage: UINT; dwFlags: DWORD;
+ var lpCPInfoEx: TCPInfoEx): BOOL; stdcall;
+
+const
+ // Import name of GetCPInfoEx. Unicode and ANSI versions.
+ {$IFDEF UNICODE}
+ cGetCPInfoEx = 'GetCPInfoExW';
+ {$ELSE}
+ cGetCPInfoEx = 'GetCPInfoExA';
+ {$ENDIF}
+
+function GetCPInfoAlt(CodePage: UINT; dwFlags: DWORD;
+ var lpCPInfoEx: TCPInfoEx): BOOL; stdcall;
+ {Local implementation of GetCPInfoEx, for use on OSs that don't support
+ GetCPInfoEx. Calls older GetCPInfo API function and calculates members of
+ TCPInfoEx not provided by GetCPInfo.
+ @param CodePage [in] Code page for which information is required.
+ @param dwFlags [in] Reserved. Must be 0.
+ @param lpCPInfoEx [in/out] Structure that receives information about the
+ code page.
+ @return True on success, False on error.
+ }
+ // ---------------------------------------------------------------------------
+ procedure CopyByteArray(const Src: array of Byte; var Dest: array of Byte);
+ {Makes a copy of a byte array.
+ @param Src [in] Byte array to be copied.
+ @param Dest [in/out] In: Array to receive copy: must be same size as Src.
+ Out: Receives copy of Src.
+ }
+ var
+ Idx: Integer; // loops thru array
+ begin
+ {$IFDEF Supports_Assert}
+ Assert((Low(Src) = Low(Dest)) and (High(Src) = High(Dest)));
+ {$ENDIF}
+ for Idx := Low(Src) to High(Src) do
+ Dest[Idx] := Src[Idx];
+ end;
+ // ---------------------------------------------------------------------------
+const
+ sCodePage = 'Code Page %d'; // description of code page if OS doesn't provide
+var
+ OldInfo: TCPInfo; // old style code page info structure for Win95/NT4
+begin
+ // We haven't got GetCPInfoEx: use old GetCPInfo to get some info
+ Result := GetCPInfo(CodePage, OldInfo);
+ if Result then
+ begin
+ // We update TCPInfoEx structure from old style structure and calculate
+ // additional info
+ // copy over from old style TCPInfo structure
+ lpCPInfoEx.MaxCharSize := OldInfo.MaxCharSize;
+ CopyByteArray(OldInfo.DefaultChar, lpCPInfoEx.DefaultChar);
+ CopyByteArray(OldInfo.LeadByte, lpCPInfoEx.LeadByte);
+ // no new default char
+ lpCPInfoEx.UnicodeDefaultChar := #0;
+ // store reference to code page
+ lpCPInfoEx.CodePage := CodePage;
+ // description is simply "Code Page NNN"
+ StrPLCopy(
+ lpCPInfoEx.CodePageName,
+ Format(sCodePage, [CodePage]),
+ SizeOf(lpCPInfoEx.CodePageName)
+ );
+ end;
+end;
+
+function VerNumToStr(const Ver: TPJVersionNumber): string;
+ {Converts a version number to its string representation as a dotted quad.
+ @param Ver [in] Version number to be converted.
+ @return Version number as dotted quad.
+ }
+begin
+ Result := Format('%d.%d.%d.%d', [Ver.V1, Ver.V2, Ver.V3, Ver.V4]);
+end;
+
+function CompareVerNums(const Ver1, Ver2: TPJVersionNumber): Integer;
+ {Compares two version numbers and returns a value indicating if the first is
+ less than, equal to or greater than the second.
+ @param Ver1 [in] First version number to compare.
+ @param Ver2 [in] Second version number to compare.
+ @return 0 if Ver1 = Ver2, -ve if Ver1 < Ver2, +ve if Ver1 > Ver2.
+ }
+begin
+ Result := Ver1.V1 - Ver2.V1;
+ if Result <> 0 then
+ Exit;
+ Result := Ver1.V2 - Ver2.V2;
+ if Result <> 0 then
+ Exit;
+ Result := Ver1.V3 - Ver2.V3;
+ if Result <> 0 then
+ Exit;
+ Result := Ver1.V4 - Ver2.V4;
+end;
+
+type
+ {
+ TTransRec:
+ Record of language code and char set codes that are returned from version
+ information.
+ }
+ TTransRec = packed record
+ Lang: Word; // language code
+ CharSet: Word; // character set code
+ end;
+ {
+ TTransRecs:
+ Type used to type cast translation data into an array of translation
+ records.
+ }
+ TTransRecs = array[0..1000] of TTransRec;
+ {
+ PTransRecs:
+ Pointer to an array of translation records.
+ }
+ PTransRecs = ^TTransRecs;
+
+
+{ TPJVersionInfo }
+
+procedure TPJVersionInfo.ClearProperties;
+ {Forces properties to return cleared values.
+ }
+begin
+ // Record that we haven't read ver info: this effectively clears properties
+ // since each property read access method checks this flag before returning
+ // result
+ fHaveInfo := False;
+end;
+
+constructor TPJVersionInfo.Create(AOwner: TComponent);
+ {Object constructor. Sets default values.
+ @param AOwner [in] Component that owns this one. May be nil.
+ }
+begin
+ inherited Create(AOwner);
+ // Default is no file name - refers to executable file for application
+ FileName := '';
+end;
+
+destructor TPJVersionInfo.Destroy;
+ {Object destructor. Frees allocated memory.
+ }
+begin
+ // Ensure that info buffer is freed if allocated
+ if fPInfoBuffer <> nil then
+ StrDispose(fPInfoBuffer);
+ // Ensure that translation buffer is free if allocated
+ if fPTransBuffer <> nil then
+ FreeMem(fPTransBuffer);
+ inherited Destroy;
+end;
+
+function TPJVersionInfo.GetCharSet: string;
+ {Read accessor for CharSet property:
+ @return String describing character set if version info is available or
+ empty string if not.
+ }
+var
+ Info: TCPInfoEx; // receives code page info
+ CP: Word; // code page
+const
+ // Special code page messages
+ sUnknownCP = '%d (Unknown Code Page)'; // unknown
+ // Messages for pages API can't return (managed apps only)
+ sUTF16LE = '%d (Unicode UTF-16, little endian byte order)';
+ sUTF16BE = '%d (Unicode UTF-16, big endian byte order)';
+ sUTF32LE = '%d (Unicode UTF-32, little endian byte order)';
+ sUTF32BE = '%d (Unicode UTF-32, big endian byte order)';
+begin
+ Result := '';
+ if fHaveInfo then
+ begin
+ CP := GetCharSetCode;
+ case CP of
+ // Check for char codes only available in managed apps (API call won't
+ // find them)
+ 1200: Result := Format(sUTF16LE, [CP]);
+ 1201: Result := Format(sUTF16BE, [CP]);
+ 12000: Result := Format(sUTF32LE, [CP]);
+ 12001: Result := Format(sUTF32BE, [CP]);
+ else
+ begin
+ // Not a known problem code page: get it from OS
+ if GetCPInfoExFn(CP, 0, Info) then
+ Result := Info.CodePageName
+ else
+ // Give up: can't find it
+ Result := Format(sUnknownCP, [CP]);
+ end;
+ end;
+ end;
+end;
+
+function TPJVersionInfo.GetCharSetCode: WORD;
+ {Read accessor for CharSetCode property.
+ @return Char set code for current translation or 0 if there is no
+ translation or there is no version info.
+ }
+begin
+ if fHaveInfo and (GetCurrentTranslation >= 0) then
+ Result := PTransRecs(fPTransBuffer)^[GetCurrentTranslation].CharSet
+ else
+ Result := 0;
+end;
+
+function TPJVersionInfo.GetCurrentTranslation: Integer;
+ {Read accessor for CurrentTranslation property.
+ @return Index to current translation if version info is available or -1 if
+ not.
+ }
+begin
+ if fHaveInfo then
+ Result := fCurrentTranslation
+ else
+ Result := -1;
+end;
+
+function TPJVersionInfo.GetFileVersionNumber: TPJVersionNumber;
+ {Read accessor for FileVersionNumber property.
+ @return Record containing version information. If there is no version info
+ then all fields will be zero.
+ }
+begin
+ Result.V1 := HiWord(fFixedFileInfo.dwFileVersionMS);
+ Result.V2 := LoWord(fFixedFileInfo.dwFileVersionMS);
+ Result.V3 := HiWord(fFixedFileInfo.dwFileVersionLS);
+ Result.V4 := LoWord(fFixedFileInfo.dwFileVersionLS);
+end;
+
+function TPJVersionInfo.GetFixedFileInfoItemByIdx(Index: Integer): DWORD;
+ {Read accessor method for various DWORD fields of the fixed file information
+ record accessed by index.
+ NOTE: This is a fix for C++ Builder. Delphi is able to access the fields of
+ the TVSFixedFileInfo record directly in the read clause of the property
+ declaration but this is not possible in C++ Builder.
+ @param Index [in] Index of required property.
+ @return Required DWORD value.
+ }
+begin
+ case Index of
+ 0: Result := fFixedFileInfo.dwFileOS;
+ 1: Result := fFixedFileInfo.dwFileType;
+ 2: Result := fFixedFileInfo.dwFileSubType;
+ 3: Result := fFixedFileInfo.dwFileFlagsMask;
+ 4: Result := fFixedFileInfo.dwFileFlags;
+ else Result := 0;
+ end;
+end;
+
+procedure TPJVersionInfo.GetInfoBuffer(Len: DWORD);
+ {Creates an info buffer of required size.
+ @param Len [in] Required buffer size in characters.
+ }
+begin
+ // Clear any existing buffer
+ if fPInfoBuffer <> nil then
+ StrDispose(fPInfoBuffer);
+ // Create the new one
+ fPInfoBuffer := StrAlloc(Len);
+end;
+
+function TPJVersionInfo.GetLanguage: string;
+ {Read accessor for Language property
+ @return String describing language or empty string if no version info
+ available.
+ }
+const
+ cBufSize = 256; // size of buffer
+var
+ Buf: array[0..Pred(cBufSize)] of Char; // stores langauge string from API call
+begin
+ // Assume failure
+ Result := '';
+ // Try to get language name from Win API if we have ver info
+ if fHaveInfo and
+ (VerLanguageName(GetLanguageCode, Buf, Pred(cBufSize)) > 0) then
+ Result := Buf;
+end;
+
+function TPJVersionInfo.GetLanguageCode: WORD;
+ {Read accessor for LanguageCode property
+ @return Language code for current translation or 0 if there is no
+ translation or there is no version info.
+ }
+begin
+ if fHaveInfo and (GetCurrentTranslation >= 0) then
+ Result := PTransRecs(fPTransBuffer)^[GetCurrentTranslation].Lang
+ else
+ Result := 0;
+end;
+
+function TPJVersionInfo.GetProductVersionNumber: TPJVersionNumber;
+ {Read accessor for ProductVersionNumber property.
+ @return Record containing version information. If there is no version info
+ then all fields will be zero.
+ }
+begin
+ Result.V1 := HiWord(fFixedFileInfo.dwProductVersionMS);
+ Result.V2 := LoWord(fFixedFileInfo.dwProductVersionMS);
+ Result.V3 := HiWord(fFixedFileInfo.dwProductVersionLS);
+ Result.V4 := LoWord(fFixedFileInfo.dwProductVersionLS);
+end;
+
+function TPJVersionInfo.GetStringFileInfo(const Name: string): string;
+ {Read accessor for StringFileInfo array property.
+ @param Name [in] Name of required string information.
+ @return String associated Name or empty string if there is no version info.
+ }
+var
+ CommandBuf: array[0..255] of char; // buffer to build API call command str
+ Ptr: Pointer; // pointer to result of API call
+ Len: UINT; // length of structure returned from API
+begin
+ // Set default failure result to empty string
+ Result := '';
+ // Check if we have valid information recorded in info buffer - exit if not
+ if fHaveInfo then
+ begin
+ // Build API call command string for reading string file info:
+ // this uses info string + language and character set
+ StrPCopy(CommandBuf, '\StringFileInfo\' + GetTransStr + '\' + Name);
+ // Call API to get required string and return it if successful
+ if VerQueryValue(fPInfoBuffer, CommandBuf, Ptr, Len) then
+ Result := PChar(Ptr);
+ end;
+end;
+
+function TPJVersionInfo.GetStringFileInfoByIdx(Index: Integer): string;
+ {Read accessor for all string file info properties.
+ @param Index [in] Index of required property.
+ @return Appropriate string value of the indexed property or empty string if
+ property has no value or there is no version info.
+ }
+const
+ cNames: array[0..11] of string =
+ ('Comments', 'CompanyName', 'FileDescription', 'FileVersion',
+ 'InternalName', 'LegalCopyright', 'LegalTrademarks', 'OriginalFileName',
+ 'PrivateBuild', 'ProductName', 'ProductVersion', 'SpecialBuild');
+ {names of predefined string file info strings}
+begin
+ Result := GetStringFileInfo(cNames[Index]);
+end;
+
+procedure TPJVersionInfo.GetTransBuffer(Len: UINT);
+ {Creates a translation table buffer of required size.
+ @param Required buffer size in bytes.
+ }
+begin
+ // Clear any existing buffer
+ if fPTransBuffer <> nil then
+ FreeMem(fPTransBuffer);
+ // Create the new one
+ GetMem(fPTransBuffer, Len);
+end;
+
+function TPJVersionInfo.GetTransStr: string;
+ {Encodes information about the current translation in a string.
+ @return Required translation information.
+ }
+var
+ TransRec: TTransRec; // translation record in array of translations
+begin
+ if GetCurrentTranslation >= 0 then
+ begin
+ // There is a valid current translation: return hex string related to it
+ TransRec := PTransRecs(fPTransBuffer)^[GetCurrentTranslation];
+ Result := Format('%4.4x%4.4x', [TransRec.Lang, TransRec.CharSet]);
+ end
+ else
+ // No valid translation string: return empty string
+ Result := '';
+end;
+
+procedure TPJVersionInfo.ReadVersionInfo;
+ {Reads version info from file named by FileName property.
+ }
+var
+ Len: UINT; // length of structs returned from API calls
+ Ptr: Pointer; // points to version info structures
+ InfoSize: DWORD; // size of info buffer
+ Dummy: DWORD; // stores 0 in call to GetFileVersionInfoSize
+begin
+ // Record default value of HaveInfo property - no info read
+ fHaveInfo := False;
+ // Store zeros in fixed file info structure: this is used when no info
+ FillChar(fFixedFileInfo, SizeOf(fFixedFileInfo), 0);
+ // Set NumTranslations property to 0: this is value if no info
+ fNumTranslations := 0;
+ // Record required size of version info buffer
+ InfoSize := GetFileVersionInfoSize(PChar(fFileName), Dummy);
+ // Check that there was no error
+ if InfoSize > 0 then
+ begin
+ // Found info size OK
+ // Ensure we have a sufficiently large buffer allocated
+ GetInfoBuffer(InfoSize);
+ // Read file version info into storage and check success
+ if GetFileVersionInfo(PChar(fFileName), Dummy, InfoSize, fPInfoBuffer) then
+ begin
+ // Success: we've read file version info to storage OK
+ fHaveInfo := True;
+ // Get fixed file info & copy to own storage
+ VerQueryValue(fPInfoBuffer, '\', Ptr, Len);
+ fFixedFileInfo := PVSFixedFileInfo(Ptr)^;
+ // Get first translation table info from API
+ VerQueryValue(fPInfoBuffer, '\VarFileInfo\Translation', Ptr, Len);
+ // Ptr is to block of translation records each of size Len:
+ // work out number of translations
+ fNumTranslations := Len div SizeOf(TTransRec);
+ // store translation array in a buffer
+ GetTransBuffer(Len);
+ Move(Ptr^, fPTransBuffer^, Len);
+ // make first translation in block current one (-1 if no translations)
+ SetCurrentTranslation(0); // adjusts value to -1 if no translations
+ end;
+ end;
+end;
+
+procedure TPJVersionInfo.SetCurrentTranslation(const Value: Integer);
+ {Write acceesor method CurrentTranslation property
+ @param Index of required translation. If Value is out of range then the
+ property is set to -1 to indicate no translation.
+ }
+begin
+ if (Value >= 0) and (Value < NumTranslations) then
+ fCurrentTranslation := Value
+ else
+ fCurrentTranslation := -1
+end;
+
+procedure TPJVersionInfo.SetFileName(AName: string);
+ {Write accessor for FileName property. Action at design time and run time is
+ different. At design time we simply record the property value while at run
+ time we store the value and read any version information from the file.
+ @param AName [in] New value of FileName property. If '' then property is set
+ to the name of the program's executable file.
+ }
+begin
+ if csDesigning in ComponentState then
+ // We are designing, simply record the required name
+ fFileName := AName
+ else
+ begin
+ // It's run-time
+ // use Application exec file name if name is ''
+ if AName = '' then
+ fFileName := ParamStr(0)
+ else
+ fFileName := AName;
+ // clear all properties and read file version info for new file
+ ClearProperties;
+ ReadVersionInfo;
+ end;
+end;
+
+{$IFDEF Supports_AdvancedRecords}
+
+{ TPJVersionNumber }
+
+class operator TPJVersionNumber.Equal(Ver1, Ver2: TPJVersionNumber): Boolean;
+ {Operator overload that compares two version numbers to check for equality.
+ @param Ver1 [in] First version number.
+ @param Ver2 [in] Second version number.
+ @return True if Ver1 = Ver2, False otherwise.
+ }
+begin
+ Result := CompareVerNums(Ver1, Ver2) = 0;
+end;
+
+class operator TPJVersionNumber.GreaterThan(Ver1,
+ Ver2: TPJVersionNumber): Boolean;
+ {Operator overload that compares two version numbers to check if first is
+ greater than second.
+ @param Ver1 [in] First version number.
+ @param Ver2 [in] Second version number.
+ @return True if Ver1 > Ver2, False otherwise.
+ }
+begin
+ Result := CompareVerNums(Ver1, Ver2) > 0;
+end;
+
+class operator TPJVersionNumber.GreaterThanOrEqual(Ver1,
+ Ver2: TPJVersionNumber): Boolean;
+ {Operator overload that compares two version numbers to check if first is
+ greater than or equal to the second.
+ @param Ver1 [in] First version number.
+ @param Ver2 [in] Second version number.
+ @return True if Ver1 >= Ver2, False otherwise.
+ }
+begin
+ Result := CompareVerNums(Ver1, Ver2) >= 0;
+end;
+
+class operator TPJVersionNumber.Implicit(Ver: TPJVersionNumber): string;
+ {Operator overload that performs implicit conversion of TPJVersionNumber to
+ string as dotted quad.
+ @param Ver [in] Version number to be converted.
+ @return Version number as dotted quad.
+ }
+begin
+ Result := VerNumToStr(Ver);
+end;
+
+class operator TPJVersionNumber.LessThan(Ver1, Ver2: TPJVersionNumber): Boolean;
+ {Operator overload that compares two version numbers to check if first is less
+ than second.
+ @param Ver1 [in] First version number.
+ @param Ver2 [in] Second version number.
+ @return True if Ver1 < Ver2, False otherwise.
+ }
+begin
+ Result := CompareVerNums(Ver1, Ver2) < 0;
+end;
+
+class operator TPJVersionNumber.LessThanOrEqual(Ver1,
+ Ver2: TPJVersionNumber): Boolean;
+ {Operator overload that compares two version numbers to check if first is less
+ than or equal to the second.
+ @param Ver1 [in] First version number.
+ @param Ver2 [in] Second version number.
+ @return True if Ver1 <= Ver2, False otherwise.
+ }
+begin
+ Result := CompareVerNums(Ver1, Ver2) <= 0;
+end;
+
+class operator TPJVersionNumber.NotEqual(Ver1, Ver2: TPJVersionNumber): Boolean;
+ {Operator overload that compares two version numbers to check for inequality.
+ @param Ver1 [in] First version number.
+ @param Ver2 [in] Second version number.
+ @return True if Ver1 <> Ver2, False otherwise.
+ }
+begin
+ Result := CompareVerNums(Ver1, Ver2) <> 0;
+end;
+
+{$ENDIF}
+
+
+initialization
+
+// Get reference to GetCPInfoEx function
+GetCPInfoExFn := GetProcAddress(GetModuleHandle('Kernel32.dll'), cGetCPInfoEx);
+if not Assigned(GetCPInfoExFn) then
+ GetCPInfoExFn := GetCPInfoAlt;
+
+end.
+
diff --git a/prereq/dd-verinfo/ReadMe.htm b/prereq/dd-verinfo/ReadMe.htm
new file mode 100644
index 0000000..88f4704
--- /dev/null
+++ b/prereq/dd-verinfo/ReadMe.htm
@@ -0,0 +1,451 @@
+
+
+
+
+
+
+
+ DelphiDabbler Version Information Component ReadMe
+
+
+
+
+
+
+
+
+
+ Version Information Component
+ ReadMe
+
+
+
+ Contents
+
+
+
+
+
+ Description
+
+
+
+ TPJVersionInfo is a 32 bit non-visual component for all Win32
+ versions of Delphi that encapsulates the version information contained in an
+ executable file's resources.
+
+
+
+ The component reads information from a designated file's
+ VERSIONINFO resource. The required file is specified in the
+ component's FileName property. Setting FileName to the
+ empty string fetches version information for the executable file containing
+ the component. The boolean HaveInfo property indicates whether the
+ file contains version information. This component can access variable file
+ information for each language provided in the resource.
+
+
+
+ Run-time properties enable access to to version information. Properties
+ enable:
+
+
+
+
+ Access to fixed file information, either by field or the whole record.
+
+
+ Access to the number of translations stored in the version information.
+
+
+ Selection of the translation for which information is to be returned by
+ other properties.
+
+
+ Access to the language and code page of the current translation – by
+ code and by name.
+
+
+ Access to the string file information for the current translation –
+ named properties access the Microsoft-defined string information, while an
+ array property gives access to any string item by name.
+
+
+
+
+ Version numbers are encapsulated in TPJVersionNumber records which,
+ on Delphi 2006 or later, can be directly assigned to a string and can be
+ compared using the normal equality operators. Helper functions are also
+ provided for use with earlier Delphis that can format version numbers as text
+ and can compare them.
+
+
+
+ Limitations
+
+
+
+ The component makes calls to the Windows API. Therefore the version
+ information being read must follow the Microsoft guidelines – be warned
+ that not all software complies!
+
+
+
+ Compatibility
+
+
+
+ TPJVersionInfo compiles on all Win32 versions and personalities of
+ Delphi. Releases up v3.3 have tested with Delphi versions 2, 3, 4, 6, 7, 2006
+ and 2010 while later releases have been tested on Delphi 7 and 2006 to XE3 and
+ are assumed to work on later versions.
+
+
+
+ The unit name changed to PJVersionInfo
at release 3 – this
+ means that programs using earlier versions will need to be modified (or to
+ have an alias set in Delphi's Project Options) before being recompiled using
+ the new version. Functionally, the component is backward compatible with
+ earlier versions.
+
+
+
+ Further information
+
+
+
+ For detailed information about version information refer to the Windows SDK.
+
+
+
+ Installation
+
+
+
+ Important Note: If you are updating from an earlier version
+ of this component and have installed the DelphiDabbler About Box
+ Component (TPJAboutBoxDlg ) you may need to uninstall it before
+ updating this component, and re-install the about box component once the
+ update has been installed. If the About Box Component is earlier that v3.2 it
+ will need to be updated to the most recent version.
+
+
+
+ The Version Information Component is supplied in a zip file. Before
+ installing you need to extract all the files from the zip file. The following
+ files will be extracted:
+
+
+
+
+ PJVersionInfo.pas
– Component source
+ code.
+
+
+ PJVersionInfo.dcr
– Component palette
+ glyph.
+
+
+ PJVersionInfo.hlp
– Help file that integrates into the
+ Delphi 3-7 IDE.
+
+
+ PJVersionInfo.als
– Keyword file required when
+ integrating the help file with Delphi 6 and 7.
+
+
+ ReadMe.htm
– This read-me file.
+
+
+ ChangeLog.txt
– Change log.
+
+
+ MPL-2.txt
– Mozilla Public License v2.0.
+
+
+ Documentation.URL
– Shortcut to the component's online
+ documentation.
+
+
+
+
+ In addition to the above files you will find the the source code of two demo projects along with readme files in the Demos\1
and
+ Demos\2
sub-directories.
+
+
+
+ You can now install the component into the Delphi IDE.
+
+
+
+ For Delphi 3 onwards you must include PJVersionInfo.pas
and
+ PJVersionInfo.dcr
in a design time package that is installed into
+ the Delphi IDE. If you need help doing this see here .
+
+
+
+ Note that the help file included in the download can only integrate with the
+ IDE in Delphi 3-7. For information on how to do this, see this article . Users of other versions of Delphi can either use the help
+ file as a stand-alone file (in which case some links won't work) or you can
+ use the component's online documentation .
+
+
+
+ Demo Projects
+
+
+
+ The source code for two demo projects is included. The demos are:
+
+
+
+
+ VIDemo.dpr
is an application that can extract and display
+ version information from any program (provided that the program has valid
+ version information).
+
+
+ HelpEgs.dpr
implements all the examples from the online documentation and help file.
+
+
+
+
+ These demos require Delphi 7 or later.
+
+
+
+ Note: To load the projects into Delphi 2007 first delete the
+ relevant .dproj
file and then load the project from the
+ .bdsproj
file.
+
+
+
+ With some minor changes they will also compile as 64 bit Windows targets using
+ the 64 bit Delphi. (Tested with Delphi XE3). To do this create a 64 bit
+ Windows target, ensure that the compiler can find the component source file
+ (or a 64 bit compiled unit) and disable automatic version information
+ generation.
+
+
+
+ Update History
+
+
+
+ A complete change log is provided in a text file that is included in the
+ download.
+
+
+
+ License
+
+
+
+ This component is released under the terms of the Mozilla Public License v2.0 .
+
+
+
+ Bugs and Feature Requests
+
+
+
+ Bugs can be reported or new features requested via the Issue Tracker .
+
+
+
+ If no similar report or request has been recorded already, use the New
+ Issue link to add a new issue. Please select the Defect Report from
+ User template and be sure to specify the Project-verinfo
+ label.
+
+
+
+ Feature requests are also made using the Issue Tracker. This time please
+ select the Feature Request template and, again, specify the
+ Project-verinfo
label.
+
+
+
+ About the Author
+
+
+
+ I'm Peter Johnson – a hobbyist programmer living in Ceredigion in West
+ Wales, UK, writing write mainly in Delphi. My programs and code are
+ available from: http://www.delphidabbler.com/ .
+
+
+
+ I can be contacted via the website .
+
+
+
+
+
+
+
diff --git a/prereq/dd-verinfo/dd_versioninfo.lpk b/prereq/dd-verinfo/dd_versioninfo.lpk
new file mode 100644
index 0000000..2a1a3d7
--- /dev/null
+++ b/prereq/dd-verinfo/dd_versioninfo.lpk
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/prereq/dd-verinfo/dd_versioninfo.pas b/prereq/dd-verinfo/dd_versioninfo.pas
new file mode 100644
index 0000000..0d3c7bc
--- /dev/null
+++ b/prereq/dd-verinfo/dd_versioninfo.pas
@@ -0,0 +1,21 @@
+{ This file was automatically created by Lazarus. Do not edit!
+ This source is only used to compile and install the package.
+ }
+
+unit dd_versioninfo;
+
+interface
+
+uses
+ PJVersionInfo, LazarusPackageIntf;
+
+implementation
+
+procedure Register;
+begin
+ RegisterUnit('PJVersionInfo', @PJVersionInfo.Register);
+end;
+
+initialization
+ RegisterPackage('dd_versioninfo', @Register);
+end.
diff --git a/prereq/fwzip/Demos/Create ZIP 1/CreateZIPDemo1.dpr b/prereq/fwzip/Demos/Create ZIP 1/CreateZIPDemo1.dpr
new file mode 100644
index 0000000..20656a1
--- /dev/null
+++ b/prereq/fwzip/Demos/Create ZIP 1/CreateZIPDemo1.dpr
@@ -0,0 +1,184 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ****************************************************************************
+// * Project : FWZip
+// * Unit Name : CreateZIPDemo1
+// * Purpose :
+// * :
+// * Author : (Rouse_)
+// * Copyright : Fangorn Wizards Lab 1998 - 2013.
+// * Version : 1.0.10
+// * Home Page : http://rouse.drkb.ru
+// * Home Blog : http://alexander-bagel.blogspot.ru
+// ****************************************************************************
+// * Stable Release : http://rouse.drkb.ru/components.php#fwzip
+// * Latest Source : https://github.com/AlexanderBagel/FWZip
+// ****************************************************************************
+//
+// :
+// ftp://ftp.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
+// http://zlib.net/zlib-1.2.5.tar.gz
+// http://www.base2ti.com/
+//
+
+//
+//
+
+program CreateZIPDemo1;
+
+{$APPTYPE CONSOLE}
+
+uses
+ SysUtils,
+ Classes,
+ TypInfo, zlib,
+ FWZipWriter;
+
+procedure CheckResult(Value: Integer);
+ begin
+ if Value < 0 then
+ raise Exception.Create(' ');
+ end;
+
+var
+ Zip: TFWZipWriter;
+ S: TStringStream;
+ PresentFiles: TStringList;
+ SR: TSearchRec;
+ I, ItemIndex: Integer;
+ BuildZipResult: TBuildZipResult;
+begin
+ SetCurrentDir(ExtractFilePath(ParamStr(0)));
+ try
+ Zip := TFWZipWriter.Create;
+ try
+ // UTF8 ( )
+ Zip.UseUTF8String := True;
+
+ //
+ Zip.Comment := ' ';
+
+ //
+ //
+
+ // (AddStream)
+ S := TStringStream.Create(' 1');
+ try
+ S.Position := 0;
+ ItemIndex := Zip.AddStream('test.txt', S);
+ CheckResult(ItemIndex);
+ //
+ Zip.Item[ItemIndex].Comment := ' ';
+
+ //TCompressionStream.Create(clDefault, S);
+ finally
+ S.Free;
+ end;
+
+ //
+ // ,
+ S := TStringStream.Create(' 2');
+ try
+ S.Position := 0;
+ CheckResult(Zip.AddStream(
+ 'AddStreamData\SubFolder1\Subfolder2\Test.txt', S));
+ finally
+ S.Free;
+ end;
+
+ //
+ //
+
+ // :
+ // "Create ZIP 2"
+ // AddFolder
+ if Zip.AddFolder('..\Create ZIP 2\') = 0 then
+ raise Exception.Create(' ');
+
+ // :
+ // AddFolderDemo
+ // AddFolder,
+ //
+ // ( )
+ if Zip.AddFolder('AddFolderDemo', '..\..\', '*.*', False) = 0 then
+ raise Exception.Create(' ');
+
+ // . - ,
+ // AddFile
+ PresentFiles := TStringList.Create;
+ try
+ //
+ if FindFirst('..\..\*.pas', faAnyFile, SR) = 0 then
+ try
+ repeat
+ if (SR.Name = '.') or (SR.Name = '..') then Continue;
+ if SR.Attr and faDirectory <> 0 then
+ Continue
+ else
+ PresentFiles.Add(SR.Name);
+ until FindNext(SR) <> 0;
+ finally
+ FindClose(SR);
+ end;
+
+ // ,
+ // .
+ for I := 0 to PresentFiles.Count - 1 do
+ CheckResult(Zip.AddFile('..\..\' + PresentFiles[I],
+ 'AddFile\' + PresentFiles[I]));
+
+ // - AddFiles.
+ // :
+ // " "=" "
+ // .. ValueFromIndex ,
+ // Names -
+ // , .
+ for I := 0 to PresentFiles.Count - 1 do
+ PresentFiles[I] :=
+ 'AddFiles\' + PresentFiles[I] + '=' + '..\..\' + PresentFiles[I];
+ if Zip.AddFiles(PresentFiles) <> PresentFiles.Count then
+ raise Exception.Create(' ');
+
+ finally
+ PresentFiles.Free;
+ end;
+
+ // , - ,
+ // . AddFilesAndFolders.
+ // - AddFiles.
+ // : " "=" "
+ // .. ValueFromIndex ,
+ // Names -
+
+ //
+ PresentFiles := TStringList.Create;
+ try
+ if FindFirst('..\..\*.*', faAnyFile, SR) = 0 then
+ try
+ repeat
+ if (SR.Name = '.') or (SR.Name = '..') then Continue;
+ PresentFiles.Add('AddFilesAndFolders\' + SR.Name + '=..\..\' + SR.Name);
+ until FindNext(SR) <> 0;
+ finally
+ FindClose(SR);
+ end;
+ Zip.AddFilesAndFolders(PresentFiles, True);
+ finally
+ PresentFiles.Free;
+ end;
+
+ // - ...
+ ForceDirectories('..\DemoResults\');
+ BuildZipResult := Zip.BuildZip('..\DemoResults\CreateZIPDemo1.zip');
+ // ...
+ Writeln(GetEnumName(TypeInfo(TBuildZipResult), Integer(BuildZipResult)));
+
+ finally
+ Zip.Free;
+ end;
+ except
+ on E: Exception do
+ Writeln(E.ClassName, ': ', E.Message);
+ end;
+ Readln;
+end.
diff --git a/prereq/fwzip/Demos/Create ZIP 1/CreateZIPDemo1.dproj b/prereq/fwzip/Demos/Create ZIP 1/CreateZIPDemo1.dproj
new file mode 100644
index 0000000..efed644
--- /dev/null
+++ b/prereq/fwzip/Demos/Create ZIP 1/CreateZIPDemo1.dproj
@@ -0,0 +1,619 @@
+
+
+ {F600CDA0-59E1-4BAD-8C76-ED197FA14494}
+ CreateZIPDemo1.dpr
+ True
+ Debug
+ 1
+ Console
+ None
+ 14.6
+ Win32
+
+
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ false
+ false
+ false
+ false
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=;CFBundleDisplayName=;UIDeviceFamily=;CFBundleIdentifier=;CFBundleVersion=;CFBundlePackageType=;CFBundleSignature=;CFBundleAllowMixedLocalizations=;UISupportedInterfaceOrientations=;CFBundleExecutable=;CFBundleResourceSpecification=;LSRequiresIPhoneOS=;CFBundleInfoDictionaryVersion=;CFBundleDevelopmentRegion=
+ false
+ 1049
+ System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)
+ 00400000
+
+
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=
+ Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
+ 1033
+
+
+ false
+ false
+ 0
+ RELEASE;$(DCC_Define)
+
+
+ DEBUG;$(DCC_Define)
+ false
+ true
+
+
+
+ MainSource
+
+
+ Cfg_2
+ Base
+
+
+ Base
+
+
+ Cfg_1
+ Base
+
+
+
+ Delphi.Personality.12
+
+
+
+
+ CreateZIPDemo1.dpr
+
+
+ False
+ False
+ 1
+ 0
+ 0
+ 0
+ False
+ False
+ False
+ False
+ False
+ 1049
+ 1251
+
+
+
+
+ 1.0.0.0
+
+
+
+
+
+ 1.0.0.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+ True
+ False
+
+
+ 12
+
+
+
+
+
+
diff --git a/prereq/fwzip/Demos/Create ZIP 2/CreateZIPDemo2.dpr b/prereq/fwzip/Demos/Create ZIP 2/CreateZIPDemo2.dpr
new file mode 100644
index 0000000..5f206df
--- /dev/null
+++ b/prereq/fwzip/Demos/Create ZIP 2/CreateZIPDemo2.dpr
@@ -0,0 +1,81 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ****************************************************************************
+// * Project : FWZip
+// * Unit Name : CreateZIPDemo2
+// * Purpose :
+// * Author : (Rouse_)
+// * Copyright : Fangorn Wizards Lab 1998 - 2013.
+// * Version : 1.0.10
+// * Home Page : http://rouse.drkb.ru
+// * Home Blog : http://alexander-bagel.blogspot.ru
+// ****************************************************************************
+// * Stable Release : http://rouse.drkb.ru/components.php#fwzip
+// * Latest Source : https://github.com/AlexanderBagel/FWZip
+// ****************************************************************************
+//
+// :
+// ftp://ftp.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
+// http://zlib.net/zlib-1.2.5.tar.gz
+// http://www.base2ti.com/
+//
+
+//
+// .
+
+program CreateZIPDemo2;
+
+{$APPTYPE CONSOLE}
+
+uses
+ SysUtils,
+ TypInfo,
+ FWZipZLib,
+ FWZipWriter;
+
+var
+ Zip: TFWZipWriter;
+ Item: TFWZipWriterItem;
+ I: Integer;
+ BuildZipResult: TBuildZipResult;
+begin
+ SetCurrentDir(ExtractFilePath(ParamStr(0)));
+ try
+ Zip := TFWZipWriter.Create;
+ try
+ //
+ Zip.AddFolder('..\..\', False);
+
+ // :
+ for I := 0 to Zip.Count - 1 do
+ begin
+ Item := Zip[I];
+ //
+ Item.Comment := ' ' + Item.FileName;
+ //
+ Item.Password := 'password';
+ //
+ Item.CompressionLevel := TCompressionLevel(Byte(I mod 3));
+ end;
+
+ // ,
+ //
+ // .
+ // - .
+ Zip.Comment := ' ';
+
+ //
+ ForceDirectories('..\DemoResults\');
+ BuildZipResult := Zip.BuildZip('..\DemoResults\CreateZIPDemo2.zip');
+ // ...
+ Writeln(GetEnumName(TypeInfo(TBuildZipResult), Integer(BuildZipResult)));
+
+ finally
+ Zip.Free;
+ end;
+ except
+ on E: Exception do
+ Writeln(E.ClassName, ': ', E.Message);
+ end;
+ Readln;
+end.
diff --git a/prereq/fwzip/Demos/Create ZIP 2/CreateZIPDemo2.dproj b/prereq/fwzip/Demos/Create ZIP 2/CreateZIPDemo2.dproj
new file mode 100644
index 0000000..ddf423a
--- /dev/null
+++ b/prereq/fwzip/Demos/Create ZIP 2/CreateZIPDemo2.dproj
@@ -0,0 +1,619 @@
+
+
+ {15CDC38C-E807-44D8-BC70-FBEB85865A1B}
+ CreateZIPDemo2.dpr
+ True
+ Debug
+ 1
+ Console
+ None
+ 14.6
+ Win32
+
+
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ false
+ false
+ false
+ false
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=;CFBundleDisplayName=;UIDeviceFamily=;CFBundleIdentifier=;CFBundleVersion=;CFBundlePackageType=;CFBundleSignature=;CFBundleAllowMixedLocalizations=;UISupportedInterfaceOrientations=;CFBundleExecutable=;CFBundleResourceSpecification=;LSRequiresIPhoneOS=;CFBundleInfoDictionaryVersion=;CFBundleDevelopmentRegion=
+ false
+ 1049
+ System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)
+ 00400000
+
+
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=
+ Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
+ 1033
+
+
+ false
+ false
+ 0
+ RELEASE;$(DCC_Define)
+
+
+ DEBUG;$(DCC_Define)
+ false
+ true
+
+
+
+ MainSource
+
+
+ Cfg_2
+ Base
+
+
+ Base
+
+
+ Cfg_1
+ Base
+
+
+
+ Delphi.Personality.12
+
+
+
+
+ CreateZIPDemo2.dpr
+
+
+ False
+ False
+ 1
+ 0
+ 0
+ 0
+ False
+ False
+ False
+ False
+ False
+ 1049
+ 1251
+
+
+
+
+ 1.0.0.0
+
+
+
+
+
+ 1.0.0.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+ True
+ False
+
+
+ 12
+
+
+
+
+
+
diff --git a/prereq/fwzip/Demos/Extract ZIP 1/ExctractZIPDemo1.dpr b/prereq/fwzip/Demos/Extract ZIP 1/ExctractZIPDemo1.dpr
new file mode 100644
index 0000000..b9abf47
--- /dev/null
+++ b/prereq/fwzip/Demos/Extract ZIP 1/ExctractZIPDemo1.dpr
@@ -0,0 +1,101 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ****************************************************************************
+// * Project : FWZip
+// * Unit Name : ExctractZIPDemo1
+// * Purpose : .
+// * : CreateZIPDemo1
+// * Author : (Rouse_)
+// * Copyright : Fangorn Wizards Lab 1998 - 2013.
+// * Version : 1.0.10
+// * Home Page : http://rouse.drkb.ru
+// * Home Blog : http://alexander-bagel.blogspot.ru
+// ****************************************************************************
+// * Stable Release : http://rouse.drkb.ru/components.php#fwzip
+// * Latest Source : https://github.com/AlexanderBagel/FWZip
+// ****************************************************************************
+//
+// :
+// ftp://ftp.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
+// http://zlib.net/zlib-1.2.5.tar.gz
+// http://www.base2ti.com/
+//
+
+// .
+
+program ExctractZIPDemo1;
+
+{$APPTYPE CONSOLE}
+
+uses
+ Windows,
+ Classes,
+ SysUtils,
+ TypInfo,
+ FWZipReader;
+
+function ExtractResultStr(Value: TExtractResult): string;
+begin
+ Result := GetEnumName(TypeInfo(TExtractResult), Integer(Value));
+end;
+
+var
+ Zip: TFWZipReader;
+ Index: Integer;
+ S: TStringStream;
+ OemString: AnsiString;
+begin
+ SetCurrentDir(ExtractFilePath(ParamStr(0)));
+ try
+ Zip := TFWZipReader.Create;
+ try
+ //
+ Zip.LoadFromFile('..\DemoResults\CreateZIPDemo1.zip');
+
+ // -
+
+ // CreateZIPDemo1 Test.txt
+ //
+ Index := Zip.GetElementIndex('test.txt');
+ if Index >= 0 then
+ begin
+ // :
+ S := TStringStream.Create('');
+ try
+ Zip[Index].ExtractToStream(S, '');
+ // ,
+ {$IFDEF UNICODE}
+ Writeln(OemString);
+ {$ELSE}
+ OemString := AnsiString(S.DataString);
+ AnsiToOem(PAnsiChar(OemString), PAnsiChar(OemString));
+ Writeln(OemString);
+ {$ENDIF}
+ finally
+ S.Free;
+ end;
+
+ // - :
+ Write('Extract "', Zip[Index].FileName, '": ');
+ Writeln(ExtractResultStr(
+ Zip[Index].Extract('..\DemoResults\CreateZIPDemo1\ManualExtract\', '')));
+ end;
+
+ // -
+
+ // -
+ //
+ Zip.ExtractAll('..\DemoResults\CreateZIPDemo1\');
+
+ // -
+ // ( AddFolderDemo )
+ Zip.ExtractAll('AddFolderDemo*', '..\DemoResults\CreateZIPDemo1\ExtractMasked\');
+ finally
+ Zip.Free;
+ end;
+ except
+ on E: Exception do
+ Writeln(E.ClassName, ': ', E.Message);
+ end;
+ Readln;
+end.
diff --git a/prereq/fwzip/Demos/Extract ZIP 1/ExctractZIPDemo1.dproj b/prereq/fwzip/Demos/Extract ZIP 1/ExctractZIPDemo1.dproj
new file mode 100644
index 0000000..877f4a1
--- /dev/null
+++ b/prereq/fwzip/Demos/Extract ZIP 1/ExctractZIPDemo1.dproj
@@ -0,0 +1,619 @@
+
+
+ {B06883A2-58D3-4606-BFC2-63551788655E}
+ ExctractZIPDemo1.dpr
+ True
+ Debug
+ 1
+ Console
+ None
+ 14.6
+ Win32
+
+
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ false
+ false
+ false
+ false
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=;CFBundleDisplayName=;UIDeviceFamily=;CFBundleIdentifier=;CFBundleVersion=;CFBundlePackageType=;CFBundleSignature=;CFBundleAllowMixedLocalizations=;UISupportedInterfaceOrientations=;CFBundleExecutable=;CFBundleResourceSpecification=;LSRequiresIPhoneOS=;CFBundleInfoDictionaryVersion=;CFBundleDevelopmentRegion=
+ false
+ 1049
+ System;Xml;Data;Datasnap;Web;Soap;Winapi;$(DCC_Namespace)
+ 00400000
+
+
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=
+ System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
+ 1033
+
+
+ false
+ false
+ 0
+ RELEASE;$(DCC_Define)
+
+
+ DEBUG;$(DCC_Define)
+ false
+ true
+
+
+
+ MainSource
+
+
+ Cfg_2
+ Base
+
+
+ Base
+
+
+ Cfg_1
+ Base
+
+
+
+ Delphi.Personality.12
+
+
+
+
+ ExctractZIPDemo1.dpr
+
+
+ False
+ False
+ 1
+ 0
+ 0
+ 0
+ False
+ False
+ False
+ False
+ False
+ 1049
+ 1251
+
+
+
+
+ 1.0.0.0
+
+
+
+
+
+ 1.0.0.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+ True
+ False
+
+
+ 12
+
+
+
+
+
+
diff --git a/prereq/fwzip/Demos/Extract ZIP 2/ExctractZIPDemo2.dpr b/prereq/fwzip/Demos/Extract ZIP 2/ExctractZIPDemo2.dpr
new file mode 100644
index 0000000..e0da832
--- /dev/null
+++ b/prereq/fwzip/Demos/Extract ZIP 2/ExctractZIPDemo2.dpr
@@ -0,0 +1,126 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ****************************************************************************
+// * Project : FWZip
+// * Unit Name : ExctractZIPDemo2
+// * Purpose : .
+// * Author : (Rouse_)
+// * Copyright : Fangorn Wizards Lab 1998 - 2013.
+// * Version : 1.0.10
+// * Home Page : http://rouse.drkb.ru
+// * Home Blog : http://alexander-bagel.blogspot.ru
+// ****************************************************************************
+// * Stable Release : http://rouse.drkb.ru/components.php#fwzip
+// * Latest Source : https://github.com/AlexanderBagel/FWZip
+// ****************************************************************************
+//
+// :
+// ftp://ftp.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
+// http://zlib.net/zlib-1.2.5.tar.gz
+// http://www.base2ti.com/
+//
+
+// .
+// ,
+// .
+//
+// .
+
+program ExctractZIPDemo2;
+
+{$APPTYPE CONSOLE}
+
+uses
+ SysUtils,
+ FWZipWriter,
+ FWZipReader,
+ FWZipConsts;
+
+const
+ PasswordList: array [0..3] of string = (
+ '', 'password1', 'password2', 'password3');
+
+procedure OnPassword(Self, Sender: TObject; const FileName: string;
+ var Password: string; var CancelExtract: Boolean);
+begin
+ Password := PasswordList[3];
+end;
+
+var
+ Writer: TFWZipWriter;
+ Reader: TFWZipReader;
+ Item: TFWZipWriterItem;
+ I: Integer;
+ ExtractResult: TExtractResult;
+ Method: TMethod;
+begin
+ SetCurrentDir(ExtractFilePath(ParamStr(0)));
+ try
+ Writer := TFWZipWriter.Create;
+ try
+
+ //
+ Writer.AddFolder('..\..\', False);
+
+ //
+ Randomize;
+
+ // ( )
+ Item := Writer[0];
+ Item.Password := PasswordList[Random(3) + 1];
+ Item.NeedDescriptor := True;
+
+ for I := 1 to Writer.Count - 1 do
+ begin
+ Item := Writer[I];
+ //
+ // . Readme.txt
+ Item.NeedDescriptor := True;
+ Item.Password := PasswordList[Random(4)];
+ end;
+
+ //
+ ForceDirectories('..\DemoResults\');
+ Writer.BuildZip('..\DemoResults\ExctractZIPDemo2.zip');
+ finally
+ Writer.Free;
+ end;
+
+ Reader := TFWZipReader.Create;
+ try
+ Reader.LoadFromFile('..\DemoResults\ExctractZIPDemo2.zip');
+
+ //
+ //
+ // :
+ I := 0;
+ repeat
+ ExtractResult := Reader[0].Extract(
+ '..\DemoResults\ExctractZIPDemo2\ManualExtract\', PasswordList[I]);
+ Inc(I);
+ until ExtractResult <> erNeedPassword;
+
+ // ,
+ //
+
+ // 1.
+ Reader.PasswordList.Add(PasswordList[1]);
+ Reader.PasswordList.Add(PasswordList[2]);
+
+ // 2.
+ Method.Code := @OnPassword;
+ Method.Data := Reader;
+ Reader.OnPassword := TZipNeedPasswordEvent(Method);
+
+ //
+ // OnPassword
+
+ Reader.ExtractAll('..\DemoResults\ExctractZIPDemo2\');
+ finally
+ Reader.Free;
+ end;
+ except
+ on E: Exception do
+ Writeln(E.ClassName, ': ', E.Message);
+ end;
+end.
diff --git a/prereq/fwzip/Demos/Extract ZIP 2/ExctractZIPDemo2.dproj b/prereq/fwzip/Demos/Extract ZIP 2/ExctractZIPDemo2.dproj
new file mode 100644
index 0000000..8a5fd07
--- /dev/null
+++ b/prereq/fwzip/Demos/Extract ZIP 2/ExctractZIPDemo2.dproj
@@ -0,0 +1,619 @@
+
+
+ {307D5F68-F671-4EF6-85EA-CF49C71350C7}
+ ExctractZIPDemo2.dpr
+ True
+ Debug
+ 1
+ Console
+ None
+ 14.6
+ Win32
+
+
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ false
+ false
+ false
+ false
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=;CFBundleDisplayName=;UIDeviceFamily=;CFBundleIdentifier=;CFBundleVersion=;CFBundlePackageType=;CFBundleSignature=;CFBundleAllowMixedLocalizations=;UISupportedInterfaceOrientations=;CFBundleExecutable=;CFBundleResourceSpecification=;LSRequiresIPhoneOS=;CFBundleInfoDictionaryVersion=;CFBundleDevelopmentRegion=
+ false
+ 1049
+ System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)
+ 00400000
+
+
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=
+ Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
+ 1033
+
+
+ false
+ false
+ 0
+ RELEASE;$(DCC_Define)
+
+
+ DEBUG;$(DCC_Define)
+ false
+ true
+
+
+
+ MainSource
+
+
+ Cfg_2
+ Base
+
+
+ Base
+
+
+ Cfg_1
+ Base
+
+
+
+ Delphi.Personality.12
+
+
+
+
+ ExctractZIPDemo2.dpr
+
+
+ False
+ False
+ 1
+ 0
+ 0
+ 0
+ False
+ False
+ False
+ False
+ False
+ 1049
+ 1251
+
+
+
+
+ 1.0.0.0
+
+
+
+
+
+ 1.0.0.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+ True
+ False
+
+
+ 12
+
+
+
+
+
+
diff --git a/prereq/fwzip/Demos/FWZipDemos.bpg b/prereq/fwzip/Demos/FWZipDemos.bpg
new file mode 100644
index 0000000..e484fae
--- /dev/null
+++ b/prereq/fwzip/Demos/FWZipDemos.bpg
@@ -0,0 +1,46 @@
+#------------------------------------------------------------------------------
+VERSION = BWS.01
+#------------------------------------------------------------------------------
+!ifndef ROOT
+ROOT = $(MAKEDIR)\..
+!endif
+#------------------------------------------------------------------------------
+MAKE = $(ROOT)\bin\make.exe -$(MAKEFLAGS) -f$**
+DCC = $(ROOT)\bin\dcc32.exe $**
+BRCC = $(ROOT)\bin\brcc32.exe $**
+#------------------------------------------------------------------------------
+PROJECTS = CreateZIPDemo1.exe CreateZIPDemo2.exe ExctractZIPDemo1.exe \
+ ExctractZIPDemo2.exe FWZipPerfomance.exe BuildWithException.exe \
+ UseExDataBlob.exe ZipAnalizer.exe ZipAnalizer2.exe
+#------------------------------------------------------------------------------
+default: $(PROJECTS)
+#------------------------------------------------------------------------------
+
+CreateZIPDemo1.exe: Create ZIP 1\CreateZIPDemo1.dpr
+ $(DCC)
+
+CreateZIPDemo2.exe: Create ZIP 2\CreateZIPDemo2.dpr
+ $(DCC)
+
+ExctractZIPDemo1.exe: Extract ZIP 1\ExctractZIPDemo1.dpr
+ $(DCC)
+
+ExctractZIPDemo2.exe: Extract ZIP 2\ExctractZIPDemo2.dpr
+ $(DCC)
+
+FWZipPerfomance.exe: PerfomanceTest\FWZipPerfomance.dpr
+ $(DCC)
+
+BuildWithException.exe: Test Build With Exception\BuildWithException.dpr
+ $(DCC)
+
+UseExDataBlob.exe: Use ZIP ExData\UseExDataBlob.dpr
+ $(DCC)
+
+ZipAnalizer.exe: ZipAnalizer\ZipAnalizer.dpr
+ $(DCC)
+
+ZipAnalizer2.exe: ZipAnalizer2\ZipAnalizer2.dpr
+ $(DCC)
+
+
diff --git a/prereq/fwzip/Demos/FWZipDemos.groupproj b/prereq/fwzip/Demos/FWZipDemos.groupproj
new file mode 100644
index 0000000..e98bd9f
--- /dev/null
+++ b/prereq/fwzip/Demos/FWZipDemos.groupproj
@@ -0,0 +1,132 @@
+
+
+ {DEBDAF2E-104F-436D-8AFC-8BAC60505E64}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Default.Personality.12
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/prereq/fwzip/Demos/PerfomanceTest/FWZipPerfomance.dproj b/prereq/fwzip/Demos/PerfomanceTest/FWZipPerfomance.dproj
new file mode 100644
index 0000000..dcbf901
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/FWZipPerfomance.dproj
@@ -0,0 +1,174 @@
+
+
+ {BEF6069D-A5FD-48FE-A930-0CE57B83DC93}
+ FWZipPerfomance.dpr
+ True
+ Debug
+ 3
+ Application
+ VCL
+ 14.6
+ Win64
+
+
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Cfg_2
+ true
+ true
+
+
+ false
+ 00400000
+ false
+ 1049
+ Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;Winapi;$(DCC_Namespace)
+ false
+ false
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=;CFBundleDisplayName=;UIDeviceFamily=;CFBundleIdentifier=;CFBundleVersion=;CFBundlePackageType=;CFBundleSignature=;CFBundleAllowMixedLocalizations=;UISupportedInterfaceOrientations=;CFBundleExecutable=;CFBundleResourceSpecification=;LSRequiresIPhoneOS=;CFBundleInfoDictionaryVersion=;CFBundleDevelopmentRegion=
+ false
+
+
+ System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
+ true
+ 1033
+ FWZipPerfomance_Icon.ico
+ $(BDS)\bin\default_app.manifest
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=
+
+
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=
+ System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)
+ 1033
+ true
+ $(BDS)\bin\default_app.manifest
+ FWZipPerfomance_Icon.ico
+
+
+ 0
+ false
+ false
+ RELEASE;$(DCC_Define)
+
+
+ true
+ DEBUG;$(DCC_Define)
+ false
+
+
+ true
+ 1033
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=
+ true
+
+
+
+ MainSource
+
+
+
+
+
+
+
+
+
+
+
+ Cfg_2
+ Base
+
+
+ Base
+
+
+ Cfg_1
+ Base
+
+
+
+ Delphi.Personality.12
+
+
+
+
+ FWZipPerfomance.dpr
+
+
+ False
+ False
+ 1
+ 0
+ 0
+ 0
+ False
+ False
+ False
+ False
+ False
+ 1049
+ 1251
+
+
+
+
+ 1.0.0.0
+
+
+
+
+
+ 1.0.0.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Microsoft Office 2000 Sample Automation Server Wrapper Components
+ Microsoft Office XP Sample Automation Server Wrapper Components
+
+
+
+ True
+ True
+
+
+ 12
+
+
+
+
diff --git a/prereq/fwzip/Demos/PerfomanceTest/FWZipPerfomance.lpi b/prereq/fwzip/Demos/PerfomanceTest/FWZipPerfomance.lpi
new file mode 100644
index 0000000..aed53ec
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/FWZipPerfomance.lpi
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/prereq/fwzip/Demos/PerfomanceTest/FWZipPerfomance.lpr b/prereq/fwzip/Demos/PerfomanceTest/FWZipPerfomance.lpr
new file mode 100644
index 0000000..a775b24
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/FWZipPerfomance.lpr
@@ -0,0 +1,13 @@
+program FWZipPerfomance;
+{$MODE Delphi}
+uses
+ Forms, Interfaces,
+ Unit1 in 'Unit1.pas' {Form1};
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
diff --git a/prereq/fwzip/Demos/PerfomanceTest/FWZipPerfomance_Icon.ico b/prereq/fwzip/Demos/PerfomanceTest/FWZipPerfomance_Icon.ico
new file mode 100644
index 0000000..379ec80
Binary files /dev/null and b/prereq/fwzip/Demos/PerfomanceTest/FWZipPerfomance_Icon.ico differ
diff --git a/prereq/fwzip/Demos/PerfomanceTest/Unit1.lfm b/prereq/fwzip/Demos/PerfomanceTest/Unit1.lfm
new file mode 100644
index 0000000..bb81605
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/Unit1.lfm
@@ -0,0 +1,285 @@
+object Form1: TForm1
+ Left = 381
+ Height = 654
+ Top = 183
+ Width = 578
+ Caption = 'Тест производительности FWZip'
+ ClientHeight = 654
+ ClientWidth = 578
+ Color = clBtnFace
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Position = poScreenCenter
+ LCLVersion = '1.2.4.0'
+ object GroupBox1: TGroupBox
+ Left = 8
+ Height = 105
+ Top = 8
+ Width = 527
+ Anchors = [akTop, akLeft, akRight]
+ Caption = 'Настройки сжатия'
+ ClientHeight = 87
+ ClientWidth = 523
+ TabOrder = 0
+ object LabeledEdit1: TLabeledEdit
+ Left = 14
+ Height = 21
+ Top = 26
+ Width = 465
+ Anchors = [akTop, akLeft, akRight]
+ EditLabel.AnchorSideLeft.Control = LabeledEdit1
+ EditLabel.AnchorSideRight.Control = LabeledEdit1
+ EditLabel.AnchorSideRight.Side = asrBottom
+ EditLabel.AnchorSideBottom.Control = LabeledEdit1
+ EditLabel.Left = 14
+ EditLabel.Height = 13
+ EditLabel.Top = 10
+ EditLabel.Width = 465
+ EditLabel.Caption = 'Выберите папку для сжатия:'
+ EditLabel.ParentColor = False
+ TabOrder = 0
+ Text = 'D:\StroyInfo 5'
+ OnChange = LabeledEdit1Change
+ end
+ object Button1: TButton
+ Left = 485
+ Height = 25
+ Hint = 'Обзор...'
+ Top = 24
+ Width = 26
+ Anchors = [akTop, akRight]
+ Caption = '...'
+ OnClick = Button1Click
+ ParentShowHint = False
+ ShowHint = True
+ TabOrder = 1
+ end
+ object CheckBox1: TCheckBox
+ Left = 14
+ Height = 19
+ Top = 58
+ Width = 141
+ Caption = 'Шифровать при сжатии'
+ OnClick = CheckBox1Click
+ TabOrder = 2
+ end
+ object LabeledEdit2: TLabeledEdit
+ Left = 262
+ Height = 21
+ Top = 56
+ Width = 168
+ Anchors = [akTop, akLeft, akRight]
+ EditLabel.AnchorSideTop.Control = LabeledEdit2
+ EditLabel.AnchorSideTop.Side = asrCenter
+ EditLabel.AnchorSideRight.Control = LabeledEdit2
+ EditLabel.AnchorSideBottom.Control = LabeledEdit2
+ EditLabel.AnchorSideBottom.Side = asrBottom
+ EditLabel.Left = 175
+ EditLabel.Height = 13
+ EditLabel.Top = 60
+ EditLabel.Width = 84
+ EditLabel.Caption = 'Укажите пароль'
+ EditLabel.ParentColor = False
+ Enabled = False
+ LabelPosition = lpLeft
+ TabOrder = 3
+ end
+ object Button2: TButton
+ Left = 436
+ Height = 25
+ Top = 55
+ Width = 75
+ Anchors = [akTop, akRight]
+ Caption = 'Сжать'
+ OnClick = Button2Click
+ TabOrder = 4
+ end
+ end
+ object GroupBox2: TGroupBox
+ Left = 8
+ Height = 137
+ Top = 128
+ Width = 527
+ Anchors = [akTop, akLeft, akRight]
+ Caption = 'Настройки распаковки'
+ ClientHeight = 119
+ ClientWidth = 523
+ TabOrder = 1
+ object LabeledEdit3: TLabeledEdit
+ Left = 14
+ Height = 21
+ Top = 26
+ Width = 465
+ Anchors = [akTop, akLeft, akRight]
+ EditLabel.AnchorSideLeft.Control = LabeledEdit3
+ EditLabel.AnchorSideRight.Control = LabeledEdit3
+ EditLabel.AnchorSideRight.Side = asrBottom
+ EditLabel.AnchorSideBottom.Control = LabeledEdit3
+ EditLabel.Left = 14
+ EditLabel.Height = 13
+ EditLabel.Top = 10
+ EditLabel.Width = 465
+ EditLabel.Caption = 'Выберите архив для распаковки:'
+ EditLabel.ParentColor = False
+ TabOrder = 0
+ OnChange = LabeledEdit3Change
+ end
+ object Button3: TButton
+ Left = 485
+ Height = 25
+ Hint = 'Обзор...'
+ Top = 24
+ Width = 26
+ Anchors = [akTop, akRight]
+ Caption = '...'
+ OnClick = Button3Click
+ ParentShowHint = False
+ ShowHint = True
+ TabOrder = 1
+ end
+ object CheckBox2: TCheckBox
+ Left = 14
+ Height = 19
+ Top = 58
+ Width = 117
+ Caption = 'Архив зашифрован'
+ OnClick = CheckBox2Click
+ TabOrder = 2
+ end
+ object LabeledEdit4: TLabeledEdit
+ Left = 262
+ Height = 21
+ Top = 56
+ Width = 163
+ Anchors = [akTop, akLeft, akRight]
+ EditLabel.AnchorSideTop.Control = LabeledEdit4
+ EditLabel.AnchorSideTop.Side = asrCenter
+ EditLabel.AnchorSideRight.Control = LabeledEdit4
+ EditLabel.AnchorSideBottom.Control = LabeledEdit4
+ EditLabel.AnchorSideBottom.Side = asrBottom
+ EditLabel.Left = 175
+ EditLabel.Height = 13
+ EditLabel.Top = 60
+ EditLabel.Width = 84
+ EditLabel.Caption = 'Укажите пароль'
+ EditLabel.ParentColor = False
+ Enabled = False
+ LabelPosition = lpLeft
+ TabOrder = 3
+ end
+ object Button4: TButton
+ Left = 436
+ Height = 25
+ Top = 54
+ Width = 75
+ Anchors = [akTop, akRight]
+ Caption = 'Распаковать'
+ OnClick = Button4Click
+ TabOrder = 4
+ end
+ object Button6: TButton
+ Tag = 1
+ Left = 436
+ Height = 25
+ Top = 85
+ Width = 75
+ Anchors = [akTop, akRight]
+ Caption = 'Проверить'
+ OnClick = Button4Click
+ TabOrder = 5
+ end
+ end
+ object GroupBox3: TGroupBox
+ Left = 8
+ Height = 178
+ Top = 271
+ Width = 527
+ Anchors = [akTop, akLeft, akRight]
+ Caption = 'Производительность:'
+ ClientHeight = 160
+ ClientWidth = 523
+ TabOrder = 2
+ object Label1: TLabel
+ Left = 14
+ Height = 13
+ Top = 10
+ Width = 163
+ Caption = 'Текущий расход памяти: 0 байт'
+ ParentColor = False
+ end
+ object Label2: TLabel
+ Left = 14
+ Height = 13
+ Top = 29
+ Width = 163
+ Caption = 'Пиковый расход памяти: 0 байт'
+ ParentColor = False
+ end
+ object Label3: TLabel
+ Left = 14
+ Height = 13
+ Top = 48
+ Width = 166
+ Caption = 'Общее количество элементов: 0'
+ ParentColor = False
+ end
+ object Label4: TLabel
+ Left = 14
+ Height = 13
+ Top = 67
+ Width = 142
+ Caption = 'Общее размер элементов: 0'
+ ParentColor = False
+ end
+ object Label5: TLabel
+ Left = 14
+ Height = 13
+ Top = 95
+ Width = 497
+ Anchors = [akTop, akLeft, akRight]
+ AutoSize = False
+ ParentColor = False
+ end
+ object ProgressBar1: TProgressBar
+ Left = 14
+ Height = 17
+ Top = 114
+ Width = 494
+ Anchors = [akTop, akLeft, akRight]
+ TabOrder = 0
+ end
+ object ProgressBar2: TProgressBar
+ Left = 14
+ Height = 17
+ Top = 137
+ Width = 494
+ Anchors = [akTop, akLeft, akRight]
+ TabOrder = 1
+ end
+ object Button5: TButton
+ Left = 433
+ Height = 25
+ Top = 83
+ Width = 75
+ Anchors = [akTop, akRight]
+ Caption = 'Остановить'
+ OnClick = Button5Click
+ TabOrder = 2
+ Visible = False
+ end
+ end
+ object Memo1: TMemo
+ Left = 8
+ Height = 146
+ Top = 456
+ Width = 527
+ Anchors = [akTop, akLeft, akRight, akBottom]
+ ScrollBars = ssVertical
+ TabOrder = 3
+ end
+ object OpenDialog1: TOpenDialog
+ left = 376
+ top = 224
+ end
+end
diff --git a/prereq/fwzip/Demos/PerfomanceTest/Unit1.pas b/prereq/fwzip/Demos/PerfomanceTest/Unit1.pas
new file mode 100644
index 0000000..17dc492
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/Unit1.pas
@@ -0,0 +1,300 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ****************************************************************************
+// * Project : FWZip - FWZipPerfomance
+// * Purpose : Тестирование производительности FWZip
+// * Author : Александр (Rouse_) Багель
+// * Copyright : © Fangorn Wizards Lab 1998 - 2013.
+// * Version : 1.0.10
+// * Home Page : http://rouse.drkb.ru
+// * Home Blog : http://alexander-bagel.blogspot.ru
+// ****************************************************************************
+// * Stable Release : http://rouse.drkb.ru/components.php#fwzip
+// * Latest Source : https://github.com/AlexanderBagel/FWZip
+// ****************************************************************************
+//
+// Используемые источники:
+// ftp://ftp.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
+// http://zlib.net/zlib-1.2.5.tar.gz
+// http://www.base2ti.com/
+//
+
+unit Unit1;
+
+{$MODE Delphi}
+
+interface
+
+{$WARN SYMBOL_PLATFORM OFF}
+{$WARN SYMBOL_DEPRECATED OFF}
+{$WARN UNIT_PLATFORM OFF}
+
+uses
+ LCLIntf, LCLType, LMessages, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+ Dialogs, StdCtrls, ExtCtrls, FileCtrl, ComCtrls, FileUtil,
+ FWZipWriter, FWZipReader, FWZipConsts, Contnrs;
+
+type
+ TForm1 = class(TForm)
+ GroupBox1: TGroupBox;
+ LabeledEdit1: TLabeledEdit;
+ Button1: TButton;
+ CheckBox1: TCheckBox;
+ LabeledEdit2: TLabeledEdit;
+ Button2: TButton;
+ GroupBox2: TGroupBox;
+ LabeledEdit3: TLabeledEdit;
+ Button3: TButton;
+ CheckBox2: TCheckBox;
+ LabeledEdit4: TLabeledEdit;
+ Button4: TButton;
+ OpenDialog1: TOpenDialog;
+ GroupBox3: TGroupBox;
+ Label1: TLabel;
+ Label2: TLabel;
+ Label3: TLabel;
+ Label4: TLabel;
+ ProgressBar1: TProgressBar;
+ ProgressBar2: TProgressBar;
+ Label5: TLabel;
+ Button5: TButton;
+ Button6: TButton;
+ Memo1: TMemo;
+ procedure CheckBox1Click(Sender: TObject);
+ procedure Button1Click(Sender: TObject);
+ procedure LabeledEdit1Change(Sender: TObject);
+ procedure Button3Click(Sender: TObject);
+ procedure CheckBox2Click(Sender: TObject);
+ procedure LabeledEdit3Change(Sender: TObject);
+ procedure Button2Click(Sender: TObject);
+ procedure Button4Click(Sender: TObject);
+ procedure Button5Click(Sender: TObject);
+ private
+ InitialHeapSize, MaxHeapSize, AverageHeapSize: Int64;
+ TotalGetHeapStatusCount: Integer;
+ StopProcess: Boolean;
+ procedure OnProgress(Sender: TObject; const FileName: string;
+ Percent, TotalPercent: Byte; var Cancel: Boolean;
+ ProgressState: TProgressState);
+ procedure UpdateMemoryStatus;
+ procedure SetEnabledState(Value: Boolean);
+ procedure ClearZipData;
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+{$R *.lfm}
+
+procedure TForm1.Button1Click(Sender: TObject);
+var
+ Dir: string;
+begin
+ if SelectDirectory('Укажите папку для сжатия', '', Dir) then
+ LabeledEdit1.Text := Dir;
+end;
+
+procedure TForm1.Button2Click(Sender: TObject);
+var
+ I: Integer;
+ TotalSize: Int64;
+ Heap: THeapStatus;
+ TicCount: DWORD;
+ Item: TFWZipWriterItem;
+ Writer: TFWZipWriter;
+begin
+ Writer := TFWZipWriter.Create;
+ try
+ Writer.UseUTF8String:= true;
+ DeleteFileUTF8(IncludeTrailingPathDelimiter(LabeledEdit1.Text) + 'FWZipTest.zip'); { *Converted from DeleteFile* }
+ Writer.AddFolder('', LabeledEdit1.Text, '');
+ TotalSize := 0;
+ InitialHeapSize := 0;
+ for I := 0 to Writer.Count - 1 do
+ begin
+ Item := Writer[I];
+ Inc(TotalSize, Item.Size);
+ Inc(InitialHeapSize, SizeOf(TCentralDirectoryFileHeaderEx));
+ if LabeledEdit2.Text <> '' then
+ begin
+ Item.Password := LabeledEdit2.Text;
+ Item.NeedDescriptor := True;
+ end;
+ end;
+ Label3.Caption := 'Общее количество элементов: ' + IntToStr(Writer.Count);
+ Label4.Caption := 'Общий размер элементов: ' + IntToStr(TotalSize);
+ Writer.OnProgress := OnProgress;
+ SetEnabledState(False);
+ try
+ Heap := GetHeapStatus;
+ Inc(InitialHeapSize, Heap.Overhead + Heap.TotalAllocated);
+ MaxHeapSize := 0;
+ AverageHeapSize := 0;
+ TotalGetHeapStatusCount := 0;
+ StopProcess := False;
+ TicCount := GetTickCount;
+ Writer.BuildZip(
+ IncludeTrailingPathDelimiter(LabeledEdit1.Text) + 'FWZipTest.zip');
+ if TotalGetHeapStatusCount = 0 then
+ TotalGetHeapStatusCount := 1;
+ ShowMessage(Format(
+ 'Пиковый расход памяти: %d байт' + sLineBreak +
+ 'Средний расход памяти: %d байт' + sLineBreak +
+ 'Общее время работы: %d секунд',
+ [MaxHeapSize, AverageHeapSize div TotalGetHeapStatusCount,
+ (GetTickCount - TicCount) div 1000]));
+ finally
+ SetEnabledState(True);
+ end;
+ finally
+ Writer.Free;
+ ClearZipData;
+ end;
+end;
+
+procedure TForm1.Button3Click(Sender: TObject);
+begin
+ if OpenDialog1.Execute then
+ LabeledEdit3.Text := OpenDialog1.FileName;
+end;
+
+procedure TForm1.Button4Click(Sender: TObject);
+var
+ I: Integer;
+ TotalSize: Int64;
+ Heap: THeapStatus;
+ TicCount: DWORD;
+ Path: string;
+ Reader: TFWZipReader;
+begin
+ SetLength(Path, MAX_PATH);
+ Path := LabeledEdit3.Text;
+ Path := ChangeFileExt(Path, '');
+ Reader := TFWZipReader.Create;
+ try
+ Reader.LoadFromFile(LabeledEdit3.Text);
+ TotalSize := 0;
+ for I := 0 to Reader.Count - 1 do
+ Inc(TotalSize, Reader[I].UncompressedSize);
+ Label3.Caption := 'Общее количество элементов: ' + IntToStr(Reader.Count);
+ Label4.Caption := 'Общий размер элементов: ' + IntToStr(TotalSize);
+ Reader.OnProgress := OnProgress;
+ if LabeledEdit4.Text <> '' then
+ Reader.PasswordList.Add(LabeledEdit4.Text);
+ SetEnabledState(False);
+ try
+ Heap := GetHeapStatus;
+ InitialHeapSize := Heap.Overhead + Heap.TotalAllocated;
+ MaxHeapSize := 0;
+ AverageHeapSize := 0;
+ TotalGetHeapStatusCount := 0;
+ StopProcess := False;
+ Memo1.Lines.Clear;
+ TicCount := GetTickCount;
+ if TButton(Sender).Tag = 0 then
+ Reader.ExtractAll(Path)
+ else
+ Reader.Check;
+ if TotalGetHeapStatusCount = 0 then
+ TotalGetHeapStatusCount := 1;
+ ShowMessage(Format(
+ 'Пиковый расход памяти: %d байт' + sLineBreak +
+ 'Средний расход памяти: %d байт' + sLineBreak +
+ 'Общее время работы: %d секунд',
+ [MaxHeapSize, AverageHeapSize div TotalGetHeapStatusCount,
+ (GetTickCount - TicCount) div 1000]));
+ finally
+ SetEnabledState(True);
+ end;
+ finally
+ Reader.Free;
+ ClearZipData;
+ end;
+end;
+
+procedure TForm1.Button5Click(Sender: TObject);
+begin
+ StopProcess := True;
+end;
+
+procedure TForm1.CheckBox1Click(Sender: TObject);
+begin
+ LabeledEdit2.Enabled := CheckBox1.Checked;
+end;
+
+procedure TForm1.CheckBox2Click(Sender: TObject);
+begin
+ LabeledEdit4.Enabled := CheckBox2.Checked;
+end;
+
+procedure TForm1.ClearZipData;
+begin
+ Label1.Caption := 'Текущий расход памяти: 0 байт';
+ Label2.Caption := 'Пиковый расход памяти: 0 байт';
+ Label3.Caption := 'Общее количество элементов: 0';
+ Label4.Caption := 'Общий размер элементов: 0';
+ Label5.Caption := '';
+end;
+
+procedure TForm1.LabeledEdit1Change(Sender: TObject);
+begin
+ Button2.Enabled := DirectoryExistsUTF8(LabeledEdit1.Text); { *Converted from DirectoryExists* }
+end;
+
+procedure TForm1.LabeledEdit3Change(Sender: TObject);
+begin
+ Button4.Enabled := FileExistsUTF8(LabeledEdit3.Text); { *Converted from FileExists* }
+end;
+
+procedure TForm1.OnProgress(Sender: TObject; const FileName: string; Percent,
+ TotalPercent: Byte; var Cancel: Boolean; ProgressState: TProgressState);
+const
+ p: array [TProgressState] of string = ('psStart', 'psInitialization',
+ 'psInProgress', 'psFinalization', 'psEnd', 'psException');
+begin
+ Cancel := StopProcess;
+ Label5.Caption := Format('(%d) %s', [Percent, FileName]);
+ ProgressBar1.Position := Percent;
+ ProgressBar2.Position := TotalPercent;
+ Memo1.Lines.Add(Format('%s - %s percent %d total %d',
+ [FileName, P[ProgressState], Percent, TotalPercent]));
+ UpdateMemoryStatus;
+end;
+
+procedure TForm1.SetEnabledState(Value: Boolean);
+begin
+ Button1.Enabled := Value;
+ Button2.Enabled := Value;
+ Button3.Enabled := Value;
+ Button4.Enabled := Value;
+ Button5.Visible := not Value;
+ Button6.Enabled := Value;
+ LabeledEdit1.Enabled := Value;
+ LabeledEdit2.Enabled := Value;
+ LabeledEdit3.Enabled := Value;
+ LabeledEdit4.Enabled := Value;
+ CheckBox1.Enabled := Value;
+ CheckBox2.Enabled := Value;
+end;
+
+procedure TForm1.UpdateMemoryStatus;
+var
+ HeapStatus: THeapStatus;
+ HeapSize: Int64;
+begin
+ HeapStatus := GetHeapStatus;
+ HeapSize := HeapStatus.Overhead + HeapStatus.TotalAllocated;
+ Dec(HeapSize, InitialHeapSize);
+ if HeapSize > MaxHeapSize then
+ MaxHeapSize := HeapSize;
+ Inc(TotalGetHeapStatusCount);
+ Inc(AverageHeapSize, HeapSize);
+ Label1.Caption := 'Текущий расход памяти: ' + IntToStr(HeapSize) + ' байт';
+ Label2.Caption := 'Пиковый расход памяти: ' + IntToStr(MaxHeapSize) + ' байт';
+ Application.ProcessMessages;
+ Application.ProcessMessages;
+end;
+
+end.
diff --git a/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpi;1 b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpi;1
new file mode 100644
index 0000000..4c03822
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpi;1
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpi;2 b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpi;2
new file mode 100644
index 0000000..a81dd8c
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpi;2
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpi;3 b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpi;3
new file mode 100644
index 0000000..d52b956
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpi;3
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpi;4 b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpi;4
new file mode 100644
index 0000000..031bc88
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpi;4
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpi;5 b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpi;5
new file mode 100644
index 0000000..031bc88
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpi;5
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpi;6 b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpi;6
new file mode 100644
index 0000000..c78e889
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpi;6
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpi;7 b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpi;7
new file mode 100644
index 0000000..aed53ec
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpi;7
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpr;1 b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpr;1
new file mode 100644
index 0000000..c7888ff
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpr;1
@@ -0,0 +1,19 @@
+program FWZipPerfomance;
+
+uses
+ Forms,
+ Unit1 in 'Unit1.pas' {Form1},
+ FWZipConsts in '..\..\FWZipConsts.pas',
+ FWZipCrc32 in '..\..\FWZipCrc32.pas',
+ FWZipCrypt in '..\..\FWZipCrypt.pas',
+ FWZipReader in '..\..\FWZipReader.pas',
+ FWZipStream in '..\..\FWZipStream.pas',
+ FWZipWriter in '..\..\FWZipWriter.pas';
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
diff --git a/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpr;2 b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpr;2
new file mode 100644
index 0000000..2bce99e
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpr;2
@@ -0,0 +1,21 @@
+program FWZipPerfomance;
+
+{$MODE Delphi}
+
+uses
+ Forms, Interfaces,
+ Unit1 in 'Unit1.pas' {Form1},
+ FWZipConsts in '..\..\FWZipConsts.pas',
+ FWZipCrc32 in '..\..\FWZipCrc32.pas',
+ FWZipCrypt in '..\..\FWZipCrypt.pas',
+ FWZipReader in '..\..\FWZipReader.pas',
+ FWZipStream in '..\..\FWZipStream.pas',
+ FWZipWriter in '..\..\FWZipWriter.pas';
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
diff --git a/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpr;3 b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpr;3
new file mode 100644
index 0000000..e7e462b
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lpr;3
@@ -0,0 +1,19 @@
+program FWZipPerfomance;
+{$MODE Delphi}
+uses
+ Forms, Interfaces,
+ Unit1 in 'Unit1.pas' {Form1},
+ FWZipConsts in '..\..\FWZipConsts.pas',
+ FWZipCrc32 in '..\..\FWZipCrc32.pas',
+ FWZipCrypt in '..\..\FWZipCrypt.pas',
+ FWZipReader in '..\..\FWZipReader.pas',
+ FWZipStream in '..\..\FWZipStream.pas',
+ FWZipWriter in '..\..\FWZipWriter.pas';
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
diff --git a/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lps;1 b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lps;1
new file mode 100644
index 0000000..544f303
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lps;1
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lps;2 b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lps;2
new file mode 100644
index 0000000..f3a6920
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lps;2
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lps;3 b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lps;3
new file mode 100644
index 0000000..0369c9c
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lps;3
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lps;4 b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lps;4
new file mode 100644
index 0000000..9a1d1b1
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lps;4
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lps;5 b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lps;5
new file mode 100644
index 0000000..92491ae
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lps;5
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lps;6 b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lps;6
new file mode 100644
index 0000000..8f33cfd
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lps;6
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lps;7 b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lps;7
new file mode 100644
index 0000000..3bdf722
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lps;7
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lps;8 b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lps;8
new file mode 100644
index 0000000..b43c903
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/__history/FWZipPerfomance.lps;8
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/prereq/fwzip/Demos/PerfomanceTest/__history/Unit1.lfm;1 b/prereq/fwzip/Demos/PerfomanceTest/__history/Unit1.lfm;1
new file mode 100644
index 0000000..0f2f115
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/__history/Unit1.lfm;1
@@ -0,0 +1,244 @@
+object Form1: TForm1
+ Left = 381
+ Top = 183
+ Width = 578
+ Height = 654
+ Caption = 'Тест производительности FWZip'
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ Position = poScreenCenter
+ PixelsPerInch = 96
+ object GroupBox1: TGroupBox
+ Left = 8
+ Top = 8
+ Width = 527
+ Height = 105
+ Anchors = [akLeft, akTop, akRight]
+ Caption = 'Настройки сжатия'
+ TabOrder = 0
+ object LabeledEdit1: TLabeledEdit
+ Left = 14
+ Top = 26
+ Width = 469
+ Height = 21
+ Anchors = [akLeft, akTop, akRight]
+ EditLabel.Width = 149
+ EditLabel.Height = 13
+ EditLabel.Caption = 'Выберите папку для сжатия:'
+ TabOrder = 0
+ Text = 'D:\StroyInfo 5'
+ OnChange = LabeledEdit1Change
+ end
+ object Button1: TButton
+ Left = 489
+ Top = 24
+ Width = 26
+ Height = 25
+ Hint = 'Обзор...'
+ Anchors = [akTop, akRight]
+ Caption = '...'
+ ParentShowHint = False
+ ShowHint = True
+ TabOrder = 1
+ OnClick = Button1Click
+ end
+ object CheckBox1: TCheckBox
+ Left = 14
+ Top = 58
+ Width = 145
+ Height = 17
+ Caption = 'Шифровать при сжатии'
+ TabOrder = 2
+ OnClick = CheckBox1Click
+ end
+ object LabeledEdit2: TLabeledEdit
+ Left = 262
+ Top = 56
+ Width = 172
+ Height = 21
+ Anchors = [akLeft, akTop, akRight]
+ EditLabel.Width = 84
+ EditLabel.Height = 13
+ EditLabel.Caption = 'Укажите пароль'
+ Enabled = False
+ LabelPosition = lpLeft
+ TabOrder = 3
+ end
+ object Button2: TButton
+ Left = 440
+ Top = 55
+ Width = 75
+ Height = 25
+ Anchors = [akTop, akRight]
+ Caption = 'Сжать'
+ TabOrder = 4
+ OnClick = Button2Click
+ end
+ end
+ object GroupBox2: TGroupBox
+ Left = 8
+ Top = 128
+ Width = 527
+ Height = 137
+ Anchors = [akLeft, akTop, akRight]
+ Caption = 'Настройки распаковки'
+ TabOrder = 1
+ object LabeledEdit3: TLabeledEdit
+ Left = 14
+ Top = 26
+ Width = 469
+ Height = 21
+ Anchors = [akLeft, akTop, akRight]
+ EditLabel.Width = 171
+ EditLabel.Height = 13
+ EditLabel.Caption = 'Выберите архив для распаковки:'
+ TabOrder = 0
+ OnChange = LabeledEdit3Change
+ end
+ object Button3: TButton
+ Left = 489
+ Top = 24
+ Width = 26
+ Height = 25
+ Hint = 'Обзор...'
+ Anchors = [akTop, akRight]
+ Caption = '...'
+ ParentShowHint = False
+ ShowHint = True
+ TabOrder = 1
+ OnClick = Button3Click
+ end
+ object CheckBox2: TCheckBox
+ Left = 14
+ Top = 58
+ Width = 145
+ Height = 17
+ Caption = 'Архив зашифрован'
+ TabOrder = 2
+ OnClick = CheckBox2Click
+ end
+ object LabeledEdit4: TLabeledEdit
+ Left = 262
+ Top = 56
+ Width = 167
+ Height = 21
+ Anchors = [akLeft, akTop, akRight]
+ EditLabel.Width = 84
+ EditLabel.Height = 13
+ EditLabel.Caption = 'Укажите пароль'
+ Enabled = False
+ LabelPosition = lpLeft
+ TabOrder = 3
+ end
+ object Button4: TButton
+ Left = 440
+ Top = 54
+ Width = 75
+ Height = 25
+ Anchors = [akTop, akRight]
+ Caption = 'Распаковать'
+ TabOrder = 4
+ OnClick = Button4Click
+ end
+ object Button6: TButton
+ Tag = 1
+ Left = 440
+ Top = 85
+ Width = 75
+ Height = 25
+ Anchors = [akTop, akRight]
+ Caption = 'Проверить'
+ TabOrder = 5
+ OnClick = Button4Click
+ end
+ end
+ object GroupBox3: TGroupBox
+ Left = 8
+ Top = 271
+ Width = 527
+ Height = 178
+ Anchors = [akLeft, akTop, akRight]
+ Caption = 'Производительность:'
+ TabOrder = 2
+ object Label1: TLabel
+ Left = 14
+ Top = 10
+ Width = 163
+ Height = 13
+ Caption = 'Текущий расход памяти: 0 байт'
+ end
+ object Label2: TLabel
+ Left = 14
+ Top = 29
+ Width = 163
+ Height = 13
+ Caption = 'Пиковый расход памяти: 0 байт'
+ end
+ object Label3: TLabel
+ Left = 14
+ Top = 48
+ Width = 166
+ Height = 13
+ Caption = 'Общее количество элементов: 0'
+ end
+ object Label4: TLabel
+ Left = 14
+ Top = 67
+ Width = 142
+ Height = 13
+ Caption = 'Общее размер элементов: 0'
+ end
+ object Label5: TLabel
+ Left = 14
+ Top = 95
+ Width = 501
+ Height = 13
+ Anchors = [akLeft, akTop, akRight]
+ AutoSize = False
+ end
+ object ProgressBar1: TProgressBar
+ Left = 14
+ Top = 114
+ Width = 498
+ Height = 17
+ Anchors = [akLeft, akTop, akRight]
+ TabOrder = 0
+ end
+ object ProgressBar2: TProgressBar
+ Left = 14
+ Top = 137
+ Width = 498
+ Height = 17
+ Anchors = [akLeft, akTop, akRight]
+ TabOrder = 1
+ end
+ object Button5: TButton
+ Left = 437
+ Top = 83
+ Width = 75
+ Height = 25
+ Anchors = [akTop, akRight]
+ Caption = 'Остановить'
+ TabOrder = 2
+ Visible = False
+ OnClick = Button5Click
+ end
+ end
+ object Memo1: TMemo
+ Left = 8
+ Top = 456
+ Width = 527
+ Height = 146
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ ScrollBars = ssVertical
+ TabOrder = 3
+ end
+ object OpenDialog1: TOpenDialog
+ Left = 376
+ Top = 224
+ end
+end
\ No newline at end of file
diff --git a/prereq/fwzip/Demos/PerfomanceTest/__history/Unit1.pas;1 b/prereq/fwzip/Demos/PerfomanceTest/__history/Unit1.pas;1
new file mode 100644
index 0000000..ae3a044
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/__history/Unit1.pas;1
@@ -0,0 +1,298 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ****************************************************************************
+// * Project : FWZip - FWZipPerfomance
+// * Purpose : FWZip
+// * Author : (Rouse_)
+// * Copyright : Fangorn Wizards Lab 1998 - 2013.
+// * Version : 1.0.10
+// * Home Page : http://rouse.drkb.ru
+// * Home Blog : http://alexander-bagel.blogspot.ru
+// ****************************************************************************
+// * Stable Release : http://rouse.drkb.ru/components.php#fwzip
+// * Latest Source : https://github.com/AlexanderBagel/FWZip
+// ****************************************************************************
+//
+// :
+// ftp://ftp.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
+// http://zlib.net/zlib-1.2.5.tar.gz
+// http://www.base2ti.com/
+//
+
+unit Unit1;
+
+interface
+
+{$WARN SYMBOL_PLATFORM OFF}
+{$WARN SYMBOL_DEPRECATED OFF}
+{$WARN UNIT_PLATFORM OFF}
+
+uses
+ Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+ Dialogs, StdCtrls, ExtCtrls, FileCtrl, ComCtrls,
+ FWZipWriter, FWZipReader, FWZipConsts, Contnrs;
+
+type
+ TForm1 = class(TForm)
+ GroupBox1: TGroupBox;
+ LabeledEdit1: TLabeledEdit;
+ Button1: TButton;
+ CheckBox1: TCheckBox;
+ LabeledEdit2: TLabeledEdit;
+ Button2: TButton;
+ GroupBox2: TGroupBox;
+ LabeledEdit3: TLabeledEdit;
+ Button3: TButton;
+ CheckBox2: TCheckBox;
+ LabeledEdit4: TLabeledEdit;
+ Button4: TButton;
+ OpenDialog1: TOpenDialog;
+ GroupBox3: TGroupBox;
+ Label1: TLabel;
+ Label2: TLabel;
+ Label3: TLabel;
+ Label4: TLabel;
+ ProgressBar1: TProgressBar;
+ ProgressBar2: TProgressBar;
+ Label5: TLabel;
+ Button5: TButton;
+ Button6: TButton;
+ Memo1: TMemo;
+ procedure CheckBox1Click(Sender: TObject);
+ procedure Button1Click(Sender: TObject);
+ procedure LabeledEdit1Change(Sender: TObject);
+ procedure Button3Click(Sender: TObject);
+ procedure CheckBox2Click(Sender: TObject);
+ procedure LabeledEdit3Change(Sender: TObject);
+ procedure Button2Click(Sender: TObject);
+ procedure Button4Click(Sender: TObject);
+ procedure Button5Click(Sender: TObject);
+ private
+ InitialHeapSize, MaxHeapSize, AverageHeapSize: Int64;
+ TotalGetHeapStatusCount: Integer;
+ StopProcess: Boolean;
+ procedure OnProgress(Sender: TObject; const FileName: string;
+ Percent, TotalPercent: Byte; var Cancel: Boolean;
+ ProgressState: TProgressState);
+ procedure UpdateMemoryStatus;
+ procedure SetEnabledState(Value: Boolean);
+ procedure ClearZipData;
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+{$R *.dfm}
+
+procedure TForm1.Button1Click(Sender: TObject);
+var
+ Dir: string;
+begin
+ if SelectDirectory(' ', '', Dir) then
+ LabeledEdit1.Text := Dir;
+end;
+
+procedure TForm1.Button2Click(Sender: TObject);
+var
+ I: Integer;
+ TotalSize: Int64;
+ Heap: THeapStatus;
+ TicCount: DWORD;
+ Item: TFWZipWriterItem;
+ Writer: TFWZipWriter;
+begin
+ Writer := TFWZipWriter.Create;
+ try
+ DeleteFile(
+ IncludeTrailingPathDelimiter(LabeledEdit1.Text) + 'FWZipTest.zip');
+ Writer.AddFolder('', LabeledEdit1.Text, '');
+ TotalSize := 0;
+ InitialHeapSize := 0;
+ for I := 0 to Writer.Count - 1 do
+ begin
+ Item := Writer[I];
+ Inc(TotalSize, Item.Size);
+ Inc(InitialHeapSize, SizeOf(TCentralDirectoryFileHeaderEx));
+ if LabeledEdit2.Text <> '' then
+ begin
+ Item.Password := LabeledEdit2.Text;
+ Item.NeedDescriptor := True;
+ end;
+ end;
+ Label3.Caption := ' : ' + IntToStr(Writer.Count);
+ Label4.Caption := ' : ' + IntToStr(TotalSize);
+ Writer.OnProgress := OnProgress;
+ SetEnabledState(False);
+ try
+ Heap := GetHeapStatus;
+ Inc(InitialHeapSize, Heap.Overhead + Heap.TotalAllocated);
+ MaxHeapSize := 0;
+ AverageHeapSize := 0;
+ TotalGetHeapStatusCount := 0;
+ StopProcess := False;
+ TicCount := GetTickCount;
+ Writer.BuildZip(
+ IncludeTrailingPathDelimiter(LabeledEdit1.Text) + 'FWZipTest.zip');
+ if TotalGetHeapStatusCount = 0 then
+ TotalGetHeapStatusCount := 1;
+ ShowMessage(Format(
+ ' : %d ' + sLineBreak +
+ ' : %d ' + sLineBreak +
+ ' : %d ',
+ [MaxHeapSize, AverageHeapSize div TotalGetHeapStatusCount,
+ (GetTickCount - TicCount) div 1000]));
+ finally
+ SetEnabledState(True);
+ end;
+ finally
+ Writer.Free;
+ ClearZipData;
+ end;
+end;
+
+procedure TForm1.Button3Click(Sender: TObject);
+begin
+ if OpenDialog1.Execute then
+ LabeledEdit3.Text := OpenDialog1.FileName;
+end;
+
+procedure TForm1.Button4Click(Sender: TObject);
+var
+ I: Integer;
+ TotalSize: Int64;
+ Heap: THeapStatus;
+ TicCount: DWORD;
+ Path: string;
+ Reader: TFWZipReader;
+begin
+ SetLength(Path, MAX_PATH);
+ Path := LabeledEdit3.Text;
+ Path := ChangeFileExt(Path, '');
+ Reader := TFWZipReader.Create;
+ try
+ Reader.LoadFromFile(LabeledEdit3.Text);
+ TotalSize := 0;
+ for I := 0 to Reader.Count - 1 do
+ Inc(TotalSize, Reader[I].UncompressedSize);
+ Label3.Caption := ' : ' + IntToStr(Reader.Count);
+ Label4.Caption := ' : ' + IntToStr(TotalSize);
+ Reader.OnProgress := OnProgress;
+ if LabeledEdit4.Text <> '' then
+ Reader.PasswordList.Add(LabeledEdit4.Text);
+ SetEnabledState(False);
+ try
+ Heap := GetHeapStatus;
+ InitialHeapSize := Heap.Overhead + Heap.TotalAllocated;
+ MaxHeapSize := 0;
+ AverageHeapSize := 0;
+ TotalGetHeapStatusCount := 0;
+ StopProcess := False;
+ Memo1.Lines.Clear;
+ TicCount := GetTickCount;
+ if TButton(Sender).Tag = 0 then
+ Reader.ExtractAll(Path)
+ else
+ Reader.Check;
+ if TotalGetHeapStatusCount = 0 then
+ TotalGetHeapStatusCount := 1;
+ ShowMessage(Format(
+ ' : %d ' + sLineBreak +
+ ' : %d ' + sLineBreak +
+ ' : %d ',
+ [MaxHeapSize, AverageHeapSize div TotalGetHeapStatusCount,
+ (GetTickCount - TicCount) div 1000]));
+ finally
+ SetEnabledState(True);
+ end;
+ finally
+ Reader.Free;
+ ClearZipData;
+ end;
+end;
+
+procedure TForm1.Button5Click(Sender: TObject);
+begin
+ StopProcess := True;
+end;
+
+procedure TForm1.CheckBox1Click(Sender: TObject);
+begin
+ LabeledEdit2.Enabled := CheckBox1.Checked;
+end;
+
+procedure TForm1.CheckBox2Click(Sender: TObject);
+begin
+ LabeledEdit4.Enabled := CheckBox2.Checked;
+end;
+
+procedure TForm1.ClearZipData;
+begin
+ Label1.Caption := ' : 0 ';
+ Label2.Caption := ' : 0 ';
+ Label3.Caption := ' : 0';
+ Label4.Caption := ' : 0';
+ Label5.Caption := '';
+end;
+
+procedure TForm1.LabeledEdit1Change(Sender: TObject);
+begin
+ Button2.Enabled := DirectoryExists(LabeledEdit1.Text);
+end;
+
+procedure TForm1.LabeledEdit3Change(Sender: TObject);
+begin
+ Button4.Enabled := FileExists(LabeledEdit3.Text);
+end;
+
+procedure TForm1.OnProgress(Sender: TObject; const FileName: string; Percent,
+ TotalPercent: Byte; var Cancel: Boolean; ProgressState: TProgressState);
+const
+ p: array [TProgressState] of string = ('psStart', 'psInitialization',
+ 'psInProgress', 'psFinalization', 'psEnd', 'psException');
+begin
+ Cancel := StopProcess;
+ Label5.Caption := Format('(%d) %s', [Percent, FileName]);
+ ProgressBar1.Position := Percent;
+ ProgressBar2.Position := TotalPercent;
+ Memo1.Lines.Add(Format('%s - %s percent %d total %d',
+ [FileName, P[ProgressState], Percent, TotalPercent]));
+ UpdateMemoryStatus;
+end;
+
+procedure TForm1.SetEnabledState(Value: Boolean);
+begin
+ Button1.Enabled := Value;
+ Button2.Enabled := Value;
+ Button3.Enabled := Value;
+ Button4.Enabled := Value;
+ Button5.Visible := not Value;
+ Button6.Enabled := Value;
+ LabeledEdit1.Enabled := Value;
+ LabeledEdit2.Enabled := Value;
+ LabeledEdit3.Enabled := Value;
+ LabeledEdit4.Enabled := Value;
+ CheckBox1.Enabled := Value;
+ CheckBox2.Enabled := Value;
+end;
+
+procedure TForm1.UpdateMemoryStatus;
+var
+ HeapStatus: THeapStatus;
+ HeapSize: Int64;
+begin
+ HeapStatus := GetHeapStatus;
+ HeapSize := HeapStatus.Overhead + HeapStatus.TotalAllocated;
+ Dec(HeapSize, InitialHeapSize);
+ if HeapSize > MaxHeapSize then
+ MaxHeapSize := HeapSize;
+ Inc(TotalGetHeapStatusCount);
+ Inc(AverageHeapSize, HeapSize);
+ Label1.Caption := ' : ' + IntToStr(HeapSize) + ' ';
+ Label2.Caption := ' : ' + IntToStr(MaxHeapSize) + ' ';
+ Application.ProcessMessages;
+ Application.ProcessMessages;
+end;
+
+end.
diff --git a/prereq/fwzip/Demos/PerfomanceTest/__history/Unit1.pas;2 b/prereq/fwzip/Demos/PerfomanceTest/__history/Unit1.pas;2
new file mode 100644
index 0000000..1e3b9ef
--- /dev/null
+++ b/prereq/fwzip/Demos/PerfomanceTest/__history/Unit1.pas;2
@@ -0,0 +1,299 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ****************************************************************************
+// * Project : FWZip - FWZipPerfomance
+// * Purpose : Тестирование производительности FWZip
+// * Author : Александр (Rouse_) Багель
+// * Copyright : © Fangorn Wizards Lab 1998 - 2013.
+// * Version : 1.0.10
+// * Home Page : http://rouse.drkb.ru
+// * Home Blog : http://alexander-bagel.blogspot.ru
+// ****************************************************************************
+// * Stable Release : http://rouse.drkb.ru/components.php#fwzip
+// * Latest Source : https://github.com/AlexanderBagel/FWZip
+// ****************************************************************************
+//
+// Используемые источники:
+// ftp://ftp.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
+// http://zlib.net/zlib-1.2.5.tar.gz
+// http://www.base2ti.com/
+//
+
+unit Unit1;
+
+{$MODE Delphi}
+
+interface
+
+{$WARN SYMBOL_PLATFORM OFF}
+{$WARN SYMBOL_DEPRECATED OFF}
+{$WARN UNIT_PLATFORM OFF}
+
+uses
+ LCLIntf, LCLType, LMessages, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+ Dialogs, StdCtrls, ExtCtrls, FileCtrl, ComCtrls, FileUtil,
+ FWZipWriter, FWZipReader, FWZipConsts, Contnrs;
+
+type
+ TForm1 = class(TForm)
+ GroupBox1: TGroupBox;
+ LabeledEdit1: TLabeledEdit;
+ Button1: TButton;
+ CheckBox1: TCheckBox;
+ LabeledEdit2: TLabeledEdit;
+ Button2: TButton;
+ GroupBox2: TGroupBox;
+ LabeledEdit3: TLabeledEdit;
+ Button3: TButton;
+ CheckBox2: TCheckBox;
+ LabeledEdit4: TLabeledEdit;
+ Button4: TButton;
+ OpenDialog1: TOpenDialog;
+ GroupBox3: TGroupBox;
+ Label1: TLabel;
+ Label2: TLabel;
+ Label3: TLabel;
+ Label4: TLabel;
+ ProgressBar1: TProgressBar;
+ ProgressBar2: TProgressBar;
+ Label5: TLabel;
+ Button5: TButton;
+ Button6: TButton;
+ Memo1: TMemo;
+ procedure CheckBox1Click(Sender: TObject);
+ procedure Button1Click(Sender: TObject);
+ procedure LabeledEdit1Change(Sender: TObject);
+ procedure Button3Click(Sender: TObject);
+ procedure CheckBox2Click(Sender: TObject);
+ procedure LabeledEdit3Change(Sender: TObject);
+ procedure Button2Click(Sender: TObject);
+ procedure Button4Click(Sender: TObject);
+ procedure Button5Click(Sender: TObject);
+ private
+ InitialHeapSize, MaxHeapSize, AverageHeapSize: Int64;
+ TotalGetHeapStatusCount: Integer;
+ StopProcess: Boolean;
+ procedure OnProgress(Sender: TObject; const FileName: string;
+ Percent, TotalPercent: Byte; var Cancel: Boolean;
+ ProgressState: TProgressState);
+ procedure UpdateMemoryStatus;
+ procedure SetEnabledState(Value: Boolean);
+ procedure ClearZipData;
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+{$R *.lfm}
+
+procedure TForm1.Button1Click(Sender: TObject);
+var
+ Dir: string;
+begin
+ if SelectDirectory('Укажите папку для сжатия', '', Dir) then
+ LabeledEdit1.Text := Dir;
+end;
+
+procedure TForm1.Button2Click(Sender: TObject);
+var
+ I: Integer;
+ TotalSize: Int64;
+ Heap: THeapStatus;
+ TicCount: DWORD;
+ Item: TFWZipWriterItem;
+ Writer: TFWZipWriter;
+begin
+ Writer := TFWZipWriter.Create;
+ try
+ DeleteFileUTF8(IncludeTrailingPathDelimiter(LabeledEdit1.Text) + 'FWZipTest.zip'); { *Converted from DeleteFile* }
+ Writer.AddFolder('', LabeledEdit1.Text, '');
+ TotalSize := 0;
+ InitialHeapSize := 0;
+ for I := 0 to Writer.Count - 1 do
+ begin
+ Item := Writer[I];
+ Inc(TotalSize, Item.Size);
+ Inc(InitialHeapSize, SizeOf(TCentralDirectoryFileHeaderEx));
+ if LabeledEdit2.Text <> '' then
+ begin
+ Item.Password := LabeledEdit2.Text;
+ Item.NeedDescriptor := True;
+ end;
+ end;
+ Label3.Caption := 'Общее количество элементов: ' + IntToStr(Writer.Count);
+ Label4.Caption := 'Общий размер элементов: ' + IntToStr(TotalSize);
+ Writer.OnProgress := OnProgress;
+ SetEnabledState(False);
+ try
+ Heap := GetHeapStatus;
+ Inc(InitialHeapSize, Heap.Overhead + Heap.TotalAllocated);
+ MaxHeapSize := 0;
+ AverageHeapSize := 0;
+ TotalGetHeapStatusCount := 0;
+ StopProcess := False;
+ TicCount := GetTickCount;
+ Writer.BuildZip(
+ IncludeTrailingPathDelimiter(LabeledEdit1.Text) + 'FWZipTest.zip');
+ if TotalGetHeapStatusCount = 0 then
+ TotalGetHeapStatusCount := 1;
+ ShowMessage(Format(
+ 'Пиковый расход памяти: %d байт' + sLineBreak +
+ 'Средний расход памяти: %d байт' + sLineBreak +
+ 'Общее время работы: %d секунд',
+ [MaxHeapSize, AverageHeapSize div TotalGetHeapStatusCount,
+ (GetTickCount - TicCount) div 1000]));
+ finally
+ SetEnabledState(True);
+ end;
+ finally
+ Writer.Free;
+ ClearZipData;
+ end;
+end;
+
+procedure TForm1.Button3Click(Sender: TObject);
+begin
+ if OpenDialog1.Execute then
+ LabeledEdit3.Text := OpenDialog1.FileName;
+end;
+
+procedure TForm1.Button4Click(Sender: TObject);
+var
+ I: Integer;
+ TotalSize: Int64;
+ Heap: THeapStatus;
+ TicCount: DWORD;
+ Path: string;
+ Reader: TFWZipReader;
+begin
+ SetLength(Path, MAX_PATH);
+ Path := LabeledEdit3.Text;
+ Path := ChangeFileExt(Path, '');
+ Reader := TFWZipReader.Create;
+ try
+ Reader.LoadFromFile(LabeledEdit3.Text);
+ TotalSize := 0;
+ for I := 0 to Reader.Count - 1 do
+ Inc(TotalSize, Reader[I].UncompressedSize);
+ Label3.Caption := 'Общее количество элементов: ' + IntToStr(Reader.Count);
+ Label4.Caption := 'Общий размер элементов: ' + IntToStr(TotalSize);
+ Reader.OnProgress := OnProgress;
+ if LabeledEdit4.Text <> '' then
+ Reader.PasswordList.Add(LabeledEdit4.Text);
+ SetEnabledState(False);
+ try
+ Heap := GetHeapStatus;
+ InitialHeapSize := Heap.Overhead + Heap.TotalAllocated;
+ MaxHeapSize := 0;
+ AverageHeapSize := 0;
+ TotalGetHeapStatusCount := 0;
+ StopProcess := False;
+ Memo1.Lines.Clear;
+ TicCount := GetTickCount;
+ if TButton(Sender).Tag = 0 then
+ Reader.ExtractAll(Path)
+ else
+ Reader.Check;
+ if TotalGetHeapStatusCount = 0 then
+ TotalGetHeapStatusCount := 1;
+ ShowMessage(Format(
+ 'Пиковый расход памяти: %d байт' + sLineBreak +
+ 'Средний расход памяти: %d байт' + sLineBreak +
+ 'Общее время работы: %d секунд',
+ [MaxHeapSize, AverageHeapSize div TotalGetHeapStatusCount,
+ (GetTickCount - TicCount) div 1000]));
+ finally
+ SetEnabledState(True);
+ end;
+ finally
+ Reader.Free;
+ ClearZipData;
+ end;
+end;
+
+procedure TForm1.Button5Click(Sender: TObject);
+begin
+ StopProcess := True;
+end;
+
+procedure TForm1.CheckBox1Click(Sender: TObject);
+begin
+ LabeledEdit2.Enabled := CheckBox1.Checked;
+end;
+
+procedure TForm1.CheckBox2Click(Sender: TObject);
+begin
+ LabeledEdit4.Enabled := CheckBox2.Checked;
+end;
+
+procedure TForm1.ClearZipData;
+begin
+ Label1.Caption := 'Текущий расход памяти: 0 байт';
+ Label2.Caption := 'Пиковый расход памяти: 0 байт';
+ Label3.Caption := 'Общее количество элементов: 0';
+ Label4.Caption := 'Общий размер элементов: 0';
+ Label5.Caption := '';
+end;
+
+procedure TForm1.LabeledEdit1Change(Sender: TObject);
+begin
+ Button2.Enabled := DirectoryExistsUTF8(LabeledEdit1.Text); { *Converted from DirectoryExists* }
+end;
+
+procedure TForm1.LabeledEdit3Change(Sender: TObject);
+begin
+ Button4.Enabled := FileExistsUTF8(LabeledEdit3.Text); { *Converted from FileExists* }
+end;
+
+procedure TForm1.OnProgress(Sender: TObject; const FileName: string; Percent,
+ TotalPercent: Byte; var Cancel: Boolean; ProgressState: TProgressState);
+const
+ p: array [TProgressState] of string = ('psStart', 'psInitialization',
+ 'psInProgress', 'psFinalization', 'psEnd', 'psException');
+begin
+ Cancel := StopProcess;
+ Label5.Caption := Format('(%d) %s', [Percent, FileName]);
+ ProgressBar1.Position := Percent;
+ ProgressBar2.Position := TotalPercent;
+ Memo1.Lines.Add(Format('%s - %s percent %d total %d',
+ [FileName, P[ProgressState], Percent, TotalPercent]));
+ UpdateMemoryStatus;
+end;
+
+procedure TForm1.SetEnabledState(Value: Boolean);
+begin
+ Button1.Enabled := Value;
+ Button2.Enabled := Value;
+ Button3.Enabled := Value;
+ Button4.Enabled := Value;
+ Button5.Visible := not Value;
+ Button6.Enabled := Value;
+ LabeledEdit1.Enabled := Value;
+ LabeledEdit2.Enabled := Value;
+ LabeledEdit3.Enabled := Value;
+ LabeledEdit4.Enabled := Value;
+ CheckBox1.Enabled := Value;
+ CheckBox2.Enabled := Value;
+end;
+
+procedure TForm1.UpdateMemoryStatus;
+var
+ HeapStatus: THeapStatus;
+ HeapSize: Int64;
+begin
+ HeapStatus := GetHeapStatus;
+ HeapSize := HeapStatus.Overhead + HeapStatus.TotalAllocated;
+ Dec(HeapSize, InitialHeapSize);
+ if HeapSize > MaxHeapSize then
+ MaxHeapSize := HeapSize;
+ Inc(TotalGetHeapStatusCount);
+ Inc(AverageHeapSize, HeapSize);
+ Label1.Caption := 'Текущий расход памяти: ' + IntToStr(HeapSize) + ' байт';
+ Label2.Caption := 'Пиковый расход памяти: ' + IntToStr(MaxHeapSize) + ' байт';
+ Application.ProcessMessages;
+ Application.ProcessMessages;
+end;
+
+end.
diff --git a/prereq/fwzip/Demos/Test Build With Exception/BuildWithException.dpr b/prereq/fwzip/Demos/Test Build With Exception/BuildWithException.dpr
new file mode 100644
index 0000000..1553f3c
--- /dev/null
+++ b/prereq/fwzip/Demos/Test Build With Exception/BuildWithException.dpr
@@ -0,0 +1,333 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ****************************************************************************
+// * Project : FWZip
+// * Unit Name : BuildWithException
+// * Purpose :
+// * :
+// * Author : (Rouse_)
+// * Copyright : Fangorn Wizards Lab 1998 - 2013.
+// * Version : 1.0.10
+// * Home Page : http://rouse.drkb.ru
+// * Home Blog : http://alexander-bagel.blogspot.ru
+// ****************************************************************************
+// * Stable Release : http://rouse.drkb.ru/components.php#fwzip
+// * Latest Source : https://github.com/AlexanderBagel/FWZip
+// ****************************************************************************
+//
+// :
+// ftp://ftp.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
+// http://zlib.net/zlib-1.2.5.tar.gz
+// http://www.base2ti.com/
+//
+
+//
+// , - .
+
+program BuildWithException;
+
+{$APPTYPE CONSOLE}
+
+uses
+ Windows,
+ Classes,
+ SysUtils,
+ TypInfo,
+ FWZipConsts,
+ FWZipWriter,
+ FWZipReader;
+
+var
+ Writer: TFWZipWriter;
+ Reader: TFWZipReader;
+ Method: TMethod;
+ hOFStruct: TOFStruct;
+ hFile: THandle;
+
+//
+// BuildZip
+// =============================================================================
+procedure ShowBuildResult(Value: TBuildZipResult);
+begin
+ Writeln(GetEnumName(TypeInfo(TBuildZipResult), Integer(Value)));
+end;
+
+//
+// Extract
+// =============================================================================
+procedure ShowManualExtractResult(const ElementName: string;
+ Value: TExtractResult);
+begin
+ Writeln(Format('%s -> %s', [ElementName,
+ GetEnumName(TypeInfo(TExtractResult), Integer(Value))]));
+end;
+
+//
+//
+// =============================================================================
+procedure OnException1(Self, Sender: TObject; E: Exception;
+ const ItemIndex: Integer; var Action: TExceptionAction;
+ var NewFilePath: string; NewFileData: TMemoryStream);
+var
+ CurrentFilePath: string;
+ Src: THandleStream;
+ Dst: TFileStream;
+ hOFStruct: TOFStruct;
+ hFile: THandle;
+begin
+ CurrentFilePath := string(TFWZipWriter(Sender)[ItemIndex].FilePath);
+ NewFilePath := ChangeFileExt(CurrentFilePath, '.tmp');
+ hFile := OpenFile(PAnsiChar(AnsiString(CurrentFilePath)),
+ hOFStruct, OF_READ);
+ try
+ Src := THandleStream.Create(hFile);
+ try
+ Dst := TFileStream.Create(NewFilePath, fmCreate);
+ try
+ Dst.CopyFrom(Src, 0);
+ finally
+ Dst.Free;
+ end;
+ finally
+ Src.Free;
+ end;
+ finally
+ CloseHandle(hFile);
+ end;
+ Action := eaUseNewFilePathAndDel;
+end;
+
+//
+//
+// =============================================================================
+procedure OnException2(Self, Sender: TObject; E: Exception;
+ const ItemIndex: Integer; var Action: TExceptionAction;
+ var NewFilePath: string; NewFileData: TMemoryStream);
+begin
+ CloseHandle(hFile);
+ hFile := INVALID_HANDLE_VALUE;
+ Action := eaRetry;
+end;
+
+//
+//
+// =============================================================================
+procedure OnException3(Self, Sender: TObject; E: Exception;
+ const ItemIndex: Integer; var Action: TExceptionAction;
+ var NewFilePath: string; NewFileData: TMemoryStream);
+var
+ Src: THandleStream;
+ hOFStruct: TOFStruct;
+ hFile: THandle;
+begin
+ hFile := OpenFile(
+ PAnsiChar(AnsiString(TFWZipWriter(Sender)[ItemIndex].FilePath)),
+ hOFStruct, OF_READ);
+ try
+ Src := THandleStream.Create(hFile);
+ try
+ NewFileData.CopyFrom(Src, 0);
+ finally
+ Src.Free;
+ end;
+ finally
+ CloseHandle(hFile);
+ end;
+ Action := eaUseNewFileData;
+end;
+
+//
+//
+// =============================================================================
+procedure OnDuplicate(Self, Sender: TObject;
+ var Path: string; var Action: TDuplicateAction);
+begin
+ Path := MakeUniqueName(Path);
+ Action := daUseNewFilePath;
+end;
+
+var
+ I: Integer;
+begin
+ SetCurrentDir(ExtractFilePath(ParamStr(0)));
+ try
+
+ // -
+ // .
+ //
+ //
+ // .
+ // ,
+ // ( eaSkip) BuildZip
+ // :
+ // brFailed -
+ // (.. )
+ // brPartialBuild - - - ,
+ //
+
+ Writer := TFWZipWriter.Create;
+ try
+ Writer.AddFolder('', '..\..\', '*.pas', False);
+ ForceDirectories('..\DemoResults\');
+ //
+ hFile := OpenFile(PAnsiChar(AnsiString('..\..\' + Writer[0].FileName)),
+ hOFStruct, OF_WRITE);
+ try
+ Write('BuildWithException1.zip -> ');
+ ShowBuildResult(Writer.BuildZip('..\DemoResults\BuildWithException1.zip'));
+ finally
+ CloseHandle(hFile);
+ end;
+ finally
+ Writer.Free;
+ end;
+
+ //
+ // OnException
+ // -
+ //
+
+ Writer := TFWZipWriter.Create;
+ try
+ Writer.AddFolder('', '..\..\', '*.pas', False);
+ ForceDirectories('..\DemoResults\');
+
+ //
+ hFile := OpenFile(PAnsiChar(AnsiString('..\..\' + Writer[0].FileName)),
+ hOFStruct, OF_WRITE);
+ try
+
+ //
+ // OnException1
+ // NewFilePath ,
+ // Action eaUseNewFilePathAndDel
+ // FWZip
+ // , ,
+ // .
+
+ Method.Code := @OnException1;
+ Method.Data := Writer;
+ Writer.OnException := TZipBuildExceptionEvent(Method);
+
+ Write('BuildWithException2.zip -> ');
+ ShowBuildResult(Writer.BuildZip('..\DemoResults\BuildWithException2.zip'));
+
+ // , OnException2
+ //
+ // Action eaRetry.
+ // FWZip
+ //
+
+ Method.Code := @OnException2;
+ Method.Data := Writer;
+ Writer.OnException := TZipBuildExceptionEvent(Method);
+
+ Write('BuildWithException3.zip -> ');
+ ShowBuildResult(Writer.BuildZip('..\DemoResults\BuildWithException3.zip'));
+
+ //
+ if hFile = INVALID_HANDLE_VALUE then
+ hFile := OpenFile(PAnsiChar(AnsiString('..\..\' + Writer[0].FileName)),
+ hOFStruct, OF_WRITE);
+
+ // , OnException3
+ //
+ // Action eaUseNewFileData
+ //
+ // NewFileData
+
+ Method.Code := @OnException3;
+ Method.Data := Writer;
+ Writer.OnException := TZipBuildExceptionEvent(Method);
+
+ Write('BuildWithException4.zip -> ');
+ ShowBuildResult(Writer.BuildZip('..\DemoResults\BuildWithException4.zip'));
+
+ // .
+ // ,
+ // Action eaSkip ( )
+ // , eaAbort,
+ // .
+
+ finally
+ if hFile <> INVALID_HANDLE_VALUE then
+ CloseHandle(hFile);
+ end;
+ finally
+ Writer.Free;
+ end;
+
+ //
+ // ,
+ // , .
+ //
+ // ZLib (. Readme.txt 9)
+ //
+ // OnException. ,
+ // TFWZipReader.ExtractAll
+ // .
+ // , ,
+ // ,
+ // Handled:
+ // (Handled = True, , )
+
+ // ,
+ // -
+ // -
+
+ Reader := TFWZipReader.Create;
+ try
+ Reader.LoadFromFile('..\DemoResults\BuildWithException1.zip');
+ ForceDirectories('..\DemoResults\BuildWithExceptionUnpack\');
+
+ //
+
+ Reader.ExtractAll('..\DemoResults\BuildWithExceptionUnpack\');
+
+ // .
+ // ,
+
+ Reader.ExtractAll('..\DemoResults\BuildWithExceptionUnpack\');
+
+ // .
+ // .. Reader[I].Extract Reader.ExtractAll
+ //
+
+ Writeln('Manual extract:');
+ for I := 0 to Reader.Count - 1 do
+ ShowManualExtractResult(
+ string(Reader[I].FileName),
+ Reader[I].Extract('..\DemoResults\BuildWithExceptionUnpack\', ''));
+
+ // ,
+ // (Reader[I].Extract erSkiped )
+
+ // (ExtractAll)
+ // OnDuplicate TFWZipReader.
+ // , OnDuplicate
+ // (Reader.Items[ ].OnDuplicate)
+
+ Method.Code := @OnDuplicate;
+ Method.Data := Reader;
+ Reader.OnDuplicate := TZipDuplicateEvent(Method);
+
+ // .
+ // OnDuplicate
+ // Action daUseNewFilePath.
+ // TFWZipReader-
+ // ...
+ // (.. Windows, :
+ // New folder -> New folder (2) -> New folder (3) ..)
+
+ Reader.ExtractAll('..\DemoResults\BuildWithExceptionUnpack\');
+
+ finally
+ Reader.Free;
+ end;
+
+ except
+ on E: Exception do
+ Writeln(E.ClassName, ': ', E.Message);
+ end;
+ Readln;
+end.
diff --git a/prereq/fwzip/Demos/Test Build With Exception/BuildWithException.dproj b/prereq/fwzip/Demos/Test Build With Exception/BuildWithException.dproj
new file mode 100644
index 0000000..01e4875
--- /dev/null
+++ b/prereq/fwzip/Demos/Test Build With Exception/BuildWithException.dproj
@@ -0,0 +1,619 @@
+
+
+ {D336C006-9204-4B8B-A8C2-88CAB9F2693C}
+ BuildWithException.dpr
+ True
+ Debug
+ 1
+ Console
+ None
+ 14.6
+ Win32
+
+
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ false
+ false
+ false
+ false
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=;CFBundleDisplayName=;UIDeviceFamily=;CFBundleIdentifier=;CFBundleVersion=;CFBundlePackageType=;CFBundleSignature=;CFBundleAllowMixedLocalizations=;UISupportedInterfaceOrientations=;CFBundleExecutable=;CFBundleResourceSpecification=;LSRequiresIPhoneOS=;CFBundleInfoDictionaryVersion=;CFBundleDevelopmentRegion=
+ false
+ 1049
+ System;Xml;Data;Datasnap;Web;Soap;Winapi;$(DCC_Namespace)
+ 00400000
+
+
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=
+ System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
+ 1033
+
+
+ false
+ false
+ 0
+ RELEASE;$(DCC_Define)
+
+
+ DEBUG;$(DCC_Define)
+ false
+ true
+
+
+
+ MainSource
+
+
+ Cfg_2
+ Base
+
+
+ Base
+
+
+ Cfg_1
+ Base
+
+
+
+ Delphi.Personality.12
+
+
+
+
+ BuildWithException.dpr
+
+
+ False
+ False
+ 1
+ 0
+ 0
+ 0
+ False
+ False
+ False
+ False
+ False
+ 1049
+ 1251
+
+
+
+
+ 1.0.0.0
+
+
+
+
+
+ 1.0.0.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+ True
+ False
+
+
+ 12
+
+
+
+
+
+
diff --git a/prereq/fwzip/Demos/Use ZIP ExData/UseExDataBlob.dpr b/prereq/fwzip/Demos/Use ZIP ExData/UseExDataBlob.dpr
new file mode 100644
index 0000000..fb2e2b3
--- /dev/null
+++ b/prereq/fwzip/Demos/Use ZIP ExData/UseExDataBlob.dpr
@@ -0,0 +1,218 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ****************************************************************************
+// * Project : FWZip
+// * Unit Name : UseExDataBlob
+// * Purpose : ExData
+// * Author : (Rouse_)
+// * Copyright : Fangorn Wizards Lab 1998 - 2013.
+// * Version : 1.0.10
+// * Home Page : http://rouse.drkb.ru
+// * Home Blog : http://alexander-bagel.blogspot.ru
+// ****************************************************************************
+// * Stable Release : http://rouse.drkb.ru/components.php#fwzip
+// * Latest Source : https://github.com/AlexanderBagel/FWZip
+// ****************************************************************************
+//
+// :
+// ftp://ftp.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
+// http://zlib.net/zlib-1.2.5.tar.gz
+// http://www.base2ti.com/
+//
+
+// ExData.
+// .
+//
+// . .
+// OnSaveExData.
+
+program UseExDataBlob;
+
+{$APPTYPE CONSOLE}
+
+uses
+ SysUtils,
+ Classes,
+ FWZipWriter,
+ FWZipReader,
+ FWZipConsts;
+
+const
+ TestExDataBlob: Cardinal = $DEADBEEF;
+
+var
+ Writer: TFWZipWriter;
+ Reader: TFWZipReader;
+ Method: TMethod;
+
+//
+// ExData
+//
+// =============================================================================
+procedure OnSaveExData(Self, Sender: TObject; ItemIndex: Integer;
+ UserExDataBlockCount: Integer; var Tag: Word; Data: TStream);
+var
+ RandomValue: Cardinal;
+begin
+
+ //
+ // Data, Data
+ // MAXWORD .
+
+ // ,
+ // . Data.
+
+ //
+ // UserExDataBlockCount
+
+ // , :
+
+ {
+ The current Header ID mappings defined by PKWARE are:
+
+ 0x0001 ZIP64 extended information extra field
+ 0x0007 AV Info
+ 0x0008 Reserved for future Unicode file name data (PFS)
+ 0x0009 OS/2 extended attributes (also Info-ZIP)
+ 0x000a NTFS (Win9x/WinNT FileTimes)
+ 0x000c OpenVMS (also Info-ZIP)
+ 0x000d Unix
+ 0x000e Reserved for file stream and fork descriptors
+ 0x000f Patch Descriptor
+ 0x0014 PKCS#7 Store for X.509 Certificates
+ 0x0015 X.509 Certificate ID and Signature for
+ individual file
+ 0x0016 X.509 Certificate ID for Central Directory
+ 0x0017 Strong Encryption Header
+ 0x0018 Record Management Controls
+ 0x0019 PKCS#7 Encryption Recipient Certificate List
+ 0x0065 IBM S/390 (Z390), AS/400 (I400) attributes
+ - uncompressed
+ 0x0066 Reserved for IBM S/390 (Z390), AS/400 (I400)
+ attributes - compressed
+
+ The Header ID mappings defined by Info-ZIP and third parties are:
+
+ 0x07c8 Info-ZIP Macintosh (old, J. Lee)
+ 0x2605 ZipIt Macintosh (first version)
+ 0x2705 ZipIt Macintosh v 1.3.5 and newer (w/o full filename)
+ 0x2805 ZipIt Macintosh 1.3.5+
+ 0x334d Info-ZIP Macintosh (new, D. Haase's 'Mac3' field)
+ 0x4154 Tandem NSK
+ 0x4341 Acorn/SparkFS (David Pilling)
+ 0x4453 Windows NT security descriptor (binary ACL)
+ 0x4704 VM/CMS
+ 0x470f MVS
+ 0x4854 Theos, old inofficial port
+ 0x4b46 FWKCS MD5 (see below)
+ 0x4c41 OS/2 access control list (text ACL)
+ 0x4d49 Info-ZIP OpenVMS (obsolete)
+ 0x4d63 Macintosh SmartZIP, by Macro Bambini
+ 0x4f4c Xceed original location extra field
+ 0x5356 AOS/VS (binary ACL)
+ 0x5455 extended timestamp
+ 0x554e Xceed unicode extra field
+ 0x5855 Info-ZIP Unix (original; also OS/2, NT, etc.)
+ 0x6542 BeOS (BeBox, PowerMac, etc.)
+ 0x6854 Theos
+ 0x7441 AtheOS (AtheOS/Syllable attributes)
+ 0x756e ASi Unix
+ 0x7855 Info-ZIP Unix (new)
+ 0xfb4a SMS/QDOS
+ }
+
+ // :
+ case UserExDataBlockCount of
+ 0:
+ begin
+ // ( $FFFA)
+ Tag := $FFFA;
+ //
+ Data.WriteBuffer(TestExDataBlob, 4);
+ end;
+ 1..2:
+ begin
+ //
+ Tag := $FFFB + UserExDataBlockCount;
+ // -
+ Randomize;
+ RandomValue := Random(MaxInt);
+ Data.WriteBuffer(RandomValue, 4);
+ end;
+ end;
+end;
+
+//
+// ExData
+// TFWZipReader.
+// ExData,
+// .
+// TFWZipReader.LoadFromFile
+// Sender TFWZipReaderItem,
+// .. ExData.
+// =============================================================================
+procedure OnLoadExData(Self, Sender: TObject; ItemIndex: Integer;
+ Tag: Word; Data: TStream);
+var
+ Value: Cardinal;
+begin
+ // $FFFA
+ //
+ if Tag = $FFFA then
+ begin
+ //
+ if Data.Size <> 4 then
+ raise Exception.Create(' ExData');
+ Data.ReadBuffer(Value, Data.Size);
+ if Value <> TestExDataBlob then
+ raise Exception.Create(' ExData');
+
+ // Tag
+ TFWZipReaderItem(Sender).Tag := Integer(Value);
+
+ // , .. Sender
+ //
+ //
+ // Reader[ItemIndex].Tag := Integer(Value); -
+ end;
+end;
+
+begin
+ SetCurrentDir(ExtractFilePath(ParamStr(0)));
+ try
+ Writer := TFWZipWriter.Create;
+ try
+ //
+ Writer.AddFolder('', '..\..\', '*.*', False);
+
+ //
+ Method.Code := @OnSaveExData;
+ Method.Data := Writer;
+ Writer.OnSaveExData := TZipSaveExDataEvent(Method);
+
+ //
+ ForceDirectories('..\DemoResults\');
+ Writer.BuildZip('..\DemoResults\UseExDataBlob.zip');
+ finally
+ Writer.Free;
+ end;
+
+ Reader := TFWZipReader.Create;
+ try
+
+ // .
+ // OnLoadExData
+ // .
+ Method.Code := @OnLoadExData;
+ Method.Data := Reader;
+ Reader.OnLoadExData := TZipLoadExDataEvent(Method);
+ Reader.LoadFromFile('..\DemoResults\UseExDataBlob.zip');
+ finally
+ Reader.Free;
+ end;
+ except
+ on E: Exception do
+ Writeln(E.ClassName, ': ', E.Message);
+ end;
+ Readln;
+end.
diff --git a/prereq/fwzip/Demos/Use ZIP ExData/UseExDataBlob.dproj b/prereq/fwzip/Demos/Use ZIP ExData/UseExDataBlob.dproj
new file mode 100644
index 0000000..78173e2
--- /dev/null
+++ b/prereq/fwzip/Demos/Use ZIP ExData/UseExDataBlob.dproj
@@ -0,0 +1,619 @@
+
+
+ {02A43576-9D18-4FA2-9764-51DAB3B92B77}
+ UseExDataBlob.dpr
+ True
+ Debug
+ 1
+ Console
+ None
+ 14.6
+ Win32
+
+
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ false
+ false
+ false
+ false
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=;CFBundleDisplayName=;UIDeviceFamily=;CFBundleIdentifier=;CFBundleVersion=;CFBundlePackageType=;CFBundleSignature=;CFBundleAllowMixedLocalizations=;UISupportedInterfaceOrientations=;CFBundleExecutable=;CFBundleResourceSpecification=;LSRequiresIPhoneOS=;CFBundleInfoDictionaryVersion=;CFBundleDevelopmentRegion=
+ false
+ 1049
+ System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)
+ 00400000
+
+
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=
+ Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
+ 1033
+
+
+ false
+ false
+ 0
+ RELEASE;$(DCC_Define)
+
+
+ DEBUG;$(DCC_Define)
+ false
+ true
+
+
+
+ MainSource
+
+
+ Cfg_2
+ Base
+
+
+ Base
+
+
+ Cfg_1
+ Base
+
+
+
+ Delphi.Personality.12
+
+
+
+
+ UseExDataBlob.dpr
+
+
+ False
+ False
+ 1
+ 0
+ 0
+ 0
+ False
+ False
+ False
+ False
+ False
+ 1049
+ 1251
+
+
+
+
+ 1.0.0.0
+
+
+
+
+
+ 1.0.0.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+ True
+ False
+
+
+ 12
+
+
+
+
+
+
diff --git a/prereq/fwzip/Demos/ZipAnalizer/ZipAnalizer.dpr b/prereq/fwzip/Demos/ZipAnalizer/ZipAnalizer.dpr
new file mode 100644
index 0000000..9144454
--- /dev/null
+++ b/prereq/fwzip/Demos/ZipAnalizer/ZipAnalizer.dpr
@@ -0,0 +1,13 @@
+program ZipAnalizer;
+
+uses
+ Forms,
+ uZipAnalizer in 'uZipAnalizer.pas' {dlgZipAnalizer};
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TdlgZipAnalizer, dlgZipAnalizer);
+ Application.Run;
+end.
diff --git a/prereq/fwzip/Demos/ZipAnalizer/ZipAnalizer.dproj b/prereq/fwzip/Demos/ZipAnalizer/ZipAnalizer.dproj
new file mode 100644
index 0000000..1ea5b35
--- /dev/null
+++ b/prereq/fwzip/Demos/ZipAnalizer/ZipAnalizer.dproj
@@ -0,0 +1,148 @@
+
+
+ {48B210D8-1C88-400C-8596-80BA4942AF52}
+ ZipAnalizer.dpr
+ True
+ Debug
+ 1
+ Application
+ VCL
+ 14.6
+ Win32
+
+
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ false
+ 00400000
+ false
+ 1049
+ Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;Winapi;$(DCC_Namespace)
+ false
+ false
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=;CFBundleDisplayName=;UIDeviceFamily=;CFBundleIdentifier=;CFBundleVersion=;CFBundlePackageType=;CFBundleSignature=;CFBundleAllowMixedLocalizations=;UISupportedInterfaceOrientations=;CFBundleExecutable=;CFBundleResourceSpecification=;LSRequiresIPhoneOS=;CFBundleInfoDictionaryVersion=;CFBundleDevelopmentRegion=
+ false
+
+
+ Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
+ true
+ 1033
+ ZipAnalizer_Icon.ico
+ $(BDS)\bin\default_app.manifest
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=
+
+
+ $(BDS)\bin\default_app.manifest
+ ZipAnalizer_Icon.ico
+
+
+ 0
+ false
+ false
+ RELEASE;$(DCC_Define)
+
+
+ true
+ DEBUG;$(DCC_Define)
+ false
+
+
+
+ MainSource
+
+
+
+
+
+ Cfg_2
+ Base
+
+
+ Base
+
+
+ Cfg_1
+ Base
+
+
+
+ Delphi.Personality.12
+
+
+
+
+ ZipAnalizer.dpr
+
+
+ False
+ False
+ 1
+ 0
+ 0
+ 0
+ False
+ False
+ False
+ False
+ False
+ 1049
+ 1251
+
+
+
+
+ 1.0.0.0
+
+
+
+
+
+ 1.0.0.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ False
+
+
+ 12
+
+
+
+
diff --git a/prereq/fwzip/Demos/ZipAnalizer/ZipAnalizer_Icon.ico b/prereq/fwzip/Demos/ZipAnalizer/ZipAnalizer_Icon.ico
new file mode 100644
index 0000000..fc7534d
Binary files /dev/null and b/prereq/fwzip/Demos/ZipAnalizer/ZipAnalizer_Icon.ico differ
diff --git a/prereq/fwzip/Demos/ZipAnalizer/uZipAnalizer.dfm b/prereq/fwzip/Demos/ZipAnalizer/uZipAnalizer.dfm
new file mode 100644
index 0000000..92d17fd
--- /dev/null
+++ b/prereq/fwzip/Demos/ZipAnalizer/uZipAnalizer.dfm
@@ -0,0 +1,104 @@
+object dlgZipAnalizer: TdlgZipAnalizer
+ Left = 301
+ Top = 184
+ Caption = #1042#1099#1074#1086#1076' '#1087#1072#1088#1072#1084#1077#1090#1088#1086#1074' ZIP '#1072#1088#1093#1080#1074#1072
+ ClientHeight = 300
+ ClientWidth = 685
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ OldCreateOrder = False
+ Position = poScreenCenter
+ OnCreate = FormCreate
+ OnDestroy = FormDestroy
+ DesignSize = (
+ 685
+ 300)
+ PixelsPerInch = 96
+ TextHeight = 13
+ object edPath: TLabeledEdit
+ Left = 8
+ Top = 24
+ Width = 550
+ Height = 21
+ Anchors = [akLeft, akTop, akRight]
+ EditLabel.Width = 124
+ EditLabel.Height = 13
+ EditLabel.Caption = #1059#1082#1072#1078#1080#1090#1077' '#1087#1091#1090#1100' '#1082' '#1072#1088#1093#1080#1074#1091':'
+ TabOrder = 0
+ OnChange = edPathChange
+ end
+ object btnBrowse: TButton
+ Left = 560
+ Top = 22
+ Width = 25
+ Height = 25
+ Anchors = [akTop, akRight]
+ Caption = '...'
+ TabOrder = 1
+ OnClick = btnBrowseClick
+ end
+ object btnAnalize: TButton
+ Left = 591
+ Top = 22
+ Width = 75
+ Height = 25
+ Anchors = [akTop, akRight]
+ Caption = #1057#1090#1072#1088#1090
+ Enabled = False
+ TabOrder = 2
+ OnClick = btnAnalizeClick
+ end
+ object GroupBox: TGroupBox
+ Left = 8
+ Top = 56
+ Width = 669
+ Height = 233
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ Caption = #1055#1072#1088#1072#1084#1077#1090#1088#1099' '#1072#1088#1093#1080#1074#1072':'
+ TabOrder = 3
+ object edReport: TRichEdit
+ Left = 2
+ Top = 15
+ Width = 665
+ Height = 216
+ Align = alClient
+ Font.Charset = RUSSIAN_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ PopupMenu = PopupMenu
+ ReadOnly = True
+ ScrollBars = ssBoth
+ TabOrder = 0
+ end
+ end
+ object OpenDialog: TOpenDialog
+ DefaultExt = 'zip'
+ Filter = 'ZIP '#1072#1088#1093#1080#1074#1099' (*.zip)|*.zip|'#1042#1089#1077' '#1092#1072#1081#1083#1099' (*.*)|*.*'
+ Options = [ofHideReadOnly, ofFileMustExist, ofEnableSizing]
+ Left = 48
+ Top = 88
+ end
+ object PopupMenu: TPopupMenu
+ OnPopup = PopupMenuPopup
+ Left = 120
+ Top = 88
+ object mnuSave: TMenuItem
+ Caption = #1057#1086#1093#1088#1072#1085#1080#1090#1100'...'
+ ShortCut = 16467
+ OnClick = mnuSaveClick
+ end
+ end
+ object SaveDialog: TSaveDialog
+ DefaultExt = 'txt'
+ Filter = #1058#1077#1082#1089#1090#1086#1074#1099#1077' '#1092#1072#1081#1083#1099' (*.txt)|*.txt|'#1042#1089#1077' '#1092#1072#1081#1083#1099' (*.*)|*.*'
+ Left = 208
+ Top = 88
+ end
+end
diff --git a/prereq/fwzip/Demos/ZipAnalizer/uZipAnalizer.pas b/prereq/fwzip/Demos/ZipAnalizer/uZipAnalizer.pas
new file mode 100644
index 0000000..aff48ab
--- /dev/null
+++ b/prereq/fwzip/Demos/ZipAnalizer/uZipAnalizer.pas
@@ -0,0 +1,351 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ****************************************************************************
+// * Project : FWZip - ZipAnalizer
+// * Unit Name : uZipAnalizer
+// * Purpose : FWZipReader
+// * Author : (Rouse_)
+// * Copyright : Fangorn Wizards Lab 1998 - 2013.
+// * Version : 1.0.10
+// * Home Page : http://rouse.drkb.ru
+// * Home Blog : http://alexander-bagel.blogspot.ru
+// ****************************************************************************
+// * Stable Release : http://rouse.drkb.ru/components.php#fwzip
+// * Latest Source : https://github.com/AlexanderBagel/FWZip
+// ****************************************************************************
+//
+// :
+// ftp://ftp.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
+// http://zlib.net/zlib-1.2.5.tar.gz
+// http://www.base2ti.com/
+//
+
+unit uZipAnalizer;
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Controls, Forms,
+ Dialogs, StdCtrls, ComCtrls, ExtCtrls, Menus,
+ FWZipReader, FWZipConsts;
+
+type
+ TFWZipReaderFriendly = class(TFWZipReader);
+ TFWZipReaderItemFriendly = class(TFWZipReaderItem);
+ TExDataRecord = record
+ Index: Integer;
+ Tag: Word;
+ Stream: TMemoryStream;
+ end;
+ TExDataRecords = array of TExDataRecord;
+
+ TdlgZipAnalizer = class(TForm)
+ edPath: TLabeledEdit;
+ btnBrowse: TButton;
+ btnAnalize: TButton;
+ GroupBox: TGroupBox;
+ edReport: TRichEdit;
+ OpenDialog: TOpenDialog;
+ PopupMenu: TPopupMenu;
+ mnuSave: TMenuItem;
+ SaveDialog: TSaveDialog;
+ procedure btnBrowseClick(Sender: TObject);
+ procedure edPathChange(Sender: TObject);
+ procedure btnAnalizeClick(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure FormDestroy(Sender: TObject);
+ procedure mnuSaveClick(Sender: TObject);
+ procedure PopupMenuPopup(Sender: TObject);
+ private
+ ExDataRecords: TExDataRecords;
+ Zip: TFWZipReaderFriendly;
+ procedure OnLoadExData(Sender: TObject; ItemIndex: Integer;
+ Tag: Word; Data: TStream);
+ private
+ procedure ClearExData;
+ procedure Log(const Value: string);
+ procedure ShowEndOfCentralDir;
+ procedure ShowZip64EOFCentralDirectoryLocator;
+ procedure ShowZip64EOFCentralDirectoryRecord;
+ procedure ShowItemData(Index: Integer);
+ end;
+
+var
+ dlgZipAnalizer: TdlgZipAnalizer;
+
+implementation
+
+const
+ Delim = '===================================================================';
+
+{$R *.dfm}
+
+procedure TdlgZipAnalizer.btnAnalizeClick(Sender: TObject);
+var
+ I: Integer;
+begin
+ edReport.Lines.BeginUpdate;
+ try
+ edReport.Clear;
+ Log(edPath.Text);
+ Log(Delim);
+ ClearExData;
+ Zip.Clear;
+ Zip.LoadFromFile(edPath.Text);
+ ShowEndOfCentralDir;
+ ShowZip64EOFCentralDirectoryLocator;
+ ShowZip64EOFCentralDirectoryRecord;
+ for I := 0 to Zip.Count - 1 do
+ ShowItemData(I);
+ Log('DONE');
+ finally
+ edReport.Lines.EndUpdate;
+ end;
+end;
+
+procedure TdlgZipAnalizer.btnBrowseClick(Sender: TObject);
+begin
+ if OpenDialog.Execute then
+ begin
+ edPath.Text := OpenDialog.FileName;
+ edReport.Clear;
+ end;
+end;
+
+procedure TdlgZipAnalizer.ClearExData;
+var
+ I: Integer;
+begin
+ for I := 0 to Length(ExDataRecords) - 1 do
+ ExDataRecords[I].Stream.Free;
+ SetLength(ExDataRecords, 0);;
+end;
+
+procedure TdlgZipAnalizer.edPathChange(Sender: TObject);
+begin
+ btnAnalize.Enabled := FileExists(edPath.Text);
+end;
+
+procedure TdlgZipAnalizer.FormCreate(Sender: TObject);
+begin
+ Zip := TFWZipReaderFriendly.Create;
+ Zip.OnLoadExData := OnLoadExData;
+ edReport.PlainText := True;
+end;
+
+procedure TdlgZipAnalizer.FormDestroy(Sender: TObject);
+begin
+ ClearExData;
+ Zip.Free;
+end;
+
+procedure TdlgZipAnalizer.Log(const Value: string);
+begin
+ edReport.Lines.Add(Value);
+end;
+
+procedure TdlgZipAnalizer.mnuSaveClick(Sender: TObject);
+begin
+ if SaveDialog.Execute then
+ edReport.Lines.SaveToFile(SaveDialog.FileName);
+end;
+
+procedure TdlgZipAnalizer.OnLoadExData(Sender: TObject; ItemIndex: Integer;
+ Tag: Word; Data: TStream);
+var
+ Count: Integer;
+begin
+ Count := Length(ExDataRecords);
+ SetLength(ExDataRecords, Count + 1);
+ ExDataRecords[Count].Index := ItemIndex;
+ ExDataRecords[Count].Tag := Tag;
+ ExDataRecords[Count].Stream := TMemoryStream.Create;
+ ExDataRecords[Count].Stream.CopyFrom(Data, 0);
+end;
+
+procedure TdlgZipAnalizer.PopupMenuPopup(Sender: TObject);
+begin
+ mnuSave.Enabled := edReport.Lines.Count > 1;
+end;
+
+procedure TdlgZipAnalizer.ShowEndOfCentralDir;
+begin
+ Log('END_OF_CENTRAL_DIR_SIGNATURE found');
+ with Zip.EndOfCentralDir do
+ begin
+ Log(Format('NumberOfThisDisk: %d', [NumberOfThisDisk]));
+ Log(Format('NumberOfTheDiskWithTheStart: %d', [NumberOfTheDiskWithTheStart]));
+ Log(Format('TotalNumberOfEntriesOnThisDisk: %d', [TotalNumberOfEntriesOnThisDisk]));
+ Log(Format('TotalNumberOfEntries: %d', [TotalNumberOfEntries]));
+ Log(Format('SizeOfTheCentralDirectory: %d', [SizeOfTheCentralDirectory]));
+ Log(Format('OffsetOfStartOfCentralDirectory: %d', [OffsetOfStartOfCentralDirectory]));
+ Log(Format('ZipfileCommentLength: %d', [ZipfileCommentLength]));
+ if ZipfileCommentLength > 0 then
+ Log(Format('Comment: %s', [Zip.Comment]));
+ end;
+ Log(Delim);
+end;
+
+procedure TdlgZipAnalizer.ShowItemData(Index: Integer);
+
+ function ByteToStr(Bytes: PByte; Size: Integer): string;
+ const
+ BytesHex: array[0..15] of char =
+ ('0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
+ var
+ I: integer;
+ begin
+ SetLength(Result, Size shl 1);
+ for I := 0 to Size - 1 do
+ begin
+ Result[I * 2 + 1] := BytesHex[Bytes^ shr 4];
+ Result[I * 2 + 2] := BytesHex[Bytes^ and $0F];
+ Inc(Bytes);
+ end;
+ end;
+
+ function GPBFToStr(Value: Word): string;
+
+ procedure AddValue(const S: string);
+ begin
+ if Result = '' then
+ Result := S
+ else
+ Result := Result + ', ' + S;
+ end;
+
+ begin
+ if Value = 0 then
+ begin
+ Result := 'EMPTY';
+ Exit;
+ end;
+ if PBF_CRYPTED and Value <> 0 then
+ AddValue('PBF_CRYPTED');
+
+ if PBF_DESCRIPTOR and Value <> 0 then
+ AddValue('PBF_DESCRIPTOR');
+
+ if PBF_UTF8 and Value <> 0 then
+ AddValue('PBF_UTF8');
+
+ if PBF_STRONG_CRYPT and Value <> 0 then
+ AddValue('PBF_STRONG_CRYPT');
+ end;
+
+var
+ I: Integer;
+ Item: TFWZipReaderItemFriendly;
+begin
+ Log('CENTRAL_FILE_HEADER_SIGNATURE found');
+ Item := TFWZipReaderItemFriendly(Zip.Item[Index]);
+ with Item.CentralDirFileHeader do
+ begin
+ Log(Format('VersionMadeBy: %d', [VersionMadeBy]));
+ Log(Format('VersionNeededToExtract: %d', [VersionNeededToExtract]));
+ Log(Format('GeneralPurposeBitFlag: %d (%s)', [GeneralPurposeBitFlag,
+ GPBFToStr(GeneralPurposeBitFlag)]));
+ Log(Format('CompressionMethod: %d', [CompressionMethod]));
+ Log(Format('LastModFileTimeTime: %d', [LastModFileTimeTime]));
+ Log(Format('LastModFileTimeDate: %d', [LastModFileTimeDate]));
+ Log(Format('Crc32: %d', [Crc32]));
+ Log(Format('CompressedSize: %d', [CompressedSize]));
+ Log(Format('UncompressedSize: %d', [UncompressedSize]));
+ Log(Format('FilenameLength: %d', [FilenameLength]));
+ if FilenameLength > 0 then
+ Log('>>> FileName: ' + Item.FileName);
+ Log(Format('ExtraFieldLength: %d', [ExtraFieldLength]));
+ Log(Format('FileCommentLength: %d', [FileCommentLength]));
+ if FileCommentLength > 0 then
+ Log('>>> FileComment: ' + Item.Comment);
+ Log(Format('DiskNumberStart: %d', [DiskNumberStart]));
+ Log(Format('InternalFileAttributes: %d', [InternalFileAttributes]));
+ Log(Format('ExternalFileAttributes: %d', [ExternalFileAttributes]));
+ Log(Format('RelativeOffsetOfLocalHeader: %d', [RelativeOffsetOfLocalHeader]));
+ end;
+
+ Log('');
+
+ Item.LoadLocalFileHeader;
+ Log('LOCAL_FILE_HEADER_SIGNATURE found');
+ with Item.LocalFileHeader do
+ begin
+ Log(Format('VersionNeededToExtract: %d', [VersionNeededToExtract]));
+ Log(Format('GeneralPurposeBitFlag: %d (%s)', [GeneralPurposeBitFlag,
+ GPBFToStr(GeneralPurposeBitFlag)]));
+ Log(Format('CompressionMethod: %d', [CompressionMethod]));
+ Log(Format('LastModFileTimeTime: %d', [LastModFileTimeTime]));
+ Log(Format('LastModFileTimeDate: %d', [LastModFileTimeDate]));
+ Log(Format('Crc32: %d', [Crc32]));
+ Log(Format('CompressedSize: %d', [CompressedSize]));
+ Log(Format('UncompressedSize: %d', [UncompressedSize]));
+ Log(Format('FilenameLength: %d', [FilenameLength]));
+ Log(Format('ExtraFieldLength: %d', [ExtraFieldLength]));
+ end;
+
+ if ssZIP64 in Item.PresentStreams then
+ begin
+ Log('');
+ Log('SUPPORTED_EXDATA_ZIP64 found');
+ with Item do
+ begin
+ Log(Format('UncompressedSize: %d', [UncompressedSize]));
+ Log(Format('CompressedSize: %d', [CompressedSize]));
+ Log(Format('RelativeOffsetOfLocalHeader: %d', [RelativeOffsetOfLocalHeader]));
+ Log(Format('DiskNumberStart: %d', [DiskNumberStart]));
+ end;
+ end;
+
+ if ssNTFS in Item.PresentStreams then
+ begin
+ Log('');
+ Log('SUPPORTED_EXDATA_NTFSTIME found');
+ end;
+
+ for I := 0 to Length(ExDataRecords) - 1 do
+ if ExDataRecords[I].Index = Index then
+ begin
+ Log('');
+ Log(Format('UNKNOWN TAG (%d) found', [ExDataRecords[I].Tag]));
+ Log(Format('ExData size %d', [ExDataRecords[I].Stream.Size]));
+ Log('ExData dump:');
+ Log(ByteToStr(ExDataRecords[I].Stream.Memory, ExDataRecords[I].Stream.Size));
+ end;
+
+ Log(Delim);
+end;
+
+procedure TdlgZipAnalizer.ShowZip64EOFCentralDirectoryLocator;
+begin
+ with Zip.Zip64EOFCentralDirectoryLocator do
+ begin
+ if Signature <> ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE then Exit;
+ Log('ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE found');
+ Log(Format('NumberOfTheDisk: %d', [NumberOfTheDisk]));
+ Log(Format('RelativeOffset: %d', [RelativeOffset]));
+ Log(Format('TotalNumberOfDisks: %d', [TotalNumberOfDisks]));
+ end;
+ Log(Delim);
+end;
+
+procedure TdlgZipAnalizer.ShowZip64EOFCentralDirectoryRecord;
+begin
+ with Zip.Zip64EOFCentralDirectoryRecord do
+ begin
+ if Zip64EndOfCentralDirSignature <> ZIP64_END_OF_CENTRAL_DIR_SIGNATURE then Exit;
+ Log('ZIP64_END_OF_CENTRAL_DIR_SIGNATURE found');
+ Log(Format('SizeOfZip64EOFCentralDirectoryRecord: %d', [SizeOfZip64EOFCentralDirectoryRecord]));
+ Log(Format('VersionMadeBy: %d', [VersionMadeBy]));
+ Log(Format('VersionNeededToExtract: %d', [VersionNeededToExtract]));
+ Log(Format('number of this disk: %d', [Number1]));
+ Log(Format('number of the disk with the start of the central directory: %d', [Number2]));
+ Log(Format('total number of entries in the central directory on this disk: %d', [TotalNumber1]));
+ Log(Format('total number of entries in the central directory: %d', [TotalNumber2]));
+ Log(Format('size of the central directory: %d', [Size]));
+ Log(Format('offset of start of central directory with respect to the starting disk number: %d', [Offset]));
+ end;
+ Log(Delim);
+end;
+
+end.
diff --git a/prereq/fwzip/Demos/ZipAnalizer2/ZipAnalizer2.dpr b/prereq/fwzip/Demos/ZipAnalizer2/ZipAnalizer2.dpr
new file mode 100644
index 0000000..b990f5f
--- /dev/null
+++ b/prereq/fwzip/Demos/ZipAnalizer2/ZipAnalizer2.dpr
@@ -0,0 +1,13 @@
+program ZipAnalizer2;
+
+uses
+ Forms,
+ uZipAnalizer2 in 'uZipAnalizer2.pas' {dlgZipAnalizer};
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TdlgZipAnalizer, dlgZipAnalizer);
+ Application.Run;
+end.
diff --git a/prereq/fwzip/Demos/ZipAnalizer2/ZipAnalizer2.dproj b/prereq/fwzip/Demos/ZipAnalizer2/ZipAnalizer2.dproj
new file mode 100644
index 0000000..8f5f5d0
--- /dev/null
+++ b/prereq/fwzip/Demos/ZipAnalizer2/ZipAnalizer2.dproj
@@ -0,0 +1,148 @@
+
+
+ {59E61B6B-6187-41F8-947A-693BE9101356}
+ ZipAnalizer2.dpr
+ True
+ Debug
+ 1
+ Application
+ VCL
+ 14.6
+ Win32
+
+
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ false
+ 00400000
+ false
+ 1049
+ Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;Winapi;$(DCC_Namespace)
+ false
+ false
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=;CFBundleDisplayName=;UIDeviceFamily=;CFBundleIdentifier=;CFBundleVersion=;CFBundlePackageType=;CFBundleSignature=;CFBundleAllowMixedLocalizations=;UISupportedInterfaceOrientations=;CFBundleExecutable=;CFBundleResourceSpecification=;LSRequiresIPhoneOS=;CFBundleInfoDictionaryVersion=;CFBundleDevelopmentRegion=
+ false
+
+
+ Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
+ true
+ 1033
+ ZipAnalizer_Icon.ico
+ $(BDS)\bin\default_app.manifest
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=
+
+
+ $(BDS)\bin\default_app.manifest
+ ZipAnalizer_Icon.ico
+
+
+ 0
+ false
+ false
+ RELEASE;$(DCC_Define)
+
+
+ true
+ DEBUG;$(DCC_Define)
+ false
+
+
+
+ MainSource
+
+
+
+
+
+ Cfg_2
+ Base
+
+
+ Base
+
+
+ Cfg_1
+ Base
+
+
+
+ Delphi.Personality.12
+
+
+
+
+ ZipAnalizer2.dpr
+
+
+ False
+ False
+ 1
+ 0
+ 0
+ 0
+ False
+ False
+ False
+ False
+ False
+ 1049
+ 1251
+
+
+
+
+ 1.0.0.0
+
+
+
+
+
+ 1.0.0.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ False
+
+
+ 12
+
+
+
+
diff --git a/prereq/fwzip/Demos/ZipAnalizer2/ZipAnalizer_Icon.ico b/prereq/fwzip/Demos/ZipAnalizer2/ZipAnalizer_Icon.ico
new file mode 100644
index 0000000..fc7534d
Binary files /dev/null and b/prereq/fwzip/Demos/ZipAnalizer2/ZipAnalizer_Icon.ico differ
diff --git a/prereq/fwzip/Demos/ZipAnalizer2/uZipAnalizer2.dfm b/prereq/fwzip/Demos/ZipAnalizer2/uZipAnalizer2.dfm
new file mode 100644
index 0000000..b43e88e
--- /dev/null
+++ b/prereq/fwzip/Demos/ZipAnalizer2/uZipAnalizer2.dfm
@@ -0,0 +1,103 @@
+object dlgZipAnalizer: TdlgZipAnalizer
+ Left = 301
+ Top = 184
+ Caption = #1042#1099#1074#1086#1076' '#1087#1072#1088#1072#1084#1077#1090#1088#1086#1074' ZIP '#1072#1088#1093#1080#1074#1072
+ ClientHeight = 300
+ ClientWidth = 685
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ OldCreateOrder = False
+ Position = poScreenCenter
+ OnCreate = FormCreate
+ DesignSize = (
+ 685
+ 300)
+ PixelsPerInch = 96
+ TextHeight = 13
+ object edPath: TLabeledEdit
+ Left = 8
+ Top = 24
+ Width = 550
+ Height = 21
+ Anchors = [akLeft, akTop, akRight]
+ EditLabel.Width = 124
+ EditLabel.Height = 13
+ EditLabel.Caption = #1059#1082#1072#1078#1080#1090#1077' '#1087#1091#1090#1100' '#1082' '#1072#1088#1093#1080#1074#1091':'
+ TabOrder = 0
+ OnChange = edPathChange
+ end
+ object btnBrowse: TButton
+ Left = 560
+ Top = 22
+ Width = 25
+ Height = 25
+ Anchors = [akTop, akRight]
+ Caption = '...'
+ TabOrder = 1
+ OnClick = btnBrowseClick
+ end
+ object btnAnalize: TButton
+ Left = 591
+ Top = 22
+ Width = 75
+ Height = 25
+ Anchors = [akTop, akRight]
+ Caption = #1057#1090#1072#1088#1090
+ Enabled = False
+ TabOrder = 2
+ OnClick = btnAnalizeClick
+ end
+ object GroupBox: TGroupBox
+ Left = 8
+ Top = 56
+ Width = 669
+ Height = 233
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ Caption = #1055#1072#1088#1072#1084#1077#1090#1088#1099' '#1072#1088#1093#1080#1074#1072':'
+ TabOrder = 3
+ object edReport: TRichEdit
+ Left = 2
+ Top = 15
+ Width = 665
+ Height = 216
+ Align = alClient
+ Font.Charset = RUSSIAN_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ PopupMenu = PopupMenu
+ ReadOnly = True
+ ScrollBars = ssBoth
+ TabOrder = 0
+ end
+ end
+ object OpenDialog: TOpenDialog
+ DefaultExt = 'zip'
+ Filter = 'ZIP '#1072#1088#1093#1080#1074#1099' (*.zip)|*.zip|'#1042#1089#1077' '#1092#1072#1081#1083#1099' (*.*)|*.*'
+ Options = [ofHideReadOnly, ofFileMustExist, ofEnableSizing]
+ Left = 48
+ Top = 88
+ end
+ object PopupMenu: TPopupMenu
+ OnPopup = PopupMenuPopup
+ Left = 120
+ Top = 88
+ object mnuSave: TMenuItem
+ Caption = #1057#1086#1093#1088#1072#1085#1080#1090#1100'...'
+ ShortCut = 16467
+ OnClick = mnuSaveClick
+ end
+ end
+ object SaveDialog: TSaveDialog
+ DefaultExt = 'txt'
+ Filter = #1058#1077#1082#1089#1090#1086#1074#1099#1077' '#1092#1072#1081#1083#1099' (*.txt)|*.txt|'#1042#1089#1077' '#1092#1072#1081#1083#1099' (*.*)|*.*'
+ Left = 208
+ Top = 88
+ end
+end
diff --git a/prereq/fwzip/Demos/ZipAnalizer2/uZipAnalizer2.pas b/prereq/fwzip/Demos/ZipAnalizer2/uZipAnalizer2.pas
new file mode 100644
index 0000000..68ac040
--- /dev/null
+++ b/prereq/fwzip/Demos/ZipAnalizer2/uZipAnalizer2.pas
@@ -0,0 +1,555 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ****************************************************************************
+// * Project : FWZip - ZipAnalizer2
+// * Unit Name : uZipAnalizer2
+// * Purpose :
+// * Author : (Rouse_)
+// * Copyright : Fangorn Wizards Lab 1998 - 2013.
+// * Version : 1.0.10
+// * Home Page : http://rouse.drkb.ru
+// * Home Blog : http://alexander-bagel.blogspot.ru
+// ****************************************************************************
+// * Stable Release : http://rouse.drkb.ru/components.php#fwzip
+// * Latest Source : https://github.com/AlexanderBagel/FWZip
+// ****************************************************************************
+//
+// :
+// ftp://ftp.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
+// http://zlib.net/zlib-1.2.5.tar.gz
+// http://www.base2ti.com/
+//
+
+unit uZipAnalizer2;
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Controls, Forms,
+ Dialogs, StdCtrls, ComCtrls, ExtCtrls, Menus,
+ FWZipConsts;
+
+type
+ TdlgZipAnalizer = class(TForm)
+ edPath: TLabeledEdit;
+ btnBrowse: TButton;
+ btnAnalize: TButton;
+ GroupBox: TGroupBox;
+ edReport: TRichEdit;
+ OpenDialog: TOpenDialog;
+ PopupMenu: TPopupMenu;
+ mnuSave: TMenuItem;
+ SaveDialog: TSaveDialog;
+ procedure btnBrowseClick(Sender: TObject);
+ procedure edPathChange(Sender: TObject);
+ procedure btnAnalizeClick(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure mnuSaveClick(Sender: TObject);
+ procedure PopupMenuPopup(Sender: TObject);
+ private
+ procedure Log(const Value: string);
+ procedure Scan(const Value: string);
+ function FindSing(Stream: TStream): DWORD;
+ procedure ShowLocalFileHeader(Stream: TStream);
+ procedure ShowDataDescryptor(Stream: TStream);
+ procedure ShowCentralFileHeader(Stream: TStream);
+ procedure ShowExtraFields(Stream: TStream; Size: Integer;
+ FileHeader: TCentralDirectoryFileHeader);
+ procedure ShowZip64(Stream: TStream);
+ procedure ShowZip64Locator(Stream: TStream);
+ procedure ShowEndOfCentralDir(Stream: TStream);
+ procedure LoadStringValue(Stream: TStream; var Value: string;
+ nSize: Cardinal; UTF: Boolean);
+ end;
+
+var
+ dlgZipAnalizer: TdlgZipAnalizer;
+
+implementation
+
+const
+ Delim = '===================================================================';
+
+{$R *.dfm}
+
+function GPBFToStr(Value: Word): string;
+
+ procedure AddValue(const S: string);
+ begin
+ if Result = '' then
+ Result := S
+ else
+ Result := Result + ', ' + S;
+ end;
+
+begin
+ if Value = 0 then
+ begin
+ Result := 'EMPTY';
+ Exit;
+ end;
+ if PBF_CRYPTED and Value <> 0 then
+ AddValue('PBF_CRYPTED');
+
+ if PBF_DESCRIPTOR and Value <> 0 then
+ AddValue('PBF_DESCRIPTOR');
+
+ if PBF_UTF8 and Value <> 0 then
+ AddValue('PBF_UTF8');
+
+ if PBF_STRONG_CRYPT and Value <> 0 then
+ AddValue('PBF_STRONG_CRYPT');
+end;
+
+procedure TdlgZipAnalizer.btnAnalizeClick(Sender: TObject);
+begin
+ edReport.Lines.BeginUpdate;
+ try
+ edReport.Clear;
+ Log(edPath.Text);
+ Log(Delim);
+ Scan(edPath.Text);
+ Log('DONE');
+ finally
+ edReport.Lines.EndUpdate;
+ end;
+end;
+
+procedure TdlgZipAnalizer.btnBrowseClick(Sender: TObject);
+begin
+ if OpenDialog.Execute then
+ begin
+ edPath.Text := OpenDialog.FileName;
+ edReport.Clear;
+ end;
+end;
+
+
+procedure TdlgZipAnalizer.edPathChange(Sender: TObject);
+begin
+ btnAnalize.Enabled := FileExists(edPath.Text);
+end;
+
+function TdlgZipAnalizer.FindSing(Stream: TStream): DWORD;
+const
+ KnownSigns: array [0..5] of DWORD = (
+ LOCAL_FILE_HEADER_SIGNATURE,
+ DATA_DESCRIPTOR_SIGNATURE,
+ CENTRAL_FILE_HEADER_SIGNATURE,
+ ZIP64_END_OF_CENTRAL_DIR_SIGNATURE,
+ ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE,
+ END_OF_CENTRAL_DIR_SIGNATURE
+ );
+
+ function CalcLen: Integer;
+ begin
+ Result := Stream.Size - Stream.Position;
+ if Result > 1024 then
+ Result := 1024;
+ end;
+
+var
+ pBuff, pCursor: PByte;
+ I, A, Len: Integer;
+ OldPosition: Int64;
+begin
+ Result := 0;
+ GetMem(pBuff, 1024);
+ try
+ Len := CalcLen;
+ while (Result = 0) and (Len > 4) do
+ begin
+ OldPosition := Stream.Position;
+ Stream.ReadBuffer(pBuff^, Len);
+ pCursor := pBuff;
+ for I := 0 to Len - 4 do
+ begin
+ for A := 0 to 5 do
+ if PDWORD(pCursor)^ = KnownSigns[A] then
+ begin
+ Result := KnownSigns[A];
+ Break;
+ end;
+ if Result = 0 then
+ Inc(pCursor)
+ else
+ begin
+ Stream.Position := OldPosition + I;
+ Break;
+ end;
+ end;
+ if Result = 0 then
+ begin
+ Len := CalcLen;
+ if Len > 0 then
+ Stream.Position := Stream.Position - 4;
+ end;
+ end;
+ finally
+ FreeMem(pBuff);
+ end;
+end;
+
+procedure TdlgZipAnalizer.FormCreate(Sender: TObject);
+begin
+ edReport.PlainText := True;
+end;
+
+procedure TdlgZipAnalizer.LoadStringValue(Stream: TStream;
+ var Value: string; nSize: Cardinal; UTF: Boolean);
+var
+ aString: AnsiString;
+begin
+ if Integer(nSize) > 0 then
+ begin
+ SetLength(aString, nSize);
+ Stream.ReadBuffer(aString[1], nSize);
+ if UTF then
+ begin
+ {$IFDEF UNICODE}
+ Value := string(UTF8ToUnicodeString(aString))
+ {$ELSE}
+ Value := string(UTF8Decode(aString));
+ Value := StringReplace(Value, '?', '_', [rfReplaceAll]);
+ {$ENDIF}
+ end
+ else
+ begin
+ OemToAnsi(@aString[1], @aString[1]);
+ Value := string(aString);
+ end;
+ end;
+end;
+
+procedure TdlgZipAnalizer.Log(const Value: string);
+begin
+ edReport.Lines.Add(Value);
+end;
+
+procedure TdlgZipAnalizer.mnuSaveClick(Sender: TObject);
+begin
+ if SaveDialog.Execute then
+ edReport.Lines.SaveToFile(SaveDialog.FileName);
+end;
+
+procedure TdlgZipAnalizer.PopupMenuPopup(Sender: TObject);
+begin
+ mnuSave.Enabled := edReport.Lines.Count > 1;
+end;
+
+procedure TdlgZipAnalizer.Scan(const Value: string);
+var
+ F: TFileStream;
+ Sign: DWORD;
+begin
+ F := TFileStream.Create(Value, fmOpenRead or fmShareDenyWrite);
+ try
+ Sign := FindSing(F);
+ while Sign <> 0 do
+ begin
+ case Sign of
+ LOCAL_FILE_HEADER_SIGNATURE: ShowLocalFileHeader(F);
+ DATA_DESCRIPTOR_SIGNATURE: ShowDataDescryptor(F);
+ CENTRAL_FILE_HEADER_SIGNATURE: ShowCentralFileHeader(F);
+ ZIP64_END_OF_CENTRAL_DIR_SIGNATURE: ShowZip64(F);
+ ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE: ShowZip64Locator(F);
+ END_OF_CENTRAL_DIR_SIGNATURE: ShowEndOfCentralDir(F);
+ end;
+ Sign := FindSing(F);
+ end;
+ finally
+ F.Free;
+ end;
+end;
+
+procedure TdlgZipAnalizer.ShowCentralFileHeader(Stream: TStream);
+var
+ Data: TCentralDirectoryFileHeader;
+ FileName, Comment: string;
+begin
+ Log('CENTRAL_FILE_HEADER_SIGNATURE found at offset: ' + IntToStr(Stream.Position));
+ Stream.ReadBuffer(Data, SizeOf(TCentralDirectoryFileHeader));
+ with Data do
+ begin
+ if CentralFileHeaderSignature <> CENTRAL_FILE_HEADER_SIGNATURE then
+ Log('INVALID SIGNATURE!!!!');
+ Log(Format('VersionMadeBy: %d', [VersionMadeBy]));
+ Log(Format('VersionNeededToExtract: %d', [VersionNeededToExtract]));
+ Log(Format('GeneralPurposeBitFlag: %d (%s)', [GeneralPurposeBitFlag,
+ GPBFToStr(GeneralPurposeBitFlag)]));
+ Log(Format('CompressionMethod: %d', [CompressionMethod]));
+ Log(Format('LastModFileTimeTime: %d', [LastModFileTimeTime]));
+ Log(Format('LastModFileTimeDate: %d', [LastModFileTimeDate]));
+ Log(Format('Crc32: %d', [Crc32]));
+ Log(Format('CompressedSize: %d', [CompressedSize]));
+ Log(Format('UncompressedSize: %d', [UncompressedSize]));
+ Log(Format('FilenameLength: %d', [FilenameLength]));
+ Log(Format('ExtraFieldLength: %d', [ExtraFieldLength]));
+ Log(Format('FileCommentLength: %d', [FileCommentLength]));
+ Log(Format('DiskNumberStart: %d', [DiskNumberStart]));
+ Log(Format('InternalFileAttributes: %d', [InternalFileAttributes]));
+ Log(Format('ExternalFileAttributes: %d', [ExternalFileAttributes]));
+ Log(Format('RelativeOffsetOfLocalHeader: %d', [RelativeOffsetOfLocalHeader]));
+ LoadStringValue(Stream, FileName, FilenameLength,
+ GeneralPurposeBitFlag and PBF_UTF8 <> 0);
+ Log('>>> FileName: ' + FileName);
+ Log(Delim);
+ ShowExtraFields(Stream, ExtraFieldLength, Data);
+ if FileCommentLength > 0 then
+ begin
+ LoadStringValue(Stream, Comment, FileCommentLength,
+ GeneralPurposeBitFlag and PBF_UTF8 <> 0);
+ Log('>>> FileComment: ' + Comment);
+ Log(Delim);
+ end;
+ end;
+end;
+
+procedure TdlgZipAnalizer.ShowDataDescryptor(Stream: TStream);
+var
+ Data: TDataDescriptor;
+begin
+ Log('DATA_DESCRIPTOR_SIGNATURE found at offset: ' + IntToStr(Stream.Position));
+ Stream.ReadBuffer(Data, SizeOf(TDataDescriptor));
+ with Data do
+ begin
+ if DescriptorSignature <> DATA_DESCRIPTOR_SIGNATURE then
+ Log('INVALID SIGNATURE!!!!');
+ Log(Format('Crc32: %d', [Crc32]));
+ Log(Format('CompressedSize: %d', [CompressedSize]));
+ Log(Format('UncompressedSize: %d', [UncompressedSize]));
+ end;
+ Log(Delim);
+end;
+
+procedure TdlgZipAnalizer.ShowEndOfCentralDir(Stream: TStream);
+var
+ Data: TEndOfCentralDir;
+ Comment: string;
+begin
+ Log('END_OF_CENTRAL_DIR_SIGNATURE found at offset: ' + IntToStr(Stream.Position));
+ Stream.ReadBuffer(Data, SizeOf(TEndOfCentralDir));
+ with Data do
+ begin
+ if EndOfCentralDirSignature <> END_OF_CENTRAL_DIR_SIGNATURE then
+ Log('INVALID SIGNATURE!!!!');
+ Log(Format('NumberOfThisDisk: %d', [NumberOfThisDisk]));
+ Log(Format('NumberOfTheDiskWithTheStart: %d', [NumberOfTheDiskWithTheStart]));
+ Log(Format('TotalNumberOfEntriesOnThisDisk: %d', [TotalNumberOfEntriesOnThisDisk]));
+ Log(Format('TotalNumberOfEntries: %d', [TotalNumberOfEntries]));
+ Log(Format('SizeOfTheCentralDirectory: %d', [SizeOfTheCentralDirectory]));
+ Log(Format('OffsetOfStartOfCentralDirectory: %d', [OffsetOfStartOfCentralDirectory]));
+ Log(Format('ZipfileCommentLength: %d', [ZipfileCommentLength]));
+ if ZipfileCommentLength > 0 then
+ begin
+ LoadStringValue(Stream, Comment, ZipfileCommentLength, False);
+ Log(Format('>>> Comment: %s', [Comment]));
+ end;
+ end;
+ Log(Delim);
+end;
+
+procedure TdlgZipAnalizer.ShowExtraFields(Stream: TStream; Size: Integer;
+ FileHeader: TCentralDirectoryFileHeader);
+var
+ Buff, EOFBuff: Pointer;
+ BuffCount: Integer;
+ HeaderID, BlockSize: Word;
+
+ function GetOffset(Value: Integer): Pointer;
+ begin
+ Result := Pointer(Integer(EOFBuff) - Value);
+ end;
+
+ function ByteToStr(Bytes: PByte; Size: Integer): string;
+ const
+ BytesHex: array[0..15] of char =
+ ('0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
+ var
+ I: integer;
+ begin
+ SetLength(Result, Size shl 1);
+ for I := 0 to Size - 1 do
+ begin
+ Result[I * 2 + 1] := BytesHex[Bytes^ shr 4];
+ Result[I * 2 + 2] := BytesHex[Bytes^ and $0F];
+ Inc(Bytes);
+ end;
+ end;
+
+var
+ ExDataStream: TMemoryStream;
+ StartPos: Int64;
+begin
+ if Size = 0 then Exit;
+ StartPos := Stream.Position;
+ Log('EXDATA found at offset: ' + IntToStr(StartPos));
+ Log(Delim);
+ GetMem(Buff, Size);
+ try
+ BuffCount := Size;
+ Stream.ReadBuffer(Buff^, BuffCount);
+ EOFBuff := Pointer(Integer(Buff) + BuffCount);
+ while BuffCount > 0 do
+ begin
+ HeaderID := PWord(GetOffset(BuffCount))^;
+ Dec(BuffCount, 2);
+ BlockSize := PWord(GetOffset(BuffCount))^;
+ Dec(BuffCount, 2);
+ case HeaderID of
+ SUPPORTED_EXDATA_ZIP64:
+ begin
+ Log('SUPPORTED_EXDATA_ZIP64 found at offset: ' +
+ IntToStr(StartPos + Size - BuffCount - 4));
+ if FileHeader.UncompressedSize = MAXDWORD then
+ begin
+ if BuffCount < 8 then Break;
+ Log('UncompressedSize: ' + IntToStr(PInt64(GetOffset(BuffCount))^));
+ Dec(BuffCount, 8);
+ Dec(BlockSize, 8);
+ end;
+ if FileHeader.CompressedSize = MAXDWORD then
+ begin
+ if BuffCount < 8 then Break;
+ Log('CompressedSize: ' + IntToStr(PInt64(GetOffset(BuffCount))^));
+ Dec(BuffCount, 8);
+ Dec(BlockSize, 8);
+ end;
+ if FileHeader.RelativeOffsetOfLocalHeader = MAXDWORD then
+ begin
+ if BuffCount < 8 then Break;
+ Log('RelativeOffsetOfLocalHeader: ' + IntToStr(PInt64(GetOffset(BuffCount))^));
+ Dec(BuffCount, 8);
+ Dec(BlockSize, 8);
+ end;
+ if FileHeader.DiskNumberStart = MAXWORD then
+ begin
+ if BuffCount < 4 then Break;
+ Log('DiskNumberStart: ' + IntToStr(PInt64(GetOffset(BuffCount))^));
+ Dec(BuffCount, 4);
+ Dec(BlockSize, 4);
+ end;
+ Dec(BuffCount, BlockSize);
+ Log(Delim);
+ end;
+
+ SUPPORTED_EXDATA_NTFSTIME:
+ begin
+
+ if BuffCount < 32 then Break;
+ if BlockSize <> 32 then
+ begin
+ Dec(BuffCount, BlockSize);
+ Continue;
+ end;
+ Dec(BuffCount, 4);
+ if PWord(GetOffset(BuffCount))^ <> 1 then
+ begin
+ Dec(BuffCount, BlockSize);
+ Continue;
+ end;
+ Dec(BuffCount, 2);
+ if PWord(GetOffset(BuffCount))^ <> SizeOf(TNTFSFileTime) then
+ begin
+ Dec(BuffCount, BlockSize);
+ Continue;
+ end;
+ Dec(BuffCount, 2);
+
+ Log('SUPPORTED_EXDATA_NTFSTIME found at offset: ' +
+ IntToStr(StartPos + Size - BuffCount - 12));
+ Log(Delim);
+
+ end;
+ else
+ Log(Format('UNKNOWN EXDATA TAG %d found at offset: %d',
+ [HeaderID, StartPos + Size - BuffCount - 8]));
+ ExDataStream := TMemoryStream.Create;
+ try
+ ExDataStream.WriteBuffer(GetOffset(BuffCount)^, BlockSize);
+ ExDataStream.Position := 0;
+ Log(ByteToStr(ExDataStream.Memory, ExDataStream.Size));
+ finally
+ ExDataStream.Free;
+ end;
+ Log(Delim);
+ end;
+ Dec(BuffCount, BlockSize);
+ end;
+ finally
+ FreeMem(Buff);
+ end;
+end;
+
+procedure TdlgZipAnalizer.ShowLocalFileHeader(Stream: TStream);
+var
+ Data: TLocalFileHeader;
+ FileName: string;
+begin
+ Log('LOCAL_FILE_HEADER_SIGNATURE found at offset: ' + IntToStr(Stream.Position));
+ Stream.ReadBuffer(Data, SizeOf(TLocalFileHeader));
+ with Data do
+ begin
+ if LocalFileHeaderSignature <> LOCAL_FILE_HEADER_SIGNATURE then
+ Log('INVALID SIGNATURE!!!!');
+ Log(Format('VersionNeededToExtract: %d', [VersionNeededToExtract]));
+ Log(Format('GeneralPurposeBitFlag: %d (%s)', [GeneralPurposeBitFlag,
+ GPBFToStr(GeneralPurposeBitFlag)]));
+ Log(Format('CompressionMethod: %d', [CompressionMethod]));
+ Log(Format('LastModFileTimeTime: %d', [LastModFileTimeTime]));
+ Log(Format('LastModFileTimeDate: %d', [LastModFileTimeDate]));
+ Log(Format('Crc32: %d', [Crc32]));
+ Log(Format('CompressedSize: %d', [CompressedSize]));
+ Log(Format('UncompressedSize: %d', [UncompressedSize]));
+ Log(Format('FilenameLength: %d', [FilenameLength]));
+ Log(Format('ExtraFieldLength: %d', [ExtraFieldLength]));
+ LoadStringValue(Stream, FileName, FilenameLength,
+ GeneralPurposeBitFlag and PBF_UTF8 <> 0);
+ Log('>>> FileName: ' + FileName);
+ //Stream.Position := Stream.Position + CompressedSize;
+ end;
+ Log(Delim);
+end;
+
+procedure TdlgZipAnalizer.ShowZip64(Stream: TStream);
+var
+ Data: TZip64EOFCentralDirectoryRecord;
+begin
+ Log('ZIP64_END_OF_CENTRAL_DIR_SIGNATURE found at offset: ' + IntToStr(Stream.Position));
+ Stream.ReadBuffer(Data, SizeOf(TZip64EOFCentralDirectoryRecord));
+ with Data do
+ begin
+ if Zip64EndOfCentralDirSignature <> ZIP64_END_OF_CENTRAL_DIR_SIGNATURE then
+ Log('INVALID SIGNATURE!!!!');
+ Log(Format('SizeOfZip64EOFCentralDirectoryRecord: %d', [SizeOfZip64EOFCentralDirectoryRecord]));
+ Log(Format('VersionMadeBy: %d', [VersionMadeBy]));
+ Log(Format('VersionNeededToExtract: %d', [VersionNeededToExtract]));
+ Log(Format('number of this disk: %d', [Number1]));
+ Log(Format('number of the disk with the start of the central directory: %d', [Number2]));
+ Log(Format('total number of entries in the central directory on this disk: %d', [TotalNumber1]));
+ Log(Format('total number of entries in the central directory: %d', [TotalNumber2]));
+ Log(Format('size of the central directory: %d', [Size]));
+ Log(Format('offset of start of central directory with respect to the starting disk number: %d', [Offset]));
+ end;
+ Log(Delim);
+end;
+
+procedure TdlgZipAnalizer.ShowZip64Locator(Stream: TStream);
+var
+ Data: TZip64EOFCentralDirectoryLocator;
+begin
+ Log('ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE found at offset: ' + IntToStr(Stream.Position));
+ Stream.ReadBuffer(Data, SizeOf(TZip64EOFCentralDirectoryLocator));
+ with Data do
+ begin
+ if Signature <> ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE then
+ Log('INVALID SIGNATURE!!!!');
+ Log(Format('NumberOfTheDisk: %d', [NumberOfTheDisk]));
+ Log(Format('RelativeOffset: %d', [RelativeOffset]));
+ Log(Format('TotalNumberOfDisks: %d', [TotalNumberOfDisks]));
+ end;
+ Log(Delim);
+end;
+
+end.
diff --git a/prereq/fwzip/Doc/rfc1950.txt b/prereq/fwzip/Doc/rfc1950.txt
new file mode 100644
index 0000000..ce6428a
--- /dev/null
+++ b/prereq/fwzip/Doc/rfc1950.txt
@@ -0,0 +1,619 @@
+
+
+
+
+
+
+Network Working Group P. Deutsch
+Request for Comments: 1950 Aladdin Enterprises
+Category: Informational J-L. Gailly
+ Info-ZIP
+ May 1996
+
+
+ ZLIB Compressed Data Format Specification version 3.3
+
+Status of This Memo
+
+ This memo provides information for the Internet community. This memo
+ does not specify an Internet standard of any kind. Distribution of
+ this memo is unlimited.
+
+IESG Note:
+
+ The IESG takes no position on the validity of any Intellectual
+ Property Rights statements contained in this document.
+
+Notices
+
+ Copyright (c) 1996 L. Peter Deutsch and Jean-Loup Gailly
+
+ Permission is granted to copy and distribute this document for any
+ purpose and without charge, including translations into other
+ languages and incorporation into compilations, provided that the
+ copyright notice and this notice are preserved, and that any
+ substantive changes or deletions from the original are clearly
+ marked.
+
+ A pointer to the latest version of this and related documentation in
+ HTML format can be found at the URL
+ .
+
+Abstract
+
+ This specification defines a lossless compressed data format. The
+ data can be produced or consumed, even for an arbitrarily long
+ sequentially presented input data stream, using only an a priori
+ bounded amount of intermediate storage. The format presently uses
+ the DEFLATE compression method but can be easily extended to use
+ other compression methods. It can be implemented readily in a manner
+ not covered by patents. This specification also defines the ADLER-32
+ checksum (an extension and improvement of the Fletcher checksum),
+ used for detection of data corruption, and provides an algorithm for
+ computing it.
+
+
+
+
+Deutsch & Gailly Informational [Page 1]
+
+RFC 1950 ZLIB Compressed Data Format Specification May 1996
+
+
+Table of Contents
+
+ 1. Introduction ................................................... 2
+ 1.1. Purpose ................................................... 2
+ 1.2. Intended audience ......................................... 3
+ 1.3. Scope ..................................................... 3
+ 1.4. Compliance ................................................ 3
+ 1.5. Definitions of terms and conventions used ................ 3
+ 1.6. Changes from previous versions ............................ 3
+ 2. Detailed specification ......................................... 3
+ 2.1. Overall conventions ....................................... 3
+ 2.2. Data format ............................................... 4
+ 2.3. Compliance ................................................ 7
+ 3. References ..................................................... 7
+ 4. Source code .................................................... 8
+ 5. Security Considerations ........................................ 8
+ 6. Acknowledgements ............................................... 8
+ 7. Authors' Addresses ............................................. 8
+ 8. Appendix: Rationale ............................................ 9
+ 9. Appendix: Sample code ..........................................10
+
+1. Introduction
+
+ 1.1. Purpose
+
+ The purpose of this specification is to define a lossless
+ compressed data format that:
+
+ * Is independent of CPU type, operating system, file system,
+ and character set, and hence can be used for interchange;
+
+ * Can be produced or consumed, even for an arbitrarily long
+ sequentially presented input data stream, using only an a
+ priori bounded amount of intermediate storage, and hence can
+ be used in data communications or similar structures such as
+ Unix filters;
+
+ * Can use a number of different compression methods;
+
+ * Can be implemented readily in a manner not covered by
+ patents, and hence can be practiced freely.
+
+ The data format defined by this specification does not attempt to
+ allow random access to compressed data.
+
+
+
+
+
+
+
+Deutsch & Gailly Informational [Page 2]
+
+RFC 1950 ZLIB Compressed Data Format Specification May 1996
+
+
+ 1.2. Intended audience
+
+ This specification is intended for use by implementors of software
+ to compress data into zlib format and/or decompress data from zlib
+ format.
+
+ The text of the specification assumes a basic background in
+ programming at the level of bits and other primitive data
+ representations.
+
+ 1.3. Scope
+
+ The specification specifies a compressed data format that can be
+ used for in-memory compression of a sequence of arbitrary bytes.
+
+ 1.4. Compliance
+
+ Unless otherwise indicated below, a compliant decompressor must be
+ able to accept and decompress any data set that conforms to all
+ the specifications presented here; a compliant compressor must
+ produce data sets that conform to all the specifications presented
+ here.
+
+ 1.5. Definitions of terms and conventions used
+
+ byte: 8 bits stored or transmitted as a unit (same as an octet).
+ (For this specification, a byte is exactly 8 bits, even on
+ machines which store a character on a number of bits different
+ from 8.) See below, for the numbering of bits within a byte.
+
+ 1.6. Changes from previous versions
+
+ Version 3.1 was the first public release of this specification.
+ In version 3.2, some terminology was changed and the Adler-32
+ sample code was rewritten for clarity. In version 3.3, the
+ support for a preset dictionary was introduced, and the
+ specification was converted to RFC style.
+
+2. Detailed specification
+
+ 2.1. Overall conventions
+
+ In the diagrams below, a box like this:
+
+ +---+
+ | | <-- the vertical bars might be missing
+ +---+
+
+
+
+
+Deutsch & Gailly Informational [Page 3]
+
+RFC 1950 ZLIB Compressed Data Format Specification May 1996
+
+
+ represents one byte; a box like this:
+
+ +==============+
+ | |
+ +==============+
+
+ represents a variable number of bytes.
+
+ Bytes stored within a computer do not have a "bit order", since
+ they are always treated as a unit. However, a byte considered as
+ an integer between 0 and 255 does have a most- and least-
+ significant bit, and since we write numbers with the most-
+ significant digit on the left, we also write bytes with the most-
+ significant bit on the left. In the diagrams below, we number the
+ bits of a byte so that bit 0 is the least-significant bit, i.e.,
+ the bits are numbered:
+
+ +--------+
+ |76543210|
+ +--------+
+
+ Within a computer, a number may occupy multiple bytes. All
+ multi-byte numbers in the format described here are stored with
+ the MOST-significant byte first (at the lower memory address).
+ For example, the decimal number 520 is stored as:
+
+ 0 1
+ +--------+--------+
+ |00000010|00001000|
+ +--------+--------+
+ ^ ^
+ | |
+ | + less significant byte = 8
+ + more significant byte = 2 x 256
+
+ 2.2. Data format
+
+ A zlib stream has the following structure:
+
+ 0 1
+ +---+---+
+ |CMF|FLG| (more-->)
+ +---+---+
+
+
+
+
+
+
+
+
+Deutsch & Gailly Informational [Page 4]
+
+RFC 1950 ZLIB Compressed Data Format Specification May 1996
+
+
+ (if FLG.FDICT set)
+
+ 0 1 2 3
+ +---+---+---+---+
+ | DICTID | (more-->)
+ +---+---+---+---+
+
+ +=====================+---+---+---+---+
+ |...compressed data...| ADLER32 |
+ +=====================+---+---+---+---+
+
+ Any data which may appear after ADLER32 are not part of the zlib
+ stream.
+
+ CMF (Compression Method and flags)
+ This byte is divided into a 4-bit compression method and a 4-
+ bit information field depending on the compression method.
+
+ bits 0 to 3 CM Compression method
+ bits 4 to 7 CINFO Compression info
+
+ CM (Compression method)
+ This identifies the compression method used in the file. CM = 8
+ denotes the "deflate" compression method with a window size up
+ to 32K. This is the method used by gzip and PNG (see
+ references [1] and [2] in Chapter 3, below, for the reference
+ documents). CM = 15 is reserved. It might be used in a future
+ version of this specification to indicate the presence of an
+ extra field before the compressed data.
+
+ CINFO (Compression info)
+ For CM = 8, CINFO is the base-2 logarithm of the LZ77 window
+ size, minus eight (CINFO=7 indicates a 32K window size). Values
+ of CINFO above 7 are not allowed in this version of the
+ specification. CINFO is not defined in this specification for
+ CM not equal to 8.
+
+ FLG (FLaGs)
+ This flag byte is divided as follows:
+
+ bits 0 to 4 FCHECK (check bits for CMF and FLG)
+ bit 5 FDICT (preset dictionary)
+ bits 6 to 7 FLEVEL (compression level)
+
+ The FCHECK value must be such that CMF and FLG, when viewed as
+ a 16-bit unsigned integer stored in MSB order (CMF*256 + FLG),
+ is a multiple of 31.
+
+
+
+
+Deutsch & Gailly Informational [Page 5]
+
+RFC 1950 ZLIB Compressed Data Format Specification May 1996
+
+
+ FDICT (Preset dictionary)
+ If FDICT is set, a DICT dictionary identifier is present
+ immediately after the FLG byte. The dictionary is a sequence of
+ bytes which are initially fed to the compressor without
+ producing any compressed output. DICT is the Adler-32 checksum
+ of this sequence of bytes (see the definition of ADLER32
+ below). The decompressor can use this identifier to determine
+ which dictionary has been used by the compressor.
+
+ FLEVEL (Compression level)
+ These flags are available for use by specific compression
+ methods. The "deflate" method (CM = 8) sets these flags as
+ follows:
+
+ 0 - compressor used fastest algorithm
+ 1 - compressor used fast algorithm
+ 2 - compressor used default algorithm
+ 3 - compressor used maximum compression, slowest algorithm
+
+ The information in FLEVEL is not needed for decompression; it
+ is there to indicate if recompression might be worthwhile.
+
+ compressed data
+ For compression method 8, the compressed data is stored in the
+ deflate compressed data format as described in the document
+ "DEFLATE Compressed Data Format Specification" by L. Peter
+ Deutsch. (See reference [3] in Chapter 3, below)
+
+ Other compressed data formats are not specified in this version
+ of the zlib specification.
+
+ ADLER32 (Adler-32 checksum)
+ This contains a checksum value of the uncompressed data
+ (excluding any dictionary data) computed according to Adler-32
+ algorithm. This algorithm is a 32-bit extension and improvement
+ of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073
+ standard. See references [4] and [5] in Chapter 3, below)
+
+ Adler-32 is composed of two sums accumulated per byte: s1 is
+ the sum of all bytes, s2 is the sum of all s1 values. Both sums
+ are done modulo 65521. s1 is initialized to 1, s2 to zero. The
+ Adler-32 checksum is stored as s2*65536 + s1 in most-
+ significant-byte first (network) order.
+
+
+
+
+
+
+
+
+Deutsch & Gailly Informational [Page 6]
+
+RFC 1950 ZLIB Compressed Data Format Specification May 1996
+
+
+ 2.3. Compliance
+
+ A compliant compressor must produce streams with correct CMF, FLG
+ and ADLER32, but need not support preset dictionaries. When the
+ zlib data format is used as part of another standard data format,
+ the compressor may use only preset dictionaries that are specified
+ by this other data format. If this other format does not use the
+ preset dictionary feature, the compressor must not set the FDICT
+ flag.
+
+ A compliant decompressor must check CMF, FLG, and ADLER32, and
+ provide an error indication if any of these have incorrect values.
+ A compliant decompressor must give an error indication if CM is
+ not one of the values defined in this specification (only the
+ value 8 is permitted in this version), since another value could
+ indicate the presence of new features that would cause subsequent
+ data to be interpreted incorrectly. A compliant decompressor must
+ give an error indication if FDICT is set and DICTID is not the
+ identifier of a known preset dictionary. A decompressor may
+ ignore FLEVEL and still be compliant. When the zlib data format
+ is being used as a part of another standard format, a compliant
+ decompressor must support all the preset dictionaries specified by
+ the other format. When the other format does not use the preset
+ dictionary feature, a compliant decompressor must reject any
+ stream in which the FDICT flag is set.
+
+3. References
+
+ [1] Deutsch, L.P.,"GZIP Compressed Data Format Specification",
+ available in ftp://ftp.uu.net/pub/archiving/zip/doc/
+
+ [2] Thomas Boutell, "PNG (Portable Network Graphics) specification",
+ available in ftp://ftp.uu.net/graphics/png/documents/
+
+ [3] Deutsch, L.P.,"DEFLATE Compressed Data Format Specification",
+ available in ftp://ftp.uu.net/pub/archiving/zip/doc/
+
+ [4] Fletcher, J. G., "An Arithmetic Checksum for Serial
+ Transmissions," IEEE Transactions on Communications, Vol. COM-30,
+ No. 1, January 1982, pp. 247-252.
+
+ [5] ITU-T Recommendation X.224, Annex D, "Checksum Algorithms,"
+ November, 1993, pp. 144, 145. (Available from
+ gopher://info.itu.ch). ITU-T X.244 is also the same as ISO 8073.
+
+
+
+
+
+
+
+Deutsch & Gailly Informational [Page 7]
+
+RFC 1950 ZLIB Compressed Data Format Specification May 1996
+
+
+4. Source code
+
+ Source code for a C language implementation of a "zlib" compliant
+ library is available at ftp://ftp.uu.net/pub/archiving/zip/zlib/.
+
+5. Security Considerations
+
+ A decoder that fails to check the ADLER32 checksum value may be
+ subject to undetected data corruption.
+
+6. Acknowledgements
+
+ Trademarks cited in this document are the property of their
+ respective owners.
+
+ Jean-Loup Gailly and Mark Adler designed the zlib format and wrote
+ the related software described in this specification. Glenn
+ Randers-Pehrson converted this document to RFC and HTML format.
+
+7. Authors' Addresses
+
+ L. Peter Deutsch
+ Aladdin Enterprises
+ 203 Santa Margarita Ave.
+ Menlo Park, CA 94025
+
+ Phone: (415) 322-0103 (AM only)
+ FAX: (415) 322-1734
+ EMail:
+
+
+ Jean-Loup Gailly
+
+ EMail:
+
+ Questions about the technical content of this specification can be
+ sent by email to
+
+ Jean-Loup Gailly and
+ Mark Adler
+
+ Editorial comments on this specification can be sent by email to
+
+ L. Peter Deutsch and
+ Glenn Randers-Pehrson
+
+
+
+
+
+
+Deutsch & Gailly Informational [Page 8]
+
+RFC 1950 ZLIB Compressed Data Format Specification May 1996
+
+
+8. Appendix: Rationale
+
+ 8.1. Preset dictionaries
+
+ A preset dictionary is specially useful to compress short input
+ sequences. The compressor can take advantage of the dictionary
+ context to encode the input in a more compact manner. The
+ decompressor can be initialized with the appropriate context by
+ virtually decompressing a compressed version of the dictionary
+ without producing any output. However for certain compression
+ algorithms such as the deflate algorithm this operation can be
+ achieved without actually performing any decompression.
+
+ The compressor and the decompressor must use exactly the same
+ dictionary. The dictionary may be fixed or may be chosen among a
+ certain number of predefined dictionaries, according to the kind
+ of input data. The decompressor can determine which dictionary has
+ been chosen by the compressor by checking the dictionary
+ identifier. This document does not specify the contents of
+ predefined dictionaries, since the optimal dictionaries are
+ application specific. Standard data formats using this feature of
+ the zlib specification must precisely define the allowed
+ dictionaries.
+
+ 8.2. The Adler-32 algorithm
+
+ The Adler-32 algorithm is much faster than the CRC32 algorithm yet
+ still provides an extremely low probability of undetected errors.
+
+ The modulo on unsigned long accumulators can be delayed for 5552
+ bytes, so the modulo operation time is negligible. If the bytes
+ are a, b, c, the second sum is 3a + 2b + c + 3, and so is position
+ and order sensitive, unlike the first sum, which is just a
+ checksum. That 65521 is prime is important to avoid a possible
+ large class of two-byte errors that leave the check unchanged.
+ (The Fletcher checksum uses 255, which is not prime and which also
+ makes the Fletcher check insensitive to single byte changes 0 <->
+ 255.)
+
+ The sum s1 is initialized to 1 instead of zero to make the length
+ of the sequence part of s2, so that the length does not have to be
+ checked separately. (Any sequence of zeroes has a Fletcher
+ checksum of zero.)
+
+
+
+
+
+
+
+
+Deutsch & Gailly Informational [Page 9]
+
+RFC 1950 ZLIB Compressed Data Format Specification May 1996
+
+
+9. Appendix: Sample code
+
+ The following C code computes the Adler-32 checksum of a data buffer.
+ It is written for clarity, not for speed. The sample code is in the
+ ANSI C programming language. Non C users may find it easier to read
+ with these hints:
+
+ & Bitwise AND operator.
+ >> Bitwise right shift operator. When applied to an
+ unsigned quantity, as here, right shift inserts zero bit(s)
+ at the left.
+ << Bitwise left shift operator. Left shift inserts zero
+ bit(s) at the right.
+ ++ "n++" increments the variable n.
+ % modulo operator: a % b is the remainder of a divided by b.
+
+ #define BASE 65521 /* largest prime smaller than 65536 */
+
+ /*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1]
+ and return the updated checksum. The Adler-32 checksum should be
+ initialized to 1.
+
+ Usage example:
+
+ unsigned long adler = 1L;
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = update_adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+ */
+ unsigned long update_adler32(unsigned long adler,
+ unsigned char *buf, int len)
+ {
+ unsigned long s1 = adler & 0xffff;
+ unsigned long s2 = (adler >> 16) & 0xffff;
+ int n;
+
+ for (n = 0; n < len; n++) {
+ s1 = (s1 + buf[n]) % BASE;
+ s2 = (s2 + s1) % BASE;
+ }
+ return (s2 << 16) + s1;
+ }
+
+ /* Return the adler32 of the bytes buf[0..len-1] */
+
+
+
+
+Deutsch & Gailly Informational [Page 10]
+
+RFC 1950 ZLIB Compressed Data Format Specification May 1996
+
+
+ unsigned long adler32(unsigned char *buf, int len)
+ {
+ return update_adler32(1L, buf, len);
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Deutsch & Gailly Informational [Page 11]
+
diff --git a/prereq/fwzip/Doc/rfc1951.txt b/prereq/fwzip/Doc/rfc1951.txt
new file mode 100644
index 0000000..403c8c7
--- /dev/null
+++ b/prereq/fwzip/Doc/rfc1951.txt
@@ -0,0 +1,955 @@
+
+
+
+
+
+
+Network Working Group P. Deutsch
+Request for Comments: 1951 Aladdin Enterprises
+Category: Informational May 1996
+
+
+ DEFLATE Compressed Data Format Specification version 1.3
+
+Status of This Memo
+
+ This memo provides information for the Internet community. This memo
+ does not specify an Internet standard of any kind. Distribution of
+ this memo is unlimited.
+
+IESG Note:
+
+ The IESG takes no position on the validity of any Intellectual
+ Property Rights statements contained in this document.
+
+Notices
+
+ Copyright (c) 1996 L. Peter Deutsch
+
+ Permission is granted to copy and distribute this document for any
+ purpose and without charge, including translations into other
+ languages and incorporation into compilations, provided that the
+ copyright notice and this notice are preserved, and that any
+ substantive changes or deletions from the original are clearly
+ marked.
+
+ A pointer to the latest version of this and related documentation in
+ HTML format can be found at the URL
+ .
+
+Abstract
+
+ This specification defines a lossless compressed data format that
+ compresses data using a combination of the LZ77 algorithm and Huffman
+ coding, with efficiency comparable to the best currently available
+ general-purpose compression methods. The data can be produced or
+ consumed, even for an arbitrarily long sequentially presented input
+ data stream, using only an a priori bounded amount of intermediate
+ storage. The format can be implemented readily in a manner not
+ covered by patents.
+
+
+
+
+
+
+
+
+Deutsch Informational [Page 1]
+
+RFC 1951 DEFLATE Compressed Data Format Specification May 1996
+
+
+Table of Contents
+
+ 1. Introduction ................................................... 2
+ 1.1. Purpose ................................................... 2
+ 1.2. Intended audience ......................................... 3
+ 1.3. Scope ..................................................... 3
+ 1.4. Compliance ................................................ 3
+ 1.5. Definitions of terms and conventions used ................ 3
+ 1.6. Changes from previous versions ............................ 4
+ 2. Compressed representation overview ............................. 4
+ 3. Detailed specification ......................................... 5
+ 3.1. Overall conventions ....................................... 5
+ 3.1.1. Packing into bytes .................................. 5
+ 3.2. Compressed block format ................................... 6
+ 3.2.1. Synopsis of prefix and Huffman coding ............... 6
+ 3.2.2. Use of Huffman coding in the "deflate" format ....... 7
+ 3.2.3. Details of block format ............................. 9
+ 3.2.4. Non-compressed blocks (BTYPE=00) ................... 11
+ 3.2.5. Compressed blocks (length and distance codes) ...... 11
+ 3.2.6. Compression with fixed Huffman codes (BTYPE=01) .... 12
+ 3.2.7. Compression with dynamic Huffman codes (BTYPE=10) .. 13
+ 3.3. Compliance ............................................... 14
+ 4. Compression algorithm details ................................. 14
+ 5. References .................................................... 16
+ 6. Security Considerations ....................................... 16
+ 7. Source code ................................................... 16
+ 8. Acknowledgements .............................................. 16
+ 9. Author's Address .............................................. 17
+
+1. Introduction
+
+ 1.1. Purpose
+
+ The purpose of this specification is to define a lossless
+ compressed data format that:
+ * Is independent of CPU type, operating system, file system,
+ and character set, and hence can be used for interchange;
+ * Can be produced or consumed, even for an arbitrarily long
+ sequentially presented input data stream, using only an a
+ priori bounded amount of intermediate storage, and hence
+ can be used in data communications or similar structures
+ such as Unix filters;
+ * Compresses data with efficiency comparable to the best
+ currently available general-purpose compression methods,
+ and in particular considerably better than the "compress"
+ program;
+ * Can be implemented readily in a manner not covered by
+ patents, and hence can be practiced freely;
+
+
+
+Deutsch Informational [Page 2]
+
+RFC 1951 DEFLATE Compressed Data Format Specification May 1996
+
+
+ * Is compatible with the file format produced by the current
+ widely used gzip utility, in that conforming decompressors
+ will be able to read data produced by the existing gzip
+ compressor.
+
+ The data format defined by this specification does not attempt to:
+
+ * Allow random access to compressed data;
+ * Compress specialized data (e.g., raster graphics) as well
+ as the best currently available specialized algorithms.
+
+ A simple counting argument shows that no lossless compression
+ algorithm can compress every possible input data set. For the
+ format defined here, the worst case expansion is 5 bytes per 32K-
+ byte block, i.e., a size increase of 0.015% for large data sets.
+ English text usually compresses by a factor of 2.5 to 3;
+ executable files usually compress somewhat less; graphical data
+ such as raster images may compress much more.
+
+ 1.2. Intended audience
+
+ This specification is intended for use by implementors of software
+ to compress data into "deflate" format and/or decompress data from
+ "deflate" format.
+
+ The text of the specification assumes a basic background in
+ programming at the level of bits and other primitive data
+ representations. Familiarity with the technique of Huffman coding
+ is helpful but not required.
+
+ 1.3. Scope
+
+ The specification specifies a method for representing a sequence
+ of bytes as a (usually shorter) sequence of bits, and a method for
+ packing the latter bit sequence into bytes.
+
+ 1.4. Compliance
+
+ Unless otherwise indicated below, a compliant decompressor must be
+ able to accept and decompress any data set that conforms to all
+ the specifications presented here; a compliant compressor must
+ produce data sets that conform to all the specifications presented
+ here.
+
+ 1.5. Definitions of terms and conventions used
+
+ Byte: 8 bits stored or transmitted as a unit (same as an octet).
+ For this specification, a byte is exactly 8 bits, even on machines
+
+
+
+Deutsch Informational [Page 3]
+
+RFC 1951 DEFLATE Compressed Data Format Specification May 1996
+
+
+ which store a character on a number of bits different from eight.
+ See below, for the numbering of bits within a byte.
+
+ String: a sequence of arbitrary bytes.
+
+ 1.6. Changes from previous versions
+
+ There have been no technical changes to the deflate format since
+ version 1.1 of this specification. In version 1.2, some
+ terminology was changed. Version 1.3 is a conversion of the
+ specification to RFC style.
+
+2. Compressed representation overview
+
+ A compressed data set consists of a series of blocks, corresponding
+ to successive blocks of input data. The block sizes are arbitrary,
+ except that non-compressible blocks are limited to 65,535 bytes.
+
+ Each block is compressed using a combination of the LZ77 algorithm
+ and Huffman coding. The Huffman trees for each block are independent
+ of those for previous or subsequent blocks; the LZ77 algorithm may
+ use a reference to a duplicated string occurring in a previous block,
+ up to 32K input bytes before.
+
+ Each block consists of two parts: a pair of Huffman code trees that
+ describe the representation of the compressed data part, and a
+ compressed data part. (The Huffman trees themselves are compressed
+ using Huffman encoding.) The compressed data consists of a series of
+ elements of two types: literal bytes (of strings that have not been
+ detected as duplicated within the previous 32K input bytes), and
+ pointers to duplicated strings, where a pointer is represented as a
+ pair . The representation used in the
+ "deflate" format limits distances to 32K bytes and lengths to 258
+ bytes, but does not limit the size of a block, except for
+ uncompressible blocks, which are limited as noted above.
+
+ Each type of value (literals, distances, and lengths) in the
+ compressed data is represented using a Huffman code, using one code
+ tree for literals and lengths and a separate code tree for distances.
+ The code trees for each block appear in a compact form just before
+ the compressed data for that block.
+
+
+
+
+
+
+
+
+
+
+Deutsch Informational [Page 4]
+
+RFC 1951 DEFLATE Compressed Data Format Specification May 1996
+
+
+3. Detailed specification
+
+ 3.1. Overall conventions In the diagrams below, a box like this:
+
+ +---+
+ | | <-- the vertical bars might be missing
+ +---+
+
+ represents one byte; a box like this:
+
+ +==============+
+ | |
+ +==============+
+
+ represents a variable number of bytes.
+
+ Bytes stored within a computer do not have a "bit order", since
+ they are always treated as a unit. However, a byte considered as
+ an integer between 0 and 255 does have a most- and least-
+ significant bit, and since we write numbers with the most-
+ significant digit on the left, we also write bytes with the most-
+ significant bit on the left. In the diagrams below, we number the
+ bits of a byte so that bit 0 is the least-significant bit, i.e.,
+ the bits are numbered:
+
+ +--------+
+ |76543210|
+ +--------+
+
+ Within a computer, a number may occupy multiple bytes. All
+ multi-byte numbers in the format described here are stored with
+ the least-significant byte first (at the lower memory address).
+ For example, the decimal number 520 is stored as:
+
+ 0 1
+ +--------+--------+
+ |00001000|00000010|
+ +--------+--------+
+ ^ ^
+ | |
+ | + more significant byte = 2 x 256
+ + less significant byte = 8
+
+ 3.1.1. Packing into bytes
+
+ This document does not address the issue of the order in which
+ bits of a byte are transmitted on a bit-sequential medium,
+ since the final data format described here is byte- rather than
+
+
+
+Deutsch Informational [Page 5]
+
+RFC 1951 DEFLATE Compressed Data Format Specification May 1996
+
+
+ bit-oriented. However, we describe the compressed block format
+ in below, as a sequence of data elements of various bit
+ lengths, not a sequence of bytes. We must therefore specify
+ how to pack these data elements into bytes to form the final
+ compressed byte sequence:
+
+ * Data elements are packed into bytes in order of
+ increasing bit number within the byte, i.e., starting
+ with the least-significant bit of the byte.
+ * Data elements other than Huffman codes are packed
+ starting with the least-significant bit of the data
+ element.
+ * Huffman codes are packed starting with the most-
+ significant bit of the code.
+
+ In other words, if one were to print out the compressed data as
+ a sequence of bytes, starting with the first byte at the
+ *right* margin and proceeding to the *left*, with the most-
+ significant bit of each byte on the left as usual, one would be
+ able to parse the result from right to left, with fixed-width
+ elements in the correct MSB-to-LSB order and Huffman codes in
+ bit-reversed order (i.e., with the first bit of the code in the
+ relative LSB position).
+
+ 3.2. Compressed block format
+
+ 3.2.1. Synopsis of prefix and Huffman coding
+
+ Prefix coding represents symbols from an a priori known
+ alphabet by bit sequences (codes), one code for each symbol, in
+ a manner such that different symbols may be represented by bit
+ sequences of different lengths, but a parser can always parse
+ an encoded string unambiguously symbol-by-symbol.
+
+ We define a prefix code in terms of a binary tree in which the
+ two edges descending from each non-leaf node are labeled 0 and
+ 1 and in which the leaf nodes correspond one-for-one with (are
+ labeled with) the symbols of the alphabet; then the code for a
+ symbol is the sequence of 0's and 1's on the edges leading from
+ the root to the leaf labeled with that symbol. For example:
+
+
+
+
+
+
+
+
+
+
+
+Deutsch Informational [Page 6]
+
+RFC 1951 DEFLATE Compressed Data Format Specification May 1996
+
+
+ /\ Symbol Code
+ 0 1 ------ ----
+ / \ A 00
+ /\ B B 1
+ 0 1 C 011
+ / \ D 010
+ A /\
+ 0 1
+ / \
+ D C
+
+ A parser can decode the next symbol from an encoded input
+ stream by walking down the tree from the root, at each step
+ choosing the edge corresponding to the next input bit.
+
+ Given an alphabet with known symbol frequencies, the Huffman
+ algorithm allows the construction of an optimal prefix code
+ (one which represents strings with those symbol frequencies
+ using the fewest bits of any possible prefix codes for that
+ alphabet). Such a code is called a Huffman code. (See
+ reference [1] in Chapter 5, references for additional
+ information on Huffman codes.)
+
+ Note that in the "deflate" format, the Huffman codes for the
+ various alphabets must not exceed certain maximum code lengths.
+ This constraint complicates the algorithm for computing code
+ lengths from symbol frequencies. Again, see Chapter 5,
+ references for details.
+
+ 3.2.2. Use of Huffman coding in the "deflate" format
+
+ The Huffman codes used for each alphabet in the "deflate"
+ format have two additional rules:
+
+ * All codes of a given bit length have lexicographically
+ consecutive values, in the same order as the symbols
+ they represent;
+
+ * Shorter codes lexicographically precede longer codes.
+
+
+
+
+
+
+
+
+
+
+
+
+Deutsch Informational [Page 7]
+
+RFC 1951 DEFLATE Compressed Data Format Specification May 1996
+
+
+ We could recode the example above to follow this rule as
+ follows, assuming that the order of the alphabet is ABCD:
+
+ Symbol Code
+ ------ ----
+ A 10
+ B 0
+ C 110
+ D 111
+
+ I.e., 0 precedes 10 which precedes 11x, and 110 and 111 are
+ lexicographically consecutive.
+
+ Given this rule, we can define the Huffman code for an alphabet
+ just by giving the bit lengths of the codes for each symbol of
+ the alphabet in order; this is sufficient to determine the
+ actual codes. In our example, the code is completely defined
+ by the sequence of bit lengths (2, 1, 3, 3). The following
+ algorithm generates the codes as integers, intended to be read
+ from most- to least-significant bit. The code lengths are
+ initially in tree[I].Len; the codes are produced in
+ tree[I].Code.
+
+ 1) Count the number of codes for each code length. Let
+ bl_count[N] be the number of codes of length N, N >= 1.
+
+ 2) Find the numerical value of the smallest code for each
+ code length:
+
+ code = 0;
+ bl_count[0] = 0;
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ code = (code + bl_count[bits-1]) << 1;
+ next_code[bits] = code;
+ }
+
+ 3) Assign numerical values to all codes, using consecutive
+ values for all codes of the same length with the base
+ values determined at step 2. Codes that are never used
+ (which have a bit length of zero) must not be assigned a
+ value.
+
+ for (n = 0; n <= max_code; n++) {
+ len = tree[n].Len;
+ if (len != 0) {
+ tree[n].Code = next_code[len];
+ next_code[len]++;
+ }
+
+
+
+Deutsch Informational [Page 8]
+
+RFC 1951 DEFLATE Compressed Data Format Specification May 1996
+
+
+ }
+
+ Example:
+
+ Consider the alphabet ABCDEFGH, with bit lengths (3, 3, 3, 3,
+ 3, 2, 4, 4). After step 1, we have:
+
+ N bl_count[N]
+ - -----------
+ 2 1
+ 3 5
+ 4 2
+
+ Step 2 computes the following next_code values:
+
+ N next_code[N]
+ - ------------
+ 1 0
+ 2 0
+ 3 2
+ 4 14
+
+ Step 3 produces the following code values:
+
+ Symbol Length Code
+ ------ ------ ----
+ A 3 010
+ B 3 011
+ C 3 100
+ D 3 101
+ E 3 110
+ F 2 00
+ G 4 1110
+ H 4 1111
+
+ 3.2.3. Details of block format
+
+ Each block of compressed data begins with 3 header bits
+ containing the following data:
+
+ first bit BFINAL
+ next 2 bits BTYPE
+
+ Note that the header bits do not necessarily begin on a byte
+ boundary, since a block does not necessarily occupy an integral
+ number of bytes.
+
+
+
+
+
+Deutsch Informational [Page 9]
+
+RFC 1951 DEFLATE Compressed Data Format Specification May 1996
+
+
+ BFINAL is set if and only if this is the last block of the data
+ set.
+
+ BTYPE specifies how the data are compressed, as follows:
+
+ 00 - no compression
+ 01 - compressed with fixed Huffman codes
+ 10 - compressed with dynamic Huffman codes
+ 11 - reserved (error)
+
+ The only difference between the two compressed cases is how the
+ Huffman codes for the literal/length and distance alphabets are
+ defined.
+
+ In all cases, the decoding algorithm for the actual data is as
+ follows:
+
+ do
+ read block header from input stream.
+ if stored with no compression
+ skip any remaining bits in current partially
+ processed byte
+ read LEN and NLEN (see next section)
+ copy LEN bytes of data to output
+ otherwise
+ if compressed with dynamic Huffman codes
+ read representation of code trees (see
+ subsection below)
+ loop (until end of block code recognized)
+ decode literal/length value from input stream
+ if value < 256
+ copy value (literal byte) to output stream
+ otherwise
+ if value = end of block (256)
+ break from loop
+ otherwise (value = 257..285)
+ decode distance from input stream
+
+ move backwards distance bytes in the output
+ stream, and copy length bytes from this
+ position to the output stream.
+ end loop
+ while not last block
+
+ Note that a duplicated string reference may refer to a string
+ in a previous block; i.e., the backward distance may cross one
+ or more block boundaries. However a distance cannot refer past
+ the beginning of the output stream. (An application using a
+
+
+
+Deutsch Informational [Page 10]
+
+RFC 1951 DEFLATE Compressed Data Format Specification May 1996
+
+
+ preset dictionary might discard part of the output stream; a
+ distance can refer to that part of the output stream anyway)
+ Note also that the referenced string may overlap the current
+ position; for example, if the last 2 bytes decoded have values
+ X and Y, a string reference with
+ adds X,Y,X,Y,X to the output stream.
+
+ We now specify each compression method in turn.
+
+ 3.2.4. Non-compressed blocks (BTYPE=00)
+
+ Any bits of input up to the next byte boundary are ignored.
+ The rest of the block consists of the following information:
+
+ 0 1 2 3 4...
+ +---+---+---+---+================================+
+ | LEN | NLEN |... LEN bytes of literal data...|
+ +---+---+---+---+================================+
+
+ LEN is the number of data bytes in the block. NLEN is the
+ one's complement of LEN.
+
+ 3.2.5. Compressed blocks (length and distance codes)
+
+ As noted above, encoded data blocks in the "deflate" format
+ consist of sequences of symbols drawn from three conceptually
+ distinct alphabets: either literal bytes, from the alphabet of
+ byte values (0..255), or pairs,
+ where the length is drawn from (3..258) and the distance is
+ drawn from (1..32,768). In fact, the literal and length
+ alphabets are merged into a single alphabet (0..285), where
+ values 0..255 represent literal bytes, the value 256 indicates
+ end-of-block, and values 257..285 represent length codes
+ (possibly in conjunction with extra bits following the symbol
+ code) as follows:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Deutsch Informational [Page 11]
+
+RFC 1951 DEFLATE Compressed Data Format Specification May 1996
+
+
+ Extra Extra Extra
+ Code Bits Length(s) Code Bits Lengths Code Bits Length(s)
+ ---- ---- ------ ---- ---- ------- ---- ---- -------
+ 257 0 3 267 1 15,16 277 4 67-82
+ 258 0 4 268 1 17,18 278 4 83-98
+ 259 0 5 269 2 19-22 279 4 99-114
+ 260 0 6 270 2 23-26 280 4 115-130
+ 261 0 7 271 2 27-30 281 5 131-162
+ 262 0 8 272 2 31-34 282 5 163-194
+ 263 0 9 273 3 35-42 283 5 195-226
+ 264 0 10 274 3 43-50 284 5 227-257
+ 265 1 11,12 275 3 51-58 285 0 258
+ 266 1 13,14 276 3 59-66
+
+ The extra bits should be interpreted as a machine integer
+ stored with the most-significant bit first, e.g., bits 1110
+ represent the value 14.
+
+ Extra Extra Extra
+ Code Bits Dist Code Bits Dist Code Bits Distance
+ ---- ---- ---- ---- ---- ------ ---- ---- --------
+ 0 0 1 10 4 33-48 20 9 1025-1536
+ 1 0 2 11 4 49-64 21 9 1537-2048
+ 2 0 3 12 5 65-96 22 10 2049-3072
+ 3 0 4 13 5 97-128 23 10 3073-4096
+ 4 1 5,6 14 6 129-192 24 11 4097-6144
+ 5 1 7,8 15 6 193-256 25 11 6145-8192
+ 6 2 9-12 16 7 257-384 26 12 8193-12288
+ 7 2 13-16 17 7 385-512 27 12 12289-16384
+ 8 3 17-24 18 8 513-768 28 13 16385-24576
+ 9 3 25-32 19 8 769-1024 29 13 24577-32768
+
+ 3.2.6. Compression with fixed Huffman codes (BTYPE=01)
+
+ The Huffman codes for the two alphabets are fixed, and are not
+ represented explicitly in the data. The Huffman code lengths
+ for the literal/length alphabet are:
+
+ Lit Value Bits Codes
+ --------- ---- -----
+ 0 - 143 8 00110000 through
+ 10111111
+ 144 - 255 9 110010000 through
+ 111111111
+ 256 - 279 7 0000000 through
+ 0010111
+ 280 - 287 8 11000000 through
+ 11000111
+
+
+
+Deutsch Informational [Page 12]
+
+RFC 1951 DEFLATE Compressed Data Format Specification May 1996
+
+
+ The code lengths are sufficient to generate the actual codes,
+ as described above; we show the codes in the table for added
+ clarity. Literal/length values 286-287 will never actually
+ occur in the compressed data, but participate in the code
+ construction.
+
+ Distance codes 0-31 are represented by (fixed-length) 5-bit
+ codes, with possible additional bits as shown in the table
+ shown in Paragraph 3.2.5, above. Note that distance codes 30-
+ 31 will never actually occur in the compressed data.
+
+ 3.2.7. Compression with dynamic Huffman codes (BTYPE=10)
+
+ The Huffman codes for the two alphabets appear in the block
+ immediately after the header bits and before the actual
+ compressed data, first the literal/length code and then the
+ distance code. Each code is defined by a sequence of code
+ lengths, as discussed in Paragraph 3.2.2, above. For even
+ greater compactness, the code length sequences themselves are
+ compressed using a Huffman code. The alphabet for code lengths
+ is as follows:
+
+ 0 - 15: Represent code lengths of 0 - 15
+ 16: Copy the previous code length 3 - 6 times.
+ The next 2 bits indicate repeat length
+ (0 = 3, ... , 3 = 6)
+ Example: Codes 8, 16 (+2 bits 11),
+ 16 (+2 bits 10) will expand to
+ 12 code lengths of 8 (1 + 6 + 5)
+ 17: Repeat a code length of 0 for 3 - 10 times.
+ (3 bits of length)
+ 18: Repeat a code length of 0 for 11 - 138 times
+ (7 bits of length)
+
+ A code length of 0 indicates that the corresponding symbol in
+ the literal/length or distance alphabet will not occur in the
+ block, and should not participate in the Huffman code
+ construction algorithm given earlier. If only one distance
+ code is used, it is encoded using one bit, not zero bits; in
+ this case there is a single code length of one, with one unused
+ code. One distance code of zero bits means that there are no
+ distance codes used at all (the data is all literals).
+
+ We can now define the format of the block:
+
+ 5 Bits: HLIT, # of Literal/Length codes - 257 (257 - 286)
+ 5 Bits: HDIST, # of Distance codes - 1 (1 - 32)
+ 4 Bits: HCLEN, # of Code Length codes - 4 (4 - 19)
+
+
+
+Deutsch Informational [Page 13]
+
+RFC 1951 DEFLATE Compressed Data Format Specification May 1996
+
+
+ (HCLEN + 4) x 3 bits: code lengths for the code length
+ alphabet given just above, in the order: 16, 17, 18,
+ 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
+
+ These code lengths are interpreted as 3-bit integers
+ (0-7); as above, a code length of 0 means the
+ corresponding symbol (literal/length or distance code
+ length) is not used.
+
+ HLIT + 257 code lengths for the literal/length alphabet,
+ encoded using the code length Huffman code
+
+ HDIST + 1 code lengths for the distance alphabet,
+ encoded using the code length Huffman code
+
+ The actual compressed data of the block,
+ encoded using the literal/length and distance Huffman
+ codes
+
+ The literal/length symbol 256 (end of data),
+ encoded using the literal/length Huffman code
+
+ The code length repeat codes can cross from HLIT + 257 to the
+ HDIST + 1 code lengths. In other words, all code lengths form
+ a single sequence of HLIT + HDIST + 258 values.
+
+ 3.3. Compliance
+
+ A compressor may limit further the ranges of values specified in
+ the previous section and still be compliant; for example, it may
+ limit the range of backward pointers to some value smaller than
+ 32K. Similarly, a compressor may limit the size of blocks so that
+ a compressible block fits in memory.
+
+ A compliant decompressor must accept the full range of possible
+ values defined in the previous section, and must accept blocks of
+ arbitrary size.
+
+4. Compression algorithm details
+
+ While it is the intent of this document to define the "deflate"
+ compressed data format without reference to any particular
+ compression algorithm, the format is related to the compressed
+ formats produced by LZ77 (Lempel-Ziv 1977, see reference [2] below);
+ since many variations of LZ77 are patented, it is strongly
+ recommended that the implementor of a compressor follow the general
+ algorithm presented here, which is known not to be patented per se.
+ The material in this section is not part of the definition of the
+
+
+
+Deutsch Informational [Page 14]
+
+RFC 1951 DEFLATE Compressed Data Format Specification May 1996
+
+
+ specification per se, and a compressor need not follow it in order to
+ be compliant.
+
+ The compressor terminates a block when it determines that starting a
+ new block with fresh trees would be useful, or when the block size
+ fills up the compressor's block buffer.
+
+ The compressor uses a chained hash table to find duplicated strings,
+ using a hash function that operates on 3-byte sequences. At any
+ given point during compression, let XYZ be the next 3 input bytes to
+ be examined (not necessarily all different, of course). First, the
+ compressor examines the hash chain for XYZ. If the chain is empty,
+ the compressor simply writes out X as a literal byte and advances one
+ byte in the input. If the hash chain is not empty, indicating that
+ the sequence XYZ (or, if we are unlucky, some other 3 bytes with the
+ same hash function value) has occurred recently, the compressor
+ compares all strings on the XYZ hash chain with the actual input data
+ sequence starting at the current point, and selects the longest
+ match.
+
+ The compressor searches the hash chains starting with the most recent
+ strings, to favor small distances and thus take advantage of the
+ Huffman encoding. The hash chains are singly linked. There are no
+ deletions from the hash chains; the algorithm simply discards matches
+ that are too old. To avoid a worst-case situation, very long hash
+ chains are arbitrarily truncated at a certain length, determined by a
+ run-time parameter.
+
+ To improve overall compression, the compressor optionally defers the
+ selection of matches ("lazy matching"): after a match of length N has
+ been found, the compressor searches for a longer match starting at
+ the next input byte. If it finds a longer match, it truncates the
+ previous match to a length of one (thus producing a single literal
+ byte) and then emits the longer match. Otherwise, it emits the
+ original match, and, as described above, advances N bytes before
+ continuing.
+
+ Run-time parameters also control this "lazy match" procedure. If
+ compression ratio is most important, the compressor attempts a
+ complete second search regardless of the length of the first match.
+ In the normal case, if the current match is "long enough", the
+ compressor reduces the search for a longer match, thus speeding up
+ the process. If speed is most important, the compressor inserts new
+ strings in the hash table only when no match was found, or when the
+ match is not "too long". This degrades the compression ratio but
+ saves time since there are both fewer insertions and fewer searches.
+
+
+
+
+
+Deutsch Informational [Page 15]
+
+RFC 1951 DEFLATE Compressed Data Format Specification May 1996
+
+
+5. References
+
+ [1] Huffman, D. A., "A Method for the Construction of Minimum
+ Redundancy Codes", Proceedings of the Institute of Radio
+ Engineers, September 1952, Volume 40, Number 9, pp. 1098-1101.
+
+ [2] Ziv J., Lempel A., "A Universal Algorithm for Sequential Data
+ Compression", IEEE Transactions on Information Theory, Vol. 23,
+ No. 3, pp. 337-343.
+
+ [3] Gailly, J.-L., and Adler, M., ZLIB documentation and sources,
+ available in ftp://ftp.uu.net/pub/archiving/zip/doc/
+
+ [4] Gailly, J.-L., and Adler, M., GZIP documentation and sources,
+ available as gzip-*.tar in ftp://prep.ai.mit.edu/pub/gnu/
+
+ [5] Schwartz, E. S., and Kallick, B. "Generating a canonical prefix
+ encoding." Comm. ACM, 7,3 (Mar. 1964), pp. 166-169.
+
+ [6] Hirschberg and Lelewer, "Efficient decoding of prefix codes,"
+ Comm. ACM, 33,4, April 1990, pp. 449-459.
+
+6. Security Considerations
+
+ Any data compression method involves the reduction of redundancy in
+ the data. Consequently, any corruption of the data is likely to have
+ severe effects and be difficult to correct. Uncompressed text, on
+ the other hand, will probably still be readable despite the presence
+ of some corrupted bytes.
+
+ It is recommended that systems using this data format provide some
+ means of validating the integrity of the compressed data. See
+ reference [3], for example.
+
+7. Source code
+
+ Source code for a C language implementation of a "deflate" compliant
+ compressor and decompressor is available within the zlib package at
+ ftp://ftp.uu.net/pub/archiving/zip/zlib/.
+
+8. Acknowledgements
+
+ Trademarks cited in this document are the property of their
+ respective owners.
+
+ Phil Katz designed the deflate format. Jean-Loup Gailly and Mark
+ Adler wrote the related software described in this specification.
+ Glenn Randers-Pehrson converted this document to RFC and HTML format.
+
+
+
+Deutsch Informational [Page 16]
+
+RFC 1951 DEFLATE Compressed Data Format Specification May 1996
+
+
+9. Author's Address
+
+ L. Peter Deutsch
+ Aladdin Enterprises
+ 203 Santa Margarita Ave.
+ Menlo Park, CA 94025
+
+ Phone: (415) 322-0103 (AM only)
+ FAX: (415) 322-1734
+ EMail:
+
+ Questions about the technical content of this specification can be
+ sent by email to:
+
+ Jean-Loup Gailly and
+ Mark Adler
+
+ Editorial comments on this specification can be sent by email to:
+
+ L. Peter Deutsch and
+ Glenn Randers-Pehrson
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Deutsch Informational [Page 17]
+
diff --git a/prereq/fwzip/Doc/rfc1952.txt b/prereq/fwzip/Doc/rfc1952.txt
new file mode 100644
index 0000000..2e9a1cb
--- /dev/null
+++ b/prereq/fwzip/Doc/rfc1952.txt
@@ -0,0 +1,675 @@
+
+
+
+
+
+
+Network Working Group P. Deutsch
+Request for Comments: 1952 Aladdin Enterprises
+Category: Informational May 1996
+
+
+ GZIP file format specification version 4.3
+
+Status of This Memo
+
+ This memo provides information for the Internet community. This memo
+ does not specify an Internet standard of any kind. Distribution of
+ this memo is unlimited.
+
+IESG Note:
+
+ The IESG takes no position on the validity of any Intellectual
+ Property Rights statements contained in this document.
+
+Notices
+
+ Copyright (c) 1996 L. Peter Deutsch
+
+ Permission is granted to copy and distribute this document for any
+ purpose and without charge, including translations into other
+ languages and incorporation into compilations, provided that the
+ copyright notice and this notice are preserved, and that any
+ substantive changes or deletions from the original are clearly
+ marked.
+
+ A pointer to the latest version of this and related documentation in
+ HTML format can be found at the URL
+ .
+
+Abstract
+
+ This specification defines a lossless compressed data format that is
+ compatible with the widely used GZIP utility. The format includes a
+ cyclic redundancy check value for detecting data corruption. The
+ format presently uses the DEFLATE method of compression but can be
+ easily extended to use other compression methods. The format can be
+ implemented readily in a manner not covered by patents.
+
+
+
+
+
+
+
+
+
+
+Deutsch Informational [Page 1]
+
+RFC 1952 GZIP File Format Specification May 1996
+
+
+Table of Contents
+
+ 1. Introduction ................................................... 2
+ 1.1. Purpose ................................................... 2
+ 1.2. Intended audience ......................................... 3
+ 1.3. Scope ..................................................... 3
+ 1.4. Compliance ................................................ 3
+ 1.5. Definitions of terms and conventions used ................. 3
+ 1.6. Changes from previous versions ............................ 3
+ 2. Detailed specification ......................................... 4
+ 2.1. Overall conventions ....................................... 4
+ 2.2. File format ............................................... 5
+ 2.3. Member format ............................................. 5
+ 2.3.1. Member header and trailer ........................... 6
+ 2.3.1.1. Extra field ................................... 8
+ 2.3.1.2. Compliance .................................... 9
+ 3. References .................................................. 9
+ 4. Security Considerations .................................... 10
+ 5. Acknowledgements ........................................... 10
+ 6. Author's Address ........................................... 10
+ 7. Appendix: Jean-Loup Gailly's gzip utility .................. 11
+ 8. Appendix: Sample CRC Code .................................. 11
+
+1. Introduction
+
+ 1.1. Purpose
+
+ The purpose of this specification is to define a lossless
+ compressed data format that:
+
+ * Is independent of CPU type, operating system, file system,
+ and character set, and hence can be used for interchange;
+ * Can compress or decompress a data stream (as opposed to a
+ randomly accessible file) to produce another data stream,
+ using only an a priori bounded amount of intermediate
+ storage, and hence can be used in data communications or
+ similar structures such as Unix filters;
+ * Compresses data with efficiency comparable to the best
+ currently available general-purpose compression methods,
+ and in particular considerably better than the "compress"
+ program;
+ * Can be implemented readily in a manner not covered by
+ patents, and hence can be practiced freely;
+ * Is compatible with the file format produced by the current
+ widely used gzip utility, in that conforming decompressors
+ will be able to read data produced by the existing gzip
+ compressor.
+
+
+
+
+Deutsch Informational [Page 2]
+
+RFC 1952 GZIP File Format Specification May 1996
+
+
+ The data format defined by this specification does not attempt to:
+
+ * Provide random access to compressed data;
+ * Compress specialized data (e.g., raster graphics) as well as
+ the best currently available specialized algorithms.
+
+ 1.2. Intended audience
+
+ This specification is intended for use by implementors of software
+ to compress data into gzip format and/or decompress data from gzip
+ format.
+
+ The text of the specification assumes a basic background in
+ programming at the level of bits and other primitive data
+ representations.
+
+ 1.3. Scope
+
+ The specification specifies a compression method and a file format
+ (the latter assuming only that a file can store a sequence of
+ arbitrary bytes). It does not specify any particular interface to
+ a file system or anything about character sets or encodings
+ (except for file names and comments, which are optional).
+
+ 1.4. Compliance
+
+ Unless otherwise indicated below, a compliant decompressor must be
+ able to accept and decompress any file that conforms to all the
+ specifications presented here; a compliant compressor must produce
+ files that conform to all the specifications presented here. The
+ material in the appendices is not part of the specification per se
+ and is not relevant to compliance.
+
+ 1.5. Definitions of terms and conventions used
+
+ byte: 8 bits stored or transmitted as a unit (same as an octet).
+ (For this specification, a byte is exactly 8 bits, even on
+ machines which store a character on a number of bits different
+ from 8.) See below for the numbering of bits within a byte.
+
+ 1.6. Changes from previous versions
+
+ There have been no technical changes to the gzip format since
+ version 4.1 of this specification. In version 4.2, some
+ terminology was changed, and the sample CRC code was rewritten for
+ clarity and to eliminate the requirement for the caller to do pre-
+ and post-conditioning. Version 4.3 is a conversion of the
+ specification to RFC style.
+
+
+
+Deutsch Informational [Page 3]
+
+RFC 1952 GZIP File Format Specification May 1996
+
+
+2. Detailed specification
+
+ 2.1. Overall conventions
+
+ In the diagrams below, a box like this:
+
+ +---+
+ | | <-- the vertical bars might be missing
+ +---+
+
+ represents one byte; a box like this:
+
+ +==============+
+ | |
+ +==============+
+
+ represents a variable number of bytes.
+
+ Bytes stored within a computer do not have a "bit order", since
+ they are always treated as a unit. However, a byte considered as
+ an integer between 0 and 255 does have a most- and least-
+ significant bit, and since we write numbers with the most-
+ significant digit on the left, we also write bytes with the most-
+ significant bit on the left. In the diagrams below, we number the
+ bits of a byte so that bit 0 is the least-significant bit, i.e.,
+ the bits are numbered:
+
+ +--------+
+ |76543210|
+ +--------+
+
+ This document does not address the issue of the order in which
+ bits of a byte are transmitted on a bit-sequential medium, since
+ the data format described here is byte- rather than bit-oriented.
+
+ Within a computer, a number may occupy multiple bytes. All
+ multi-byte numbers in the format described here are stored with
+ the least-significant byte first (at the lower memory address).
+ For example, the decimal number 520 is stored as:
+
+ 0 1
+ +--------+--------+
+ |00001000|00000010|
+ +--------+--------+
+ ^ ^
+ | |
+ | + more significant byte = 2 x 256
+ + less significant byte = 8
+
+
+
+Deutsch Informational [Page 4]
+
+RFC 1952 GZIP File Format Specification May 1996
+
+
+ 2.2. File format
+
+ A gzip file consists of a series of "members" (compressed data
+ sets). The format of each member is specified in the following
+ section. The members simply appear one after another in the file,
+ with no additional information before, between, or after them.
+
+ 2.3. Member format
+
+ Each member has the following structure:
+
+ +---+---+---+---+---+---+---+---+---+---+
+ |ID1|ID2|CM |FLG| MTIME |XFL|OS | (more-->)
+ +---+---+---+---+---+---+---+---+---+---+
+
+ (if FLG.FEXTRA set)
+
+ +---+---+=================================+
+ | XLEN |...XLEN bytes of "extra field"...| (more-->)
+ +---+---+=================================+
+
+ (if FLG.FNAME set)
+
+ +=========================================+
+ |...original file name, zero-terminated...| (more-->)
+ +=========================================+
+
+ (if FLG.FCOMMENT set)
+
+ +===================================+
+ |...file comment, zero-terminated...| (more-->)
+ +===================================+
+
+ (if FLG.FHCRC set)
+
+ +---+---+
+ | CRC16 |
+ +---+---+
+
+ +=======================+
+ |...compressed blocks...| (more-->)
+ +=======================+
+
+ 0 1 2 3 4 5 6 7
+ +---+---+---+---+---+---+---+---+
+ | CRC32 | ISIZE |
+ +---+---+---+---+---+---+---+---+
+
+
+
+
+Deutsch Informational [Page 5]
+
+RFC 1952 GZIP File Format Specification May 1996
+
+
+ 2.3.1. Member header and trailer
+
+ ID1 (IDentification 1)
+ ID2 (IDentification 2)
+ These have the fixed values ID1 = 31 (0x1f, \037), ID2 = 139
+ (0x8b, \213), to identify the file as being in gzip format.
+
+ CM (Compression Method)
+ This identifies the compression method used in the file. CM
+ = 0-7 are reserved. CM = 8 denotes the "deflate"
+ compression method, which is the one customarily used by
+ gzip and which is documented elsewhere.
+
+ FLG (FLaGs)
+ This flag byte is divided into individual bits as follows:
+
+ bit 0 FTEXT
+ bit 1 FHCRC
+ bit 2 FEXTRA
+ bit 3 FNAME
+ bit 4 FCOMMENT
+ bit 5 reserved
+ bit 6 reserved
+ bit 7 reserved
+
+ If FTEXT is set, the file is probably ASCII text. This is
+ an optional indication, which the compressor may set by
+ checking a small amount of the input data to see whether any
+ non-ASCII characters are present. In case of doubt, FTEXT
+ is cleared, indicating binary data. For systems which have
+ different file formats for ascii text and binary data, the
+ decompressor can use FTEXT to choose the appropriate format.
+ We deliberately do not specify the algorithm used to set
+ this bit, since a compressor always has the option of
+ leaving it cleared and a decompressor always has the option
+ of ignoring it and letting some other program handle issues
+ of data conversion.
+
+ If FHCRC is set, a CRC16 for the gzip header is present,
+ immediately before the compressed data. The CRC16 consists
+ of the two least significant bytes of the CRC32 for all
+ bytes of the gzip header up to and not including the CRC16.
+ [The FHCRC bit was never set by versions of gzip up to
+ 1.2.4, even though it was documented with a different
+ meaning in gzip 1.2.4.]
+
+ If FEXTRA is set, optional extra fields are present, as
+ described in a following section.
+
+
+
+Deutsch Informational [Page 6]
+
+RFC 1952 GZIP File Format Specification May 1996
+
+
+ If FNAME is set, an original file name is present,
+ terminated by a zero byte. The name must consist of ISO
+ 8859-1 (LATIN-1) characters; on operating systems using
+ EBCDIC or any other character set for file names, the name
+ must be translated to the ISO LATIN-1 character set. This
+ is the original name of the file being compressed, with any
+ directory components removed, and, if the file being
+ compressed is on a file system with case insensitive names,
+ forced to lower case. There is no original file name if the
+ data was compressed from a source other than a named file;
+ for example, if the source was stdin on a Unix system, there
+ is no file name.
+
+ If FCOMMENT is set, a zero-terminated file comment is
+ present. This comment is not interpreted; it is only
+ intended for human consumption. The comment must consist of
+ ISO 8859-1 (LATIN-1) characters. Line breaks should be
+ denoted by a single line feed character (10 decimal).
+
+ Reserved FLG bits must be zero.
+
+ MTIME (Modification TIME)
+ This gives the most recent modification time of the original
+ file being compressed. The time is in Unix format, i.e.,
+ seconds since 00:00:00 GMT, Jan. 1, 1970. (Note that this
+ may cause problems for MS-DOS and other systems that use
+ local rather than Universal time.) If the compressed data
+ did not come from a file, MTIME is set to the time at which
+ compression started. MTIME = 0 means no time stamp is
+ available.
+
+ XFL (eXtra FLags)
+ These flags are available for use by specific compression
+ methods. The "deflate" method (CM = 8) sets these flags as
+ follows:
+
+ XFL = 2 - compressor used maximum compression,
+ slowest algorithm
+ XFL = 4 - compressor used fastest algorithm
+
+ OS (Operating System)
+ This identifies the type of file system on which compression
+ took place. This may be useful in determining end-of-line
+ convention for text files. The currently defined values are
+ as follows:
+
+
+
+
+
+
+Deutsch Informational [Page 7]
+
+RFC 1952 GZIP File Format Specification May 1996
+
+
+ 0 - FAT filesystem (MS-DOS, OS/2, NT/Win32)
+ 1 - Amiga
+ 2 - VMS (or OpenVMS)
+ 3 - Unix
+ 4 - VM/CMS
+ 5 - Atari TOS
+ 6 - HPFS filesystem (OS/2, NT)
+ 7 - Macintosh
+ 8 - Z-System
+ 9 - CP/M
+ 10 - TOPS-20
+ 11 - NTFS filesystem (NT)
+ 12 - QDOS
+ 13 - Acorn RISCOS
+ 255 - unknown
+
+ XLEN (eXtra LENgth)
+ If FLG.FEXTRA is set, this gives the length of the optional
+ extra field. See below for details.
+
+ CRC32 (CRC-32)
+ This contains a Cyclic Redundancy Check value of the
+ uncompressed data computed according to CRC-32 algorithm
+ used in the ISO 3309 standard and in section 8.1.1.6.2 of
+ ITU-T recommendation V.42. (See http://www.iso.ch for
+ ordering ISO documents. See gopher://info.itu.ch for an
+ online version of ITU-T V.42.)
+
+ ISIZE (Input SIZE)
+ This contains the size of the original (uncompressed) input
+ data modulo 2^32.
+
+ 2.3.1.1. Extra field
+
+ If the FLG.FEXTRA bit is set, an "extra field" is present in
+ the header, with total length XLEN bytes. It consists of a
+ series of subfields, each of the form:
+
+ +---+---+---+---+==================================+
+ |SI1|SI2| LEN |... LEN bytes of subfield data ...|
+ +---+---+---+---+==================================+
+
+ SI1 and SI2 provide a subfield ID, typically two ASCII letters
+ with some mnemonic value. Jean-Loup Gailly
+ is maintaining a registry of subfield
+ IDs; please send him any subfield ID you wish to use. Subfield
+ IDs with SI2 = 0 are reserved for future use. The following
+ IDs are currently defined:
+
+
+
+Deutsch Informational [Page 8]
+
+RFC 1952 GZIP File Format Specification May 1996
+
+
+ SI1 SI2 Data
+ ---------- ---------- ----
+ 0x41 ('A') 0x70 ('P') Apollo file type information
+
+ LEN gives the length of the subfield data, excluding the 4
+ initial bytes.
+
+ 2.3.1.2. Compliance
+
+ A compliant compressor must produce files with correct ID1,
+ ID2, CM, CRC32, and ISIZE, but may set all the other fields in
+ the fixed-length part of the header to default values (255 for
+ OS, 0 for all others). The compressor must set all reserved
+ bits to zero.
+
+ A compliant decompressor must check ID1, ID2, and CM, and
+ provide an error indication if any of these have incorrect
+ values. It must examine FEXTRA/XLEN, FNAME, FCOMMENT and FHCRC
+ at least so it can skip over the optional fields if they are
+ present. It need not examine any other part of the header or
+ trailer; in particular, a decompressor may ignore FTEXT and OS
+ and always produce binary output, and still be compliant. A
+ compliant decompressor must give an error indication if any
+ reserved bit is non-zero, since such a bit could indicate the
+ presence of a new field that would cause subsequent data to be
+ interpreted incorrectly.
+
+3. References
+
+ [1] "Information Processing - 8-bit single-byte coded graphic
+ character sets - Part 1: Latin alphabet No.1" (ISO 8859-1:1987).
+ The ISO 8859-1 (Latin-1) character set is a superset of 7-bit
+ ASCII. Files defining this character set are available as
+ iso_8859-1.* in ftp://ftp.uu.net/graphics/png/documents/
+
+ [2] ISO 3309
+
+ [3] ITU-T recommendation V.42
+
+ [4] Deutsch, L.P.,"DEFLATE Compressed Data Format Specification",
+ available in ftp://ftp.uu.net/pub/archiving/zip/doc/
+
+ [5] Gailly, J.-L., GZIP documentation, available as gzip-*.tar in
+ ftp://prep.ai.mit.edu/pub/gnu/
+
+ [6] Sarwate, D.V., "Computation of Cyclic Redundancy Checks via Table
+ Look-Up", Communications of the ACM, 31(8), pp.1008-1013.
+
+
+
+
+Deutsch Informational [Page 9]
+
+RFC 1952 GZIP File Format Specification May 1996
+
+
+ [7] Schwaderer, W.D., "CRC Calculation", April 85 PC Tech Journal,
+ pp.118-133.
+
+ [8] ftp://ftp.adelaide.edu.au/pub/rocksoft/papers/crc_v3.txt,
+ describing the CRC concept.
+
+4. Security Considerations
+
+ Any data compression method involves the reduction of redundancy in
+ the data. Consequently, any corruption of the data is likely to have
+ severe effects and be difficult to correct. Uncompressed text, on
+ the other hand, will probably still be readable despite the presence
+ of some corrupted bytes.
+
+ It is recommended that systems using this data format provide some
+ means of validating the integrity of the compressed data, such as by
+ setting and checking the CRC-32 check value.
+
+5. Acknowledgements
+
+ Trademarks cited in this document are the property of their
+ respective owners.
+
+ Jean-Loup Gailly designed the gzip format and wrote, with Mark Adler,
+ the related software described in this specification. Glenn
+ Randers-Pehrson converted this document to RFC and HTML format.
+
+6. Author's Address
+
+ L. Peter Deutsch
+ Aladdin Enterprises
+ 203 Santa Margarita Ave.
+ Menlo Park, CA 94025
+
+ Phone: (415) 322-0103 (AM only)
+ FAX: (415) 322-1734
+ EMail:
+
+ Questions about the technical content of this specification can be
+ sent by email to:
+
+ Jean-Loup Gailly and
+ Mark Adler
+
+ Editorial comments on this specification can be sent by email to:
+
+ L. Peter Deutsch and
+ Glenn Randers-Pehrson
+
+
+
+Deutsch Informational [Page 10]
+
+RFC 1952 GZIP File Format Specification May 1996
+
+
+7. Appendix: Jean-Loup Gailly's gzip utility
+
+ The most widely used implementation of gzip compression, and the
+ original documentation on which this specfication is based, were
+ created by Jean-Loup Gailly . Since this
+ implementation is a de facto standard, we mention some more of its
+ features here. Again, the material in this section is not part of
+ the specification per se, and implementations need not follow it to
+ be compliant.
+
+ When compressing or decompressing a file, gzip preserves the
+ protection, ownership, and modification time attributes on the local
+ file system, since there is no provision for representing protection
+ attributes in the gzip file format itself. Since the file format
+ includes a modification time, the gzip decompressor provides a
+ command line switch that assigns the modification time from the file,
+ rather than the local modification time of the compressed input, to
+ the decompressed output.
+
+8. Appendix: Sample CRC Code
+
+ The following sample code represents a practical implementation of
+ the CRC (Cyclic Redundancy Check). (See also ISO 3309 and ITU-T V.42
+ for a formal specification.)
+
+ The sample code is in the ANSI C programming language. Non C users
+ may find it easier to read with these hints:
+
+ & Bitwise AND operator.
+ ^ Bitwise exclusive-OR operator.
+ >> Bitwise right shift operator. When applied to an
+ unsigned quantity, as here, right shift inserts zero
+ bit(s) at the left.
+ ! Logical NOT operator.
+ ++ "n++" increments the variable n.
+ 0xNNN 0x introduces a hexadecimal (base 16) constant.
+ Suffix L indicates a long value (at least 32 bits).
+
+ /* Table of CRCs of all 8-bit messages. */
+ unsigned long crc_table[256];
+
+ /* Flag: has the table been computed? Initially false. */
+ int crc_table_computed = 0;
+
+ /* Make the table for a fast CRC. */
+ void make_crc_table(void)
+ {
+ unsigned long c;
+
+
+
+Deutsch Informational [Page 11]
+
+RFC 1952 GZIP File Format Specification May 1996
+
+
+ int n, k;
+ for (n = 0; n < 256; n++) {
+ c = (unsigned long) n;
+ for (k = 0; k < 8; k++) {
+ if (c & 1) {
+ c = 0xedb88320L ^ (c >> 1);
+ } else {
+ c = c >> 1;
+ }
+ }
+ crc_table[n] = c;
+ }
+ crc_table_computed = 1;
+ }
+
+ /*
+ Update a running crc with the bytes buf[0..len-1] and return
+ the updated crc. The crc should be initialized to zero. Pre- and
+ post-conditioning (one's complement) is performed within this
+ function so it shouldn't be done by the caller. Usage example:
+
+ unsigned long crc = 0L;
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = update_crc(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+ */
+ unsigned long update_crc(unsigned long crc,
+ unsigned char *buf, int len)
+ {
+ unsigned long c = crc ^ 0xffffffffL;
+ int n;
+
+ if (!crc_table_computed)
+ make_crc_table();
+ for (n = 0; n < len; n++) {
+ c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
+ }
+ return c ^ 0xffffffffL;
+ }
+
+ /* Return the CRC of the bytes buf[0..len-1]. */
+ unsigned long crc(unsigned char *buf, int len)
+ {
+ return update_crc(0L, buf, len);
+ }
+
+
+
+
+Deutsch Informational [Page 12]
+
diff --git a/prereq/fwzip/Doc/zip_format.txt b/prereq/fwzip/Doc/zip_format.txt
new file mode 100644
index 0000000..3d64ccf
--- /dev/null
+++ b/prereq/fwzip/Doc/zip_format.txt
@@ -0,0 +1,3495 @@
+File: APPNOTE.TXT - .ZIP File Format Specification
+Version: 6.3.3
+Status: Final - replaces version 6.3.2
+Revised: September 1, 2012
+Copyright (c) 1989 - 2012 PKWARE Inc., All Rights Reserved.
+
+1.0 Introduction
+---------------
+
+1.1 Purpose
+-----------
+
+ 1.1.1 This specification is intended to define a cross-platform,
+ interoperable file storage and transfer format. Since its
+ first publication in 1989, PKWARE, Inc. ("PKWARE") has remained
+ committed to ensuring the interoperability of the .ZIP file
+ format through periodic publication and maintenance of this
+ specification. We trust that all .ZIP compatible vendors and
+ application developers that use and benefit from this format
+ will share and support this commitment to interoperability.
+
+1.2 Scope
+---------
+
+ 1.2.1 ZIP is one of the most widely used compressed file formats. It is
+ universally used to aggregate, compress, and encrypt files into a single
+ interoperable container. No specific use or application need is
+ defined by this format and no specific implementation guidance is
+ provided. This document provides details on the storage format for
+ creating ZIP files. Information is provided on the records and
+ fields that describe what a ZIP file is.
+
+1.3 Trademarks
+--------------
+
+ 1.3.1 PKWARE, PKZIP, SecureZIP, and PKSFX are registered trademarks of
+ PKWARE, Inc. in the United States and elsewhere. PKPatchMaker,
+ Deflate64, and ZIP64 are trademarks of PKWARE, Inc. Other marks
+ referenced within this document appear for identification
+ purposes only and are the property of their respective owners.
+
+
+1.4 Permitted Use
+-----------------
+
+ 1.4.1 This document, "APPNOTE.TXT - .ZIP File Format Specification" is the
+ exclusive property of PKWARE. Use of the information contained in this
+ document is permitted solely for the purpose of creating products,
+ programs and processes that read and write files in the ZIP format
+ subject to the terms and conditions herein.
+
+ 1.4.2 Use of the content of this document within other publications is
+ permitted only through reference to this document. Any reproduction
+ or distribution of this document in whole or in part without prior
+ written permission from PKWARE is strictly prohibited.
+
+ 1.4.3 Certain technological components provided in this document are the
+ patented proprietary technology of PKWARE and as such require a
+ separate, executed license agreement from PKWARE. Applicable
+ components are marked with the following, or similar, statement:
+ 'Refer to the section in this document entitled "Incorporating
+ PKWARE Proprietary Technology into Your Product" for more information'.
+
+1.5 Contacting PKWARE
+---------------------
+
+ 1.5.1 If you have questions on this format, its use, or licensing, or if you
+ wish to report defects, request changes or additions, please contact:
+
+ PKWARE, Inc.
+ 648 N. Plankinton Avenue, Suite 220
+ Milwaukee, WI 53203
+ +1-414-289-9788
+ +1-414-289-9789 FAX
+ zipformat@pkware.com
+
+ 1.5.2 Information about this format and copies of this document are publicly
+ available at:
+
+ http://www.pkware.com/appnote
+
+1.6 Disclaimer
+--------------
+
+ 1.6.1 Although PKWARE will attempt to supply current and accurate
+ information relating to its file formats, algorithms, and the
+ subject programs, the possibility of error or omission cannot
+ be eliminated. PKWARE therefore expressly disclaims any warranty
+ that the information contained in the associated materials relating
+ to the subject programs and/or the format of the files created or
+ accessed by the subject programs and/or the algorithms used by
+ the subject programs, or any other matter, is current, correct or
+ accurate as delivered. Any risk of damage due to any possible
+ inaccurate information is assumed by the user of the information.
+ Furthermore, the information relating to the subject programs
+ and/or the file formats created or accessed by the subject
+ programs and/or the algorithms used by the subject programs is
+ subject to change without notice.
+
+2.0 Revisions
+--------------
+
+2.1 Document Status
+--------------------
+
+ 2.1.1 If the STATUS of this file is marked as DRAFT, the content
+ defines proposed revisions to this specification which may consist
+ of changes to the ZIP format itself, or that may consist of other
+ content changes to this document. Versions of this document and
+ the format in DRAFT form may be subject to modification prior to
+ publication STATUS of FINAL. DRAFT versions are published periodically
+ to provide notification to the ZIP community of pending changes and to
+ provide opportunity for review and comment.
+
+ 2.1.2 Versions of this document having a STATUS of FINAL are
+ considered to be in the final form for that version of the document
+ and are not subject to further change until a new, higher version
+ numbered document is published. Newer versions of this format
+ specification are intended to remain interoperable with with all prior
+ versions whenever technically possible.
+
+2.2 Change Log
+--------------
+
+ Version Change Description Date
+ ------- ------------------ ----------
+ 5.2 -Single Password Symmetric Encryption 06/02/2003
+ storage
+
+ 6.1.0 -Smartcard compatibility 01/20/2004
+ -Documentation on certificate storage
+
+ 6.2.0 -Introduction of Central Directory 04/26/2004
+ Encryption for encrypting metadata
+ -Added OS X to Version Made By values
+
+ 6.2.1 -Added Extra Field placeholder for 04/01/2005
+ POSZIP using ID 0x4690
+
+ -Clarified size field on
+ "zip64 end of central directory record"
+
+ 6.2.2 -Documented Final Feature Specification 01/06/2006
+ for Strong Encryption
+
+ -Clarifications and typographical
+ corrections
+
+ 6.3.0 -Added tape positioning storage 09/29/2006
+ parameters
+
+ -Expanded list of supported hash algorithms
+
+ -Expanded list of supported compression
+ algorithms
+
+ -Expanded list of supported encryption
+ algorithms
+
+ -Added option for Unicode filename
+ storage
+
+ -Clarifications for consistent use
+ of Data Descriptor records
+
+ -Added additional "Extra Field"
+ definitions
+
+ 6.3.1 -Corrected standard hash values for 04/11/2007
+ SHA-256/384/512
+
+ 6.3.2 -Added compression method 97 09/28/2007
+
+ -Documented InfoZIP "Extra Field"
+ values for UTF-8 file name and
+ file comment storage
+
+ 6.3.3 -Formatting changes to support 09/01/2012
+ easier referencing of this APPNOTE
+ from other documents and standards
+
+
+3.0 Notations
+-------------
+
+ 3.1 Use of the term MUST or SHALL indicates a required element.
+
+ 3.2 MAY NOT or SHALL NOT indicates an element is prohibited from use.
+
+ 3.3 SHOULD indicates a RECOMMENDED element.
+
+ 3.4 SHOULD NOT indicates an element NOT RECOMMENDED for use.
+
+ 3.5 MAY indicates an OPTIONAL element.
+
+
+4.0 ZIP Files
+-------------
+
+4.1 What is a ZIP file
+----------------------
+
+ 4.1.1 ZIP files MAY be identified by the standard .ZIP file extension
+ although use of a file extension is not required. Use of the
+ extension .ZIPX is also recognized and MAY be used for ZIP files.
+ Other common file extensions using the ZIP format include .JAR, .WAR,
+ .DOCX, .XLXS, .PPTX, .ODT, .ODS, .ODP and others. Programs reading or
+ writing ZIP files SHOULD rely on internal record signatures described
+ in this document to identify files in this format.
+
+ 4.1.2 ZIP files SHOULD contain at least one file and MAY contain
+ multiple files.
+
+ 4.1.3 Data compression MAY be used to reduce the size of files
+ placed into a ZIP file, but is not required. This format supports the
+ use of multiple data compression algorithms. When compression is used,
+ one of the documented compression algorithms MUST be used. Implementors
+ are advised to experiment with their data to determine which of the
+ available algorithms provides the best compression for their needs.
+ Compression method 8 (Deflate) is the method used by default by most
+ ZIP compatible application programs.
+
+
+ 4.1.4 Data encryption MAY be used to protect files within a ZIP file.
+ Keying methods supported for encryption within this format include
+ passwords and public/private keys. Either MAY be used individually
+ or in combination. Encryption MAY be applied to individual files.
+ Additional security MAY be used through the encryption of ZIP file
+ metadata stored within the Central Directory. See the section on the
+ Strong Encryption Specification for information. Refer to the section
+ in this document entitled "Incorporating PKWARE Proprietary Technology
+ into Your Product" for more information.
+
+ 4.1.5 Data integrity MUST be provided for each file using CRC32.
+
+ 4.1.6 Additional data integrity MAY be included through the use of
+ digital signatures. Individual files MAY be signed with one or more
+ digital signatures. The Central Directory, if signed, MUST use a
+ single signature.
+
+ 4.1.7 Files MAY be placed within a ZIP file uncompressed or stored.
+ The term "stored" as used in the context of this document means the file
+ is copied into the ZIP file uncompressed.
+
+ 4.1.8 Each data file placed into a ZIP file MAY be compressed, stored,
+ encrypted or digitally signed independent of how other data files in the
+ same ZIP file are archived.
+
+ 4.1.9 ZIP files MAY be streamed, split into segments (on fixed or on
+ removable media) or "self-extracting". Self-extracting ZIP
+ files MUST include extraction code for a target platform within
+ the ZIP file.
+
+ 4.1.10 Extensibility is provided for platform or application specific
+ needs through extra data fields that MAY be defined for custom
+ purposes. Extra data definitions MUST NOT conflict with existing
+ documented record definitions.
+
+ 4.1.11 Common uses for ZIP MAY also include the use of manifest files.
+ Manifest files store application specific information within a file stored
+ within the ZIP file. This manifest file SHOULD be the first file in the
+ ZIP file. This specification does not provide any information or guidance on
+ the use of manifest files within ZIP files. Refer to the application developer
+ for information on using manifest files and for any additional profile
+ information on using ZIP within an application.
+
+ 4.1.12 ZIP files MAY be placed within other ZIP files.
+
+4.2 ZIP Metadata
+----------------
+
+ 4.2.1 ZIP files are identified by metadata consisting of defined record types
+ containing the storage information necessary for maintaining the files
+ placed into a ZIP file. Each record type MUST be identified using a header
+ signature that identifies the record type. Signature values begin with the
+ two byte constant marker of 0x4b50, representing the characters "PK".
+
+
+4.3 General Format of a .ZIP file
+---------------------------------
+
+ 4.3.1 A ZIP file MUST contain an "end of central directory record". A ZIP
+ file containing only an "end of central directory record" is considered an
+ empty ZIP file. Files may be added or replaced within a ZIP file, or deleted.
+ A ZIP file MUST have only one "end of central directory record". Other
+ records defined in this specification MAY be used as needed to support
+ storage requirements for individual ZIP files.
+
+ 4.3.2 Each file placed into a ZIP file MUST be preceeded by a "local
+ file header" record for that file. Each "local file header" MUST be
+ accompanied by a corresponding "central directory header" record within
+ the central directory section of the ZIP file.
+
+ 4.3.3 Files MAY be stored in arbitrary order within a ZIP file. A ZIP
+ file MAY span multiple volumes or it MAY be split into user-defined
+ segment sizes. All values MUST be stored in little-endian byte order unless
+ otherwise specified in this document for a specific data element.
+
+ 4.3.4 Compression MUST NOT be applied to a "local file header", an "encryption
+ header", or an "end of central directory record". Individual "central
+ directory records" must not be compressed, but the aggregate of all central
+ directory records MAY be compressed.
+
+ 4.3.5 File data MAY be followed by a "data descriptor" for the file. Data
+ descriptors are used to facilitate ZIP file streaming.
+
+
+ 4.3.6 Overall .ZIP file format:
+
+ [local file header 1]
+ [encryption header 1]
+ [file data 1]
+ [data descriptor 1]
+ .
+ .
+ .
+ [local file header n]
+ [encryption header n]
+ [file data n]
+ [data descriptor n]
+ [archive decryption header]
+ [archive extra data record]
+ [central directory header 1]
+ .
+ .
+ .
+ [central directory header n]
+ [zip64 end of central directory record]
+ [zip64 end of central directory locator]
+ [end of central directory record]
+
+
+ 4.3.7 Local file header:
+
+ local file header signature 4 bytes (0x04034b50)
+ version needed to extract 2 bytes
+ general purpose bit flag 2 bytes
+ compression method 2 bytes
+ last mod file time 2 bytes
+ last mod file date 2 bytes
+ crc-32 4 bytes
+ compressed size 4 bytes
+ uncompressed size 4 bytes
+ file name length 2 bytes
+ extra field length 2 bytes
+
+ file name (variable size)
+ extra field (variable size)
+
+ 4.3.8 File data
+
+ Immediately following the local header for a file
+ SHOULD be placed the compressed or stored data for the file.
+ If the file is encrypted, the encryption header for the file
+ SHOULD be placed after the local header and before the file
+ data. The series of [local file header][encryption header]
+ [file data][data descriptor] repeats for each file in the
+ .ZIP archive.
+
+ Zero-byte files, directories, and other file types that
+ contain no content MUST not include file data.
+
+ 4.3.9 Data descriptor:
+
+ crc-32 4 bytes
+ compressed size 4 bytes
+ uncompressed size 4 bytes
+
+ 4.3.9.1 This descriptor MUST exist if bit 3 of the general
+ purpose bit flag is set (see below). It is byte aligned
+ and immediately follows the last byte of compressed data.
+ This descriptor SHOULD be used only when it was not possible to
+ seek in the output .ZIP file, e.g., when the output .ZIP file
+ was standard output or a non-seekable device. For ZIP64(tm) format
+ archives, the compressed and uncompressed sizes are 8 bytes each.
+
+ 4.3.9.2 When compressing files, compressed and uncompressed sizes
+ should be stored in ZIP64 format (as 8 byte values) when a
+ file's size exceeds 0xFFFFFFFF. However ZIP64 format may be
+ used regardless of the size of a file. When extracting, if
+ the zip64 extended information extra field is present for
+ the file the compressed and uncompressed sizes will be 8
+ byte values.
+
+ 4.3.9.3 Although not originally assigned a signature, the value
+ 0x08074b50 has commonly been adopted as a signature value
+ for the data descriptor record. Implementers should be
+ aware that ZIP files may be encountered with or without this
+ signature marking data descriptors and SHOULD account for
+ either case when reading ZIP files to ensure compatibility.
+
+ 4.3.9.4 When writing ZIP files, implementors SHOULD include the
+ signature value marking the data descriptor record. When
+ the signature is used, the fields currently defined for
+ the data descriptor record will immediately follow the
+ signature.
+
+ 4.3.9.5 An extensible data descriptor will be released in a
+ future version of this APPNOTE. This new record is intended to
+ resolve conflicts with the use of this record going forward,
+ and to provide better support for streamed file processing.
+
+ 4.3.9.6 When the Central Directory Encryption method is used,
+ the data descriptor record is not required, but MAY be used.
+ If present, and bit 3 of the general purpose bit field is set to
+ indicate its presence, the values in fields of the data descriptor
+ record MUST be set to binary zeros. See the section on the Strong
+ Encryption Specification for information. Refer to the section in
+ this document entitled "Incorporating PKWARE Proprietary Technology
+ into Your Product" for more information.
+
+
+ 4.3.10 Archive decryption header:
+
+ 4.3.10.1 The Archive Decryption Header is introduced in version 6.2
+ of the ZIP format specification. This record exists in support
+ of the Central Directory Encryption Feature implemented as part of
+ the Strong Encryption Specification as described in this document.
+ When the Central Directory Structure is encrypted, this decryption
+ header MUST precede the encrypted data segment.
+
+ 4.3.10.2 The encrypted data segment SHALL consist of the Archive
+ extra data record (if present) and the encrypted Central Directory
+ Structure data. The format of this data record is identical to the
+ Decryption header record preceding compressed file data. If the
+ central directory structure is encrypted, the location of the start of
+ this data record is determined using the Start of Central Directory
+ field in the Zip64 End of Central Directory record. See the
+ section on the Strong Encryption Specification for information
+ on the fields used in the Archive Decryption Header record.
+ Refer to the section in this document entitled "Incorporating
+ PKWARE Proprietary Technology into Your Product" for more information.
+
+
+ 4.3.11 Archive extra data record:
+
+ archive extra data signature 4 bytes (0x08064b50)
+ extra field length 4 bytes
+ extra field data (variable size)
+
+ 4.3.11.1 The Archive Extra Data Record is introduced in version 6.2
+ of the ZIP format specification. This record MAY be used in support
+ of the Central Directory Encryption Feature implemented as part of
+ the Strong Encryption Specification as described in this document.
+ When present, this record MUST immediately precede the central
+ directory data structure.
+
+ 4.3.11.2 The size of this data record SHALL be included in the
+ Size of the Central Directory field in the End of Central
+ Directory record. If the central directory structure is compressed,
+ but not encrypted, the location of the start of this data record is
+ determined using the Start of Central Directory field in the Zip64
+ End of Central Directory record. Refer to the section in this document
+ entitled "Incorporating PKWARE Proprietary Technology into Your
+ Product" for more information.
+
+ 4.3.12 Central directory structure:
+
+ [central directory header 1]
+ .
+ .
+ .
+ [central directory header n]
+ [digital signature]
+
+ File header:
+
+ central file header signature 4 bytes (0x02014b50)
+ version made by 2 bytes
+ version needed to extract 2 bytes
+ general purpose bit flag 2 bytes
+ compression method 2 bytes
+ last mod file time 2 bytes
+ last mod file date 2 bytes
+ crc-32 4 bytes
+ compressed size 4 bytes
+ uncompressed size 4 bytes
+ file name length 2 bytes
+ extra field length 2 bytes
+ file comment length 2 bytes
+ disk number start 2 bytes
+ internal file attributes 2 bytes
+ external file attributes 4 bytes
+ relative offset of local header 4 bytes
+
+ file name (variable size)
+ extra field (variable size)
+ file comment (variable size)
+
+ 4.3.13 Digital signature:
+
+ header signature 4 bytes (0x05054b50)
+ size of data 2 bytes
+ signature data (variable size)
+
+ With the introduction of the Central Directory Encryption
+ feature in version 6.2 of this specification, the Central
+ Directory Structure MAY be stored both compressed and encrypted.
+ Although not required, it is assumed when encrypting the
+ Central Directory Structure, that it will be compressed
+ for greater storage efficiency. Information on the
+ Central Directory Encryption feature can be found in the section
+ describing the Strong Encryption Specification. The Digital
+ Signature record will be neither compressed nor encrypted.
+
+ 4.3.14 Zip64 end of central directory record
+
+ zip64 end of central dir
+ signature 4 bytes (0x06064b50)
+ size of zip64 end of central
+ directory record 8 bytes
+ version made by 2 bytes
+ version needed to extract 2 bytes
+ number of this disk 4 bytes
+ number of the disk with the
+ start of the central directory 4 bytes
+ total number of entries in the
+ central directory on this disk 8 bytes
+ total number of entries in the
+ central directory 8 bytes
+ size of the central directory 8 bytes
+ offset of start of central
+ directory with respect to
+ the starting disk number 8 bytes
+ zip64 extensible data sector (variable size)
+
+ 4.3.14.1 The value stored into the "size of zip64 end of central
+ directory record" should be the size of the remaining
+ record and should not include the leading 12 bytes.
+
+ Size = SizeOfFixedFields + SizeOfVariableData - 12.
+
+ 4.3.14.2 The above record structure defines Version 1 of the
+ zip64 end of central directory record. Version 1 was
+ implemented in versions of this specification preceding
+ 6.2 in support of the ZIP64 large file feature. The
+ introduction of the Central Directory Encryption feature
+ implemented in version 6.2 as part of the Strong Encryption
+ Specification defines Version 2 of this record structure.
+ Refer to the section describing the Strong Encryption
+ Specification for details on the version 2 format for
+ this record. Refer to the section in this document entitled
+ "Incorporating PKWARE Proprietary Technology into Your Product"
+ for more information applicable to use of Version 2 of this
+ record.
+
+ 4.3.14.3 Special purpose data MAY reside in the zip64 extensible
+ data sector field following either a V1 or V2 version of this
+ record. To ensure identification of this special purpose data
+ it must include an identifying header block consisting of the
+ following:
+
+ Header ID - 2 bytes
+ Data Size - 4 bytes
+
+ The Header ID field indicates the type of data that is in the
+ data block that follows.
+
+ Data Size identifies the number of bytes that follow for this
+ data block type.
+
+ 4.3.14.4 Multiple special purpose data blocks MAY be present.
+ Each MUST be preceded by a Header ID and Data Size field. Current
+ mappings of Header ID values supported in this field are as
+ defined in APPENDIX C.
+
+ 4.3.15 Zip64 end of central directory locator
+
+ zip64 end of central dir locator
+ signature 4 bytes (0x07064b50)
+ number of the disk with the
+ start of the zip64 end of
+ central directory 4 bytes
+ relative offset of the zip64
+ end of central directory record 8 bytes
+ total number of disks 4 bytes
+
+ 4.3.16 End of central directory record:
+
+ end of central dir signature 4 bytes (0x06054b50)
+ number of this disk 2 bytes
+ number of the disk with the
+ start of the central directory 2 bytes
+ total number of entries in the
+ central directory on this disk 2 bytes
+ total number of entries in
+ the central directory 2 bytes
+ size of the central directory 4 bytes
+ offset of start of central
+ directory with respect to
+ the starting disk number 4 bytes
+ .ZIP file comment length 2 bytes
+ .ZIP file comment (variable size)
+
+4.4 Explanation of fields
+--------------------------
+
+ 4.4.1 General notes on fields
+
+ 4.4.1.1 All fields unless otherwise noted are unsigned and stored
+ in Intel low-byte:high-byte, low-word:high-word order.
+
+ 4.4.1.2 String fields are not null terminated, since the length
+ is given explicitly.
+
+ 4.4.1.3 The entries in the central directory may not necessarily
+ be in the same order that files appear in the .ZIP file.
+
+ 4.4.1.4 If one of the fields in the end of central directory
+ record is too small to hold required data, the field should be
+ set to -1 (0xFFFF or 0xFFFFFFFF) and the ZIP64 format record
+ should be created.
+
+ 4.4.1.5 The end of central directory record and the Zip64 end
+ of central directory locator record MUST reside on the same
+ disk when splitting or spanning an archive.
+
+ 4.4.2 version made by (2 bytes)
+
+ 4.4.2.1 The upper byte indicates the compatibility of the file
+ attribute information. If the external file attributes
+ are compatible with MS-DOS and can be read by PKZIP for
+ DOS version 2.04g then this value will be zero. If these
+ attributes are not compatible, then this value will
+ identify the host system on which the attributes are
+ compatible. Software can use this information to determine
+ the line record format for text files etc.
+
+ 4.4.2.2 The current mappings are:
+
+ 0 - MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)
+ 1 - Amiga 2 - OpenVMS
+ 3 - UNIX 4 - VM/CMS
+ 5 - Atari ST 6 - OS/2 H.P.F.S.
+ 7 - Macintosh 8 - Z-System
+ 9 - CP/M 10 - Windows NTFS
+ 11 - MVS (OS/390 - Z/OS) 12 - VSE
+ 13 - Acorn Risc 14 - VFAT
+ 15 - alternate MVS 16 - BeOS
+ 17 - Tandem 18 - OS/400
+ 19 - OS X (Darwin) 20 thru 255 - unused
+
+ 4.4.2.3 The lower byte indicates the ZIP specification version
+ (the version of this document) supported by the software
+ used to encode the file. The value/10 indicates the major
+ version number, and the value mod 10 is the minor version
+ number.
+
+ 4.4.3 version needed to extract (2 bytes)
+
+ 4.4.3.1 The minimum supported ZIP specification version needed
+ to extract the file, mapped as above. This value is based on
+ the specific format features a ZIP program MUST support to
+ be able to extract the file. If multiple features are
+ applied to a file, the minimum version MUST be set to the
+ feature having the highest value. New features or feature
+ changes affecting the published format specification will be
+ implemented using higher version numbers than the last
+ published value to avoid conflict.
+
+ 4.4.3.2 Current minimum feature versions are as defined below:
+
+ 1.0 - Default value
+ 1.1 - File is a volume label
+ 2.0 - File is a folder (directory)
+ 2.0 - File is compressed using Deflate compression
+ 2.0 - File is encrypted using traditional PKWARE encryption
+ 2.1 - File is compressed using Deflate64(tm)
+ 2.5 - File is compressed using PKWARE DCL Implode
+ 2.7 - File is a patch data set
+ 4.5 - File uses ZIP64 format extensions
+ 4.6 - File is compressed using BZIP2 compression*
+ 5.0 - File is encrypted using DES
+ 5.0 - File is encrypted using 3DES
+ 5.0 - File is encrypted using original RC2 encryption
+ 5.0 - File is encrypted using RC4 encryption
+ 5.1 - File is encrypted using AES encryption
+ 5.1 - File is encrypted using corrected RC2 encryption**
+ 5.2 - File is encrypted using corrected RC2-64 encryption**
+ 6.1 - File is encrypted using non-OAEP key wrapping***
+ 6.2 - Central directory encryption
+ 6.3 - File is compressed using LZMA
+ 6.3 - File is compressed using PPMd+
+ 6.3 - File is encrypted using Blowfish
+ 6.3 - File is encrypted using Twofish
+
+ 4.4.3.3 Notes on version needed to extract
+
+ * Early 7.x (pre-7.2) versions of PKZIP incorrectly set the
+ version needed to extract for BZIP2 compression to be 50
+ when it should have been 46.
+
+ ** Refer to the section on Strong Encryption Specification
+ for additional information regarding RC2 corrections.
+
+ *** Certificate encryption using non-OAEP key wrapping is the
+ intended mode of operation for all versions beginning with 6.1.
+ Support for OAEP key wrapping MUST only be used for
+ backward compatibility when sending ZIP files to be opened by
+ versions of PKZIP older than 6.1 (5.0 or 6.0).
+
+ + Files compressed using PPMd MUST set the version
+ needed to extract field to 6.3, however, not all ZIP
+ programs enforce this and may be unable to decompress
+ data files compressed using PPMd if this value is set.
+
+ When using ZIP64 extensions, the corresponding value in the
+ zip64 end of central directory record MUST also be set.
+ This field should be set appropriately to indicate whether
+ Version 1 or Version 2 format is in use.
+
+
+ 4.4.4 general purpose bit flag: (2 bytes)
+
+ Bit 0: If set, indicates that the file is encrypted.
+
+ (For Method 6 - Imploding)
+ Bit 1: If the compression method used was type 6,
+ Imploding, then this bit, if set, indicates
+ an 8K sliding dictionary was used. If clear,
+ then a 4K sliding dictionary was used.
+
+ Bit 2: If the compression method used was type 6,
+ Imploding, then this bit, if set, indicates
+ 3 Shannon-Fano trees were used to encode the
+ sliding dictionary output. If clear, then 2
+ Shannon-Fano trees were used.
+
+ (For Methods 8 and 9 - Deflating)
+ Bit 2 Bit 1
+ 0 0 Normal (-en) compression option was used.
+ 0 1 Maximum (-exx/-ex) compression option was used.
+ 1 0 Fast (-ef) compression option was used.
+ 1 1 Super Fast (-es) compression option was used.
+
+ (For Method 14 - LZMA)
+ Bit 1: If the compression method used was type 14,
+ LZMA, then this bit, if set, indicates
+ an end-of-stream (EOS) marker is used to
+ mark the end of the compressed data stream.
+ If clear, then an EOS marker is not present
+ and the compressed data size must be known
+ to extract.
+
+ Note: Bits 1 and 2 are undefined if the compression
+ method is any other.
+
+ Bit 3: If this bit is set, the fields crc-32, compressed
+ size and uncompressed size are set to zero in the
+ local header. The correct values are put in the
+ data descriptor immediately following the compressed
+ data. (Note: PKZIP version 2.04g for DOS only
+ recognizes this bit for method 8 compression, newer
+ versions of PKZIP recognize this bit for any
+ compression method.)
+
+ Bit 4: Reserved for use with method 8, for enhanced
+ deflating.
+
+ Bit 5: If this bit is set, this indicates that the file is
+ compressed patched data. (Note: Requires PKZIP
+ version 2.70 or greater)
+
+ Bit 6: Strong encryption. If this bit is set, you MUST
+ set the version needed to extract value to at least
+ 50 and you MUST also set bit 0. If AES encryption
+ is used, the version needed to extract value MUST
+ be at least 51. See the section describing the Strong
+ Encryption Specification for details. Refer to the
+ section in this document entitled "Incorporating PKWARE
+ Proprietary Technology into Your Product" for more
+ information.
+
+ Bit 7: Currently unused.
+
+ Bit 8: Currently unused.
+
+ Bit 9: Currently unused.
+
+ Bit 10: Currently unused.
+
+ Bit 11: Language encoding flag (EFS). If this bit is set,
+ the filename and comment fields for this file
+ MUST be encoded using UTF-8. (see APPENDIX D)
+
+ Bit 12: Reserved by PKWARE for enhanced compression.
+
+ Bit 13: Set when encrypting the Central Directory to indicate
+ selected data values in the Local Header are masked to
+ hide their actual values. See the section describing
+ the Strong Encryption Specification for details. Refer
+ to the section in this document entitled "Incorporating
+ PKWARE Proprietary Technology into Your Product" for
+ more information.
+
+ Bit 14: Reserved by PKWARE.
+
+ Bit 15: Reserved by PKWARE.
+
+ 4.4.5 compression method: (2 bytes)
+
+ 0 - The file is stored (no compression)
+ 1 - The file is Shrunk
+ 2 - The file is Reduced with compression factor 1
+ 3 - The file is Reduced with compression factor 2
+ 4 - The file is Reduced with compression factor 3
+ 5 - The file is Reduced with compression factor 4
+ 6 - The file is Imploded
+ 7 - Reserved for Tokenizing compression algorithm
+ 8 - The file is Deflated
+ 9 - Enhanced Deflating using Deflate64(tm)
+ 10 - PKWARE Data Compression Library Imploding (old IBM TERSE)
+ 11 - Reserved by PKWARE
+ 12 - File is compressed using BZIP2 algorithm
+ 13 - Reserved by PKWARE
+ 14 - LZMA (EFS)
+ 15 - Reserved by PKWARE
+ 16 - Reserved by PKWARE
+ 17 - Reserved by PKWARE
+ 18 - File is compressed using IBM TERSE (new)
+ 19 - IBM LZ77 z Architecture (PFS)
+ 97 - WavPack compressed data
+ 98 - PPMd version I, Rev 1
+
+
+ 4.4.6 date and time fields: (2 bytes each)
+
+ The date and time are encoded in standard MS-DOS format.
+ If input came from standard input, the date and time are
+ those at which compression was started for this data.
+ If encrypting the central directory and general purpose bit
+ flag 13 is set indicating masking, the value stored in the
+ Local Header will be zero.
+
+ 4.4.7 CRC-32: (4 bytes)
+
+ The CRC-32 algorithm was generously contributed by
+ David Schwaderer and can be found in his excellent
+ book "C Programmers Guide to NetBIOS" published by
+ Howard W. Sams & Co. Inc. The 'magic number' for
+ the CRC is 0xdebb20e3. The proper CRC pre and post
+ conditioning is used, meaning that the CRC register
+ is pre-conditioned with all ones (a starting value
+ of 0xffffffff) and the value is post-conditioned by
+ taking the one's complement of the CRC residual.
+ If bit 3 of the general purpose flag is set, this
+ field is set to zero in the local header and the correct
+ value is put in the data descriptor and in the central
+ directory. When encrypting the central directory, if the
+ local header is not in ZIP64 format and general purpose
+ bit flag 13 is set indicating masking, the value stored
+ in the Local Header will be zero.
+
+ 4.4.8 compressed size: (4 bytes)
+ 4.4.9 uncompressed size: (4 bytes)
+
+ The size of the file compressed (4.4.8) and uncompressed,
+ (4.4.9) respectively. When a decryption header is present it
+ will be placed in front of the file data and the value of the
+ compressed file size will include the bytes of the decryption
+ header. If bit 3 of the general purpose bit flag is set,
+ these fields are set to zero in the local header and the
+ correct values are put in the data descriptor and
+ in the central directory. If an archive is in ZIP64 format
+ and the value in this field is 0xFFFFFFFF, the size will be
+ in the corresponding 8 byte ZIP64 extended information
+ extra field. When encrypting the central directory, if the
+ local header is not in ZIP64 format and general purpose bit
+ flag 13 is set indicating masking, the value stored for the
+ uncompressed size in the Local Header will be zero.
+
+ 4.4.10 file name length: (2 bytes)
+ 4.4.11 extra field length: (2 bytes)
+ 4.4.12 file comment length: (2 bytes)
+
+ The length of the file name, extra field, and comment
+ fields respectively. The combined length of any
+ directory record and these three fields should not
+ generally exceed 65,535 bytes. If input came from standard
+ input, the file name length is set to zero.
+
+
+ 4.4.13 disk number start: (2 bytes)
+
+ The number of the disk on which this file begins. If an
+ archive is in ZIP64 format and the value in this field is
+ 0xFFFF, the size will be in the corresponding 4 byte zip64
+ extended information extra field.
+
+ 4.4.14 internal file attributes: (2 bytes)
+
+ Bits 1 and 2 are reserved for use by PKWARE.
+
+ 4.4.14.1 The lowest bit of this field indicates, if set,
+ that the file is apparently an ASCII or text file. If not
+ set, that the file apparently contains binary data.
+ The remaining bits are unused in version 1.0.
+
+ 4.4.14.2 The 0x0002 bit of this field indicates, if set, that
+ a 4 byte variable record length control field precedes each
+ logical record indicating the length of the record. The
+ record length control field is stored in little-endian byte
+ order. This flag is independent of text control characters,
+ and if used in conjunction with text data, includes any
+ control characters in the total length of the record. This
+ value is provided for mainframe data transfer support.
+
+ 4.4.15 external file attributes: (4 bytes)
+
+ The mapping of the external attributes is
+ host-system dependent (see 'version made by'). For
+ MS-DOS, the low order byte is the MS-DOS directory
+ attribute byte. If input came from standard input, this
+ field is set to zero.
+
+ 4.4.16 relative offset of local header: (4 bytes)
+
+ This is the offset from the start of the first disk on
+ which this file appears, to where the local header should
+ be found. If an archive is in ZIP64 format and the value
+ in this field is 0xFFFFFFFF, the size will be in the
+ corresponding 8 byte zip64 extended information extra field.
+
+ 4.4.17 file name: (Variable)
+
+ 4.4.17.1 The name of the file, with optional relative path.
+ The path stored MUST not contain a drive or
+ device letter, or a leading slash. All slashes
+ MUST be forward slashes '/' as opposed to
+ backwards slashes '\' for compatibility with Amiga
+ and UNIX file systems etc. If input came from standard
+ input, there is no file name field.
+
+ 4.4.17.2 If using the Central Directory Encryption Feature and
+ general purpose bit flag 13 is set indicating masking, the file
+ name stored in the Local Header will not be the actual file name.
+ A masking value consisting of a unique hexadecimal value will
+ be stored. This value will be sequentially incremented for each
+ file in the archive. See the section on the Strong Encryption
+ Specification for details on retrieving the encrypted file name.
+ Refer to the section in this document entitled "Incorporating PKWARE
+ Proprietary Technology into Your Product" for more information.
+
+
+ 4.4.18 file comment: (Variable)
+
+ The comment for this file.
+
+ 4.4.19 number of this disk: (2 bytes)
+
+ The number of this disk, which contains central
+ directory end record. If an archive is in ZIP64 format
+ and the value in this field is 0xFFFF, the size will
+ be in the corresponding 4 byte zip64 end of central
+ directory field.
+
+
+ 4.4.20 number of the disk with the start of the central
+ directory: (2 bytes)
+
+ The number of the disk on which the central
+ directory starts. If an archive is in ZIP64 format
+ and the value in this field is 0xFFFF, the size will
+ be in the corresponding 4 byte zip64 end of central
+ directory field.
+
+ 4.4.21 total number of entries in the central dir on
+ this disk: (2 bytes)
+
+ The number of central directory entries on this disk.
+ If an archive is in ZIP64 format and the value in
+ this field is 0xFFFF, the size will be in the
+ corresponding 8 byte zip64 end of central
+ directory field.
+
+ 4.4.22 total number of entries in the central dir: (2 bytes)
+
+ The total number of files in the .ZIP file. If an
+ archive is in ZIP64 format and the value in this field
+ is 0xFFFF, the size will be in the corresponding 8 byte
+ zip64 end of central directory field.
+
+ 4.4.23 size of the central directory: (4 bytes)
+
+ The size (in bytes) of the entire central directory.
+ If an archive is in ZIP64 format and the value in
+ this field is 0xFFFFFFFF, the size will be in the
+ corresponding 8 byte zip64 end of central
+ directory field.
+
+ 4.4.24 offset of start of central directory with respect to
+ the starting disk number: (4 bytes)
+
+ Offset of the start of the central directory on the
+ disk on which the central directory starts. If an
+ archive is in ZIP64 format and the value in this
+ field is 0xFFFFFFFF, the size will be in the
+ corresponding 8 byte zip64 end of central
+ directory field.
+
+ 4.4.25 .ZIP file comment length: (2 bytes)
+
+ The length of the comment for this .ZIP file.
+
+ 4.4.26 .ZIP file comment: (Variable)
+
+ The comment for this .ZIP file. ZIP file comment data
+ is stored unsecured. No encryption or data authentication
+ is applied to this area at this time. Confidential information
+ should not be stored in this section.
+
+ 4.4.27 zip64 extensible data sector (variable size)
+
+ (currently reserved for use by PKWARE)
+
+
+ 4.4.28 extra field: (Variable)
+
+ This SHOULD be used for storage expansion. If additional
+ information needs to be stored within a ZIP file for special
+ application or platform needs, it SHOULD be stored here.
+ Programs supporting earlier versions of this specification can
+ then safely skip the file, and find the next file or header.
+ This field will be 0 length in version 1.0.
+
+ Existing extra fields are defined in the section
+ Extensible data fields that follows.
+
+4.5 Extensible data fields
+--------------------------
+
+ 4.5.1 In order to allow different programs and different types
+ of information to be stored in the 'extra' field in .ZIP
+ files, the following structure MUST be used for all
+ programs storing data in this field:
+
+ header1+data1 + header2+data2 . . .
+
+ Each header should consist of:
+
+ Header ID - 2 bytes
+ Data Size - 2 bytes
+
+ Note: all fields stored in Intel low-byte/high-byte order.
+
+ The Header ID field indicates the type of data that is in
+ the following data block.
+
+ Header IDs of 0 thru 31 are reserved for use by PKWARE.
+ The remaining IDs can be used by third party vendors for
+ proprietary usage.
+
+ 4.5.2 The current Header ID mappings defined by PKWARE are:
+
+ 0x0001 Zip64 extended information extra field
+ 0x0007 AV Info
+ 0x0008 Reserved for extended language encoding data (PFS)
+ (see APPENDIX D)
+ 0x0009 OS/2
+ 0x000a NTFS
+ 0x000c OpenVMS
+ 0x000d UNIX
+ 0x000e Reserved for file stream and fork descriptors
+ 0x000f Patch Descriptor
+ 0x0014 PKCS#7 Store for X.509 Certificates
+ 0x0015 X.509 Certificate ID and Signature for
+ individual file
+ 0x0016 X.509 Certificate ID for Central Directory
+ 0x0017 Strong Encryption Header
+ 0x0018 Record Management Controls
+ 0x0019 PKCS#7 Encryption Recipient Certificate List
+ 0x0065 IBM S/390 (Z390), AS/400 (I400) attributes
+ - uncompressed
+ 0x0066 Reserved for IBM S/390 (Z390), AS/400 (I400)
+ attributes - compressed
+ 0x4690 POSZIP 4690 (reserved)
+
+
+ 4.5.3 -Zip64 Extended Information Extra Field (0x0001):
+
+ The following is the layout of the zip64 extended
+ information "extra" block. If one of the size or
+ offset fields in the Local or Central directory
+ record is too small to hold the required data,
+ a Zip64 extended information record is created.
+ The order of the fields in the zip64 extended
+ information record is fixed, but the fields MUST
+ only appear if the corresponding Local or Central
+ directory record field is set to 0xFFFF or 0xFFFFFFFF.
+
+ Note: all fields stored in Intel low-byte/high-byte order.
+
+ Value Size Description
+ ----- ---- -----------
+(ZIP64) 0x0001 2 bytes Tag for this "extra" block type
+ Size 2 bytes Size of this "extra" block
+ Original
+ Size 8 bytes Original uncompressed file size
+ Compressed
+ Size 8 bytes Size of compressed data
+ Relative Header
+ Offset 8 bytes Offset of local header record
+ Disk Start
+ Number 4 bytes Number of the disk on which
+ this file starts
+
+ This entry in the Local header MUST include BOTH original
+ and compressed file size fields. If encrypting the
+ central directory and bit 13 of the general purpose bit
+ flag is set indicating masking, the value stored in the
+ Local Header for the original file size will be zero.
+
+
+ 4.5.4 -OS/2 Extra Field (0x0009):
+
+ The following is the layout of the OS/2 attributes "extra"
+ block. (Last Revision 09/05/95)
+
+ Note: all fields stored in Intel low-byte/high-byte order.
+
+ Value Size Description
+ ----- ---- -----------
+(OS/2) 0x0009 2 bytes Tag for this "extra" block type
+ TSize 2 bytes Size for the following data block
+ BSize 4 bytes Uncompressed Block Size
+ CType 2 bytes Compression type
+ EACRC 4 bytes CRC value for uncompress block
+ (var) variable Compressed block
+
+ The OS/2 extended attribute structure (FEA2LIST) is
+ compressed and then stored in its entirety within this
+ structure. There will only ever be one "block" of data in
+ VarFields[].
+
+ 4.5.5 -NTFS Extra Field (0x000a):
+
+ The following is the layout of the NTFS attributes
+ "extra" block. (Note: At this time the Mtime, Atime
+ and Ctime values MAY be used on any WIN32 system.)
+
+ Note: all fields stored in Intel low-byte/high-byte order.
+
+ Value Size Description
+ ----- ---- -----------
+(NTFS) 0x000a 2 bytes Tag for this "extra" block type
+ TSize 2 bytes Size of the total "extra" block
+ Reserved 4 bytes Reserved for future use
+ Tag1 2 bytes NTFS attribute tag value #1
+ Size1 2 bytes Size of attribute #1, in bytes
+ (var) Size1 Attribute #1 data
+ .
+ .
+ .
+ TagN 2 bytes NTFS attribute tag value #N
+ SizeN 2 bytes Size of attribute #N, in bytes
+ (var) SizeN Attribute #N data
+
+ For NTFS, values for Tag1 through TagN are as follows:
+ (currently only one set of attributes is defined for NTFS)
+
+ Tag Size Description
+ ----- ---- -----------
+ 0x0001 2 bytes Tag for attribute #1
+ Size1 2 bytes Size of attribute #1, in bytes
+ Mtime 8 bytes File last modification time
+ Atime 8 bytes File last access time
+ Ctime 8 bytes File creation time
+
+ 4.5.6 -OpenVMS Extra Field (0x000c):
+
+ The following is the layout of the OpenVMS attributes
+ "extra" block.
+
+ Note: all fields stored in Intel low-byte/high-byte order.
+
+ Value Size Description
+ ----- ---- -----------
+ (VMS) 0x000c 2 bytes Tag for this "extra" block type
+ TSize 2 bytes Size of the total "extra" block
+ CRC 4 bytes 32-bit CRC for remainder of the block
+ Tag1 2 bytes OpenVMS attribute tag value #1
+ Size1 2 bytes Size of attribute #1, in bytes
+ (var) Size1 Attribute #1 data
+ .
+ .
+ .
+ TagN 2 bytes OpenVMS attribute tag value #N
+ SizeN 2 bytes Size of attribute #N, in bytes
+ (var) SizeN Attribute #N data
+
+ OpenVMS Extra Field Rules:
+
+ 4.5.6.1. There will be one or more attributes present, which
+ will each be preceded by the above TagX & SizeX values.
+ These values are identical to the ATR$C_XXXX and ATR$S_XXXX
+ constants which are defined in ATR.H under OpenVMS C. Neither
+ of these values will ever be zero.
+
+ 4.5.6.2. No word alignment or padding is performed.
+
+ 4.5.6.3. A well-behaved PKZIP/OpenVMS program should never produce
+ more than one sub-block with the same TagX value. Also, there will
+ never be more than one "extra" block of type 0x000c in a particular
+ directory record.
+
+ 4.5.7 -UNIX Extra Field (0x000d):
+
+ The following is the layout of the UNIX "extra" block.
+ Note: all fields are stored in Intel low-byte/high-byte
+ order.
+
+ Value Size Description
+ ----- ---- -----------
+(UNIX) 0x000d 2 bytes Tag for this "extra" block type
+ TSize 2 bytes Size for the following data block
+ Atime 4 bytes File last access time
+ Mtime 4 bytes File last modification time
+ Uid 2 bytes File user ID
+ Gid 2 bytes File group ID
+ (var) variable Variable length data field
+
+ The variable length data field will contain file type
+ specific data. Currently the only values allowed are
+ the original "linked to" file names for hard or symbolic
+ links, and the major and minor device node numbers for
+ character and block device nodes. Since device nodes
+ cannot be either symbolic or hard links, only one set of
+ variable length data is stored. Link files will have the
+ name of the original file stored. This name is NOT NULL
+ terminated. Its size can be determined by checking TSize -
+ 12. Device entries will have eight bytes stored as two 4
+ byte entries (in little endian format). The first entry
+ will be the major device number, and the second the minor
+ device number.
+
+ 4.5.8 -PATCH Descriptor Extra Field (0x000f):
+
+ 4.5.8.1 The following is the layout of the Patch Descriptor
+ "extra" block.
+
+ Note: all fields stored in Intel low-byte/high-byte order.
+
+ Value Size Description
+ ----- ---- -----------
+(Patch) 0x000f 2 bytes Tag for this "extra" block type
+ TSize 2 bytes Size of the total "extra" block
+ Version 2 bytes Version of the descriptor
+ Flags 4 bytes Actions and reactions (see below)
+ OldSize 4 bytes Size of the file about to be patched
+ OldCRC 4 bytes 32-bit CRC of the file to be patched
+ NewSize 4 bytes Size of the resulting file
+ NewCRC 4 bytes 32-bit CRC of the resulting file
+
+ 4.5.8.2 Actions and reactions
+
+ Bits Description
+ ---- ----------------
+ 0 Use for auto detection
+ 1 Treat as a self-patch
+ 2-3 RESERVED
+ 4-5 Action (see below)
+ 6-7 RESERVED
+ 8-9 Reaction (see below) to absent file
+ 10-11 Reaction (see below) to newer file
+ 12-13 Reaction (see below) to unknown file
+ 14-15 RESERVED
+ 16-31 RESERVED
+
+ 4.5.8.2.1 Actions
+
+ Action Value
+ ------ -----
+ none 0
+ add 1
+ delete 2
+ patch 3
+
+ 4.5.8.2.2 Reactions
+
+ Reaction Value
+ -------- -----
+ ask 0
+ skip 1
+ ignore 2
+ fail 3
+
+ 4.5.8.3 Patch support is provided by PKPatchMaker(tm) technology
+ and is covered under U.S. Patents and Patents Pending. The use or
+ implementation in a product of certain technological aspects set
+ forth in the current APPNOTE, including those with regard to
+ strong encryption or patching requires a license from PKWARE.
+ Refer to the section in this document entitled "Incorporating
+ PKWARE Proprietary Technology into Your Product" for more
+ information.
+
+ 4.5.9 -PKCS#7 Store for X.509 Certificates (0x0014):
+
+ This field MUST contain information about each of the certificates
+ files may be signed with. When the Central Directory Encryption
+ feature is enabled for a ZIP file, this record will appear in
+ the Archive Extra Data Record, otherwise it will appear in the
+ first central directory record and will be ignored in any
+ other record.
+
+
+ Note: all fields stored in Intel low-byte/high-byte order.
+
+ Value Size Description
+ ----- ---- -----------
+(Store) 0x0014 2 bytes Tag for this "extra" block type
+ TSize 2 bytes Size of the store data
+ TData TSize Data about the store
+
+
+ 4.5.10 -X.509 Certificate ID and Signature for individual file (0x0015):
+
+ This field contains the information about which certificate in
+ the PKCS#7 store was used to sign a particular file. It also
+ contains the signature data. This field can appear multiple
+ times, but can only appear once per certificate.
+
+ Note: all fields stored in Intel low-byte/high-byte order.
+
+ Value Size Description
+ ----- ---- -----------
+(CID) 0x0015 2 bytes Tag for this "extra" block type
+ TSize 2 bytes Size of data that follows
+ TData TSize Signature Data
+
+ 4.5.11 -X.509 Certificate ID and Signature for central directory (0x0016):
+
+ This field contains the information about which certificate in
+ the PKCS#7 store was used to sign the central directory structure.
+ When the Central Directory Encryption feature is enabled for a
+ ZIP file, this record will appear in the Archive Extra Data Record,
+ otherwise it will appear in the first central directory record.
+
+ Note: all fields stored in Intel low-byte/high-byte order.
+
+ Value Size Description
+ ----- ---- -----------
+(CDID) 0x0016 2 bytes Tag for this "extra" block type
+ TSize 2 bytes Size of data that follows
+ TData TSize Data
+
+ 4.5.12 -Strong Encryption Header (0x0017):
+
+ Value Size Description
+ ----- ---- -----------
+ 0x0017 2 bytes Tag for this "extra" block type
+ TSize 2 bytes Size of data that follows
+ Format 2 bytes Format definition for this record
+ AlgID 2 bytes Encryption algorithm identifier
+ Bitlen 2 bytes Bit length of encryption key
+ Flags 2 bytes Processing flags
+ CertData TSize-8 Certificate decryption extra field data
+ (refer to the explanation for CertData
+ in the section describing the
+ Certificate Processing Method under
+ the Strong Encryption Specification)
+
+ See the section describing the Strong Encryption Specification
+ for details. Refer to the section in this document entitled
+ "Incorporating PKWARE Proprietary Technology into Your Product"
+ for more information.
+
+ 4.5.13 -Record Management Controls (0x0018):
+
+ Value Size Description
+ ----- ---- -----------
+(Rec-CTL) 0x0018 2 bytes Tag for this "extra" block type
+ CSize 2 bytes Size of total extra block data
+ Tag1 2 bytes Record control attribute 1
+ Size1 2 bytes Size of attribute 1, in bytes
+ Data1 Size1 Attribute 1 data
+ .
+ .
+ .
+ TagN 2 bytes Record control attribute N
+ SizeN 2 bytes Size of attribute N, in bytes
+ DataN SizeN Attribute N data
+
+
+ 4.5.14 -PKCS#7 Encryption Recipient Certificate List (0x0019):
+
+ This field MAY contain information about each of the certificates
+ used in encryption processing and it can be used to identify who is
+ allowed to decrypt encrypted files. This field should only appear
+ in the archive extra data record. This field is not required and
+ serves only to aid archive modifications by preserving public
+ encryption key data. Individual security requirements may dictate
+ that this data be omitted to deter information exposure.
+
+ Note: all fields stored in Intel low-byte/high-byte order.
+
+ Value Size Description
+ ----- ---- -----------
+(CStore) 0x0019 2 bytes Tag for this "extra" block type
+ TSize 2 bytes Size of the store data
+ TData TSize Data about the store
+
+ TData:
+
+ Value Size Description
+ ----- ---- -----------
+ Version 2 bytes Format version number - must 0x0001 at this time
+ CStore (var) PKCS#7 data blob
+
+ See the section describing the Strong Encryption Specification
+ for details. Refer to the section in this document entitled
+ "Incorporating PKWARE Proprietary Technology into Your Product"
+ for more information.
+
+ 4.5.15 -MVS Extra Field (0x0065):
+
+ The following is the layout of the MVS "extra" block.
+ Note: Some fields are stored in Big Endian format.
+ All text is in EBCDIC format unless otherwise specified.
+
+ Value Size Description
+ ----- ---- -----------
+(MVS) 0x0065 2 bytes Tag for this "extra" block type
+ TSize 2 bytes Size for the following data block
+ ID 4 bytes EBCDIC "Z390" 0xE9F3F9F0 or
+ "T4MV" for TargetFour
+ (var) TSize-4 Attribute data (see APPENDIX B)
+
+
+ 4.5.16 -OS/400 Extra Field (0x0065):
+
+ The following is the layout of the OS/400 "extra" block.
+ Note: Some fields are stored in Big Endian format.
+ All text is in EBCDIC format unless otherwise specified.
+
+ Value Size Description
+ ----- ---- -----------
+(OS400) 0x0065 2 bytes Tag for this "extra" block type
+ TSize 2 bytes Size for the following data block
+ ID 4 bytes EBCDIC "I400" 0xC9F4F0F0 or
+ "T4MV" for TargetFour
+ (var) TSize-4 Attribute data (see APPENDIX A)
+
+4.6 Third Party Mappings
+------------------------
+
+ 4.6.1 Third party mappings commonly used are:
+
+ 0x07c8 Macintosh
+ 0x2605 ZipIt Macintosh
+ 0x2705 ZipIt Macintosh 1.3.5+
+ 0x2805 ZipIt Macintosh 1.3.5+
+ 0x334d Info-ZIP Macintosh
+ 0x4341 Acorn/SparkFS
+ 0x4453 Windows NT security descriptor (binary ACL)
+ 0x4704 VM/CMS
+ 0x470f MVS
+ 0x4b46 FWKCS MD5 (see below)
+ 0x4c41 OS/2 access control list (text ACL)
+ 0x4d49 Info-ZIP OpenVMS
+ 0x4f4c Xceed original location extra field
+ 0x5356 AOS/VS (ACL)
+ 0x5455 extended timestamp
+ 0x554e Xceed unicode extra field
+ 0x5855 Info-ZIP UNIX (original, also OS/2, NT, etc)
+ 0x6375 Info-ZIP Unicode Comment Extra Field
+ 0x6542 BeOS/BeBox
+ 0x7075 Info-ZIP Unicode Path Extra Field
+ 0x756e ASi UNIX
+ 0x7855 Info-ZIP UNIX (new)
+ 0xa220 Microsoft Open Packaging Growth Hint
+ 0xfd4a SMS/QDOS
+
+ Detailed descriptions of Extra Fields defined by third
+ party mappings will be documented as information on
+ these data structures is made available to PKWARE.
+ PKWARE does not guarantee the accuracy of any published
+ third party data.
+
+ 4.6.2 Third-party Extra Fields must include a Header ID using
+ the format defined in the section of this document
+ titled Extensible Data Fields (section 4.5).
+
+ The Data Size field indicates the size of the following
+ data block. Programs can use this value to skip to the
+ next header block, passing over any data blocks that are
+ not of interest.
+
+ Note: As stated above, the size of the entire .ZIP file
+ header, including the file name, comment, and extra
+ field should not exceed 64K in size.
+
+ 4.6.3 In case two different programs should appropriate the same
+ Header ID value, it is strongly recommended that each
+ program SHOULD place a unique signature of at least two bytes in
+ size (and preferably 4 bytes or bigger) at the start of
+ each data area. Every program SHOULD verify that its
+ unique signature is present, in addition to the Header ID
+ value being correct, before assuming that it is a block of
+ known type.
+
+ Third-party Mappings:
+
+ 4.6.4 -ZipIt Macintosh Extra Field (long) (0x2605):
+
+ The following is the layout of the ZipIt extra block
+ for Macintosh. The local-header and central-header versions
+ are identical. This block must be present if the file is
+ stored MacBinary-encoded and it should not be used if the file
+ is not stored MacBinary-encoded.
+
+ Value Size Description
+ ----- ---- -----------
+ (Mac2) 0x2605 Short tag for this extra block type
+ TSize Short total data size for this block
+ "ZPIT" beLong extra-field signature
+ FnLen Byte length of FileName
+ FileName variable full Macintosh filename
+ FileType Byte[4] four-byte Mac file type string
+ Creator Byte[4] four-byte Mac creator string
+
+
+ 4.6.5 -ZipIt Macintosh Extra Field (short, for files) (0x2705):
+
+ The following is the layout of a shortened variant of the
+ ZipIt extra block for Macintosh (without "full name" entry).
+ This variant is used by ZipIt 1.3.5 and newer for entries of
+ files (not directories) that do not have a MacBinary encoded
+ file. The local-header and central-header versions are identical.
+
+ Value Size Description
+ ----- ---- -----------
+ (Mac2b) 0x2705 Short tag for this extra block type
+ TSize Short total data size for this block (12)
+ "ZPIT" beLong extra-field signature
+ FileType Byte[4] four-byte Mac file type string
+ Creator Byte[4] four-byte Mac creator string
+ fdFlags beShort attributes from FInfo.frFlags,
+ may be omitted
+ 0x0000 beShort reserved, may be omitted
+
+
+ 4.6.6 -ZipIt Macintosh Extra Field (short, for directories) (0x2805):
+
+ The following is the layout of a shortened variant of the
+ ZipIt extra block for Macintosh used only for directory
+ entries. This variant is used by ZipIt 1.3.5 and newer to
+ save some optional Mac-specific information about directories.
+ The local-header and central-header versions are identical.
+
+ Value Size Description
+ ----- ---- -----------
+ (Mac2c) 0x2805 Short tag for this extra block type
+ TSize Short total data size for this block (12)
+ "ZPIT" beLong extra-field signature
+ frFlags beShort attributes from DInfo.frFlags, may
+ be omitted
+ View beShort ZipIt view flag, may be omitted
+
+
+ The View field specifies ZipIt-internal settings as follows:
+
+ Bits of the Flags:
+ bit 0 if set, the folder is shown expanded (open)
+ when the archive contents are viewed in ZipIt.
+ bits 1-15 reserved, zero;
+
+
+ 4.6.7 -FWKCS MD5 Extra Field (0x4b46):
+
+ The FWKCS Contents_Signature System, used in
+ automatically identifying files independent of file name,
+ optionally adds and uses an extra field to support the
+ rapid creation of an enhanced contents_signature:
+
+ Header ID = 0x4b46
+ Data Size = 0x0013
+ Preface = 'M','D','5'
+ followed by 16 bytes containing the uncompressed file's
+ 128_bit MD5 hash(1), low byte first.
+
+ When FWKCS revises a .ZIP file central directory to add
+ this extra field for a file, it also replaces the
+ central directory entry for that file's uncompressed
+ file length with a measured value.
+
+ FWKCS provides an option to strip this extra field, if
+ present, from a .ZIP file central directory. In adding
+ this extra field, FWKCS preserves .ZIP file Authenticity
+ Verification; if stripping this extra field, FWKCS
+ preserves all versions of AV through PKZIP version 2.04g.
+
+ FWKCS, and FWKCS Contents_Signature System, are
+ trademarks of Frederick W. Kantor.
+
+ (1) R. Rivest, RFC1321.TXT, MIT Laboratory for Computer
+ Science and RSA Data Security, Inc., April 1992.
+ ll.76-77: "The MD5 algorithm is being placed in the
+ public domain for review and possible adoption as a
+ standard."
+
+
+ 4.6.8 -Info-ZIP Unicode Comment Extra Field (0x6375):
+
+ Stores the UTF-8 version of the file comment as stored in the
+ central directory header. (Last Revision 20070912)
+
+ Value Size Description
+ ----- ---- -----------
+ (UCom) 0x6375 Short tag for this extra block type ("uc")
+ TSize Short total data size for this block
+ Version 1 byte version of this extra field, currently 1
+ ComCRC32 4 bytes Comment Field CRC32 Checksum
+ UnicodeCom Variable UTF-8 version of the entry comment
+
+ Currently Version is set to the number 1. If there is a need
+ to change this field, the version will be incremented. Changes
+ may not be backward compatible so this extra field should not be
+ used if the version is not recognized.
+
+ The ComCRC32 is the standard zip CRC32 checksum of the File Comment
+ field in the central directory header. This is used to verify that
+ the comment field has not changed since the Unicode Comment extra field
+ was created. This can happen if a utility changes the File Comment
+ field but does not update the UTF-8 Comment extra field. If the CRC
+ check fails, this Unicode Comment extra field should be ignored and
+ the File Comment field in the header should be used instead.
+
+ The UnicodeCom field is the UTF-8 version of the File Comment field
+ in the header. As UnicodeCom is defined to be UTF-8, no UTF-8 byte
+ order mark (BOM) is used. The length of this field is determined by
+ subtracting the size of the previous fields from TSize. If both the
+ File Name and Comment fields are UTF-8, the new General Purpose Bit
+ Flag, bit 11 (Language encoding flag (EFS)), can be used to indicate
+ both the header File Name and Comment fields are UTF-8 and, in this
+ case, the Unicode Path and Unicode Comment extra fields are not
+ needed and should not be created. Note that, for backward
+ compatibility, bit 11 should only be used if the native character set
+ of the paths and comments being zipped up are already in UTF-8. It is
+ expected that the same file comment storage method, either general
+ purpose bit 11 or extra fields, be used in both the Local and Central
+ Directory Header for a file.
+
+
+ 4.6.9 -Info-ZIP Unicode Path Extra Field (0x7075):
+
+ Stores the UTF-8 version of the file name field as stored in the
+ local header and central directory header. (Last Revision 20070912)
+
+ Value Size Description
+ ----- ---- -----------
+ (UPath) 0x7075 Short tag for this extra block type ("up")
+ TSize Short total data size for this block
+ Version 1 byte version of this extra field, currently 1
+ NameCRC32 4 bytes File Name Field CRC32 Checksum
+ UnicodeName Variable UTF-8 version of the entry File Name
+
+ Currently Version is set to the number 1. If there is a need
+ to change this field, the version will be incremented. Changes
+ may not be backward compatible so this extra field should not be
+ used if the version is not recognized.
+
+ The NameCRC32 is the standard zip CRC32 checksum of the File Name
+ field in the header. This is used to verify that the header
+ File Name field has not changed since the Unicode Path extra field
+ was created. This can happen if a utility renames the File Name but
+ does not update the UTF-8 path extra field. If the CRC check fails,
+ this UTF-8 Path Extra Field should be ignored and the File Name field
+ in the header should be used instead.
+
+ The UnicodeName is the UTF-8 version of the contents of the File Name
+ field in the header. As UnicodeName is defined to be UTF-8, no UTF-8
+ byte order mark (BOM) is used. The length of this field is determined
+ by subtracting the size of the previous fields from TSize. If both
+ the File Name and Comment fields are UTF-8, the new General Purpose
+ Bit Flag, bit 11 (Language encoding flag (EFS)), can be used to
+ indicate that both the header File Name and Comment fields are UTF-8
+ and, in this case, the Unicode Path and Unicode Comment extra fields
+ are not needed and should not be created. Note that, for backward
+ compatibility, bit 11 should only be used if the native character set
+ of the paths and comments being zipped up are already in UTF-8. It is
+ expected that the same file name storage method, either general
+ purpose bit 11 or extra fields, be used in both the Local and Central
+ Directory Header for a file.
+
+
+ 4.6.10 -Microsoft Open Packaging Growth Hint (0xa220):
+
+ Value Size Description
+ ----- ---- -----------
+ 0xa220 Short tag for this extra block type
+ TSize Short size of Sig + PadVal + Padding
+ Sig Short verification signature (A028)
+ PadVal Short Initial padding value
+ Padding variable filled with NULL characters
+
+4.7 Manifest Files
+------------------
+
+ 4.7.1 Applications using ZIP files may have a need for additional
+ information that must be included with the files placed into
+ a ZIP file. Application specific information that cannot be
+ stored using the defined ZIP storage records SHOULD be stored
+ using the extensible Extra Field convention defined in this
+ document. However, some applications may use a manifest
+ file as a means for storing additional information. One
+ example is the META-INF/MANIFEST.MF file used in ZIP formatted
+ files having the .JAR extension (JAR files).
+
+ 4.7.2 A manifest file is a file created for the application process
+ that requires this information. A manifest file MAY be of any
+ file type required by the defining application process. It is
+ placed within the same ZIP file as files to which this information
+ applies. By convention, this file is typically the first file placed
+ into the ZIP file and it may include a defined directory path.
+
+ 4.7.3 Manifest files may be compressed or encrypted as needed for
+ application processing of the files inside the ZIP files.
+
+ Manifest files are outside of the scope of this specification.
+
+
+5.0 Explanation of compression methods
+--------------------------------------
+
+
+5.1 UnShrinking - Method 1
+--------------------------
+
+ 5.1.1 Shrinking is a Dynamic Ziv-Lempel-Welch compression algorithm
+ with partial clearing. The initial code size is 9 bits, and the
+ maximum code size is 13 bits. Shrinking differs from conventional
+ Dynamic Ziv-Lempel-Welch implementations in several respects:
+
+ 5.1.2 The code size is controlled by the compressor, and is
+ not automatically increased when codes larger than the current
+ code size are created (but not necessarily used). When
+ the decompressor encounters the code sequence 256
+ (decimal) followed by 1, it should increase the code size
+ read from the input stream to the next bit size. No
+ blocking of the codes is performed, so the next code at
+ the increased size should be read from the input stream
+ immediately after where the previous code at the smaller
+ bit size was read. Again, the decompressor should not
+ increase the code size used until the sequence 256,1 is
+ encountered.
+
+ 5.1.3 When the table becomes full, total clearing is not
+ performed. Rather, when the compressor emits the code
+ sequence 256,2 (decimal), the decompressor should clear
+ all leaf nodes from the Ziv-Lempel tree, and continue to
+ use the current code size. The nodes that are cleared
+ from the Ziv-Lempel tree are then re-used, with the lowest
+ code value re-used first, and the highest code value
+ re-used last. The compressor can emit the sequence 256,2
+ at any time.
+
+5.2 Expanding - Methods 2-5
+---------------------------
+
+ 5.2.1 The Reducing algorithm is actually a combination of two
+ distinct algorithms. The first algorithm compresses repeated
+ byte sequences, and the second algorithm takes the compressed
+ stream from the first algorithm and applies a probabilistic
+ compression method.
+
+ 5.2.2 The probabilistic compression stores an array of 'follower
+ sets' S(j), for j=0 to 255, corresponding to each possible
+ ASCII character. Each set contains between 0 and 32
+ characters, to be denoted as S(j)[0],...,S(j)[m], where m<32.
+ The sets are stored at the beginning of the data area for a
+ Reduced file, in reverse order, with S(255) first, and S(0)
+ last.
+
+ 5.2.3 The sets are encoded as { N(j), S(j)[0],...,S(j)[N(j)-1] },
+ where N(j) is the size of set S(j). N(j) can be 0, in which
+ case the follower set for S(j) is empty. Each N(j) value is
+ encoded in 6 bits, followed by N(j) eight bit character values
+ corresponding to S(j)[0] to S(j)[N(j)-1] respectively. If
+ N(j) is 0, then no values for S(j) are stored, and the value
+ for N(j-1) immediately follows.
+
+ 5.2.4 Immediately after the follower sets, is the compressed data
+ stream. The compressed data stream can be interpreted for the
+ probabilistic decompression as follows:
+
+ let Last-Character <- 0.
+ loop until done
+ if the follower set S(Last-Character) is empty then
+ read 8 bits from the input stream, and copy this
+ value to the output stream.
+ otherwise if the follower set S(Last-Character) is non-empty then
+ read 1 bit from the input stream.
+ if this bit is not zero then
+ read 8 bits from the input stream, and copy this
+ value to the output stream.
+ otherwise if this bit is zero then
+ read B(N(Last-Character)) bits from the input
+ stream, and assign this value to I.
+ Copy the value of S(Last-Character)[I] to the
+ output stream.
+
+ assign the last value placed on the output stream to
+ Last-Character.
+ end loop
+
+ B(N(j)) is defined as the minimal number of bits required to
+ encode the value N(j)-1.
+
+ 5.2.5 The decompressed stream from above can then be expanded to
+ re-create the original file as follows:
+
+ let State <- 0.
+
+ loop until done
+ read 8 bits from the input stream into C.
+ case State of
+ 0: if C is not equal to DLE (144 decimal) then
+ copy C to the output stream.
+ otherwise if C is equal to DLE then
+ let State <- 1.
+
+ 1: if C is non-zero then
+ let V <- C.
+ let Len <- L(V)
+ let State <- F(Len).
+ otherwise if C is zero then
+ copy the value 144 (decimal) to the output stream.
+ let State <- 0
+
+ 2: let Len <- Len + C
+ let State <- 3.
+
+ 3: move backwards D(V,C) bytes in the output stream
+ (if this position is before the start of the output
+ stream, then assume that all the data before the
+ start of the output stream is filled with zeros).
+ copy Len+3 bytes from this position to the output stream.
+ let State <- 0.
+ end case
+ end loop
+
+ The functions F,L, and D are dependent on the 'compression
+ factor', 1 through 4, and are defined as follows:
+
+ For compression factor 1:
+ L(X) equals the lower 7 bits of X.
+ F(X) equals 2 if X equals 127 otherwise F(X) equals 3.
+ D(X,Y) equals the (upper 1 bit of X) * 256 + Y + 1.
+ For compression factor 2:
+ L(X) equals the lower 6 bits of X.
+ F(X) equals 2 if X equals 63 otherwise F(X) equals 3.
+ D(X,Y) equals the (upper 2 bits of X) * 256 + Y + 1.
+ For compression factor 3:
+ L(X) equals the lower 5 bits of X.
+ F(X) equals 2 if X equals 31 otherwise F(X) equals 3.
+ D(X,Y) equals the (upper 3 bits of X) * 256 + Y + 1.
+ For compression factor 4:
+ L(X) equals the lower 4 bits of X.
+ F(X) equals 2 if X equals 15 otherwise F(X) equals 3.
+ D(X,Y) equals the (upper 4 bits of X) * 256 + Y + 1.
+
+5.3 Imploding - Method 6
+------------------------
+
+ 5.3.1 The Imploding algorithm is actually a combination of two
+ distinct algorithms. The first algorithm compresses repeated byte
+ sequences using a sliding dictionary. The second algorithm is
+ used to compress the encoding of the sliding dictionary output,
+ using multiple Shannon-Fano trees.
+
+ 5.3.2 The Imploding algorithm can use a 4K or 8K sliding dictionary
+ size. The dictionary size used can be determined by bit 1 in the
+ general purpose flag word; a 0 bit indicates a 4K dictionary
+ while a 1 bit indicates an 8K dictionary.
+
+ 5.3.3 The Shannon-Fano trees are stored at the start of the
+ compressed file. The number of trees stored is defined by bit 2 in
+ the general purpose flag word; a 0 bit indicates two trees stored,
+ a 1 bit indicates three trees are stored. If 3 trees are stored,
+ the first Shannon-Fano tree represents the encoding of the
+ Literal characters, the second tree represents the encoding of
+ the Length information, the third represents the encoding of the
+ Distance information. When 2 Shannon-Fano trees are stored, the
+ Length tree is stored first, followed by the Distance tree.
+
+ 5.3.4 The Literal Shannon-Fano tree, if present is used to represent
+ the entire ASCII character set, and contains 256 values. This
+ tree is used to compress any data not compressed by the sliding
+ dictionary algorithm. When this tree is present, the Minimum
+ Match Length for the sliding dictionary is 3. If this tree is
+ not present, the Minimum Match Length is 2.
+
+ 5.3.5 The Length Shannon-Fano tree is used to compress the Length
+ part of the (length,distance) pairs from the sliding dictionary
+ output. The Length tree contains 64 values, ranging from the
+ Minimum Match Length, to 63 plus the Minimum Match Length.
+
+ 5.3.6 The Distance Shannon-Fano tree is used to compress the Distance
+ part of the (length,distance) pairs from the sliding dictionary
+ output. The Distance tree contains 64 values, ranging from 0 to
+ 63, representing the upper 6 bits of the distance value. The
+ distance values themselves will be between 0 and the sliding
+ dictionary size, either 4K or 8K.
+
+ 5.3.7 The Shannon-Fano trees themselves are stored in a compressed
+ format. The first byte of the tree data represents the number of
+ bytes of data representing the (compressed) Shannon-Fano tree
+ minus 1. The remaining bytes represent the Shannon-Fano tree
+ data encoded as:
+
+ High 4 bits: Number of values at this bit length + 1. (1 - 16)
+ Low 4 bits: Bit Length needed to represent value + 1. (1 - 16)
+
+ 5.3.8 The Shannon-Fano codes can be constructed from the bit lengths
+ using the following algorithm:
+
+ 1) Sort the Bit Lengths in ascending order, while retaining the
+ order of the original lengths stored in the file.
+
+ 2) Generate the Shannon-Fano trees:
+
+ Code <- 0
+ CodeIncrement <- 0
+ LastBitLength <- 0
+ i <- number of Shannon-Fano codes - 1 (either 255 or 63)
+
+ loop while i >= 0
+ Code = Code + CodeIncrement
+ if BitLength(i) <> LastBitLength then
+ LastBitLength=BitLength(i)
+ CodeIncrement = 1 shifted left (16 - LastBitLength)
+ ShannonCode(i) = Code
+ i <- i - 1
+ end loop
+
+ 3) Reverse the order of all the bits in the above ShannonCode()
+ vector, so that the most significant bit becomes the least
+ significant bit. For example, the value 0x1234 (hex) would
+ become 0x2C48 (hex).
+
+ 4) Restore the order of Shannon-Fano codes as originally stored
+ within the file.
+
+ Example:
+
+ This example will show the encoding of a Shannon-Fano tree
+ of size 8. Notice that the actual Shannon-Fano trees used
+ for Imploding are either 64 or 256 entries in size.
+
+ Example: 0x02, 0x42, 0x01, 0x13
+
+ The first byte indicates 3 values in this table. Decoding the
+ bytes:
+ 0x42 = 5 codes of 3 bits long
+ 0x01 = 1 code of 2 bits long
+ 0x13 = 2 codes of 4 bits long
+
+ This would generate the original bit length array of:
+ (3, 3, 3, 3, 3, 2, 4, 4)
+
+ There are 8 codes in this table for the values 0 thru 7. Using
+ the algorithm to obtain the Shannon-Fano codes produces:
+
+ Reversed Order Original
+ Val Sorted Constructed Code Value Restored Length
+ --- ------ ----------------- -------- -------- ------
+ 0: 2 1100000000000000 11 101 3
+ 1: 3 1010000000000000 101 001 3
+ 2: 3 1000000000000000 001 110 3
+ 3: 3 0110000000000000 110 010 3
+ 4: 3 0100000000000000 010 100 3
+ 5: 3 0010000000000000 100 11 2
+ 6: 4 0001000000000000 1000 1000 4
+ 7: 4 0000000000000000 0000 0000 4
+
+ The values in the Val, Order Restored and Original Length columns
+ now represent the Shannon-Fano encoding tree that can be used for
+ decoding the Shannon-Fano encoded data. How to parse the
+ variable length Shannon-Fano values from the data stream is beyond
+ the scope of this document. (See the references listed at the end of
+ this document for more information.) However, traditional decoding
+ schemes used for Huffman variable length decoding, such as the
+ Greenlaw algorithm, can be successfully applied.
+
+ 5.3.9 The compressed data stream begins immediately after the
+ compressed Shannon-Fano data. The compressed data stream can be
+ interpreted as follows:
+
+ loop until done
+ read 1 bit from input stream.
+
+ if this bit is non-zero then (encoded data is literal data)
+ if Literal Shannon-Fano tree is present
+ read and decode character using Literal Shannon-Fano tree.
+ otherwise
+ read 8 bits from input stream.
+ copy character to the output stream.
+ otherwise (encoded data is sliding dictionary match)
+ if 8K dictionary size
+ read 7 bits for offset Distance (lower 7 bits of offset).
+ otherwise
+ read 6 bits for offset Distance (lower 6 bits of offset).
+
+ using the Distance Shannon-Fano tree, read and decode the
+ upper 6 bits of the Distance value.
+
+ using the Length Shannon-Fano tree, read and decode
+ the Length value.
+
+ Length <- Length + Minimum Match Length
+
+ if Length = 63 + Minimum Match Length
+ read 8 bits from the input stream,
+ add this value to Length.
+
+ move backwards Distance+1 bytes in the output stream, and
+ copy Length characters from this position to the output
+ stream. (if this position is before the start of the output
+ stream, then assume that all the data before the start of
+ the output stream is filled with zeros).
+ end loop
+
+5.4 Tokenizing - Method 7
+-------------------------
+
+ 5.4.1 This method is not used by PKZIP.
+
+5.5 Deflating - Method 8
+------------------------
+
+ 5.5.1 The Deflate algorithm is similar to the Implode algorithm using
+ a sliding dictionary of up to 32K with secondary compression
+ from Huffman/Shannon-Fano codes.
+
+ 5.5.2 The compressed data is stored in blocks with a header describing
+ the block and the Huffman codes used in the data block. The header
+ format is as follows:
+
+ Bit 0: Last Block bit This bit is set to 1 if this is the last
+ compressed block in the data.
+ Bits 1-2: Block type
+ 00 (0) - Block is stored - All stored data is byte aligned.
+ Skip bits until next byte, then next word = block
+ length, followed by the ones compliment of the block
+ length word. Remaining data in block is the stored
+ data.
+
+ 01 (1) - Use fixed Huffman codes for literal and distance codes.
+ Lit Code Bits Dist Code Bits
+ --------- ---- --------- ----
+ 0 - 143 8 0 - 31 5
+ 144 - 255 9
+ 256 - 279 7
+ 280 - 287 8
+
+ Literal codes 286-287 and distance codes 30-31 are
+ never used but participate in the huffman construction.
+
+ 10 (2) - Dynamic Huffman codes. (See expanding Huffman codes)
+
+ 11 (3) - Reserved - Flag a "Error in compressed data" if seen.
+
+ 5.5.3 Expanding Huffman Codes
+
+ If the data block is stored with dynamic Huffman codes, the Huffman
+ codes are sent in the following compressed format:
+
+ 5 Bits: # of Literal codes sent - 256 (256 - 286)
+ All other codes are never sent.
+ 5 Bits: # of Dist codes - 1 (1 - 32)
+ 4 Bits: # of Bit Length codes - 3 (3 - 19)
+
+ The Huffman codes are sent as bit lengths and the codes are built as
+ described in the implode algorithm. The bit lengths themselves are
+ compressed with Huffman codes. There are 19 bit length codes:
+
+ 0 - 15: Represent bit lengths of 0 - 15
+ 16: Copy the previous bit length 3 - 6 times.
+ The next 2 bits indicate repeat length (0 = 3, ... ,3 = 6)
+ Example: Codes 8, 16 (+2 bits 11), 16 (+2 bits 10) will
+ expand to 12 bit lengths of 8 (1 + 6 + 5)
+ 17: Repeat a bit length of 0 for 3 - 10 times. (3 bits of length)
+ 18: Repeat a bit length of 0 for 11 - 138 times (7 bits of length)
+
+ The lengths of the bit length codes are sent packed 3 bits per value
+ (0 - 7) in the following order:
+
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
+
+ The Huffman codes should be built as described in the Implode algorithm
+ except codes are assigned starting at the shortest bit length, i.e. the
+ shortest code should be all 0's rather than all 1's. Also, codes with
+ a bit length of zero do not participate in the tree construction. The
+ codes are then used to decode the bit lengths for the literal and
+ distance tables.
+
+ The bit lengths for the literal tables are sent first with the number
+ of entries sent described by the 5 bits sent earlier. There are up
+ to 286 literal characters; the first 256 represent the respective 8
+ bit character, code 256 represents the End-Of-Block code, the remaining
+ 29 codes represent copy lengths of 3 thru 258. There are up to 30
+ distance codes representing distances from 1 thru 32k as described
+ below.
+
+ Length Codes
+ ------------
+ Extra Extra Extra Extra
+ Code Bits Length Code Bits Lengths Code Bits Lengths Code Bits Length(s)
+ ---- ---- ------ ---- ---- ------- ---- ---- ------- ---- ---- ---------
+ 257 0 3 265 1 11,12 273 3 35-42 281 5 131-162
+ 258 0 4 266 1 13,14 274 3 43-50 282 5 163-194
+ 259 0 5 267 1 15,16 275 3 51-58 283 5 195-226
+ 260 0 6 268 1 17,18 276 3 59-66 284 5 227-257
+ 261 0 7 269 2 19-22 277 4 67-82 285 0 258
+ 262 0 8 270 2 23-26 278 4 83-98
+ 263 0 9 271 2 27-30 279 4 99-114
+ 264 0 10 272 2 31-34 280 4 115-130
+
+ Distance Codes
+ --------------
+ Extra Extra Extra Extra
+ Code Bits Dist Code Bits Dist Code Bits Distance Code Bits Distance
+ ---- ---- ---- ---- ---- ------ ---- ---- -------- ---- ---- --------
+ 0 0 1 8 3 17-24 16 7 257-384 24 11 4097-6144
+ 1 0 2 9 3 25-32 17 7 385-512 25 11 6145-8192
+ 2 0 3 10 4 33-48 18 8 513-768 26 12 8193-12288
+ 3 0 4 11 4 49-64 19 8 769-1024 27 12 12289-16384
+ 4 1 5,6 12 5 65-96 20 9 1025-1536 28 13 16385-24576
+ 5 1 7,8 13 5 97-128 21 9 1537-2048 29 13 24577-32768
+ 6 2 9-12 14 6 129-192 22 10 2049-3072
+ 7 2 13-16 15 6 193-256 23 10 3073-4096
+
+ 5.5.4 The compressed data stream begins immediately after the
+ compressed header data. The compressed data stream can be
+ interpreted as follows:
+
+ do
+ read header from input stream.
+
+ if stored block
+ skip bits until byte aligned
+ read count and 1's compliment of count
+ copy count bytes data block
+ otherwise
+ loop until end of block code sent
+ decode literal character from input stream
+ if literal < 256
+ copy character to the output stream
+ otherwise
+ if literal = end of block
+ break from loop
+ otherwise
+ decode distance from input stream
+
+ move backwards distance bytes in the output stream, and
+ copy length characters from this position to the output
+ stream.
+ end loop
+ while not last block
+
+ if data descriptor exists
+ skip bits until byte aligned
+ read crc and sizes
+ endif
+
+5.6 Enhanced Deflating - Method 9
+---------------------------------
+
+ 5.6.1 The Enhanced Deflating algorithm is similar to Deflate but uses
+ a sliding dictionary of up to 64K. Deflate64(tm) is supported
+ by the Deflate extractor.
+
+5.7 BZIP2 - Method 12
+---------------------
+
+ 5.7.1 BZIP2 is an open-source data compression algorithm developed by
+ Julian Seward. Information and source code for this algorithm
+ can be found on the internet.
+
+5.8 LZMA - Method 14
+---------------------
+
+ 5.8.1 LZMA is a block-oriented, general purpose data compression
+ algorithm developed and maintained by Igor Pavlov. It is a derivative
+ of LZ77 that utilizes Markov chains and a range coder. Information and
+ source code for this algorithm can be found on the internet. Consult
+ with the author of this algorithm for information on terms or
+ restrictions on use.
+
+ Support for LZMA within the ZIP format is defined as follows:
+
+ 5.8.2 The Compression method field within the ZIP Local and Central
+ Header records will be set to the value 14 to indicate data was
+ compressed using LZMA.
+
+ 5.8.3 The Version needed to extract field within the ZIP Local and
+ Central Header records will be set to 6.3 to indicate the minimum
+ ZIP format version supporting this feature.
+
+ 5.8.4 File data compressed using the LZMA algorithm must be placed
+ immediately following the Local Header for the file. If a standard
+ ZIP encryption header is required, it will follow the Local Header
+ and will precede the LZMA compressed file data segment. The location
+ of LZMA compressed data segment within the ZIP format will be as shown:
+
+ [local header file 1]
+ [encryption header file 1]
+ [LZMA compressed data segment for file 1]
+ [data descriptor 1]
+ [local header file 2]
+
+ 5.8.5 The encryption header and data descriptor records may
+ be conditionally present. The LZMA Compressed Data Segment
+ will consist of an LZMA Properties Header followed by the
+ LZMA Compressed Data as shown:
+
+ [LZMA properties header for file 1]
+ [LZMA compressed data for file 1]
+
+ 5.8.6 The LZMA Compressed Data will be stored as provided by the
+ LZMA compression library. Compressed size, uncompressed size and
+ other file characteristics about the file being compressed must be
+ stored in standard ZIP storage format.
+
+ 5.8.7 The LZMA Properties Header will store specific data required
+ to decompress the LZMA compressed Data. This data is set by the
+ LZMA compression engine using the function WriteCoderProperties()
+ as documented within the LZMA SDK.
+
+ 5.8.8 Storage fields for the property information within the LZMA
+ Properties Header are as follows:
+
+ LZMA Version Information 2 bytes
+ LZMA Properties Size 2 bytes
+ LZMA Properties Data variable, defined by "LZMA Properties Size"
+
+ 5.8.8.1 LZMA Version Information - this field identifies which version
+ of the LZMA SDK was used to compress a file. The first byte will
+ store the major version number of the LZMA SDK and the second
+ byte will store the minor number.
+
+ 5.8.8.2 LZMA Properties Size - this field defines the size of the
+ remaining property data. Typically this size should be determined by
+ the version of the SDK. This size field is included as a convenience
+ and to help avoid any ambiguity should it arise in the future due
+ to changes in this compression algorithm.
+
+ 5.8.8.3 LZMA Property Data - this variable sized field records the
+ required values for the decompressor as defined by the LZMA SDK.
+ The data stored in this field should be obtained using the
+ WriteCoderProperties() in the version of the SDK defined by
+ the "LZMA Version Information" field.
+
+ 5.8.8.4 The layout of the "LZMA Properties Data" field is a function of
+ the LZMA compression algorithm. It is possible that this layout may be
+ changed by the author over time. The data layout in version 4.3 of the
+ LZMA SDK defines a 5 byte array that uses 4 bytes to store the dictionary
+ size in little-endian order. This is preceded by a single packed byte as
+ the first element of the array that contains the following fields:
+
+ PosStateBits
+ LiteralPosStateBits
+ LiteralContextBits
+
+ Refer to the LZMA documentation for a more detailed explanation of
+ these fields.
+
+ 5.8.9 Data compressed with method 14, LZMA, may include an end-of-stream
+ (EOS) marker ending the compressed data stream. This marker is not
+ required, but its use is highly recommended to facilitate processing
+ and implementers should include the EOS marker whenever possible.
+ When the EOS marker is used, general purpose bit 1 must be set. If
+ general purpose bit 1 is not set, the EOS marker is not present.
+
+5.9 WavPack - Method 97
+-----------------------
+
+ 5.9.1 Information describing the use of compression method 97 is
+ provided by WinZIP International, LLC. This method relies on the
+ open source WavPack audio compression utility developed by David Bryant.
+ Information on WavPack is available at www.wavpack.com. Please consult
+ with the author of this algorithm for information on terms and
+ restrictions on use.
+
+ 5.9.2 WavPack data for a file begins immediately after the end of the
+ local header data. This data is the output from WavPack compression
+ routines. Within the ZIP file, the use of WavPack compression is
+ indicated by setting the compression method field to a value of 97
+ in both the local header and the central directory header. The Version
+ needed to extract and version made by fields use the same values as are
+ used for data compressed using the Deflate algorithm.
+
+ 5.9.3 An implementation note for storing digital sample data when using
+ WavPack compression within ZIP files is that all of the bytes of
+ the sample data should be compressed. This includes any unused
+ bits up to the byte boundary. An example is a 2 byte sample that
+ uses only 12 bits for the sample data with 4 unused bits. If only
+ 12 bits are passed as the sample size to the WavPack routines, the 4
+ unused bits will be set to 0 on extraction regardless of their original
+ state. To avoid this, the full 16 bits of the sample data size
+ should be provided.
+
+5.10 PPMd - Method 98
+---------------------
+
+ 5.10.1 PPMd is a data compression algorithm developed by Dmitry Shkarin
+ which includes a carryless rangecoder developed by Dmitry Subbotin.
+ This algorithm is based on predictive phrase matching on multiple
+ order contexts. Information and source code for this algorithm
+ can be found on the internet. Consult with the author of this
+ algorithm for information on terms or restrictions on use.
+
+ 5.10.2 Support for PPMd within the ZIP format currently is provided only
+ for version I, revision 1 of the algorithm. Storage requirements
+ for using this algorithm are as follows:
+
+ 5.10.3 Parameters needed to control the algorithm are stored in the two
+ bytes immediately preceding the compressed data. These bytes are
+ used to store the following fields:
+
+ Model order - sets the maximum model order, default is 8, possible
+ values are from 2 to 16 inclusive
+
+ Sub-allocator size - sets the size of sub-allocator in MB, default is 50,
+ possible values are from 1MB to 256MB inclusive
+
+ Model restoration method - sets the method used to restart context
+ model at memory insufficiency, values are:
+
+ 0 - restarts model from scratch - default
+ 1 - cut off model - decreases performance by as much as 2x
+ 2 - freeze context tree - not recommended
+
+ 5.10.4 An example for packing these fields into the 2 byte storage field is
+ illustrated below. These values are stored in Intel low-byte/high-byte
+ order.
+
+ wPPMd = (Model order - 1) +
+ ((Sub-allocator size - 1) << 4) +
+ (Model restoration method << 12)
+
+
+6.0 Traditional PKWARE Encryption
+----------------------------------
+
+ 6.0.1 The following information discusses the decryption steps
+ required to support traditional PKWARE encryption. This
+ form of encryption is considered weak by today's standards
+ and its use is recommended only for situations with
+ low security needs or for compatibility with older .ZIP
+ applications.
+
+6.1 Traditional PKWARE Decryption
+---------------------------------
+
+ 6.1.1 PKWARE is grateful to Mr. Roger Schlafly for his expert
+ contribution towards the development of PKWARE's traditional
+ encryption.
+
+ 6.1.2 PKZIP encrypts the compressed data stream. Encrypted files
+ must be decrypted before they can be extracted to their original
+ form.
+
+ 6.1.3 Each encrypted file has an extra 12 bytes stored at the start
+ of the data area defining the encryption header for that file. The
+ encryption header is originally set to random values, and then
+ itself encrypted, using three, 32-bit keys. The key values are
+ initialized using the supplied encryption password. After each byte
+ is encrypted, the keys are then updated using pseudo-random number
+ generation techniques in combination with the same CRC-32 algorithm
+ used in PKZIP and described elsewhere in this document.
+
+ 6.1.4 The following are the basic steps required to decrypt a file:
+
+ 1) Initialize the three 32-bit keys with the password.
+ 2) Read and decrypt the 12-byte encryption header, further
+ initializing the encryption keys.
+ 3) Read and decrypt the compressed data stream using the
+ encryption keys.
+
+ 6.1.5 Initializing the encryption keys
+
+ Key(0) <- 305419896
+ Key(1) <- 591751049
+ Key(2) <- 878082192
+
+ loop for i <- 0 to length(password)-1
+ update_keys(password(i))
+ end loop
+
+ Where update_keys() is defined as:
+
+ update_keys(char):
+ Key(0) <- crc32(key(0),char)
+ Key(1) <- Key(1) + (Key(0) & 000000ffH)
+ Key(1) <- Key(1) * 134775813 + 1
+ Key(2) <- crc32(key(2),key(1) >> 24)
+ end update_keys
+
+ Where crc32(old_crc,char) is a routine that given a CRC value and a
+ character, returns an updated CRC value after applying the CRC-32
+ algorithm described elsewhere in this document.
+
+ 6.1.6 Decrypting the encryption header
+
+ The purpose of this step is to further initialize the encryption
+ keys, based on random data, to render a plaintext attack on the
+ data ineffective.
+
+ Read the 12-byte encryption header into Buffer, in locations
+ Buffer(0) thru Buffer(11).
+
+ loop for i <- 0 to 11
+ C <- buffer(i) ^ decrypt_byte()
+ update_keys(C)
+ buffer(i) <- C
+ end loop
+
+ Where decrypt_byte() is defined as:
+
+ unsigned char decrypt_byte()
+ local unsigned short temp
+ temp <- Key(2) | 2
+ decrypt_byte <- (temp * (temp ^ 1)) >> 8
+ end decrypt_byte
+
+ After the header is decrypted, the last 1 or 2 bytes in Buffer
+ should be the high-order word/byte of the CRC for the file being
+ decrypted, stored in Intel low-byte/high-byte order. Versions of
+ PKZIP prior to 2.0 used a 2 byte CRC check; a 1 byte CRC check is
+ used on versions after 2.0. This can be used to test if the password
+ supplied is correct or not.
+
+ 6.1.7 Decrypting the compressed data stream
+
+ The compressed data stream can be decrypted as follows:
+
+ loop until done
+ read a character into C
+ Temp <- C ^ decrypt_byte()
+ update_keys(temp)
+ output Temp
+ end loop
+
+
+7.0 Strong Encryption Specification
+-----------------------------------
+
+ 7.0.1 Portions of the Strong Encryption technology defined in this
+ specification are covered under patents and pending patent applications.
+ Refer to the section in this document entitled "Incorporating
+ PKWARE Proprietary Technology into Your Product" for more information.
+
+7.1 Strong Encryption Overview
+------------------------------
+
+ 7.1.1 Version 5.x of this specification introduced support for strong
+ encryption algorithms. These algorithms can be used with either
+ a password or an X.509v3 digital certificate to encrypt each file.
+ This format specification supports either password or certificate
+ based encryption to meet the security needs of today, to enable
+ interoperability between users within both PKI and non-PKI
+ environments, and to ensure interoperability between different
+ computing platforms that are running a ZIP program.
+
+ 7.1.2 Password based encryption is the most common form of encryption
+ people are familiar with. However, inherent weaknesses with
+ passwords (e.g. susceptibility to dictionary/brute force attack)
+ as well as password management and support issues make certificate
+ based encryption a more secure and scalable option. Industry
+ efforts and support are defining and moving towards more advanced
+ security solutions built around X.509v3 digital certificates and
+ Public Key Infrastructures(PKI) because of the greater scalability,
+ administrative options, and more robust security over traditional
+ password based encryption.
+
+ 7.1.3 Most standard encryption algorithms are supported with this
+ specification. Reference implementations for many of these
+ algorithms are available from either commercial or open source
+ distributors. Readily available cryptographic toolkits make
+ implementation of the encryption features straight-forward.
+ This document is not intended to provide a treatise on data
+ encryption principles or theory. Its purpose is to document the
+ data structures required for implementing interoperable data
+ encryption within the .ZIP format. It is strongly recommended that
+ you have a good understanding of data encryption before reading
+ further.
+
+ 7.1.4 The algorithms introduced in Version 5.0 of this specification
+ include:
+
+ RC2 40 bit, 64 bit, and 128 bit
+ RC4 40 bit, 64 bit, and 128 bit
+ DES
+ 3DES 112 bit and 168 bit
+
+ Version 5.1 adds support for the following:
+
+ AES 128 bit, 192 bit, and 256 bit
+
+
+ 7.1.5 Version 6.1 introduces encryption data changes to support
+ interoperability with Smartcard and USB Token certificate storage
+ methods which do not support the OAEP strengthening standard.
+
+ 7.1.6 Version 6.2 introduces support for encrypting metadata by compressing
+ and encrypting the central directory data structure to reduce information
+ leakage. Information leakage can occur in legacy ZIP applications
+ through exposure of information about a file even though that file is
+ stored encrypted. The information exposed consists of file
+ characteristics stored within the records and fields defined by this
+ specification. This includes data such as a file's name, its original
+ size, timestamp and CRC32 value.
+
+ 7.1.7 Version 6.3 introduces support for encrypting data using the Blowfish
+ and Twofish algorithms. These are symmetric block ciphers developed
+ by Bruce Schneier. Blowfish supports using a variable length key from
+ 32 to 448 bits. Block size is 64 bits. Implementations should use 16
+ rounds and the only mode supported within ZIP files is CBC. Twofish
+ supports key sizes 128, 192 and 256 bits. Block size is 128 bits.
+ Implementations should use 16 rounds and the only mode supported within
+ ZIP files is CBC. Information and source code for both Blowfish and
+ Twofish algorithms can be found on the internet. Consult with the author
+ of these algorithms for information on terms or restrictions on use.
+
+ 7.1.8 Central Directory Encryption provides greater protection against
+ information leakage by encrypting the Central Directory structure and
+ by masking key values that are replicated in the unencrypted Local
+ Header. ZIP compatible programs that cannot interpret an encrypted
+ Central Directory structure cannot rely on the data in the corresponding
+ Local Header for decompression information.
+
+ 7.1.9 Extra Field records that may contain information about a file that should
+ not be exposed should not be stored in the Local Header and should only
+ be written to the Central Directory where they can be encrypted. This
+ design currently does not support streaming. Information in the End of
+ Central Directory record, the Zip64 End of Central Directory Locator,
+ and the Zip64 End of Central Directory records are not encrypted. Access
+ to view data on files within a ZIP file with an encrypted Central Directory
+ requires the appropriate password or private key for decryption prior to
+ viewing any files, or any information about the files, in the archive.
+
+ 7.1.10 Older ZIP compatible programs not familiar with the Central Directory
+ Encryption feature will no longer be able to recognize the Central
+ Directory and may assume the ZIP file is corrupt. Programs that
+ attempt streaming access using Local Headers will see invalid
+ information for each file. Central Directory Encryption need not be
+ used for every ZIP file. Its use is recommended for greater security.
+ ZIP files not using Central Directory Encryption should operate as
+ in the past.
+
+ 7.1.11 This strong encryption feature specification is intended to provide for
+ scalable, cross-platform encryption needs ranging from simple password
+ encryption to authenticated public/private key encryption.
+
+ 7.1.12 Encryption provides data confidentiality and privacy. It is
+ recommended that you combine X.509 digital signing with encryption
+ to add authentication and non-repudiation.
+
+
+7.2 Single Password Symmetric Encryption Method
+-----------------------------------------------
+
+ 7.2.1 The Single Password Symmetric Encryption Method using strong
+ encryption algorithms operates similarly to the traditional
+ PKWARE encryption defined in this format. Additional data
+ structures are added to support the processing needs of the
+ strong algorithms.
+
+ The Strong Encryption data structures are:
+
+ 7.2.2 General Purpose Bits - Bits 0 and 6 of the General Purpose bit
+ flag in both local and central header records. Both bits set
+ indicates strong encryption. Bit 13, when set indicates the Central
+ Directory is encrypted and that selected fields in the Local Header
+ are masked to hide their actual value.
+
+
+ 7.2.3 Extra Field 0x0017 in central header only.
+
+ Fields to consider in this record are:
+
+ 7.2.3.1 Format - the data format identifier for this record. The only
+ value allowed at this time is the integer value 2.
+
+ 7.2.3.2 AlgId - integer identifier of the encryption algorithm from the
+ following range
+
+ 0x6601 - DES
+ 0x6602 - RC2 (version needed to extract < 5.2)
+ 0x6603 - 3DES 168
+ 0x6609 - 3DES 112
+ 0x660E - AES 128
+ 0x660F - AES 192
+ 0x6610 - AES 256
+ 0x6702 - RC2 (version needed to extract >= 5.2)
+ 0x6720 - Blowfish
+ 0x6721 - Twofish
+ 0x6801 - RC4
+ 0xFFFF - Unknown algorithm
+
+ 7.2.3.3 Bitlen - Explicit bit length of key
+
+ 32 - 448 bits
+
+ 7.2.3.4 Flags - Processing flags needed for decryption
+
+ 0x0001 - Password is required to decrypt
+ 0x0002 - Certificates only
+ 0x0003 - Password or certificate required to decrypt
+
+ Values > 0x0003 reserved for certificate processing
+
+
+ 7.2.4 Decryption header record preceding compressed file data.
+
+ -Decryption Header:
+
+ Value Size Description
+ ----- ---- -----------
+ IVSize 2 bytes Size of initialization vector (IV)
+ IVData IVSize Initialization vector for this file
+ Size 4 bytes Size of remaining decryption header data
+ Format 2 bytes Format definition for this record
+ AlgID 2 bytes Encryption algorithm identifier
+ Bitlen 2 bytes Bit length of encryption key
+ Flags 2 bytes Processing flags
+ ErdSize 2 bytes Size of Encrypted Random Data
+ ErdData ErdSize Encrypted Random Data
+ Reserved1 4 bytes Reserved certificate processing data
+ Reserved2 (var) Reserved for certificate processing data
+ VSize 2 bytes Size of password validation data
+ VData VSize-4 Password validation data
+ VCRC32 4 bytes Standard ZIP CRC32 of password validation data
+
+ 7.2.4.1 IVData - The size of the IV should match the algorithm block size.
+ The IVData can be completely random data. If the size of
+ the randomly generated data does not match the block size
+ it should be complemented with zero's or truncated as
+ necessary. If IVSize is 0,then IV = CRC32 + Uncompressed
+ File Size (as a 64 bit little-endian, unsigned integer value).
+
+ 7.2.4.2 Format - the data format identifier for this record. The only
+ value allowed at this time is the integer value 3.
+
+ 7.2.4.3 AlgId - integer identifier of the encryption algorithm from the
+ following range
+
+ 0x6601 - DES
+ 0x6602 - RC2 (version needed to extract < 5.2)
+ 0x6603 - 3DES 168
+ 0x6609 - 3DES 112
+ 0x660E - AES 128
+ 0x660F - AES 192
+ 0x6610 - AES 256
+ 0x6702 - RC2 (version needed to extract >= 5.2)
+ 0x6720 - Blowfish
+ 0x6721 - Twofish
+ 0x6801 - RC4
+ 0xFFFF - Unknown algorithm
+
+ 7.2.4.4 Bitlen - Explicit bit length of key
+
+ 32 - 448 bits
+
+ 7.2.4.5 Flags - Processing flags needed for decryption
+
+ 0x0001 - Password is required to decrypt
+ 0x0002 - Certificates only
+ 0x0003 - Password or certificate required to decrypt
+
+ Values > 0x0003 reserved for certificate processing
+
+ 7.2.4.6 ErdData - Encrypted random data is used to store random data that
+ is used to generate a file session key for encrypting
+ each file. SHA1 is used to calculate hash data used to
+ derive keys. File session keys are derived from a master
+ session key generated from the user-supplied password.
+ If the Flags field in the decryption header contains
+ the value 0x4000, then the ErdData field must be
+ decrypted using 3DES. If the value 0x4000 is not set,
+ then the ErdData field must be decrypted using AlgId.
+
+
+ 7.2.4.7 Reserved1 - Reserved for certificate processing, if value is
+ zero, then Reserved2 data is absent. See the explanation
+ under the Certificate Processing Method for details on
+ this data structure.
+
+ 7.2.4.8 Reserved2 - If present, the size of the Reserved2 data structure
+ is located by skipping the first 4 bytes of this field
+ and using the next 2 bytes as the remaining size. See
+ the explanation under the Certificate Processing Method
+ for details on this data structure.
+
+ 7.2.4.9 VSize - This size value will always include the 4 bytes of the
+ VCRC32 data and will be greater than 4 bytes.
+
+ 7.2.4.10 VData - Random data for password validation. This data is VSize
+ in length and VSize must be a multiple of the encryption
+ block size. VCRC32 is a checksum value of VData.
+ VData and VCRC32 are stored encrypted and start the
+ stream of encrypted data for a file.
+
+
+ 7.2.5 Useful Tips
+
+ 7.2.5.1 Strong Encryption is always applied to a file after compression. The
+ block oriented algorithms all operate in Cypher Block Chaining (CBC)
+ mode. The block size used for AES encryption is 16. All other block
+ algorithms use a block size of 8. Two IDs are defined for RC2 to
+ account for a discrepancy found in the implementation of the RC2
+ algorithm in the cryptographic library on Windows XP SP1 and all
+ earlier versions of Windows. It is recommended that zero length files
+ not be encrypted, however programs should be prepared to extract them
+ if they are found within a ZIP file.
+
+ 7.2.5.2 A pseudo-code representation of the encryption process is as follows:
+
+ Password = GetUserPassword()
+ MasterSessionKey = DeriveKey(SHA1(Password))
+ RD = CryptographicStrengthRandomData()
+ For Each File
+ IV = CryptographicStrengthRandomData()
+ VData = CryptographicStrengthRandomData()
+ VCRC32 = CRC32(VData)
+ FileSessionKey = DeriveKey(SHA1(IV + RD)
+ ErdData = Encrypt(RD,MasterSessionKey,IV)
+ Encrypt(VData + VCRC32 + FileData, FileSessionKey,IV)
+ Done
+
+ 7.2.5.3 The function names and parameter requirements will depend on
+ the choice of the cryptographic toolkit selected. Almost any
+ toolkit supporting the reference implementations for each
+ algorithm can be used. The RSA BSAFE(r), OpenSSL, and Microsoft
+ CryptoAPI libraries are all known to work well.
+
+
+ 7.3 Single Password - Central Directory Encryption
+ --------------------------------------------------
+
+ 7.3.1 Central Directory Encryption is achieved within the .ZIP format by
+ encrypting the Central Directory structure. This encapsulates the metadata
+ most often used for processing .ZIP files. Additional metadata is stored for
+ redundancy in the Local Header for each file. The process of concealing
+ metadata by encrypting the Central Directory does not protect the data within
+ the Local Header. To avoid information leakage from the exposed metadata
+ in the Local Header, the fields containing information about a file are masked.
+
+ 7.3.2 Local Header
+
+ Masking replaces the true content of the fields for a file in the Local
+ Header with false information. When masked, the Local Header is not
+ suitable for streaming access and the options for data recovery of damaged
+ archives is reduced. Extra Data fields that may contain confidential
+ data should not be stored within the Local Header. The value set into
+ the Version needed to extract field should be the correct value needed to
+ extract the file without regard to Central Directory Encryption. The fields
+ within the Local Header targeted for masking when the Central Directory is
+ encrypted are:
+
+ Field Name Mask Value
+ ------------------ ---------------------------
+ compression method 0
+ last mod file time 0
+ last mod file date 0
+ crc-32 0
+ compressed size 0
+ uncompressed size 0
+ file name (variable size) Base 16 value from the
+ range 1 - 0xFFFFFFFFFFFFFFFF
+ represented as a string whose
+ size will be set into the
+ file name length field
+
+ The Base 16 value assigned as a masked file name is simply a sequentially
+ incremented value for each file starting with 1 for the first file.
+ Modifications to a ZIP file may cause different values to be stored for
+ each file. For compatibility, the file name field in the Local Header
+ should never be left blank. As of Version 6.2 of this specification,
+ the Compression Method and Compressed Size fields are not yet masked.
+ Fields having a value of 0xFFFF or 0xFFFFFFFF for the ZIP64 format
+ should not be masked.
+
+ 7.3.3 Encrypting the Central Directory
+
+ Encryption of the Central Directory does not include encryption of the
+ Central Directory Signature data, the Zip64 End of Central Directory
+ record, the Zip64 End of Central Directory Locator, or the End
+ of Central Directory record. The ZIP file comment data is never
+ encrypted.
+
+ Before encrypting the Central Directory, it may optionally be compressed.
+ Compression is not required, but for storage efficiency it is assumed
+ this structure will be compressed before encrypting. Similarly, this
+ specification supports compressing the Central Directory without
+ requiring that it also be encrypted. Early implementations of this
+ feature will assume the encryption method applied to files matches the
+ encryption applied to the Central Directory.
+
+ Encryption of the Central Directory is done in a manner similar to
+ that of file encryption. The encrypted data is preceded by a
+ decryption header. The decryption header is known as the Archive
+ Decryption Header. The fields of this record are identical to
+ the decryption header preceding each encrypted file. The location
+ of the Archive Decryption Header is determined by the value in the
+ Start of the Central Directory field in the Zip64 End of Central
+ Directory record. When the Central Directory is encrypted, the
+ Zip64 End of Central Directory record will always be present.
+
+ The layout of the Zip64 End of Central Directory record for all
+ versions starting with 6.2 of this specification will follow the
+ Version 2 format. The Version 2 format is as follows:
+
+ The leading fixed size fields within the Version 1 format for this
+ record remain unchanged. The record signature for both Version 1
+ and Version 2 will be 0x06064b50. Immediately following the last
+ byte of the field known as the Offset of Start of Central
+ Directory With Respect to the Starting Disk Number will begin the
+ new fields defining Version 2 of this record.
+
+ 7.3.4 New fields for Version 2
+
+ Note: all fields stored in Intel low-byte/high-byte order.
+
+ Value Size Description
+ ----- ---- -----------
+ Compression Method 2 bytes Method used to compress the
+ Central Directory
+ Compressed Size 8 bytes Size of the compressed data
+ Original Size 8 bytes Original uncompressed size
+ AlgId 2 bytes Encryption algorithm ID
+ BitLen 2 bytes Encryption key length
+ Flags 2 bytes Encryption flags
+ HashID 2 bytes Hash algorithm identifier
+ Hash Length 2 bytes Length of hash data
+ Hash Data (variable) Hash data
+
+ The Compression Method accepts the same range of values as the
+ corresponding field in the Central Header.
+
+ The Compressed Size and Original Size values will not include the
+ data of the Central Directory Signature which is compressed or
+ encrypted.
+
+ The AlgId, BitLen, and Flags fields accept the same range of values
+ the corresponding fields within the 0x0017 record.
+
+ Hash ID identifies the algorithm used to hash the Central Directory
+ data. This data does not have to be hashed, in which case the
+ values for both the HashID and Hash Length will be 0. Possible
+ values for HashID are:
+
+ Value Algorithm
+ ------ ---------
+ 0x0000 none
+ 0x0001 CRC32
+ 0x8003 MD5
+ 0x8004 SHA1
+ 0x8007 RIPEMD160
+ 0x800C SHA256
+ 0x800D SHA384
+ 0x800E SHA512
+
+ 7.3.5 When the Central Directory data is signed, the same hash algorithm
+ used to hash the Central Directory for signing should be used.
+ This is recommended for processing efficiency, however, it is
+ permissible for any of the above algorithms to be used independent
+ of the signing process.
+
+ The Hash Data will contain the hash data for the Central Directory.
+ The length of this data will vary depending on the algorithm used.
+
+ The Version Needed to Extract should be set to 62.
+
+ The value for the Total Number of Entries on the Current Disk will
+ be 0. These records will no longer support random access when
+ encrypting the Central Directory.
+
+ 7.3.6 When the Central Directory is compressed and/or encrypted, the
+ End of Central Directory record will store the value 0xFFFFFFFF
+ as the value for the Total Number of Entries in the Central
+ Directory. The value stored in the Total Number of Entries in
+ the Central Directory on this Disk field will be 0. The actual
+ values will be stored in the equivalent fields of the Zip64
+ End of Central Directory record.
+
+ 7.3.7 Decrypting and decompressing the Central Directory is accomplished
+ in the same manner as decrypting and decompressing a file.
+
+ 7.4 Certificate Processing Method
+ ---------------------------------
+
+ The Certificate Processing Method for ZIP file encryption
+ defines the following additional data fields:
+
+ 7.4.1 Certificate Flag Values
+
+ Additional processing flags that can be present in the Flags field of both
+ the 0x0017 field of the central directory Extra Field and the Decryption
+ header record preceding compressed file data are:
+
+ 0x0007 - reserved for future use
+ 0x000F - reserved for future use
+ 0x0100 - Indicates non-OAEP key wrapping was used. If this
+ this field is set, the version needed to extract must
+ be at least 61. This means OAEP key wrapping is not
+ used when generating a Master Session Key using
+ ErdData.
+ 0x4000 - ErdData must be decrypted using 3DES-168, otherwise use the
+ same algorithm used for encrypting the file contents.
+ 0x8000 - reserved for future use
+
+
+ 7.4.2 CertData - Extra Field 0x0017 record certificate data structure
+
+ The data structure used to store certificate data within the section
+ of the Extra Field defined by the CertData field of the 0x0017
+ record are as shown:
+
+ Value Size Description
+ ----- ---- -----------
+ RCount 4 bytes Number of recipients.
+ HashAlg 2 bytes Hash algorithm identifier
+ HSize 2 bytes Hash size
+ SRList (var) Simple list of recipients hashed public keys
+
+
+ RCount This defines the number intended recipients whose
+ public keys were used for encryption. This identifies
+ the number of elements in the SRList.
+
+ HashAlg This defines the hash algorithm used to calculate
+ the public key hash of each public key used
+ for encryption. This field currently supports
+ only the following value for SHA-1
+
+ 0x8004 - SHA1
+
+ HSize This defines the size of a hashed public key.
+
+ SRList This is a variable length list of the hashed
+ public keys for each intended recipient. Each
+ element in this list is HSize. The total size of
+ SRList is determined using RCount * HSize.
+
+
+ 7.4.3 Reserved1 - Certificate Decryption Header Reserved1 Data
+
+ Value Size Description
+ ----- ---- -----------
+ RCount 4 bytes Number of recipients.
+
+ RCount This defines the number intended recipients whose
+ public keys were used for encryption. This defines
+ the number of elements in the REList field defined below.
+
+
+ 7.4.4 Reserved2 - Certificate Decryption Header Reserved2 Data Structures
+
+
+ Value Size Description
+ ----- ---- -----------
+ HashAlg 2 bytes Hash algorithm identifier
+ HSize 2 bytes Hash size
+ REList (var) List of recipient data elements
+
+
+ HashAlg This defines the hash algorithm used to calculate
+ the public key hash of each public key used
+ for encryption. This field currently supports
+ only the following value for SHA-1
+
+ 0x8004 - SHA1
+
+ HSize This defines the size of a hashed public key
+ defined in REHData.
+
+ REList This is a variable length of list of recipient data.
+ Each element in this list consists of a Recipient
+ Element data structure as follows:
+
+
+ Recipient Element (REList) Data Structure:
+
+ Value Size Description
+ ----- ---- -----------
+ RESize 2 bytes Size of REHData + REKData
+ REHData HSize Hash of recipients public key
+ REKData (var) Simple key blob
+
+
+ RESize This defines the size of an individual REList
+ element. This value is the combined size of the
+ REHData field + REKData field. REHData is defined by
+ HSize. REKData is variable and can be calculated
+ for each REList element using RESize and HSize.
+
+ REHData Hashed public key for this recipient.
+
+ REKData Simple Key Blob. The format of this data structure
+ is identical to that defined in the Microsoft
+ CryptoAPI and generated using the CryptExportKey()
+ function. The version of the Simple Key Blob
+ supported at this time is 0x02 as defined by
+ Microsoft.
+
+7.5 Certificate Processing - Central Directory Encryption
+---------------------------------------------------------
+
+ 7.5.1 Central Directory Encryption using Digital Certificates will
+ operate in a manner similar to that of Single Password Central
+ Directory Encryption. This record will only be present when there
+ is data to place into it. Currently, data is placed into this
+ record when digital certificates are used for either encrypting
+ or signing the files within a ZIP file. When only password
+ encryption is used with no certificate encryption or digital
+ signing, this record is not currently needed. When present, this
+ record will appear before the start of the actual Central Directory
+ data structure and will be located immediately after the Archive
+ Decryption Header if the Central Directory is encrypted.
+
+ 7.5.2 The Archive Extra Data record will be used to store the following
+ information. Additional data may be added in future versions.
+
+ Extra Data Fields:
+
+ 0x0014 - PKCS#7 Store for X.509 Certificates
+ 0x0016 - X.509 Certificate ID and Signature for central directory
+ 0x0019 - PKCS#7 Encryption Recipient Certificate List
+
+ The 0x0014 and 0x0016 Extra Data records that otherwise would be
+ located in the first record of the Central Directory for digital
+ certificate processing. When encrypting or compressing the Central
+ Directory, the 0x0014 and 0x0016 records must be located in the
+ Archive Extra Data record and they should not remain in the first
+ Central Directory record. The Archive Extra Data record will also
+ be used to store the 0x0019 data.
+
+ 7.5.3 When present, the size of the Archive Extra Data record will be
+ included in the size of the Central Directory. The data of the
+ Archive Extra Data record will also be compressed and encrypted
+ along with the Central Directory data structure.
+
+7.6 Certificate Processing Differences
+--------------------------------------
+
+ 7.6.1 The Certificate Processing Method of encryption differs from the
+ Single Password Symmetric Encryption Method as follows. Instead
+ of using a user-defined password to generate a master session key,
+ cryptographically random data is used. The key material is then
+ wrapped using standard key-wrapping techniques. This key material
+ is wrapped using the public key of each recipient that will need
+ to decrypt the file using their corresponding private key.
+
+ 7.6.2 This specification currently assumes digital certificates will follow
+ the X.509 V3 format for 1024 bit and higher RSA format digital
+ certificates. Implementation of this Certificate Processing Method
+ requires supporting logic for key access and management. This logic
+ is outside the scope of this specification.
+
+7.7 OAEP Processing with Certificate-based Encryption
+-----------------------------------------------------
+
+ 7.7.1 OAEP stands for Optimal Asymmetric Encryption Padding. It is a
+ strengthening technique used for small encoded items such as decryption
+ keys. This is commonly applied in cryptographic key-wrapping techniques
+ and is supported by PKCS #1. Versions 5.0 and 6.0 of this specification
+ were designed to support OAEP key-wrapping for certificate-based
+ decryption keys for additional security.
+
+ 7.7.2 Support for private keys stored on Smartcards or Tokens introduced
+ a conflict with this OAEP logic. Most card and token products do
+ not support the additional strengthening applied to OAEP key-wrapped
+ data. In order to resolve this conflict, versions 6.1 and above of this
+ specification will no longer support OAEP when encrypting using
+ digital certificates.
+
+ 7.7.3 Versions of PKZIP available during initial development of the
+ certificate processing method set a value of 61 into the
+ version needed to extract field for a file. This indicates that
+ non-OAEP key wrapping is used. This affects certificate encryption
+ only, and password encryption functions should not be affected by
+ this value. This means values of 61 may be found on files encrypted
+ with certificates only, or on files encrypted with both password
+ encryption and certificate encryption. Files encrypted with both
+ methods can safely be decrypted using the password methods documented.
+
+8.0 Splitting and Spanning ZIP files
+-------------------------------------
+
+ 8.1 Spanned ZIP files
+
+ 8.1.1 Spanning is the process of segmenting a ZIP file across
+ multiple removable media. This support has typically only
+ been provided for DOS formatted floppy diskettes.
+
+ 8.2 Split ZIP files
+
+ 8.2.1 File splitting is a newer derivation of spanning.
+ Splitting follows the same segmentation process as
+ spanning, however, it does not require writing each
+ segment to a unique removable medium and instead supports
+ placing all pieces onto local or non-removable locations
+ such as file systems, local drives, folders, etc.
+
+ 8.3 File Naming Differences
+
+ 8.3.1 A key difference between spanned and split ZIP files is
+ that all pieces of a spanned ZIP file have the same name.
+ Since each piece is written to a separate volume, no name
+ collisions occur and each segment can reuse the original
+ .ZIP file name given to the archive.
+
+ 8.3.2 Sequence ordering for DOS spanned archives uses the DOS
+ volume label to determine segment numbers. Volume labels
+ for each segment are written using the form PKBACK#xxx,
+ where xxx is the segment number written as a decimal
+ value from 001 - nnn.
+
+ 8.3.3 Split ZIP files are typically written to the same location
+ and are subject to name collisions if the spanned name
+ format is used since each segment will reside on the same
+ drive. To avoid name collisions, split archives are named
+ as follows.
+
+ Segment 1 = filename.z01
+ Segment n-1 = filename.z(n-1)
+ Segment n = filename.zip
+
+ 8.3.4 The .ZIP extension is used on the last segment to support
+ quickly reading the central directory. The segment number
+ n should be a decimal value.
+
+ 8.4 Spanned Self-extracting ZIP Files
+
+ 8.4.1 Spanned ZIP files may be PKSFX Self-extracting ZIP files.
+ PKSFX files may also be split, however, in this case
+ the first segment must be named filename.exe. The first
+ segment of a split PKSFX archive must be large enough to
+ include the entire executable program.
+
+ 8.5 Capacities and Markers
+
+ 8.5.1 Capacities for split archives are as follows:
+
+ Maximum number of segments = 4,294,967,295 - 1
+ Maximum .ZIP segment size = 4,294,967,295 bytes
+ Minimum segment size = 64K
+ Maximum PKSFX segment size = 2,147,483,647 bytes
+
+ 8.5.2 Segment sizes may be different however by convention, all
+ segment sizes should be the same with the exception of the
+ last, which may be smaller. Local and central directory
+ header records must never be split across a segment boundary.
+ When writing a header record, if the number of bytes remaining
+ within a segment is less than the size of the header record,
+ end the current segment and write the header at the start
+ of the next segment. The central directory may span segment
+ boundaries, but no single record in the central directory
+ should be split across segments.
+
+ 8.5.3 Spanned/Split archives created using PKZIP for Windows
+ (V2.50 or greater), PKZIP Command Line (V2.50 or greater),
+ or PKZIP Explorer will include a special spanning
+ signature as the first 4 bytes of the first segment of
+ the archive. This signature (0x08074b50) will be
+ followed immediately by the local header signature for
+ the first file in the archive.
+
+ 8.5.4 A special spanning marker may also appear in spanned/split
+ archives if the spanning or splitting process starts but
+ only requires one segment. In this case the 0x08074b50
+ signature will be replaced with the temporary spanning
+ marker signature of 0x30304b50. Split archives can
+ only be uncompressed by other versions of PKZIP that
+ know how to create a split archive.
+
+ 8.5.5 The signature value 0x08074b50 is also used by some
+ ZIP implementations as a marker for the Data Descriptor
+ record. Conflict in this alternate assignment can be
+ avoided by ensuring the position of the signature
+ within the ZIP file to determine the use for which it
+ is intended.
+
+9.0 Change Process
+------------------
+
+ 9.1 In order for the .ZIP file format to remain a viable technology, this
+ specification should be considered as open for periodic review and
+ revision. Although this format was originally designed with a
+ certain level of extensibility, not all changes in technology
+ (present or future) were or will be necessarily considered in its
+ design.
+
+ 9.2 If your application requires new definitions to the
+ extensible sections in this format, or if you would like to
+ submit new data structures or new capabilities, please forward
+ your request to zipformat@pkware.com. All submissions will be
+ reviewed by the ZIP File Specification Committee for possible
+ inclusion into future versions of this specification.
+
+ 9.3 Periodic revisions to this specification will be published as
+ DRAFT or as FINAL status to ensure interoperability. We encourage
+ comments and feedback that may help improve clarity or content.
+
+
+10.0 Incorporating PKWARE Proprietary Technology into Your Product
+------------------------------------------------------------------
+
+ 10.1 The Use or Implementation in a product of APPNOTE technological
+ components pertaining to either strong encryption or patching requires
+ a separate, executed license agreement from PKWARE. Please contact
+ PKWARE at zipformat@pkware.com or +1-414-289-9788 with regard to
+ acquiring such a license.
+
+ 10.2 Additional information regarding PKWARE proprietray technology is
+ available at http://www.pkware.com/appnote.
+
+11.0 Acknowledgements
+---------------------
+
+ In addition to the above mentioned contributors to PKZIP and PKUNZIP,
+ PKWARE would like to extend special thanks to Robert Mahoney for
+ suggesting the extension .ZIP for this software.
+
+12.0 References
+---------------
+
+ Fiala, Edward R., and Greene, Daniel H., "Data compression with
+ finite windows", Communications of the ACM, Volume 32, Number 4,
+ April 1989, pages 490-505.
+
+ Held, Gilbert, "Data Compression, Techniques and Applications,
+ Hardware and Software Considerations", John Wiley & Sons, 1987.
+
+ Huffman, D.A., "A method for the construction of minimum-redundancy
+ codes", Proceedings of the IRE, Volume 40, Number 9, September 1952,
+ pages 1098-1101.
+
+ Nelson, Mark, "LZW Data Compression", Dr. Dobbs Journal, Volume 14,
+ Number 10, October 1989, pages 29-37.
+
+ Nelson, Mark, "The Data Compression Book", M&T Books, 1991.
+
+ Storer, James A., "Data Compression, Methods and Theory",
+ Computer Science Press, 1988
+
+ Welch, Terry, "A Technique for High-Performance Data Compression",
+ IEEE Computer, Volume 17, Number 6, June 1984, pages 8-19.
+
+ Ziv, J. and Lempel, A., "A universal algorithm for sequential data
+ compression", Communications of the ACM, Volume 30, Number 6,
+ June 1987, pages 520-540.
+
+ Ziv, J. and Lempel, A., "Compression of individual sequences via
+ variable-rate coding", IEEE Transactions on Information Theory,
+ Volume 24, Number 5, September 1978, pages 530-536.
+
+
+APPENDIX A - AS/400 Extra Field (0x0065) Attribute Definitions
+--------------------------------------------------------------
+
+A.1 Field Definition Structure:
+
+ a. field length including length 2 bytes
+ b. field code 2 bytes
+ c. data x bytes
+
+A.2 Field Code Description
+
+ 4001 Source type i.e. CLP etc
+ 4002 The text description of the library
+ 4003 The text description of the file
+ 4004 The text description of the member
+ 4005 x'F0' or 0 is PF-DTA, x'F1' or 1 is PF_SRC
+ 4007 Database Type Code 1 byte
+ 4008 Database file and fields definition
+ 4009 GZIP file type 2 bytes
+ 400B IFS code page 2 bytes
+ 400C IFS Creation Time 4 bytes
+ 400D IFS Access Time 4 bytes
+ 400E IFS Modification time 4 bytes
+ 005C Length of the records in the file 2 bytes
+ 0068 GZIP two words 8 bytes
+
+APPENDIX B - z/OS Extra Field (0x0065) Attribute Definitions
+------------------------------------------------------------
+
+B.1 Field Definition Structure:
+
+ a. field length including length 2 bytes
+ b. field code 2 bytes
+ c. data x bytes
+
+B.2 Field Code Description
+
+ 0001 File Type 2 bytes
+ 0002 NonVSAM Record Format 1 byte
+ 0003 Reserved
+ 0004 NonVSAM Block Size 2 bytes Big Endian
+ 0005 Primary Space Allocation 3 bytes Big Endian
+ 0006 Secondary Space Allocation 3 bytes Big Endian
+ 0007 Space Allocation Type1 byte flag
+ 0008 Modification Date Retired with PKZIP 5.0 +
+ 0009 Expiration Date Retired with PKZIP 5.0 +
+ 000A PDS Directory Block Allocation 3 bytes Big Endian binary value
+ 000B NonVSAM Volume List variable
+ 000C UNIT Reference Retired with PKZIP 5.0 +
+ 000D DF/SMS Management Class 8 bytes EBCDIC Text Value
+ 000E DF/SMS Storage Class 8 bytes EBCDIC Text Value
+ 000F DF/SMS Data Class 8 bytes EBCDIC Text Value
+ 0010 PDS/PDSE Member Info. 30 bytes
+ 0011 VSAM sub-filetype 2 bytes
+ 0012 VSAM LRECL 13 bytes EBCDIC "(num_avg num_max)"
+ 0013 VSAM Cluster Name Retired with PKZIP 5.0 +
+ 0014 VSAM KSDS Key Information 13 bytes EBCDIC "(num_length num_position)"
+ 0015 VSAM Average LRECL 5 bytes EBCDIC num_value padded with blanks
+ 0016 VSAM Maximum LRECL 5 bytes EBCDIC num_value padded with blanks
+ 0017 VSAM KSDS Key Length 5 bytes EBCDIC num_value padded with blanks
+ 0018 VSAM KSDS Key Position 5 bytes EBCDIC num_value padded with blanks
+ 0019 VSAM Data Name 1-44 bytes EBCDIC text string
+ 001A VSAM KSDS Index Name 1-44 bytes EBCDIC text string
+ 001B VSAM Catalog Name 1-44 bytes EBCDIC text string
+ 001C VSAM Data Space Type 9 bytes EBCDIC text string
+ 001D VSAM Data Space Primary 9 bytes EBCDIC num_value left-justified
+ 001E VSAM Data Space Secondary 9 bytes EBCDIC num_value left-justified
+ 001F VSAM Data Volume List variable EBCDIC text list of 6-character Volume IDs
+ 0020 VSAM Data Buffer Space 8 bytes EBCDIC num_value left-justified
+ 0021 VSAM Data CISIZE 5 bytes EBCDIC num_value left-justified
+ 0022 VSAM Erase Flag 1 byte flag
+ 0023 VSAM Free CI % 3 bytes EBCDIC num_value left-justified
+ 0024 VSAM Free CA % 3 bytes EBCDIC num_value left-justified
+ 0025 VSAM Index Volume List variable EBCDIC text list of 6-character Volume IDs
+ 0026 VSAM Ordered Flag 1 byte flag
+ 0027 VSAM REUSE Flag 1 byte flag
+ 0028 VSAM SPANNED Flag 1 byte flag
+ 0029 VSAM Recovery Flag 1 byte flag
+ 002A VSAM WRITECHK Flag 1 byte flag
+ 002B VSAM Cluster/Data SHROPTS 3 bytes EBCDIC "n,y"
+ 002C VSAM Index SHROPTS 3 bytes EBCDIC "n,y"
+ 002D VSAM Index Space Type 9 bytes EBCDIC text string
+ 002E VSAM Index Space Primary 9 bytes EBCDIC num_value left-justified
+ 002F VSAM Index Space Secondary 9 bytes EBCDIC num_value left-justified
+ 0030 VSAM Index CISIZE 5 bytes EBCDIC num_value left-justified
+ 0031 VSAM Index IMBED 1 byte flag
+ 0032 VSAM Index Ordered Flag 1 byte flag
+ 0033 VSAM REPLICATE Flag 1 byte flag
+ 0034 VSAM Index REUSE Flag 1 byte flag
+ 0035 VSAM Index WRITECHK Flag 1 byte flag Retired with PKZIP 5.0 +
+ 0036 VSAM Owner 8 bytes EBCDIC text string
+ 0037 VSAM Index Owner 8 bytes EBCDIC text string
+ 0038 Reserved
+ 0039 Reserved
+ 003A Reserved
+ 003B Reserved
+ 003C Reserved
+ 003D Reserved
+ 003E Reserved
+ 003F Reserved
+ 0040 Reserved
+ 0041 Reserved
+ 0042 Reserved
+ 0043 Reserved
+ 0044 Reserved
+ 0045 Reserved
+ 0046 Reserved
+ 0047 Reserved
+ 0048 Reserved
+ 0049 Reserved
+ 004A Reserved
+ 004B Reserved
+ 004C Reserved
+ 004D Reserved
+ 004E Reserved
+ 004F Reserved
+ 0050 Reserved
+ 0051 Reserved
+ 0052 Reserved
+ 0053 Reserved
+ 0054 Reserved
+ 0055 Reserved
+ 0056 Reserved
+ 0057 Reserved
+ 0058 PDS/PDSE Member TTR Info. 6 bytes Big Endian
+ 0059 PDS 1st LMOD Text TTR 3 bytes Big Endian
+ 005A PDS LMOD EP Rec # 4 bytes Big Endian
+ 005B Reserved
+ 005C Max Length of records 2 bytes Big Endian
+ 005D PDSE Flag 1 byte flag
+ 005E Reserved
+ 005F Reserved
+ 0060 Reserved
+ 0061 Reserved
+ 0062 Reserved
+ 0063 Reserved
+ 0064 Reserved
+ 0065 Last Date Referenced 4 bytes Packed Hex "yyyymmdd"
+ 0066 Date Created 4 bytes Packed Hex "yyyymmdd"
+ 0068 GZIP two words 8 bytes
+ 0071 Extended NOTE Location 12 bytes Big Endian
+ 0072 Archive device UNIT 6 bytes EBCDIC
+ 0073 Archive 1st Volume 6 bytes EBCDIC
+ 0074 Archive 1st VOL File Seq# 2 bytes Binary
+
+APPENDIX C - Zip64 Extensible Data Sector Mappings
+---------------------------------------------------
+
+ -Z390 Extra Field:
+
+ The following is the general layout of the attributes for the
+ ZIP 64 "extra" block for extended tape operations.
+
+ Note: some fields stored in Big Endian format. All text is
+ in EBCDIC format unless otherwise specified.
+
+ Value Size Description
+ ----- ---- -----------
+ (Z390) 0x0065 2 bytes Tag for this "extra" block type
+ Size 4 bytes Size for the following data block
+ Tag 4 bytes EBCDIC "Z390"
+ Length71 2 bytes Big Endian
+ Subcode71 2 bytes Enote type code
+ FMEPos 1 byte
+ Length72 2 bytes Big Endian
+ Subcode72 2 bytes Unit type code
+ Unit 1 byte Unit
+ Length73 2 bytes Big Endian
+ Subcode73 2 bytes Volume1 type code
+ FirstVol 1 byte Volume
+ Length74 2 bytes Big Endian
+ Subcode74 2 bytes FirstVol file sequence
+ FileSeq 2 bytes Sequence
+
+APPENDIX D - Language Encoding (EFS)
+------------------------------------
+
+D.1 The ZIP format has historically supported only the original IBM PC character
+encoding set, commonly referred to as IBM Code Page 437. This limits storing
+file name characters to only those within the original MS-DOS range of values
+and does not properly support file names in other character encodings, or
+languages. To address this limitation, this specification will support the
+following change.
+
+D.2 If general purpose bit 11 is unset, the file name and comment should conform
+to the original ZIP character encoding. If general purpose bit 11 is set, the
+filename and comment must support The Unicode Standard, Version 4.1.0 or
+greater using the character encoding form defined by the UTF-8 storage
+specification. The Unicode Standard is published by the The Unicode
+Consortium (www.unicode.org). UTF-8 encoded data stored within ZIP files
+is expected to not include a byte order mark (BOM).
+
+D.3 Applications may choose to supplement this file name storage through the use
+of the 0x0008 Extra Field. Storage for this optional field is currently
+undefined, however it will be used to allow storing extended information
+on source or target encoding that may further assist applications with file
+name, or file content encoding tasks. Please contact PKWARE with any
+requirements on how this field should be used.
+
+D.4 The 0x0008 Extra Field storage may be used with either setting for general
+purpose bit 11. Examples of the intended usage for this field is to store
+whether "modified-UTF-8" (JAVA) is used, or UTF-8-MAC. Similarly, other
+commonly used character encoding (code page) designations can be indicated
+through this field. Formalized values for use of the 0x0008 record remain
+undefined at this time. The definition for the layout of the 0x0008 field
+will be published when available. Use of the 0x0008 Extra Field provides
+for storing data within a ZIP file in an encoding other than IBM Code
+Page 437 or UTF-8.
+
+D.5 General purpose bit 11 will not imply any encoding of file content or
+password. Values defining character encoding for file content or
+password must be stored within the 0x0008 Extended Language Encoding
+Extra Field.
+
+D.6 Ed Gordon of the Info-ZIP group has defined a pair of "extra field" records
+that can be used to store UTF-8 file name and file comment fields. These
+records can be used for cases when the general purpose bit 11 method
+for storing UTF-8 data in the standard file name and comment fields is
+not desirable. A common case for this alternate method is if backward
+compatibility with older programs is required.
+
+D.7 Definitions for the record structure of these fields are included above
+in the section on 3rd party mappings for "extra field" records. These
+records are identified by Header ID's 0x6375 (Info-ZIP Unicode Comment
+Extra Field) and 0x7075 (Info-ZIP Unicode Path Extra Field).
+
+D.8 The choice of which storage method to use when writing a ZIP file is left
+to the implementation. Developers should expect that a ZIP file may
+contain either method and should provide support for reading data in
+either format. Use of general purpose bit 11 reduces storage requirements
+for file name data by not requiring additional "extra field" data for
+each file, but can result in older ZIP programs not being able to extract
+files. Use of the 0x6375 and 0x7075 records will result in a ZIP file
+that should always be readable by older ZIP programs, but requires more
+storage per file to write file name and/or file comment fields.
\ No newline at end of file
diff --git a/prereq/fwzip/FWZipConsts.pas b/prereq/fwzip/FWZipConsts.pas
new file mode 100644
index 0000000..75f178a
--- /dev/null
+++ b/prereq/fwzip/FWZipConsts.pas
@@ -0,0 +1,447 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ****************************************************************************
+// * Project : FWZip
+// * Unit Name : FWZipConsts
+// * Purpose : Типы и константы используемые для работы с ZIP архивами
+// * Author : Александр (Rouse_) Багель
+// * Copyright : © Fangorn Wizards Lab 1998 - 2015.
+// * Version : 1.0.11
+// * Home Page : http://rouse.drkb.ru
+// * Home Blog : http://alexander-bagel.blogspot.ru
+// ****************************************************************************
+// * Stable Release : http://rouse.drkb.ru/components.php#fwzip
+// * Latest Source : https://github.com/AlexanderBagel/FWZip
+// ****************************************************************************
+//
+// Используемые источники:
+// ftp://ftp.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
+// http://zlib.net/zlib-1.2.5.tar.gz
+// http://www.base2ti.com/
+//
+
+unit FWZipConsts;
+{$mode delphi}
+{$codepage UTF8}
+
+interface
+
+uses
+ LCLIntf, LCLType, LMessages, windows,
+ SysUtils,
+ Classes, FileUtil, LazFileUtils;
+
+type
+
+{
+ IV. General Format of a .ZIP file
+ ---------------------------------
+
+ Files stored in arbitrary order. Large .ZIP files can span multiple
+ diskette media or be split into user-defined segment sizes. [The
+ minimum user-defined segment size for a split .ZIP file is 64K.
+ (removed by PKWare 2003-06-01)]
+
+ Overall .ZIP file format:
+
+ [local file header 1]
+ [file data 1]
+ [data descriptor 1]
+ .
+ .
+ .
+ [local file header n]
+ [file data n]
+ [data descriptor n]
+ [archive decryption header] (EFS)
+ [archive extra data record] (EFS)
+ [central directory]
+ [zip64 end of central directory record]
+ [zip64 end of central directory locator]
+ [end of central directory record]
+ }
+ PLocalFileHeader = ^TLocalFileHeader;
+ TLocalFileHeader = packed record
+ LocalFileHeaderSignature: Cardinal; // (0x04034b50)
+ VersionNeededToExtract,
+ GeneralPurposeBitFlag,
+ CompressionMethod,
+ LastModFileTimeTime,
+ LastModFileTimeDate: Word;
+ Crc32,
+ CompressedSize,
+ UncompressedSize: Cardinal;
+ FilenameLength,
+ ExtraFieldLength: Word;
+ // file name (variable size)
+ // extra field (variable size)
+ end;
+
+ {
+ If bit 3 of the general purpose bit flag
+ is set, these fields are set to zero in the local header
+ and the correct values are put in the data descriptor and
+ in the central directory.
+ }
+
+ TDataDescriptor = packed record
+ DescriptorSignature, // (0x08074b50)
+ Crc32,
+ CompressedSize,
+ UncompressedSize: Cardinal;
+ {For Zip64 format archives, the compressed
+ and uncompressed sizes are 8 bytes each. ??!!}
+ end;
+
+ TEFS = packed record
+ ArchiveExtraDataSignature, // (0x08064b50)
+ ExtraFieldLength: Cardinal;
+ // extra field data (variable size)
+ end;
+
+ {
+ F. Central directory structure:
+
+ [file header 1]
+ .
+ .
+ .
+ [file header n]
+ [digital signature]
+ }
+
+ TCentralDirectoryFileHeader = packed record
+ CentralFileHeaderSignature: Cardinal; // (0x02014b50)
+ VersionMadeBy,
+ VersionNeededToExtract,
+ GeneralPurposeBitFlag,
+ CompressionMethod,
+ LastModFileTimeTime,
+ LastModFileTimeDate: Word;
+ Crc32,
+ CompressedSize,
+ UncompressedSize: Cardinal;
+ FilenameLength,
+ ExtraFieldLength,
+ FileCommentLength,
+ DiskNumberStart,
+ InternalFileAttributes: Word;
+ ExternalFileAttributes,
+ RelativeOffsetOfLocalHeader: Cardinal;
+ // file name (variable size)
+ // extra field (variable size)
+ // file comment (variable size)
+ end;
+
+ TCentralDirectoryFileHeaderEx = packed record
+ Header: TCentralDirectoryFileHeader;
+ UncompressedSize,
+ CompressedSize,
+ RelativeOffsetOfLocalHeader,
+ DataOffset: Int64;
+ DiskNumberStart: Integer;
+ FileName,
+ FileComment: string;
+ Attributes: TWin32FileAttributeData;
+ ExceptOnWrite: Boolean;
+ end;
+
+ TNTFSFileTime = packed record
+ Mtime: TFileTime;
+ Atime: TFileTime;
+ Ctime: TFileTime;
+ end;
+
+ TExDataHeaderAndSize = packed record
+ Header: Word;
+ Size: Word;
+ end;
+
+ TExDataNTFS = packed record
+ HS: TExDataHeaderAndSize;
+ Reserved: Cardinal;
+ Tag: Word;
+ RecordSize: Word;
+ Data: TNTFSFileTime;
+ end;
+
+ TExDataInfo64 = packed record
+ HS: TExDataHeaderAndSize;
+ UncompressedSize, CompressedSize: Int64;
+ end;
+
+ TCentralDirectoryDigitalSignature = packed record
+ HeaderSignature: Cardinal; // (0x05054b50)
+ SizeOfData: Word;
+ // signature data (variable size)
+ end;
+
+ TZip64EOFCentralDirectoryRecord = packed record
+ Zip64EndOfCentralDirSignature: Cardinal; // (0x06064b50)
+ SizeOfZip64EOFCentralDirectoryRecord: int64;
+ VersionMadeBy,
+ VersionNeededToExtract: Word;
+ Number1, // number of this disk
+ Number2: Cardinal; // number of the disk with the start of the central directory
+ TotalNumber1, // total number of entries in the central directory on this disk
+ TotalNumber2, // total number of entries in the central directory
+ Size, // size of the central directory
+ Offset: Int64; // offset of start of central directory with respect to the starting disk number
+ // zip64 extensible data sector (variable size)
+ end;
+
+ TZip64EOFCentralDirectoryLocator = packed record
+ Signature, // zip64 end of central dir locator signature (0x07064b50)
+ NumberOfTheDisk: Cardinal; // number of the disk with the start of the zip64 end of central directory
+ RelativeOffset: Int64; // relative offset of the zip64 end of central directory record
+ TotalNumberOfDisks: Cardinal;
+ end;
+
+ TEndOfCentralDir = packed record
+ EndOfCentralDirSignature: Cardinal; // (0x06054b50)
+ NumberOfThisDisk,
+ NumberOfTheDiskWithTheStart,
+ TotalNumberOfEntriesOnThisDisk,
+ TotalNumberOfEntries: Word;
+ SizeOfTheCentralDirectory,
+ OffsetOfStartOfCentralDirectory: Cardinal;
+ ZipfileCommentLength: Word;
+ // .ZIP file comment (variable size)
+ end;
+
+const
+ LOCAL_FILE_HEADER_SIGNATURE = $04034B50;
+ DATA_DESCRIPTOR_SIGNATURE = $08074B50;
+ EXTRA_DATA_SIGNATURE = $08064B50;
+ CENTRAL_FILE_HEADER_SIGNATURE = $02014B50;
+ CENTRAL_DIRECTORY_DIGITAL_SIGNATURE = $05054B50;
+ ZIP64_END_OF_CENTRAL_DIR_SIGNATURE = $06064B50;
+ ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE = $07064B50;
+ END_OF_CENTRAL_DIR_SIGNATURE = $06054B50;
+
+ ZIP_SLASH = '/';
+
+ // Флаги для GeneralPurposeBitFlag
+ PBF_CRYPTED = 1;
+
+ // (For Methods 8 and 9 - Deflating)
+ PBF_COMPRESS_NORMAL = 0;
+ PBF_COMPRESS_MAXIMUM = 2;
+ PBF_COMPRESS_FAST = 4;
+ PBF_COMPRESS_SUPERFAST = 6;
+
+ PBF_DESCRIPTOR = 8;
+ PBF_STRONG_CRYPT = 64;
+
+ PBF_UTF8 = $800;
+
+ // константы поддерживаемых полей ExData
+ SUPPORTED_EXDATA_ZIP64 = 1;
+ SUPPORTED_EXDATA_NTFSTIME = 10;
+
+ defaultWindowBits = -15;
+
+type
+ TProgressState = (
+ psStart, // начало распаковки элемента, результирующий файл еще не создан
+ psInitialization, // результирующий файл создан и залочен, производится подготовка к распаковке
+ psInProgress, // идет распаковка
+ psFinalization, // распаковка завершена, сейчас будут разрушены все служебные объекты, результирующий файл все еще залочен
+ psEnd, // операция распаковки полностью завершена, результирующий файл доступен на чтение/запись
+ psException // ошибка
+ );
+
+ TZipProgressEvent = procedure(Sender: TObject; const FileName: string;
+ Percent, TotalPercent: Byte; var Cancel: Boolean; ProgressState: TProgressState) of object;
+ TZipExtractItemEvent = procedure(Sender: TObject; const FileName: string;
+ Extracted, TotalSize: Int64; ProgressState: TProgressState) of object;
+ TZipNeedPasswordEvent = procedure(Sender: TObject; const FileName: string;
+ var Password: string; var CancelExtract: Boolean) of object;
+ TZipSaveExDataEvent = procedure(Sender: TObject; ItemIndex: Integer;
+ UserExDataBlockCount: Integer; var Tag: Word; Data: TStream) of object;
+ TZipLoadExDataEvent = procedure(Sender: TObject; ItemIndex: Integer;
+ Tag: Word; Data: TStream) of object;
+
+ // Типы поведения TFWZipWriter при ошибке в процессе создания архива
+ TExceptionAction =
+ (
+ eaRetry, // повторить попытку
+ eaSkip, // пропустить текущий элемент
+ eaAbort, // остановить создание архива
+ eaUseNewFilePath, // использовать новый путь к файлу (пар. NewFilePath)
+ eaUseNewFilePathAndDel, // то-же что и acUseNewFilePath, только файл удаляется после использования
+ eaUseNewFileData // использовать содержимое файла из стрима (пар. NewFileData)
+ );
+
+ TZipBuildExceptionEvent = procedure(Sender: TObject;
+ E: Exception; const ItemIndex: Integer;
+ var Action: TExceptionAction;
+ var NewFilePath: string; NewFileData: TMemoryStream) of object;
+
+ TZipExtractExceptionEvent = procedure(Sender: TObject;
+ E: Exception; const ItemIndex: Integer;
+ var Handled: Boolean) of object;
+
+ // Типы поведения TFWZipReader при конфликте имен файлов
+ TDuplicateAction =
+ (
+ daSkip, // пропустить файл
+ daOverwrite, // перезаписать
+ daUseNewFilePath, // сохранить с новым именем
+ daAbort // отменить распаковку
+ );
+
+ TZipDuplicateEvent = procedure(Sender: TObject;
+ var Path: string; var Action: TDuplicateAction) of object;
+
+const
+ CRC32Table: array[Byte] of Cardinal =
+ (
+ $00000000, $77073096, $EE0E612C, $990951BA, $076DC419, $706AF48F,
+ $E963A535, $9E6495A3, $0EDB8832, $79DCB8A4, $E0D5E91E, $97D2D988,
+ $09B64C2B, $7EB17CBD, $E7B82D07, $90BF1D91, $1DB71064, $6AB020F2,
+ $F3B97148, $84BE41DE, $1ADAD47D, $6DDDE4EB, $F4D4B551, $83D385C7,
+ $136C9856, $646BA8C0, $FD62F97A, $8A65C9EC, $14015C4F, $63066CD9,
+ $FA0F3D63, $8D080DF5, $3B6E20C8, $4C69105E, $D56041E4, $A2677172,
+ $3C03E4D1, $4B04D447, $D20D85FD, $A50AB56B, $35B5A8FA, $42B2986C,
+ $DBBBC9D6, $ACBCF940, $32D86CE3, $45DF5C75, $DCD60DCF, $ABD13D59,
+ $26D930AC, $51DE003A, $C8D75180, $BFD06116, $21B4F4B5, $56B3C423,
+ $CFBA9599, $B8BDA50F, $2802B89E, $5F058808, $C60CD9B2, $B10BE924,
+ $2F6F7C87, $58684C11, $C1611DAB, $B6662D3D, $76DC4190, $01DB7106,
+ $98D220BC, $EFD5102A, $71B18589, $06B6B51F, $9FBFE4A5, $E8B8D433,
+ $7807C9A2, $0F00F934, $9609A88E, $E10E9818, $7F6A0DBB, $086D3D2D,
+ $91646C97, $E6635C01, $6B6B51F4, $1C6C6162, $856530D8, $F262004E,
+ $6C0695ED, $1B01A57B, $8208F4C1, $F50FC457, $65B0D9C6, $12B7E950,
+ $8BBEB8EA, $FCB9887C, $62DD1DDF, $15DA2D49, $8CD37CF3, $FBD44C65,
+ $4DB26158, $3AB551CE, $A3BC0074, $D4BB30E2, $4ADFA541, $3DD895D7,
+ $A4D1C46D, $D3D6F4FB, $4369E96A, $346ED9FC, $AD678846, $DA60B8D0,
+ $44042D73, $33031DE5, $AA0A4C5F, $DD0D7CC9, $5005713C, $270241AA,
+ $BE0B1010, $C90C2086, $5768B525, $206F85B3, $B966D409, $CE61E49F,
+ $5EDEF90E, $29D9C998, $B0D09822, $C7D7A8B4, $59B33D17, $2EB40D81,
+ $B7BD5C3B, $C0BA6CAD, $EDB88320, $9ABFB3B6, $03B6E20C, $74B1D29A,
+ $EAD54739, $9DD277AF, $04DB2615, $73DC1683, $E3630B12, $94643B84,
+ $0D6D6A3E, $7A6A5AA8, $E40ECF0B, $9309FF9D, $0A00AE27, $7D079EB1,
+ $F00F9344, $8708A3D2, $1E01F268, $6906C2FE, $F762575D, $806567CB,
+ $196C3671, $6E6B06E7, $FED41B76, $89D32BE0, $10DA7A5A, $67DD4ACC,
+ $F9B9DF6F, $8EBEEFF9, $17B7BE43, $60B08ED5, $D6D6A3E8, $A1D1937E,
+ $38D8C2C4, $4FDFF252, $D1BB67F1, $A6BC5767, $3FB506DD, $48B2364B,
+ $D80D2BDA, $AF0A1B4C, $36034AF6, $41047A60, $DF60EFC3, $A867DF55,
+ $316E8EEF, $4669BE79, $CB61B38C, $BC66831A, $256FD2A0, $5268E236,
+ $CC0C7795, $BB0B4703, $220216B9, $5505262F, $C5BA3BBE, $B2BD0B28,
+ $2BB45A92, $5CB36A04, $C2D7FFA7, $B5D0CF31, $2CD99E8B, $5BDEAE1D,
+ $9B64C2B0, $EC63F226, $756AA39C, $026D930A, $9C0906A9, $EB0E363F,
+ $72076785, $05005713, $95BF4A82, $E2B87A14, $7BB12BAE, $0CB61B38,
+ $92D28E9B, $E5D5BE0D, $7CDCEFB7, $0BDBDF21, $86D3D2D4, $F1D4E242,
+ $68DDB3F8, $1FDA836E, $81BE16CD, $F6B9265B, $6FB077E1, $18B74777,
+ $88085AE6, $FF0F6A70, $66063BCA, $11010B5C, $8F659EFF, $F862AE69,
+ $616BFFD3, $166CCF45, $A00AE278, $D70DD2EE, $4E048354, $3903B3C2,
+ $A7672661, $D06016F7, $4969474D, $3E6E77DB, $AED16A4A, $D9D65ADC,
+ $40DF0B66, $37D83BF0, $A9BCAE53, $DEBB9EC5, $47B2CF7F, $30B5FFE9,
+ $BDBDF21C, $CABAC28A, $53B39330, $24B4A3A6, $BAD03605, $CDD70693,
+ $54DE5729, $23D967BF,$B3667A2E, $C4614AB8, $5D681B02, $2A6F2B94,
+ $B40BBE37, $C30C8EA1, $5A05DF1B, $2D02EF8D
+ );
+
+ CurrentVersionMadeBy = 63;
+
+ function IsAttributesPresent(Value: TWin32FileAttributeData): Boolean;
+ function FileSizeToInt64(FileSizeLo, FileSizeHi: DWORD): Int64;
+ function PathCanonicalize(Value: string): string;
+ function MakeUniqueName(const Value: string): string;
+ function FileSizeToStr(Value: Int64): string;
+
+implementation
+
+ function PathCanonicalizeA(lpszDes, lpszSrc: PAnsiChar): BOOL; stdcall; external 'shlwapi.dll';
+ function PathCanonicalizeW(lpszDes, lpszSrc: PWideChar): BOOL; stdcall; external 'shlwapi.dll';
+ function PathMakeUniqueName(pszUniqueName: PWideChar; cchMax: UINT;
+ pszTemplate, pszLongPlate, pszDir: PWideChar): BOOL; stdcall; external 'shell32.dll';
+
+function IsAttributesPresent(Value: TWin32FileAttributeData): Boolean;
+begin
+ Result := (Value.ftCreationTime.dwLowDateTime <> 0) and
+ (Value.ftCreationTime.dwHighDateTime <> 0);
+end;
+
+function FileSizeToInt64(FileSizeLo, FileSizeHi: DWORD): Int64;
+begin
+ Result := FileSizeHi;
+ Result := Result shl 32;
+ Inc(Result, FileSizeLo);
+end;
+
+function PathCanonicalize(Value: string): string;
+begin
+ if Value = '' then
+ begin
+ Result := '';
+ Exit;
+ end;
+ if Value[1] = '.' then
+ Value := IncludeTrailingPathDelimiter(GetCurrentDirUTF8 { *Преобразовано из GetCurrentDir* }) + Value;
+ SetLength(Result, MAX_PATH);
+ {$IFDEF UNICODE}
+ PathCanonicalizeW(PWideChar(Result), PWideChar(Value));
+ {$ELSE}
+ PathCanonicalizeA(PAnsiChar(Result), PAnsiChar(Value));
+ {$ENDIF}
+ Result := PChar(Result);
+end;
+
+function MakeUniqueName(const Value: string): string;
+{$IFDEF UNICODE}
+var
+ FilePath, FileName: string;
+begin
+ Result := Value;
+ FilePath := ExtractFilePath(Value);
+ FileName := ExtractFileName(Value);
+ SetLength(Result, MAX_PATH);
+ if PathMakeUniqueName(PWideChar(Result), MAX_PATH,
+ nil, PWideChar(FileName), PWideChar(FilePath)) then
+ Result := PWideChar(Result);
+{$ELSE}
+var
+ UnicodeResult, FilePath, FileName: WideString;
+begin
+ Result := Value;
+ FilePath := WideString(ExtractFilePath(Value));
+ FileName := WideString(ExtractFileName(Value));
+ SetLength(UnicodeResult, MAX_PATH);
+ if PathMakeUniqueName(PWideChar(UnicodeResult), MAX_PATH,
+ nil, PWideChar(FileName), PWideChar(FilePath)) then
+ Result := AnsiString(PWideChar(UnicodeResult));
+{$ENDIF}
+end;
+
+function FileSizeToStr(Value: Int64): string;
+begin
+ if Value < 1024 then
+ begin
+ Result := Format('%d байт', [Value]);
+ Exit;
+ end;
+ Value := Value div 1024;
+ if Value < 1024 then
+ begin
+ Result := Format('%d килобайт', [Value]);
+ Exit;
+ end;
+ Value := Value div 1024;
+ if Value < 1024 then
+ begin
+ Result := Format('%d мегабайт', [Value]);
+ Exit;
+ end;
+ Value := Value div 1024;
+ if Value < 1024 then
+ begin
+ Result := Format('%d гигабайт', [Value]);
+ Exit;
+ end;
+ // ну а чем бог не шутит? :)
+ Value := Value div 1024;
+ Result := Format('%d терабайт', [Value]);
+end;
+
+end.
diff --git a/prereq/fwzip/FWZipCrc32.pas b/prereq/fwzip/FWZipCrc32.pas
new file mode 100644
index 0000000..e8cfda9
--- /dev/null
+++ b/prereq/fwzip/FWZipCrc32.pas
@@ -0,0 +1,147 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ****************************************************************************
+// * Project : FWZip
+// * Unit Name : FWZipCrc32
+// * Purpose : Набор функций для рассчета контрольной суммы блока данных
+// * : Класс TFWZipCRC32Stream используется в качестве посредника
+// * : между двумя стримами и предназначен для бастрого
+// * : рассчета контрольной суммы передаваемых блоков данных
+// * Author : Александр (Rouse_) Багель
+// * Copyright : © Fangorn Wizards Lab 1998 - 2015.
+// * Version : 1.0.11
+// * Home Page : http://rouse.drkb.ru
+// * Home Blog : http://alexander-bagel.blogspot.ru
+// ****************************************************************************
+// * Stable Release : http://rouse.drkb.ru/components.php#fwzip
+// * Latest Source : https://github.com/AlexanderBagel/FWZip
+// ****************************************************************************
+//
+// Используемые источники:
+// ftp://ftp.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
+// http://zlib.net/zlib-1.2.5.tar.gz
+// http://www.base2ti.com/
+//
+
+unit FWZipCrc32;
+{$mode delphi}
+{$codepage UTF8}
+
+interface
+
+uses
+ Classes,
+ SysUtils,
+ FWZipConsts;
+
+type
+ TFWZipCRC32Stream = class(TStream)
+ private
+ FOwner: TStream;
+ FCRC32: Cardinal;
+ protected
+ function GetSize: Int64; override;
+ public
+ constructor Create(AOwner: TStream);
+ function Seek(Offset: Longint; Origin: Word): Longint; overload; override;
+ function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; overload; override;
+ function Read(var Buffer; Count: Longint): Longint; override;
+ function Write(const Buffer; Count: Longint): Longint; override;
+ function CRC32: Cardinal;
+ end;
+
+ function CRC32Calc(CurrCRC: Cardinal;
+ Buffer: PByte; const BufferLen: Int64): Cardinal; overload;
+ function CRC32Calc(Buffer: PByte; const BufferLen: Int64): Cardinal; overload;
+ function FileCRC32(const FileName: string): Cardinal;
+
+implementation
+
+
+function CRC32Calc(CurrCRC: Cardinal;
+ Buffer: PByte; const BufferLen: Int64): Cardinal;
+var
+ I: Integer;
+begin
+ Result := CurrCRC;
+ for I := 0 to BufferLen - 1 do
+ begin
+ Result := ((Result shr 8) and $00FFFFFF) xor
+ CRC32Table[(Result xor Buffer^) and $FF];
+ Inc(Buffer);
+ end;
+end;
+
+function CRC32Calc(Buffer: PByte; const BufferLen: Int64): Cardinal;
+begin
+ Result := CRC32Calc($FFFFFFFF, Buffer, BufferLen) xor $FFFFFFFF;
+end;
+
+function FileCRC32(const FileName: string): Cardinal;
+var
+ Buff: Pointer;
+ F: TFileStream;
+ Size: Integer;
+begin
+ Result := $FFFFFFFF;
+ GetMem(Buff, $FFFF);
+ try
+ F := TFileStream.Create(FileName, fmOpenRead);
+ try
+ Size := 1;
+ while Size > 0 do
+ begin
+ Size := F.Read(Buff^, $FFFF);
+ Result := CRC32Calc(Result, Buff, Size);
+ end;
+ finally
+ F.Free;
+ end;
+ finally
+ FreeMem(Buff);
+ end;
+ Result := Result xor $FFFFFFFF;
+end;
+
+{ TFWZipCRC32Stream }
+
+function TFWZipCRC32Stream.CRC32: Cardinal;
+begin
+ Result := FCRC32 xor $FFFFFFFF;
+end;
+
+constructor TFWZipCRC32Stream.Create(AOwner: TStream);
+begin
+ FOwner := AOwner;
+ FCRC32 := $FFFFFFFF;
+end;
+
+function TFWZipCRC32Stream.GetSize: Int64;
+begin
+ Result := FOwner.Size;
+end;
+
+function TFWZipCRC32Stream.Read(var Buffer; Count: Integer): Longint;
+begin
+ Result := FOwner.Read(Buffer, Count);
+ FCRC32 := CRC32Calc(FCRC32, @Buffer, Result);
+end;
+
+function TFWZipCRC32Stream.Seek(Offset: Integer; Origin: Word): Longint;
+begin
+ Result := FOwner.Seek(Offset, Origin);
+end;
+
+function TFWZipCRC32Stream.Seek(const Offset: Int64;
+ Origin: TSeekOrigin): Int64;
+begin
+ Result := FOwner.Seek(Offset, Origin);
+end;
+
+function TFWZipCRC32Stream.Write(const Buffer; Count: Integer): Longint;
+begin
+ Result := FOwner.Write(Buffer, Count);
+ FCRC32 := CRC32Calc(FCRC32, @Buffer, Result);
+end;
+
+end.
diff --git a/prereq/fwzip/FWZipCrypt.pas b/prereq/fwzip/FWZipCrypt.pas
new file mode 100644
index 0000000..0380f18
--- /dev/null
+++ b/prereq/fwzip/FWZipCrypt.pas
@@ -0,0 +1,361 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ****************************************************************************
+// * Project : FWZip
+// * Unit Name : FWZipCrypt
+// * Purpose : Реализация криптографии по методу PKWARE
+// * Author : Александр (Rouse_) Багель
+// * Copyright : © Fangorn Wizards Lab 1998 - 2015.
+// * Version : 1.0.11
+// * Home Page : http://rouse.drkb.ru
+// * Home Blog : http://alexander-bagel.blogspot.ru
+// ****************************************************************************
+// * Stable Release : http://rouse.drkb.ru/components.php#fwzip
+// * Latest Source : https://github.com/AlexanderBagel/FWZip
+// ****************************************************************************
+//
+// Используемые источники:
+// ftp://ftp.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
+// http://zlib.net/zlib-1.2.5.tar.gz
+// http://www.base2ti.com/
+//
+
+unit FWZipCrypt;
+{$mode delphi}
+{$codepage UTF8}
+
+interface
+
+ // Переполнения и выход за диапазон неизбежны
+ // поэтому отключаем данные проверки
+ {$OVERFLOWCHECKS OFF}
+ {$RANGECHECKS OFF}
+
+uses
+ LCLIntf, LCLType, LMessages, windows,
+ Classes,
+ FWZipConsts;
+
+{
+XIII. Decryption
+----------------
+
+The encryption used in PKZIP was generously supplied by Roger
+Schlafly. PKWARE is grateful to Mr. Schlafly for his expert
+help and advice in the field of data encryption.
+
+PKZIP encrypts the compressed data stream. Encrypted files must
+be decrypted before they can be extracted.
+
+Each encrypted file has an extra 12 bytes stored at the start of
+the data area defining the encryption header for that file. The
+encryption header is originally set to random values, and then
+itself encrypted, using three, 32-bit keys. The key values are
+initialized using the supplied encryption password. After each byte
+is encrypted, the keys are then updated using pseudo-random number
+generation techniques in combination with the same CRC-32 algorithm
+used in PKZIP and described elsewhere in this document.
+
+The following is the basic steps required to decrypt a file:
+
+1) Initialize the three 32-bit keys with the password.
+2) Read and decrypt the 12-byte encryption header, further
+ initializing the encryption keys.
+3) Read and decrypt the compressed data stream using the
+ encryption keys.
+
+
+Step 1 - Initializing the encryption keys
+-----------------------------------------
+
+Key(0) <- 305419896
+Key(1) <- 591751049
+Key(2) <- 878082192
+
+loop for i <- 0 to length(password)-1
+ update_keys(password(i))
+end loop
+
+
+Where update_keys() is defined as:
+
+
+update_keys(char):
+ Key(0) <- crc32(key(0),char)
+ Key(1) <- Key(1) + (Key(0) & 000000ffH)
+ Key(1) <- Key(1) * 134775813 + 1
+ Key(2) <- crc32(key(2),key(1) >> 24)
+end update_keys
+
+
+Where crc32(old_crc,char) is a routine that given a CRC value and a
+character, returns an updated CRC value after applying the CRC-32
+algorithm described elsewhere in this document.
+
+
+Step 2 - Decrypting the encryption header
+-----------------------------------------
+
+The purpose of this step is to further initialize the encryption
+keys, based on random data, to render a plaintext attack on the
+data ineffective.
+
+
+Read the 12-byte encryption header into Buffer, in locations
+Buffer(0) thru Buffer(11).
+
+loop for i <- 0 to 11
+ C <- buffer(i) ^ decrypt_byte()
+ update_keys(C)
+ buffer(i) <- C
+end loop
+
+
+Where decrypt_byte() is defined as:
+
+
+unsigned char decrypt_byte()
+ local unsigned short temp
+ temp <- Key(2) | 2
+ decrypt_byte <- (temp * (temp ^ 1)) >> 8
+end decrypt_byte
+
+
+After the header is decrypted, the last 1 or 2 bytes in Buffer
+should be the high-order word/byte of the CRC for the file being
+decrypted, stored in Intel low-byte/high-byte order, or the high-order
+byte of the file time if bit 3 of the general purpose bit flag is set.
+Versions of PKZIP prior to 2.0 used a 2 byte CRC check; a 1 byte CRC check is
+used on versions after 2.0. This can be used to test if the password
+supplied is correct or not.
+
+
+Step 3 - Decrypting the compressed data stream
+----------------------------------------------
+
+The compressed data stream can be decrypted as follows:
+
+
+loop until done
+ read a character into C
+ Temp <- C ^ decrypt_byte()
+ update_keys(temp)
+ output Temp
+end loop
+}
+
+const
+ EncryptedHeaderSize = 12;
+ LastEncryptedHeaderByte = EncryptedHeaderSize - 1;
+
+type
+ TZipKeys = array [0..2] of Cardinal;
+
+ TFWZipKeys = class
+ private
+ FKeys: TZipKeys;
+ protected
+ procedure UpdateKeys(Value: Byte);
+ function DecryptByte: Byte;
+ public
+ constructor Create(const Password: AnsiString);
+ end;
+
+ TFWZipCryptor = class(TFWZipKeys)
+ protected
+ function EncryptByte(Value: Byte): Byte;
+ public
+ procedure GenerateEncryptionHeader(Stream: TStream;
+ IsDescryptorFlagPresent: Boolean;
+ CRC32, FileDate: Cardinal);
+ procedure EncryptBuffer(Buffer: PByte; Size: Int64);
+ end;
+
+ TFWZipDecryptor = class(TFWZipKeys)
+ public
+ function LoadEncryptionHeader(Stream: TStream;
+ IsDescryptorFlagPresent: Boolean;
+ CRC32, FileDate: Cardinal): Boolean;
+ procedure DecryptBuffer(Buffer: PByte; Size: Int64);
+ end;
+
+implementation
+
+const
+ DefaultKeys: TZipKeys = (305419896, 591751049, 878082192);
+
+{ TFWZipKeys }
+
+constructor TFWZipKeys.Create(const Password: AnsiString);
+var
+ I: Integer;
+begin
+ inherited Create;
+{
+Step 1 - Initializing the encryption keys
+-----------------------------------------
+
+Key(0) <- 305419896
+Key(1) <- 591751049
+Key(2) <- 878082192
+
+loop for i <- 0 to length(password)-1
+ update_keys(password(i))
+end loop
+
+}
+ FKeys := DefaultKeys;
+ for I := 1 to Length(Password) do
+ UpdateKeys(Byte(Password[I]));
+end;
+
+function TFWZipKeys.DecryptByte: Byte;
+var
+ temp: Word;
+begin
+{
+Where decrypt_byte() is defined as:
+
+unsigned char decrypt_byte()
+ local unsigned short temp
+ temp <- Key(2) | 2
+ decrypt_byte <- (temp * (temp ^ 1)) >> 8
+end decrypt_byte
+
+}
+ temp := FKeys[2] or 2;
+ Result := (temp * (temp xor 1)) shr 8;
+end;
+
+procedure TFWZipKeys.UpdateKeys(Value: Byte);
+begin
+{
+ Key(0) <- crc32(key(0),char)
+ Key(1) <- Key(1) + (Key(0) & 000000ffH)
+ Key(1) <- Key(1) * 134775813 + 1
+ Key(2) <- crc32(key(2),key(1) >> 24)
+}
+ FKeys[0] := ((FKeys[0] shr 8) and $FFFFFF) xor
+ CRC32Table[(FKeys[0] xor Value) and $FF];
+ FKeys[1] := FKeys[1] + (FKeys[0] and $FF);
+ FKeys[1] := FKeys[1] * 134775813 + 1;
+ FKeys[2] := ((FKeys[2] shr 8) and $FFFFFF) xor
+ CRC32Table[(FKeys[2] xor (FKeys[1] shr 24)) and $FF];
+end;
+
+{ TFWZipCryptor }
+
+procedure TFWZipCryptor.EncryptBuffer(Buffer: PByte; Size: Int64);
+var
+ temp: Byte;
+begin
+ // реверсированный вариант TFWZipDecryptor.DecryptBuffer
+ while Size > 0 do
+ begin
+ Dec(Size);
+ temp := DecryptByte;
+ UpdateKeys(Buffer^);
+ Buffer^ := temp xor Buffer^;
+ Inc(Buffer);
+ end;
+end;
+
+function TFWZipCryptor.EncryptByte(Value: Byte): Byte;
+var
+ temp: Byte;
+begin
+ temp := DecryptByte;
+ UpdateKeys(Value);
+ Result := temp xor Value;
+end;
+
+procedure TFWZipCryptor.GenerateEncryptionHeader(Stream: TStream;
+ IsDescryptorFlagPresent: Boolean; CRC32, FileDate: Cardinal);
+var
+ Buffer: array [0..EncryptedHeaderSize - 1] of Byte;
+ I: Integer;
+begin
+ // реверсированный вариант TFWZipDecryptor.LoadEncryptionHeader
+ Randomize;
+ for I := 0 to LastEncryptedHeaderByte - 2 do
+ Buffer[I] := EncryptByte(Byte(Random(MAXBYTE)));
+ if IsDescryptorFlagPresent then
+ begin
+ Buffer[10] := EncryptByte(LoByte(LoWord(FileDate)));
+ Buffer[11] := EncryptByte(HiByte(LoWord(FileDate)));
+ end
+ else
+ begin
+ Buffer[10] := EncryptByte(LoByte(HiWord(CRC32)));
+ Buffer[11] := EncryptByte(HiByte(HiWord(CRC32)));
+ end;
+ Stream.WriteBuffer(Buffer[0], EncryptedHeaderSize);
+end;
+
+{ TFWZipDecryptor }
+
+procedure TFWZipDecryptor.DecryptBuffer(Buffer: PByte; Size: Int64);
+var
+ temp: Byte;
+begin
+{
+Step 3 - Decrypting the compressed data stream
+----------------------------------------------
+
+The compressed data stream can be decrypted as follows:
+
+loop until done
+ read a character into C
+ Temp <- C ^ decrypt_byte()
+ update_keys(temp)
+ output Temp
+end loop
+}
+ while Size > 0 do
+ begin
+ Dec(Size);
+ temp := Buffer^ xor DecryptByte;
+ UpdateKeys(temp);
+ Buffer^ := temp;
+ Inc(Buffer);
+ end;
+end;
+
+function TFWZipDecryptor.LoadEncryptionHeader(Stream: TStream;
+ IsDescryptorFlagPresent: Boolean; CRC32, FileDate: Cardinal): Boolean;
+var
+ Buffer: array [0..EncryptedHeaderSize - 1] of Byte;
+ I: Integer;
+ C: Byte;
+begin
+{
+Read the 12-byte encryption header into Buffer, in locations
+Buffer(0) thru Buffer(11).
+
+loop for i <- 0 to 11
+ C <- buffer(i) ^ decrypt_byte()
+ update_keys(C)
+ buffer(i) <- C
+end loop
+}
+ Stream.ReadBuffer(Buffer[0], EncryptedHeaderSize);
+ for I := 0 to LastEncryptedHeaderByte do
+ begin
+ C := Buffer[I] xor DecryptByte;
+ UpdateKeys(C);
+ Buffer[I] := C;
+ end;
+
+{
+After the header is decrypted, the last 1 or 2 bytes in Buffer
+should be the high-order word/byte of the CRC for the file being
+decrypted, stored in Intel low-byte/high-byte order, or the high-order
+byte of the file time if bit 3 of the general purpose bit flag is set.
+}
+ if IsDescryptorFlagPresent then
+ Result := Buffer[LastEncryptedHeaderByte] = HiByte(LoWord(FileDate))
+ else
+ Result := Buffer[LastEncryptedHeaderByte] = HiByte(HiWord(CRC32));
+end;
+
+end.
diff --git a/prereq/fwzip/FWZipModifier.pas b/prereq/fwzip/FWZipModifier.pas
new file mode 100644
index 0000000..3b8f4e5
--- /dev/null
+++ b/prereq/fwzip/FWZipModifier.pas
@@ -0,0 +1,402 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ****************************************************************************
+// * Project : FWZip
+// * Unit Name : FWZipModifier
+// * Purpose : Класс для модификации созданного ранее ZIP архива
+// * Author : Александр (Rouse_) Багель
+// * Copyright : © Fangorn Wizards Lab 1998 - 2015.
+// * Version : 1.0.11
+// * Home Page : http://rouse.drkb.ru
+// * Home Blog : http://alexander-bagel.blogspot.ru
+// ****************************************************************************
+// * Stable Release : http://rouse.drkb.ru/components.php#fwzip
+// * Latest Source : https://github.com/AlexanderBagel/FWZip
+// ****************************************************************************
+//
+// Используемые источники:
+// ftp://ftp.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
+// http://zlib.net/zlib-1.2.5.tar.gz
+// http://www.base2ti.com/
+//
+
+unit FWZipModifier;
+{$mode delphi}
+{$codepage UTF8}
+
+interface
+
+uses
+ LCLIntf, LCLType, LMessages, windows,
+ Classes,
+ SysUtils,
+ FWZipConsts,
+ FWZipReader,
+ FWZipWriter,
+ FWZipZLib;
+
+type
+ TReaderIndex = Integer;
+
+ TFWZipModifierItem = class(TFWZipWriterItem)
+ private
+ FReaderIndex: TReaderIndex; // индекс TFWZipReader в массиве TFWZipModifier.FReaderList
+ FOriginalItemIndex: Integer; // оригинальный индекс элемента в изначальном архиве
+ protected
+ property ReaderIndex: TReaderIndex read FReaderIndex write FReaderIndex;
+ property OriginalItemIndex: Integer read FOriginalItemIndex write FOriginalItemIndex;
+ public
+ constructor Create(Owner: TFWZipWriter;
+ const InitFilePath: string;
+ InitAttributes: TWin32FileAttributeData;
+ const InitFileName: string = ''); override;
+ end;
+
+ EFWZipModifier = class(Exception);
+
+ // Данная структура хранит все блоки ExData из подключаемых архивов
+ TExDataRecord = record
+ Index: Integer;
+ Tag: Word;
+ Stream: TMemoryStream;
+ end;
+ TExDataRecords = array of TExDataRecord;
+
+ // структура для хранения подключенного архива и его блоков ExData
+ TReaderData = record
+ Reader: TFWZipReader;
+ ExDataRecords: TExDataRecords;
+ end;
+
+ TReaderList = array of TReaderData;
+
+ TFWZipModifier = class(TFWZipWriter)
+ private
+ FReaderList: TReaderList;
+ function CheckZipFileIndex(Value: TReaderIndex): TReaderIndex;
+ function AddItemFromZip(AReader: TFWZipReader;
+ ReaderIndex: TReaderIndex; ItemIndex: Integer): Integer;
+ protected
+ function GetItemClass: TFWZipWriterItemClass; override;
+ procedure FillItemCDFHeader(CurrentItem: TFWZipWriterItem;
+ var Value: TCentralDirectoryFileHeaderEx); override;
+ procedure CompressItem(CurrentItem: TFWZipWriterItem;
+ Index: Integer; StreamSizeBeforeCompress: Int64; Stream: TStream); override;
+ procedure FillExData(Stream: TStream; Index: Integer); override;
+ procedure OnLoadExData(Sender: TObject; ItemIndex: Integer;
+ Tag: Word; Data: TStream);
+ public
+ destructor Destroy; override;
+ function AddZipFile(const FilePath: string; SFXOffset: Integer = -1;
+ ZipEndOffset: Integer = -1): TReaderIndex; overload;
+ function AddZipFile(FileStream: TStream; SFXOffset: Integer = -1;
+ ZipEndOffset: Integer = -1): TReaderIndex; overload;
+ function AddFromZip(ReaderIndex: TReaderIndex): Integer; overload;
+ function AddFromZip(ReaderIndex: TReaderIndex; const ItemPath: string): Integer; overload;
+ function AddFromZip(ReaderIndex: TReaderIndex; ItemsList: TStringList): Integer; overload;
+ end;
+
+implementation
+
+type
+ TFWZipReaderFriendly = class(TFWZipReader);
+ TFWZipReaderItemFriendly = class(TFWZipReaderItem);
+
+{ TFWZipModifierItem }
+
+//
+// В конструкторе производим первичную инициализацию полей
+// Сами поля ReaderIndex и OriginalItemIndex будут инициализироваться только
+// при добавлении их посредством класса TFWZipModifier
+// =============================================================================
+constructor TFWZipModifierItem.Create(Owner: TFWZipWriter;
+ const InitFilePath: string; InitAttributes: TWin32FileAttributeData;
+ const InitFileName: string);
+begin
+ inherited Create(Owner, InitFilePath, InitAttributes, InitFileName);
+ FReaderIndex := -1;
+ FOriginalItemIndex := -1;
+end;
+
+{ TFWZipModifier }
+
+//
+// Функция переносит элемент в финальный архив из ранее добавленного архива.
+// В качестве результата возвращает индекс элемента в списке.
+// Параметры:
+// ReaderIndex - индекс ранее добавленно функцией AddZipFile архива
+// ItemPath - имя элемента, которое требуется добавить
+// =============================================================================
+function TFWZipModifier.AddFromZip(ReaderIndex: TReaderIndex;
+ const ItemPath: string): Integer;
+var
+ Reader: TFWZipReader;
+begin
+ CheckZipFileIndex(ReaderIndex);
+ Reader := FReaderList[ReaderIndex].Reader;
+ Result :=
+ AddItemFromZip(Reader, ReaderIndex, Reader.GetElementIndex(ItemPath));
+end;
+
+//
+// Функция переносит все элементы из ранее добавленного архива в финальный архив.
+// В качестве результата возвращает количество успешно добавленных элементов.
+// Параметры:
+// ReaderIndex - индекс ранее добавленно функцией AddZipFile архива
+// =============================================================================
+function TFWZipModifier.AddFromZip(ReaderIndex: TReaderIndex): Integer;
+var
+ I: Integer;
+ Reader: TFWZipReader;
+begin
+ CheckZipFileIndex(ReaderIndex);
+ Result := 0;
+ Reader := FReaderList[ReaderIndex].Reader;
+ for I := 0 to Reader.Count - 1 do
+ if AddItemFromZip(Reader, ReaderIndex, I) >= 0 then
+ Inc(Result);
+end;
+
+//
+// Функция переносит все элементы из ранее добавленного архива
+// по списку в финальный архив.
+// В качестве результата возвращает количество успешно добавленных элементов.
+// Параметры:
+// ReaderIndex - индекс ранее добавленно функцией AddZipFile архива
+// ItemsList - список элементов к добавлению
+// =============================================================================
+function TFWZipModifier.AddFromZip(ReaderIndex: TReaderIndex;
+ ItemsList: TStringList): Integer;
+var
+ I: Integer;
+ Reader: TFWZipReader;
+begin
+ CheckZipFileIndex(ReaderIndex);
+ Result := 0;
+ Reader := FReaderList[ReaderIndex].Reader;
+ for I := 0 to ItemsList.Count - 1 do
+ if AddItemFromZip(Reader, ReaderIndex,
+ Reader.GetElementIndex(ItemsList[I])) >= 0 then
+ Inc(Result);
+end;
+
+//
+// Функция переносит элемент в финальный архив из ранее добавленного архива.
+// В качестве результата возвращает индекс элемента в списке.
+// =============================================================================
+function TFWZipModifier.AddItemFromZip(AReader: TFWZipReader;
+ ReaderIndex: TReaderIndex; ItemIndex: Integer): Integer;
+var
+ OldItem: TFWZipReaderItemFriendly;
+ NewItem: TFWZipModifierItem;
+begin
+ Result := -1;
+ if ItemIndex < 0 then Exit;
+ // Получаем указатель на элемент из уже существующего архива
+ OldItem := TFWZipReaderItemFriendly(AReader.Item[ItemIndex]);
+ // создаем новый элемент, который будем добавлять к новому архиву
+ NewItem := TFWZipModifierItem(
+ GetItemClass.Create(Self, '', OldItem.Attributes, OldItem.FileName));
+ // переключаем его в режим получения данных вручную
+ NewItem.UseExternalData := True;
+ // инициализируем ему индексы, дабы потом понять, откуда брать о нем данные
+ NewItem.ReaderIndex := ReaderIndex;
+ NewItem.OriginalItemIndex := ItemIndex;
+ // инициализируем внешние и рассчитываемые поля
+ NewItem.Comment := OldItem.Comment;
+ NewItem.NeedDescriptor :=
+ OldItem.CentralDirFileHeader.GeneralPurposeBitFlag and PBF_DESCRIPTOR <> 0;
+ NewItem.UseUTF8String :=
+ OldItem.CentralDirFileHeader.GeneralPurposeBitFlag and PBF_UTF8 <> 0;
+ // добавляем
+ Result := AddNewItem(NewItem);
+end;
+
+//
+// Функция добавляет новый архив из которого можно брать готовые данные.
+// В качестве результата возвращает индекс архива в списке добавленных.
+// Параметры:
+// FileStream - поток с данными архива
+// SFXOffset и ZipEndOffset - его границы
+// =============================================================================
+function TFWZipModifier.AddZipFile(FileStream: TStream; SFXOffset,
+ ZipEndOffset: Integer): TReaderIndex;
+var
+ AReader: TFWZipReader;
+begin
+ Result := Length(FReaderList);
+ SetLength(FReaderList, Result + 1);
+ AReader := TFWZipReader.Create;
+ AReader.OnLoadExData := OnLoadExData;
+ AReader.LoadFromStream(FileStream, SFXOffset, ZipEndOffset);
+ FReaderList[Result].Reader := AReader;
+end;
+
+//
+// Функция добавляет новый архив из которого можно брать готовые данные.
+// В качестве результата возвращает индекс архива в списке добавленных.
+// Параметры:
+// FilePath - путь к добавляемому архиву
+// SFXOffset и ZipEndOffset - его границы
+// =============================================================================
+function TFWZipModifier.AddZipFile(const FilePath: string;
+ SFXOffset, ZipEndOffset: Integer): TReaderIndex;
+var
+ AReader: TFWZipReader;
+begin
+ Result := Length(FReaderList);
+ SetLength(FReaderList, Result + 1);
+ AReader := TFWZipReader.Create;
+ AReader.OnLoadExData := OnLoadExData;
+ AReader.LoadFromFile(FilePath, SFXOffset, ZipEndOffset);
+ FReaderList[Result].Reader := AReader;
+end;
+
+//
+// Функция проверяет правильность переданного индекса архива в списке
+// =============================================================================
+function TFWZipModifier.CheckZipFileIndex(Value: TReaderIndex): TReaderIndex;
+begin
+ Result := Value;
+ if (Value < 0) or (Value >= Length(FReaderList)) then
+ raise EFWZipModifier.CreateFmt('Invalid index value (%d).', [Value]);
+end;
+
+//
+// Процедура перекрывает сжатие данных эелемента
+// и берет эти данные из ранее сформированного архива.
+// =============================================================================
+procedure TFWZipModifier.CompressItem(CurrentItem: TFWZipWriterItem;
+ Index: Integer; StreamSizeBeforeCompress: Int64; Stream: TStream);
+var
+ OldItem: TFWZipReaderItemFriendly;
+ NewItem: TFWZipModifierItem;
+ Reader: TFWZipReaderFriendly;
+ Offset: Int64;
+begin
+ NewItem := TFWZipModifierItem(CurrentItem);
+ // проверка, работаем ли мы с элементом, данные которого заполняются вручную?
+ if not NewItem.UseExternalData then
+ begin
+ inherited;
+ Exit;
+ end;
+ // получаем указатель на класс, который держит добавленный ранее архив
+ Reader := TFWZipReaderFriendly(FReaderList[NewItem.ReaderIndex].Reader);
+ // получаем указатель на оригинальный элемент архива
+ OldItem := TFWZipReaderItemFriendly(Reader.Item[NewItem.OriginalItemIndex]);
+ // рассчитываем его позицию в архиве
+ Offset := OldItem.CentralDirFileHeader.RelativeOffsetOfLocalHeader;
+ Inc(Offset, SizeOf(TLocalFileHeader));
+ Inc(Offset, OldItem.CentralDirFileHeader.FilenameLength);
+ if OldItem.CentralDirFileHeaderEx.UncompressedSize >= MAXDWORD then
+ Inc(Offset, SizeOf(TExDataInfo64));
+ Reader.ZIPStream.Position := Offset;
+ // копируем данные как есть, без перепаковки
+ Stream.CopyFrom(Reader.ZIPStream, OldItem.CentralDirFileHeaderEx.CompressedSize);
+end;
+
+//
+// Modifier слегка не оптимально расходует память, поэтому подчищаем.
+// =============================================================================
+destructor TFWZipModifier.Destroy;
+var
+ I, A: Integer;
+begin
+ for I := 0 to Length(FReaderList) - 1 do
+ begin
+ FReaderList[I].Reader.Free;
+ for A := 0 to Length(FReaderList[I].ExDataRecords) - 1 do
+ FReaderList[I].ExDataRecords[A].Stream.Free;
+ end;
+ inherited;
+end;
+
+//
+// Процедура перекрывает заполнение блоков ExData
+// и берет эти данные из ранее сформированного архива.
+// =============================================================================
+procedure TFWZipModifier.FillExData(Stream: TStream; Index: Integer);
+var
+ NewItem: TFWZipModifierItem;
+ ReaderIndex: TReaderIndex;
+ I: Integer;
+ ExDataSize: Word;
+ ExDataRecord: TExDataRecord;
+begin
+ NewItem := TFWZipModifierItem(Item[Index]);
+ // проверка, работаем ли мы с элементом, данные которого заполняются вручную?
+ if not NewItem.UseExternalData then
+ begin
+ inherited;
+ Exit;
+ end;
+ // проверяем привязку к архиву, с елементов которого мы будем добавлять блоки ExData
+ ReaderIndex := CheckZipFileIndex(NewItem.ReaderIndex);
+ for I := 0 to Length(FReaderList[ReaderIndex].ExDataRecords) - 1 do
+ if FReaderList[ReaderIndex].ExDataRecords[I].Index = NewItem.OriginalItemIndex then
+ begin
+ // блоков может быть несколько, поэтому добавляем их все
+ ExDataRecord := FReaderList[ReaderIndex].ExDataRecords[I];
+ Stream.WriteBuffer(ExDataRecord.Tag, 2);
+ ExDataSize := ExDataRecord.Stream.Size;
+ Stream.WriteBuffer(ExDataSize, 2);
+ Stream.CopyFrom(ExDataRecord.Stream, 0);
+ end;
+end;
+
+//
+// Процедура перекрывает заполнение сьруктуры TCentralDirectoryFileHeaderEx
+// и берет эти данные из ранее сформированного архива.
+// =============================================================================
+procedure TFWZipModifier.FillItemCDFHeader(CurrentItem: TFWZipWriterItem;
+ var Value: TCentralDirectoryFileHeaderEx);
+var
+ OldItem: TFWZipReaderItemFriendly;
+ NewItem: TFWZipModifierItem;
+ Reader: TFWZipReader;
+begin
+ NewItem := TFWZipModifierItem(CurrentItem);
+ // проверка, работаем ли мы с элементом, данные которого заполняются вручную?
+ if not NewItem.UseExternalData then
+ begin
+ inherited;
+ Exit;
+ end;
+ Reader := FReaderList[NewItem.ReaderIndex].Reader;
+ OldItem := TFWZipReaderItemFriendly(Reader.Item[NewItem.OriginalItemIndex]);
+ // полностью перезаписываем все данные структуры
+ // исключением является поле RelativeOffsetOfLocalHeader
+ // но оно реинициализируется после вызова данного метода
+ Value := OldItem.CentralDirFileHeaderEx;
+end;
+
+//
+// Расширяем коллекцию
+// =============================================================================
+function TFWZipModifier.GetItemClass: TFWZipWriterItemClass;
+begin
+ Result := TFWZipModifierItem;
+end;
+
+//
+// Задача процедуры собрать все ExData в локальное хранилище,
+// чтобы их можно было присоединить к структуре архива на этапе ребилда
+// =============================================================================
+procedure TFWZipModifier.OnLoadExData(Sender: TObject; ItemIndex: Integer;
+ Tag: Word; Data: TStream);
+var
+ ReaderCount, ExDataCount: Integer;
+ ExData: TExDataRecord;
+begin
+ ExData.Index := ItemIndex;
+ ExData.Tag := Tag;
+ ExData.Stream := TMemoryStream.Create;
+ ExData.Stream.CopyFrom(Data, 0);
+ ReaderCount := Length(FReaderList);
+ ExDataCount := Length(FReaderList[ReaderCount - 1].ExDataRecords);
+ SetLength(FReaderList[ReaderCount - 1].ExDataRecords, ExDataCount + 1);
+ FReaderList[ReaderCount - 1].ExDataRecords[ExDataCount] := ExData;
+end;
+
+end.
diff --git a/prereq/fwzip/FWZipReader.pas b/prereq/fwzip/FWZipReader.pas
new file mode 100644
index 0000000..0df71bb
--- /dev/null
+++ b/prereq/fwzip/FWZipReader.pas
@@ -0,0 +1,1569 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ****************************************************************************
+// * Project : FWZip
+// * Unit Name : FWZipReader
+// * Purpose : Набор классов для распаковки ZIP архива
+// * Author : Александр (Rouse_) Багель
+// * Copyright : © Fangorn Wizards Lab 1998 - 2015.
+// * Version : 1.0.11
+// * Home Page : http://rouse.drkb.ru
+// * Home Blog : http://alexander-bagel.blogspot.ru
+// ****************************************************************************
+// * Stable Release : http://rouse.drkb.ru/components.php#fwzip
+// * Latest Source : https://github.com/AlexanderBagel/FWZip
+// ****************************************************************************
+//
+// Используемые источники:
+// ftp://ftp.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
+// http://zlib.net/zlib-1.2.5.tar.gz
+// http://www.base2ti.com/
+//
+
+unit FWZipReader;
+{$mode delphi}
+{$codepage UTF8}
+
+interface
+
+{$I fwzip.inc}
+
+uses
+ LCLIntf, LCLType, LMessages, windows,
+ SysUtils,
+ Classes,
+ Contnrs,
+ FWZipConsts,
+ FWZipCrc32,
+ FWZipCrypt,
+ FWZipStream,
+ Masks, FileUtil,
+ FWZipZLib, LazFileUtils;
+
+type
+ TFWZipReader = class;
+
+ TExtractResult = (erError, erDone, erNeedPassword, erWrongCRC32, erSkiped);
+ TPresentStream = (ssZIP64, ssNTFS);
+ TPresentStreams = set of TPresentStream;
+
+ TFWZipReaderItem = class
+ private
+ FOwner: TFWZipReader;
+ FLocalFileHeader: TLocalFileHeader;
+ FFileHeader: TCentralDirectoryFileHeaderEx;
+ FIsFolder: Boolean;
+ FOnProgress: TZipExtractItemEvent;
+ FTotalExtracted, FExtractStreamStartSize: Int64;
+ FExtractStream: TStream;
+ FItemIndex, FTag: Integer;
+ FDuplicate: TZipDuplicateEvent;
+ FPresentStreams: TPresentStreams;
+ function GetString(const Index: Integer): string;
+ protected
+ procedure DoProgress(Sender: TObject; ProgressState: TProgressState);
+ procedure DecompressorOnProcess(Sender: TObject);
+ procedure LoadExData;
+ procedure LoadStringValue(var Value: string; nSize: Cardinal;
+ CheckEncoding: Boolean);
+ procedure LoadLocalFileHeader;
+ constructor InitFromStream(Owner: TFWZipReader;
+ Index: Integer; Value: TStream);
+ protected
+ property LocalFileHeader: TLocalFileHeader read FLocalFileHeader;
+ property CentralDirFileHeader: TCentralDirectoryFileHeader
+ read FFileHeader.Header;
+ property CentralDirFileHeaderEx: TCentralDirectoryFileHeaderEx read FFileHeader;
+ property RelativeOffsetOfLocalHeader: Int64 read
+ FFileHeader.RelativeOffsetOfLocalHeader;
+ property DiskNumberStart: Integer read FFileHeader.DiskNumberStart;
+ public
+ function Extract(const Path, Password: string): TExtractResult; overload;
+ function Extract(const Path, NewFileName, Password: string): TExtractResult; overload;
+ function ExtractToStream(Value: TStream; const Password: string;
+ CheckCRC32: Boolean = True): TExtractResult;
+ property Attributes: TWin32FileAttributeData read FFileHeader.Attributes;
+ property Comment: string index 0 read GetString;
+ property ItemIndex: Integer read FItemIndex;
+ property IsFolder: Boolean read FIsFolder;
+ property FileName: string index 1 read GetString;
+ property VersionMadeBy: Word read FFileHeader.Header.VersionMadeBy;
+ property VersionNeededToExtract: Word read
+ FFileHeader.Header.VersionNeededToExtract;
+ property CompressionMethod: Word read FFileHeader.Header.CompressionMethod;
+ property LastModFileTime: Word read FFileHeader.Header.LastModFileTimeTime;
+ property LastModFileDate: Word read FFileHeader.Header.LastModFileTimeDate;
+ property Crc32: Cardinal read FFileHeader.Header.Crc32;
+ property CompressedSize: Int64 read FFileHeader.CompressedSize;
+ property PresentStreams: TPresentStreams read FPresentStreams;
+ property Tag: Integer read FTag write FTag;
+ property UncompressedSize: Int64 read FFileHeader.UncompressedSize;
+ property OnProgress: TZipExtractItemEvent
+ read FOnProgress write FOnProgress;
+ property OnDuplicate: TZipDuplicateEvent read FDuplicate write FDuplicate;
+ end;
+
+ TFWZipReader = class
+ private
+ FZIPStream, FFileStream: TStream;
+ FLocalFiles: TObjectList;
+ FZip64EOFCentralDirectoryRecord: TZip64EOFCentralDirectoryRecord;
+ FZip64EOFCentralDirectoryLocator: TZip64EOFCentralDirectoryLocator;
+ FEndOfCentralDir: TEndOfCentralDir;
+ FEndOfCentralDirComment: AnsiString;
+ FOnProgress: TZipProgressEvent;
+ FOnNeedPwd: TZipNeedPasswordEvent;
+ FTotalSizeCount, FTotalProcessedCount: Int64;
+ FPasswordList: TStringList;
+ FOnLoadExData: TZipLoadExDataEvent;
+ FException: TZipExtractExceptionEvent;
+ FDuplicate: TZipDuplicateEvent;
+ FStartZipDataOffset, FEndZipDataOffset: Int64;
+ FDefaultDuplicateAction: TDuplicateAction;
+ function GetItem(Index: Integer): TFWZipReaderItem;
+ procedure SetDefaultDuplicateAction(const Value: TDuplicateAction);
+ protected
+ property ZIPStream: TStream read FZIPStream;
+ // Rouse_ 02.10.2012
+ // Добавлены поля для указания кастомной позиции архива в стриме с данными
+ property StartZipDataOffset: Int64 read FStartZipDataOffset;
+ property EndZipDataOffset: Int64 read FEndZipDataOffset;
+ protected
+ function Zip64Present: Boolean;
+ function SizeOfCentralDirectory: Int64;
+ function TotalEntryesCount: Integer;
+ procedure LoadStringValue(var Value: AnsiString; nSize: Cardinal);
+ procedure LoadEndOfCentralDirectory;
+ procedure LoadZIP64Locator;
+ procedure LoadZip64EOFCentralDirectoryRecord;
+ procedure LoadCentralDirectoryFileHeader;
+ procedure ProcessExtractOrCheckAllData(const ExtractMask: string;
+ Path: string; CheckMode: Boolean);
+ protected
+ procedure DoProgress(Sender: TObject;
+ const FileName: string; Extracted, TotalSize: Int64;
+ ProgressState: TProgressState);
+ protected
+ property Zip64EOFCentralDirectoryRecord: TZip64EOFCentralDirectoryRecord
+ read FZip64EOFCentralDirectoryRecord;
+ property Zip64EOFCentralDirectoryLocator: TZip64EOFCentralDirectoryLocator
+ read FZip64EOFCentralDirectoryLocator;
+ property EndOfCentralDir: TEndOfCentralDir read FEndOfCentralDir;
+ public
+ constructor Create;
+ destructor Destroy; override;
+ procedure Clear;
+ function GetElementIndex(const FileName: string): Integer;
+ procedure LoadFromFile(const Value: string; SFXOffset: Integer = -1;
+ ZipEndOffset: Integer = -1);
+ procedure LoadFromStream(Value: TStream; SFXOffset: Integer = -1;
+ ZipEndOffset: Integer = -1);
+ procedure ExtractAll(const Path: string); overload;
+ procedure ExtractAll(const ExtractMask: string; Path: string); overload;
+ procedure Check(const ExtractMask: string = '');
+ function Count: Integer;
+ property DefaultDuplicateAction: TDuplicateAction
+ read FDefaultDuplicateAction write SetDefaultDuplicateAction;
+ property Item[Index: Integer]: TFWZipReaderItem read GetItem; default;
+ property Comment: AnsiString read FEndOfCentralDirComment;
+ property PasswordList: TStringList read FPasswordList;
+ property OnProgress: TZipProgressEvent read FOnProgress write FOnProgress;
+ property OnPassword: TZipNeedPasswordEvent
+ read FOnNeedPwd write FOnNeedPwd;
+ property OnLoadExData: TZipLoadExDataEvent
+ read FOnLoadExData write FOnLoadExData;
+ property OnException: TZipExtractExceptionEvent
+ read FException write FException;
+ property OnDuplicate: TZipDuplicateEvent read FDuplicate write FDuplicate;
+ end;
+
+ EWrongPasswordException = class(Exception);
+ EZipReaderItem = class(Exception);
+ EZipReader = class(Exception);
+ EZipReaderRead = class(Exception);
+
+implementation
+
+{ TFWZipReaderItem }
+
+//
+// Обработчик OnProcess у распаковщика
+// =============================================================================
+procedure TFWZipReaderItem.DecompressorOnProcess(Sender: TObject);
+begin
+ DoProgress(Sender, psInProgress);
+end;
+
+//
+// Процедура вызывает внешнее событие OnProcess
+// =============================================================================
+procedure TFWZipReaderItem.DoProgress(Sender: TObject;
+ ProgressState: TProgressState);
+begin
+ if Assigned(FOnProgress) then
+ if Sender = nil then
+ FOnProgress(Self, FileName, FTotalExtracted,
+ UncompressedSize, ProgressState)
+ else
+ begin
+ FTotalExtracted := FExtractStream.Size - FExtractStreamStartSize;
+ FOnProgress(Self, FileName, FTotalExtracted,
+ UncompressedSize, ProgressState);
+ end;
+end;
+
+//
+// Функция распаковывает текущий элемент архва в указанную папку
+// =============================================================================
+function TFWZipReaderItem.Extract(const Path, Password: string): TExtractResult;
+begin
+ Result := Extract(Path, '', Password);
+end;
+
+//
+// Функция распаковывает текущий элемент архва в указанный файл
+// =============================================================================
+function TFWZipReaderItem.Extract(
+ const Path, NewFileName, Password: string): TExtractResult;
+var
+ UnpackedFile: TFileStream;
+ FullPath: string;
+ hFile: THandle;
+ FileDate: Integer;
+ DuplicateAction: TDuplicateAction;
+begin
+ Result := erDone;
+
+ // Правка пустого и относительного пути
+ FullPath := PathCanonicalize(Path);
+ if Path = '' then
+ FullPath := GetCurrentDirUTF8; { *Преобразовано из GetCurrentDir* }
+
+ FullPath := StringReplace(
+ IncludeTrailingPathDelimiter(FullPath) + FFileHeader.FileName,
+ ZIP_SLASH, '\', [rfReplaceAll]);
+
+ // Rouse_ 23.03.2015
+ // Даем возможность поменять имя распаковываемого файла на лету
+ if NewFileName <> '' then
+ FullPath := ExtractFilePath(FullPath) + NewFileName;
+
+ if Length(FullPath) > MAX_PATH then
+ raise EZipReaderItem.CreateFmt(
+ 'Элемент архива №%d "%s" не может быть распакован.' + sLineBreak +
+ 'Общая длина пути и имени файла не должна превышать 260 символов',
+ [ItemIndex, FFileHeader.FileName]);
+ if IsFolder then
+ begin
+ ForceDirectoriesUTF8(FullPath); { *Преобразовано из ForceDirectories* }
+ Exit;
+ end;
+ ForceDirectoriesUTF8(ExtractFilePath(FullPath)); { *Преобразовано из ForceDirectories* }
+ try
+
+ // проверка на существование файла
+ if FileExistsUTF8(FullPath) { *Преобразовано из FileExists* } then
+ begin
+
+ // если файл уже существует, узнаем - как жить дальше с этим ;)
+ DuplicateAction := FOwner.DefaultDuplicateAction;
+ if Assigned(FDuplicate) then
+ FDuplicate(Self, FullPath, DuplicateAction);
+
+ case DuplicateAction of
+
+ // пропустить файл
+ daSkip:
+ begin
+ Result := erSkiped;
+ Exit;
+ end;
+
+ // перезаписать
+ daOverwrite:
+ SetFileAttributes(PChar(FullPath), FILE_ATTRIBUTE_NORMAL);
+
+ // распаковать с другим именем
+ daUseNewFilePath:
+ // если программист указал новый пусть к файлу,
+ // то о существовании директории он должен позаботиться сам
+ if not DirectoryExistsUTF8(ExtractFilePath(FullPath)) { *Преобразовано из DirectoryExists* } then
+ begin
+ Result := erSkiped;
+ Exit;
+ end;
+
+ // прервать распаковку
+ daAbort:
+ Abort;
+
+ end;
+ end;
+
+ UnpackedFile := TFileStream.Create(FullPath, fmCreate);
+ try
+ Result := ExtractToStream(UnpackedFile, Password);
+ finally
+ UnpackedFile.Free;
+ end;
+
+ if Result <> erDone then
+ begin
+ DeleteFileUTF8(FullPath); { *Преобразовано из DeleteFile* }
+ Exit;
+ end;
+
+ if IsAttributesPresent(FFileHeader.Attributes) then
+ begin
+ hFile := FileOpen(FullPath, fmOpenWrite);
+ try
+ SetFileTime(hFile,
+ @FFileHeader.Attributes.ftCreationTime,
+ @FFileHeader.Attributes.ftLastAccessTime,
+ @FFileHeader.Attributes.ftLastWriteTime);
+ finally
+ FileClose(hFile);
+ end;
+ SetFileAttributes(PChar(FullPath),
+ FFileHeader.Attributes.dwFileAttributes);
+ end
+ else
+ begin
+ FileDate :=
+ FFileHeader.Header.LastModFileTimeTime +
+ FFileHeader.Header.LastModFileTimeDate shl 16;
+ FileSetDateUTF8(FullPath,FileDate); { *Преобразовано из FileSetDate* }
+ end;
+
+ except
+ DeleteFileUTF8(FullPath); { *Преобразовано из DeleteFile* }
+ raise;
+ end;
+end;
+
+//
+// Функция распаковывает текущий элемент архва в стрим
+// =============================================================================
+function TFWZipReaderItem.ExtractToStream(Value: TStream;
+ const Password: string; CheckCRC32: Boolean): TExtractResult;
+
+ function CopyWithProgress(Src, Dst: TStream; Count: Int64;
+ Decryptor: TFWZipDecryptor): Cardinal;
+ var
+ Buff: Pointer;
+ Size: Integer;
+ begin
+ Result := $FFFFFFFF;
+ try
+ GetMem(Buff, MAXWORD);
+ try
+ Size := MAXWORD;
+ DoProgress(nil, psInitialization);
+ while Size = MAXWORD do
+ begin
+ if Count - FTotalExtracted < MAXWORD then
+ Size := Count - FTotalExtracted;
+ if Src.Read(Buff^, Size) <> Size then
+ raise EZipReaderRead.CreateFmt(
+ 'Ошибка чтения данных элемента №%d "%s".', [ItemIndex, FileName]);
+ if Decryptor <> nil then
+ Decryptor.DecryptBuffer(Buff, Size);
+ Result := CRC32Calc(Result, Buff, Size);
+ Dst.WriteBuffer(Buff^, Size);
+ Inc(FTotalExtracted, Size);
+ DoProgress(nil, psInProgress);
+ end;
+ DoProgress(nil, psFinalization);
+ finally
+ FreeMem(Buff);
+ end;
+ Result := Result xor $FFFFFFFF;
+ except
+ DoProgress(nil, psException);
+ raise;
+ end;
+ end;
+
+const
+ CompressionMetods: array [0..12] of string = (
+ 'Store',
+ 'Shrunk',
+ 'Reduced1',
+ 'Reduced2',
+ 'Reduced3',
+ 'Reduced4',
+ 'Imploded',
+ 'Tokenizing compression algorithm',
+ 'Deflate',
+ 'Deflate64',
+ 'PKWARE Data Compression Library Imploding',
+ 'PKWARE',
+ 'BZIP2'
+ );
+var
+ Decompressor: TZDecompressionStream;
+ ZipItemStream: TFWZipItemStream;
+ Decryptor: TFWZipDecryptor;
+ RealCompressedSize: Int64;
+ CurrItemCRC32: Cardinal;
+ CRC32Stream: TFWZipCRC32Stream;
+begin
+ Result := erError;
+ CurrItemCRC32 := 0;
+ FTotalExtracted := 0;
+ Decryptor := nil;
+ try
+ if IsFolder then Exit;
+
+ // Данные для распаковки находятся сразу за LocalFileHeader.
+ // Для получения оффсета на начало данных необходимо распарсить
+ // данную структуру включая блоки с дополнительной информацией.
+ if FFileHeader.DataOffset = 0 then
+ LoadLocalFileHeader;
+
+ FOwner.FZIPStream.Position := FFileHeader.DataOffset;
+ RealCompressedSize := FFileHeader.CompressedSize;
+
+ // Если файл зашифрован, необходимо инициализировать ключ для распаковки
+ if FFileHeader.Header.GeneralPurposeBitFlag and PBF_CRYPTED <> 0 then
+ begin
+
+ if FFileHeader.Header.GeneralPurposeBitFlag and
+ PBF_STRONG_CRYPT <> 0 then
+ raise EZipReaderItem.CreateFmt(
+ 'Ошибка извлечения данных элемента №%d "%s".' + sLineBreak +
+ 'Не поддерживаемый режим шифрования',
+ [ItemIndex, FileName]);
+
+ if Password = '' then
+ begin
+ // пароль не может быть пустым
+ Result := erNeedPassword;
+ Exit;
+ end;
+ Decryptor := TFWZipDecryptor.Create(AnsiString(Password));
+ if not Decryptor.LoadEncryptionHeader(FOwner.FZIPStream,
+ FFileHeader.Header.GeneralPurposeBitFlag and PBF_DESCRIPTOR <> 0,
+ FFileHeader.Header.Crc32,
+ FFileHeader.Header.LastModFileTimeTime +
+ FFileHeader.Header.LastModFileTimeDate shl 16) then
+ begin
+ // ошика инициализации ключа
+ Result := erNeedPassword;
+ Exit;
+ end
+ else
+ // если ключ инициализирован успешно - вычитаем из сжатого размера
+ // размер заголовка инициализации ключа
+ Dec(RealCompressedSize, EncryptedHeaderSize);
+ end;
+
+ case FFileHeader.Header.CompressionMethod of
+ Z_NO_COMPRESSION:
+ begin
+ CurrItemCRC32 :=
+ CopyWithProgress(FOwner.FZIPStream, Value,
+ UncompressedSize, Decryptor);
+ // Rouse_ 11.03.2011
+ // А выставить результат то и забыли.
+ // Cпасибо Ромкину за обнаружение косяка
+ Result := erDone;
+ end;
+ Z_DEFLATED:
+ begin
+
+ // TFWZipItemStream выступает как посредник между FOwner.FZIPStream
+ // и TDecompressionStream. Его задача добавить в передаваемый
+ // буффер данных отсутствующий ZLib заголовок и расшифровать
+ // данные при необходимости
+ ZipItemStream := TFWZipItemStream.Create(FOwner.FZIPStream,
+ nil, Decryptor,
+ FFileHeader.Header.GeneralPurposeBitFlag and 6,
+ RealCompressedSize
+ {$IFNDEF USE_AUTOGENERATED_ZLIB_HEADER}
+ + 4 // буффер, он все равно не используется,
+ // но нужен для завершения ZInflate при использовании windowBits
+ // особенно для архивов запакованных 7Zip
+ {$ENDIF}
+ );
+ try
+ Decompressor := TZDecompressionStream.Create(
+ ZipItemStream, defaultWindowBits);
+ try
+ Decompressor.OnProgress := DecompressorOnProcess;
+ FExtractStreamStartSize := Value.Size;
+ FExtractStream := Value;
+ // TFWZipCRC32Stream выступает как посредник между
+ // TDecompressionStream и результирующим стримом,
+ // в который происходит распаковка данных.
+ // Его задача отследить все распакованные блоки данных
+ // и рассчитать их контрольную сумму
+ DoProgress(Decompressor, psInitialization);
+ CRC32Stream := TFWZipCRC32Stream.Create(Value);
+ try
+ try
+ CRC32Stream.CopyFrom(Decompressor, UncompressedSize);
+ except
+ on E: EReadError do
+ raise EZipReaderRead.CreateFmt(
+ 'Ошибка чтения данных элемента №%d "%s".', [ItemIndex, FileName]);
+
+ // Rouse_ 04.04.2010
+ // Ранее это исключенияе было EDecompressionError
+ // Поэтому привяжемся к базовому исключению EZLibError
+ // on E: EZDecompressionError do
+ on E: EZLibError do
+ begin
+ if FFileHeader.Header.GeneralPurposeBitFlag and
+ PBF_CRYPTED <> 0 then
+ begin
+ // Ошибка может подняться из-за того что инициализация
+ // криптозаголовка прошла успешно, но пароль был указан не верный
+ // Такое может произойти, т.к. количество коллизий
+ // при проверке заголовка очень велико
+ Result := erNeedPassword;
+ Exit;
+ end
+ else
+ DoProgress(Decompressor, psException);
+ raise EZipReaderRead.CreateFmt(
+ 'Ошибка распаковки данных элемента №%d "%s".' + sLineBreak +
+ E.ClassName + ': ' + E.Message, [ItemIndex, FileName]);
+ end;
+
+ // Rouse_ 01.11.2013
+ // Для остальных исключений тоже нужно говорить с каким элементом беда приключилась.
+ on E: Exception do
+ raise EZipReaderRead.CreateFmt(
+ 'Ошибка распаковки данных элемента №%d "%s".' + sLineBreak +
+ E.ClassName + ': ' + E.Message, [ItemIndex, FileName]);
+
+ end;
+ CurrItemCRC32 := CRC32Stream.CRC32;
+ finally
+ CRC32Stream.Free;
+ end;
+ DoProgress(Decompressor, psFinalization);
+ Result := erDone;
+ finally
+ Decompressor.Free;
+ end;
+ finally
+ ZipItemStream.Free;
+ end;
+ end;
+ 1..7, 9..12:
+ raise EZipReaderItem.CreateFmt(
+ 'Ошибка извлечения данных элемента №%d "%s".' + sLineBreak +
+ 'Не поддерживаемый алгоритм декомпрессии "%s"',
+ [ItemIndex, FileName, CompressionMetods[CompressionMethod]]);
+ else
+ raise EZipReaderItem.CreateFmt(
+ 'Ошибка извлечения данных элемента №%d "%s".' + sLineBreak +
+ 'Не поддерживаемый алгоритм декомпрессии (%d)',
+ [ItemIndex, FileName, FFileHeader.Header.CompressionMethod]);
+ end;
+ if CurrItemCRC32 <> Crc32 then
+ if CheckCRC32 then
+ raise EZipReaderItem.CreateFmt(
+ 'Ошибка извлечения данных элемента №%d "%s".' + sLineBreak +
+ 'Неверная контрольная сумма.',
+ [ItemIndex, FileName])
+ else
+ Result := erWrongCRC32;
+ finally
+ Decryptor.Free;
+ end;
+end;
+
+//
+// =============================================================================
+function TFWZipReaderItem.GetString(const Index: Integer): string;
+begin
+ case Index of
+ 0: Result := FFileHeader.FileComment;
+ 1: Result := FFileHeader.FileName;
+ end;
+end;
+
+//
+// Конструктор элемента архива.
+// Инициализация класса происходит на основе данных из архива
+// =============================================================================
+constructor TFWZipReaderItem.InitFromStream(Owner: TFWZipReader;
+ Index: Integer; Value: TStream);
+var
+ Len: Integer;
+begin
+ inherited Create;
+
+ FOwner := Owner;
+ FItemIndex := Index;
+ ZeroMemory(@FFileHeader, SizeOf(TCentralDirectoryFileHeaderEx));
+
+ if Owner.ZIPStream.Read(FFileHeader.Header,
+ SizeOf(TCentralDirectoryFileHeader)) <> SizeOf(TCentralDirectoryFileHeader) then
+ raise EZipReaderRead.CreateFmt(
+ 'Отсутствуют данные TCentralDirectoryFileHeader элемента №%d', [ItemIndex]);
+
+ if FFileHeader.Header.CentralFileHeaderSignature <>
+ CENTRAL_FILE_HEADER_SIGNATURE then
+ raise EZipReaderItem.CreateFmt(
+ 'Ошибка чтения структуры TCentralDirectoryFileHeader элемента №%d', [ItemIndex]);
+
+ LoadStringValue(FFileHeader.FileName, FFileHeader.Header.FilenameLength, True);
+
+ FIsFolder := FFileHeader.Header.ExternalFileAttributes and faDirectory <> 0;
+
+ // Rouse_ 31.08.2015
+ // Если используем UTF8 то FilenameLength это размер в байтах а не в символах
+ // поэтому вместо этого:
+ //if FFileHeader.Header.FilenameLength > 0 then
+ // FIsFolder := FIsFolder or
+ // (FFileHeader.FileName[FFileHeader.Header.FilenameLength] = ZIP_SLASH);
+ // пишем вот так:
+ Len := Length(FFileHeader.FileName);
+ if Len > 0 then
+ FIsFolder := FIsFolder or
+ (FFileHeader.FileName[Len] = ZIP_SLASH);
+
+ // Следующие 4 параметра могут быть выставлены в -1 из-за переполнения
+ // и их реальные значения будут содержаться в блоке расширенных данных.
+ // Запоминаем их текущие значения.
+ // В случае если какой-либо из параметров выставлен в -1,
+ // его значение поменяется при вызове процедуры LoadExData.
+ FFileHeader.UncompressedSize := FFileHeader.Header.UncompressedSize;
+ FFileHeader.CompressedSize := FFileHeader.Header.CompressedSize;
+ FFileHeader.RelativeOffsetOfLocalHeader :=
+ FFileHeader.Header.RelativeOffsetOfLocalHeader;
+ FFileHeader.DiskNumberStart := FFileHeader.Header.DiskNumberStart;
+
+ LoadExData;
+
+ LoadStringValue(FFileHeader.FileComment,
+ FFileHeader.Header.FileCommentLength, False);
+
+ // часть информации дублируется в расширенном заголовке
+ // необходимо ее заполнить
+ FFileHeader.Attributes.dwFileAttributes :=
+ FFileHeader.Header.ExternalFileAttributes;
+ FFileHeader.Attributes.nFileSizeHigh :=
+ Cardinal(FFileHeader.UncompressedSize shr 32);
+ FFileHeader.Attributes.nFileSizeLow :=
+ FFileHeader.UncompressedSize and MAXDWORD;
+end;
+
+//
+// Процедура зачитывает дополнительные данные о элементе
+// =============================================================================
+procedure TFWZipReaderItem.LoadExData;
+var
+ Buff, EOFBuff: Pointer;
+ BuffCount: Integer;
+ HeaderID, BlockSize: Word;
+
+ function GetOffset(Value: Integer): Pointer;
+ begin
+ Result := Pointer(Integer(EOFBuff) - Value);
+ end;
+
+var
+ ExDataStream: TMemoryStream;
+begin
+ if FFileHeader.Header.ExtraFieldLength = 0 then Exit;
+ GetMem(Buff, FFileHeader.Header.ExtraFieldLength);
+ try
+ BuffCount := FFileHeader.Header.ExtraFieldLength;
+
+ if FOwner.ZIPStream.Read(Buff^, BuffCount) <> BuffCount then
+ raise EZipReaderRead.CreateFmt(
+ 'Отсутствуют данные поля ExtraField элемента №%d "%s"', [ItemIndex, FileName]);
+
+ EOFBuff := Pointer(Integer(Buff) + BuffCount);
+ while BuffCount > 0 do
+ begin
+ HeaderID := PWord(GetOffset(BuffCount))^;
+ Dec(BuffCount, 2);
+ BlockSize := PWord(GetOffset(BuffCount))^;
+ Dec(BuffCount, 2);
+ case HeaderID of
+ SUPPORTED_EXDATA_ZIP64:
+ begin
+
+ {
+ -ZIP64 Extended Information Extra Field (0x0001):
+ ===============================================
+
+ The following is the layout of the ZIP64 extended
+ information "extra" block. If one of the size or
+ offset fields in the Local or Central directory
+ record is too small to hold the required data,
+ a ZIP64 extended information record is created.
+ The order of the fields in the ZIP64 extended
+ information record is fixed, but the fields will
+ only appear if the corresponding Local or Central
+ directory record field is set to 0xFFFF or 0xFFFFFFFF.
+
+ Note: all fields stored in Intel low-byte/high-byte order.
+
+ Value Size Description
+ ----- ---- -----------
+ (ZIP64) 0x0001 2 bytes Tag for this "extra" block type
+ Size 2 bytes Size of this "extra" block
+ Original
+ Size 8 bytes Original uncompressed file size
+ Compressed
+ Size 8 bytes Size of compressed data
+ Relative Header
+ Offset 8 bytes Offset of local header record
+ Disk Start
+ Number 4 bytes Number of the disk on which
+ this file starts
+
+ This entry in the Local header must include BOTH original
+ and compressed file sizes.
+ }
+
+ if FFileHeader.UncompressedSize = MAXDWORD then
+ begin
+ if BuffCount < 8 then Break;
+ FFileHeader.UncompressedSize := PInt64(GetOffset(BuffCount))^;
+ Dec(BuffCount, 8);
+ Dec(BlockSize, 8);
+ end;
+ if FFileHeader.CompressedSize = MAXDWORD then
+ begin
+ if BuffCount < 8 then Break;
+ FFileHeader.CompressedSize := PInt64(GetOffset(BuffCount))^;
+ Dec(BuffCount, 8);
+ Dec(BlockSize, 8);
+ end;
+ if FFileHeader.RelativeOffsetOfLocalHeader = MAXDWORD then
+ begin
+ if BuffCount < 8 then Break;
+ FFileHeader.RelativeOffsetOfLocalHeader := PInt64(GetOffset(BuffCount))^;
+ Dec(BuffCount, 8);
+ Dec(BlockSize, 8);
+ end;
+ if FFileHeader.DiskNumberStart = MAXWORD then
+ begin
+ if BuffCount < 4 then Break;
+ FFileHeader.DiskNumberStart := PCardinal(GetOffset(BuffCount))^;
+ Dec(BuffCount, 4);
+ Dec(BlockSize, 4);
+ end;
+ Dec(BuffCount, BlockSize);
+ Include(FPresentStreams, ssZIP64);
+ end;
+
+ SUPPORTED_EXDATA_NTFSTIME:
+ begin
+
+ {
+ -PKWARE Win95/WinNT Extra Field (0x000a):
+ =======================================
+
+ The following description covers PKWARE's "NTFS" attributes
+ "extra" block, introduced with the release of PKZIP 2.50 for
+ Windows. (Last Revision 20001118)
+
+ (Note: At this time the Mtime, Atime and Ctime values may
+ be used on any WIN32 system.)
+ [Info-ZIP note: In the current implementations, this field has
+ a fixed total data size of 32 bytes and is only stored as local
+ extra field.]
+
+ Value Size Description
+ ----- ---- -----------
+ (NTFS) 0x000a Short Tag for this "extra" block type
+ TSize Short Total Data Size for this block
+ Reserved Long for future use
+ Tag1 Short NTFS attribute tag value #1
+ Size1 Short Size of attribute #1, in bytes
+ (var.) SubSize1 Attribute #1 data
+ .
+ .
+ .
+ TagN Short NTFS attribute tag value #N
+ SizeN Short Size of attribute #N, in bytes
+ (var.) SubSizeN Attribute #N data
+
+ For NTFS, values for Tag1 through TagN are as follows:
+ (currently only one set of attributes is defined for NTFS)
+
+ Tag Size Description
+ ----- ---- -----------
+ 0x0001 2 bytes Tag for attribute #1
+ Size1 2 bytes Size of attribute #1, in bytes (24)
+ Mtime 8 bytes 64-bit NTFS file last modification time
+ Atime 8 bytes 64-bit NTFS file last access time
+ Ctime 8 bytes 64-bit NTFS file creation time
+
+ The total length for this block is 28 bytes, resulting in a
+ fixed size value of 32 for the TSize field of the NTFS block.
+
+ The NTFS filetimes are 64-bit unsigned integers, stored in Intel
+ (least significant byte first) byte order. They determine the
+ number of 1.0E-07 seconds (1/10th microseconds!) past WinNT "epoch",
+ which is "01-Jan-1601 00:00:00 UTC".
+ }
+
+ // проверяем размерность поля с учетом примечания:
+ // this field has a fixed total data size of 32 bytes
+
+ // если размер буффера меньше 32 байт - то выходим из процедуры
+ if BuffCount < 32 then Break;
+
+ // если же он не равер 32 байтам,
+ // то просто пропускаем его и ереходим к слежующей записи
+ if BlockSize <> 32 then
+ begin
+ Dec(BuffCount, BlockSize);
+ Continue;
+ end;
+
+ // пропускаем поле Reserved
+ Dec(BuffCount, 4);
+
+ // Проверяем поле Tag
+ if PWord(GetOffset(BuffCount))^ <> 1 then
+ begin
+ Dec(BuffCount, BlockSize);
+ Continue;
+ end;
+ Dec(BuffCount, 2);
+
+ // Проверяем размер блока данных
+ if PWord(GetOffset(BuffCount))^ <> SizeOf(TNTFSFileTime) then
+ begin
+ Dec(BuffCount, BlockSize);
+ Continue;
+ end;
+ Dec(BuffCount, 2);
+
+ // Читаем сами данные
+ FFileHeader.Attributes.ftLastWriteTime := PFileTime(GetOffset(BuffCount))^;
+ Dec(BuffCount, SizeOf(TFileTime));
+ FFileHeader.Attributes.ftLastAccessTime := PFileTime(GetOffset(BuffCount))^;
+ Dec(BuffCount, SizeOf(TFileTime));
+ FFileHeader.Attributes.ftCreationTime := PFileTime(GetOffset(BuffCount))^;
+ Dec(BuffCount, SizeOf(TFileTime));
+ Include(FPresentStreams, ssNTFS);
+ end;
+ else
+ if Assigned(FOwner.OnLoadExData) then
+ begin
+ ExDataStream := TMemoryStream.Create;
+ try
+ ExDataStream.WriteBuffer(GetOffset(BuffCount)^, BlockSize);
+ ExDataStream.Position := 0;
+ FOwner.OnLoadExData(Self, FItemIndex, HeaderID, ExDataStream);
+ finally
+ ExDataStream.Free;
+ end;
+ end;
+ Dec(BuffCount, BlockSize);
+ end;
+ end;
+ finally
+ FreeMem(Buff);
+ end;
+end;
+
+//
+// Процедура зачитывает и проверяет валидность структуры LocalFileHeader
+// Задача процедуры получить правильное значение оффсета на начало
+// запакованного блока данных.
+// =============================================================================
+procedure TFWZipReaderItem.LoadLocalFileHeader;
+begin
+ // Rouse_ 02.10.2012
+ // При чтении учитываем оффсет на начало архива StartZipDataOffset
+ FOwner.ZIPStream.Position :=
+ FFileHeader.RelativeOffsetOfLocalHeader + FOwner.StartZipDataOffset;
+
+ if FOwner.ZIPStream.Read(FLocalFileHeader,
+ SizeOf(TLocalFileHeader)) <> SizeOf(TLocalFileHeader) then
+ raise EZipReaderRead.CreateFmt(
+ 'Отсутстсвуют данные TLocalFileHeader элемента №%d "%s"', [ItemIndex, FileName]);
+
+ if FLocalFileHeader.LocalFileHeaderSignature <>
+ LOCAL_FILE_HEADER_SIGNATURE then
+ raise EZipReaderItem.CreateFmt(
+ 'Ошибка чтения TLocalFileHeader элемента №%d "%s"', [ItemIndex, FileName]);
+
+ FFileHeader.DataOffset := FOwner.ZIPStream.Position +
+ FLocalFileHeader.FilenameLength + FLocalFileHeader.ExtraFieldLength;
+end;
+
+//
+// Процедура зачитывает строковое значение и переводит его в Ansi формат
+// =============================================================================
+procedure TFWZipReaderItem.LoadStringValue(var Value: string;
+ nSize: Cardinal; CheckEncoding: Boolean);
+var
+ aString: AnsiString;
+begin
+ if Integer(nSize) > 0 then
+ begin
+ SetLength(aString, nSize);
+
+ if FOwner.ZIPStream.Read(aString[1], nSize) <> Integer(nSize) then
+ raise EZipReaderRead.CreateFmt(
+ 'Ошибка чтения строковых данных элемента №%d "%s"', [ItemIndex, FileName]);
+
+ // Rouse_ 13.06.2013
+ // 11 бит отвечает за UTF8 кодировку
+ if FFileHeader.Header.GeneralPurposeBitFlag and PBF_UTF8 = PBF_UTF8 then
+ begin
+ {$IFDEF UNICODE}
+ Value := string(UTF8ToUnicodeString(aString))
+ {$ELSE}
+ Value := string(UTF8Decode(aString));
+ // в неюникодных версиях Delphi юникодные символы будут преобразованы в знаки вопроса
+ if CheckEncoding then
+ Value := StringReplace(Value, '?', '_', [rfReplaceAll]);
+ {$ENDIF}
+ end
+ else
+ begin
+ OemToAnsi(@aString[1], @aString[1]);
+ Value := string(aString);
+ end;
+ end;
+end;
+
+{ TFWZipReader }
+
+//
+// Процедура производит проверку архива с учетом маски файла в архиве
+// Данные распаковываются, но не сохраняются
+// =============================================================================
+procedure TFWZipReader.Check(const ExtractMask: string);
+begin
+ ProcessExtractOrCheckAllData(ExtractMask, '', True);
+end;
+
+//
+// Процедура очищает данные о открытом ранее архиве
+// =============================================================================
+procedure TFWZipReader.Clear;
+begin
+ ZeroMemory(@FZip64EOFCentralDirectoryRecord,
+ SizeOf(TZip64EOFCentralDirectoryRecord));
+ ZeroMemory(@FZip64EOFCentralDirectoryLocator,
+ SizeOf(TZip64EOFCentralDirectoryLocator));
+ ZeroMemory(@FEndOfCentralDir, SizeOf(TEndOfCentralDir));
+ FLocalFiles.Clear;
+ FreeAndNil(FFileStream);
+end;
+
+//
+// Функция возвращает количество элементов открытого архива
+// =============================================================================
+function TFWZipReader.Count: Integer;
+begin
+ Result := FLocalFiles.Count;
+end;
+
+// =============================================================================
+constructor TFWZipReader.Create;
+begin
+ inherited;
+ FLocalFiles := TObjectList.Create;
+ FPasswordList := TStringList.Create;
+ FPasswordList.Duplicates := dupIgnore;
+ FPasswordList.Sorted := True;
+ DefaultDuplicateAction := daSkip;
+end;
+
+// =============================================================================
+destructor TFWZipReader.Destroy;
+begin
+ FPasswordList.Free;
+ FLocalFiles.Free;
+ FFileStream.Free;
+ inherited;
+end;
+
+//
+// Процедура вызывает обработчик OnProgress
+// =============================================================================
+procedure TFWZipReader.DoProgress(Sender: TObject; const FileName: string;
+ Extracted, TotalSize: Int64; ProgressState: TProgressState);
+var
+ Percent, TotalPercent: Byte;
+ Cancel: Boolean;
+begin
+ if Assigned(FOnProgress) then
+ begin
+ if TotalSize = 0 then
+ if ProgressState in [psStart, psInitialization] then
+ Percent := 0
+ else
+ Percent := 100
+ else
+ if ProgressState = psEnd then
+ Percent := 100
+ else
+ Percent := Round(Extracted / (TotalSize / 100));
+ if FTotalSizeCount = 0 then
+ TotalPercent := 100
+ else
+ TotalPercent :=
+ Round((FTotalProcessedCount + Extracted) / (FTotalSizeCount / 100));
+ Cancel := False;
+ FOnProgress(Self, FileName, Percent, TotalPercent, Cancel, ProgressState);
+ if Cancel then Abort;
+ end;
+end;
+
+//
+// Процедура производит автоматическую распаковку архива в указанную папку
+// с учетом маски файла в архиве
+// =============================================================================
+procedure TFWZipReader.ExtractAll(const ExtractMask: string; Path: string);
+begin
+ ProcessExtractOrCheckAllData(ExtractMask, Path, False);
+end;
+
+//
+// Процедура производит автоматическую распаковку архива в указанную папку
+// =============================================================================
+procedure TFWZipReader.ExtractAll(const Path: string);
+begin
+ ExtractAll('', Path);
+end;
+
+//
+// Функция возвращает индекс элемента по его имени
+// =============================================================================
+function TFWZipReader.GetElementIndex(const FileName: string): Integer;
+var
+ I: Integer;
+begin
+ Result := -1;
+ for I := 0 to Count - 1 do
+ if AnsiCompareText(Item[I].FileName, FileName) = 0 then
+ begin
+ Result := I;
+ Break;
+ end;
+end;
+
+//
+// Функция возвращает элемент архива по его индексу
+// =============================================================================
+function TFWZipReader.GetItem(Index: Integer): TFWZipReaderItem;
+begin
+ Result := TFWZipReaderItem(FLocalFiles[Index]);
+end;
+
+//
+// Процедура зачитывает центральную директорию архива
+// =============================================================================
+procedure TFWZipReader.LoadCentralDirectoryFileHeader;
+var
+ EndOfLoadCentralDirectory: Int64;
+begin
+ EndOfLoadCentralDirectory := FZIPStream.Position + SizeOfCentralDirectory;
+ while FZIPStream.Position < EndOfLoadCentralDirectory do
+ FLocalFiles.Add(TFWZipReaderItem.InitFromStream(Self, Count, FZIPStream));
+
+ // Rouse_ 01.11.2013
+ // Исключение будем поднимать только в случае если заявленное кол-во элементов
+ // больше чем удалось прочитать.
+ // Ибо попался мне один архив в котором кол-во элементов 95188,
+ // (превышение по количеству элементов и нужно использовать ZIP64),
+ // но ZIP64 не использовался и поле TotalNumberOfEntries хранило значение 29652
+ // Собственно что и равняется 95188 - $10000
+
+ // Поэтому вместо такого условия:
+ //if Count <> TotalEntryesCount then
+ //пишем вот так:
+ if Count < TotalEntryesCount then
+
+ raise EZipReader.CreateFmt(
+ 'Ошибка чтения центральной директории. ' + sLineBreak +
+ 'Прочитанное количество элементов (%d) не соответствует заявленному (%d).',
+ [Count, TotalEntryesCount]);
+end;
+
+//
+// Процедура проеряет валидность структуры EndOfCentralDirectory
+// Задача процедуры получить оффсет на начало CentralDirectory
+// =============================================================================
+procedure TFWZipReader.LoadEndOfCentralDirectory;
+var
+ Zip64LocatorOffset: Int64;
+begin
+ // Согласно спецификации в случае наличия 64-битных структур
+ // TZip64EOFCentralDirectoryLocator идет сразу перед EndOfCentralDirectory.
+ // Запоминаем оффсет на предполагаемую позицию данной структуры.
+ Zip64LocatorOffset := FZIPStream.Position -
+ SizeOf(TZip64EOFCentralDirectoryLocator);
+
+ if FZIPStream.Read(FEndOfCentralDir, SizeOf(TEndOfCentralDir)) <>
+ SizeOf(TEndOfCentralDir) then
+ raise EZipReader.Create('Отсутствуют данные структуры TEndOfCentralDir.');
+
+ if FEndOfCentralDir.NumberOfThisDisk <> 0 then
+ raise EZipReader.Create('Многотомные архивы не поддерживаются.');
+
+ if FEndOfCentralDir.EndOfCentralDirSignature <>
+ END_OF_CENTRAL_DIR_SIGNATURE then
+ raise EZipReader.Create('Ошибка чтения структуры TEndOfCentralDir.');
+
+ LoadStringValue(FEndOfCentralDirComment,
+ FEndOfCentralDir.ZipfileCommentLength);
+
+ {
+ 6) If one of the fields in the end of central directory
+ record is too small to hold required data, the field
+ should be set to -1 (0xFFFF or 0xFFFFFFFF) and the
+ Zip64 format record should be created.
+ }
+
+ if (FEndOfCentralDir.NumberOfThisDisk = MAXWORD) or
+ (FEndOfCentralDir.NumberOfTheDiskWithTheStart = MAXWORD) or
+ (FEndOfCentralDir.TotalNumberOfEntriesOnThisDisk = MAXWORD) or
+ (FEndOfCentralDir.TotalNumberOfEntries = MAXWORD) or
+ (FEndOfCentralDir.SizeOfTheCentralDirectory = MAXDWORD) or
+ (FEndOfCentralDir.OffsetOfStartOfCentralDirectory = MAXDWORD) then
+ begin
+ // Одна из позиций не содержит валидных данных
+ // Согласно спецификации их необходимо получить через Zip64Locator
+ FZIPStream.Position := Zip64LocatorOffset + StartZipDataOffset;
+ LoadZIP64Locator;
+ end
+ else
+ // Rouse_ 02.10.2012
+ // При чтении учитываем оффсет на начало архива StartZipDataOffset
+ FZIPStream.Position :=
+ FEndOfCentralDir.OffsetOfStartOfCentralDirectory + StartZipDataOffset;
+end;
+
+//
+// Процедура открывает архив по указанному пути
+// =============================================================================
+procedure TFWZipReader.LoadFromFile(const Value: string;
+ SFXOffset, ZipEndOffset: Integer);
+begin
+ // Rouse_ 20.02.2012
+ // Если TFileStream не создался FFileStream может содержать реф на разрушенный TFileStream,
+ // созданный при предыдущем вызове LoadFromFile,
+ // что приведет к ошибке в деструкторе при разрушении FFileStream
+ // Спасибо v1ctar за найденый глюк
+ //FFileStream.Free;
+ FreeAndNil(FFileStream);
+ FFileStream := TFileStream.Create(Value, fmOpenRead or fmShareDenyWrite);
+ LoadFromStream(FFileStream, SFXOffset, ZipEndOffset);
+end;
+
+//
+// Процерура открывает архив из переданного стрима
+// =============================================================================
+procedure TFWZipReader.LoadFromStream(Value: TStream;
+ SFXOffset, ZipEndOffset: Integer);
+var
+ Buff: Pointer;
+ I, BuffSize, SignOffset: Integer;
+ Offset, EndOfCentralDirectoryOffset: Int64;
+ Cursor: PByte;
+begin
+ FLocalFiles.Clear;
+ FZIPStream := Value;
+
+ // Rouse_ 02.10.2012
+ // Теперь могут передаватся оффсеты на расположение архива в стриме с данными
+ // SFXOffset указывает на начало архива
+ // ZipEndOffset указывает на позицию после которой не производится поиск
+ // сигнатуры EndOfCentralDir
+ if SFXOffset < 0 then
+ FStartZipDataOffset := 0
+ else
+ FStartZipDataOffset := SFXOffset;
+
+ if ZipEndOffset < 0 then
+ FEndZipDataOffset := Value.Size
+ else
+ FEndZipDataOffset := ZipEndOffset;
+
+ // Ищем сигнатуру EndOfCentralDir
+ BuffSize := $FFFF;
+
+ // Rouse_ 13.03.2015
+ // Если архив пустой, то END_OF_CENTRAL_DIR_SIGNATURE будет распологаться
+ // по нулевому оффсету, стало быть ноль - это тоже правильное значение
+ // Поэтому флаг отсутствия данного маркера будет не ноль, а отрицательное значение
+ EndOfCentralDirectoryOffset := -1;
+ //EndOfCentralDirectoryOffset := 0;
+
+ Offset := EndZipDataOffset;
+ SignOffset := 0;
+ GetMem(Buff, BuffSize);
+ try
+ while Offset > StartZipDataOffset do
+ begin
+ Dec(Offset, BuffSize - SignOffset);
+ if Offset < StartZipDataOffset then
+ begin
+ Inc(BuffSize, Offset - StartZipDataOffset);
+ Offset := StartZipDataOffset;
+ end;
+ Value.Position := Offset;
+
+ if Value.Read(Buff^, BuffSize) <> BuffSize then
+ raise EZipReaderRead.Create('Ошибка чтения данных при поиске END_OF_CENTRAL_DIR_SIGNATURE');
+
+ // Rouse_ 14.02.2013
+ // Если в архиве будет незапакованый ZIP архив,
+ // то есть большой шанс что первую END_OF_CENTRAL_DIR_SIGNATURE мы
+ // обнаружим у него, а не у нашего архива
+
+ {
+ Cursor := Buff;
+ for I := 0 to BuffSize - 1 do
+ begin
+ if PCardinal(Cursor)^ = END_OF_CENTRAL_DIR_SIGNATURE then
+ begin
+ EndOfCentralDirectoryOffset := Offset + I;
+ Break;
+ end
+ else
+ Inc(Cursor);
+ }
+
+ // поэтому сигнатуру END_OF_CENTRAL_DIR_SIGNATURE будем искать вот так
+ Cursor := PByte(PAnsiChar(Buff) + BuffSize - 5);
+ for I := BuffSize - 5 downto 0 do
+ begin
+ if PCardinal(Cursor)^ = END_OF_CENTRAL_DIR_SIGNATURE then
+ begin
+ EndOfCentralDirectoryOffset := Offset + I;
+ Break;
+ end
+ else
+ Dec(Cursor);
+ end;
+
+ if EndOfCentralDirectoryOffset >= 0 then
+ Break;
+
+ // Rouse_ 14.02.2013
+ // Сигнатура может располагаться на границе между двумя буферами
+ // поэтому чтобы считать граничное состояние делаем поправку
+ SignOffset := 4;
+
+ end;
+ finally
+ FreeMem(Buff);
+ end;
+ if EndOfCentralDirectoryOffset < 0 then
+ raise EZipReader.Create('Не найдена сигнатура END_OF_CENTRAL_DIR_SIGNATURE.');
+
+ // Зачитываем саму структуру EndOfCentralDirectory
+ // При необходимости будут зачитаны данные из 64 битных структур
+ Value.Position := EndOfCentralDirectoryOffset;
+ LoadEndOfCentralDirectory;
+
+ // Теперь указатель стрима выставлен на начало структуры CentralDirectory
+ // Зачитываем ее саму
+ LoadCentralDirectoryFileHeader;
+end;
+
+//
+// Процедура зачитывает строковое значение и переводит его в Ansi формат
+// =============================================================================
+procedure TFWZipReader.LoadStringValue(var Value: AnsiString; nSize: Cardinal);
+begin
+ if Integer(nSize) > 0 then
+ begin
+ SetLength(Value, nSize);
+
+ if FZIPStream.Read(Value[1], nSize) <> Integer(nSize) then
+ raise EZipReaderRead.Create('Ошибка чтения коментария к архиву');
+
+ OemToAnsi(@Value[1], @Value[1]);
+ end;
+end;
+
+//
+// Процедура проверяет валидность структуры Zip64EOFCentralDirectoryRecord
+// Задача процедуру получить оффсет на CentralDirectory
+// =============================================================================
+procedure TFWZipReader.LoadZip64EOFCentralDirectoryRecord;
+begin
+ FZIPStream.ReadBuffer(FZip64EOFCentralDirectoryRecord,
+ SizeOf(TZip64EOFCentralDirectoryRecord));
+
+ if not Zip64Present then
+ raise EZipReader.Create(
+ 'Ошибка чтения структуры TZip64EOFCentralDirectoryRecord');
+
+ // Rouse_ 02.10.2012
+ // При чтении учитываем оффсет на начало архива StartZipDataOffset
+ FZIPStream.Position := FZip64EOFCentralDirectoryRecord.Offset +
+ StartZipDataOffset;
+end;
+
+//
+// Процедура проверяет валидность структуры ZIP64Locator
+// Задача процедуру получить оффсет на Zip64EOFCentralDirectoryRecord
+// =============================================================================
+procedure TFWZipReader.LoadZIP64Locator;
+begin
+ FZIPStream.ReadBuffer(FZip64EOFCentralDirectoryLocator,
+ SizeOf(TZip64EOFCentralDirectoryLocator));
+
+ if FZip64EOFCentralDirectoryLocator.Signature <>
+ ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE then
+ raise EZipReader.Create(
+ 'Ошибка чтения структуры TZip64EOFCentralDirectoryLocator');
+
+ // Данная структура хранит оффсет на TZip64EOFCentralDirectoryRecord
+ // В котором и храниться расширенная информация
+ FZIPStream.Position := FZip64EOFCentralDirectoryLocator.RelativeOffset +
+ StartZipDataOffset;
+ LoadZip64EOFCentralDirectoryRecord;
+end;
+
+{ TFakeStream }
+
+//
+// TFakeStream предназначен для проверки архива на целостность
+// =============================================================================
+type
+ TFakeStream = class(TStream)
+ private
+ FSize: Int64;
+ FPosition: Int64;
+ protected
+ procedure SetSize(const NewSize: Int64); override;
+ public
+ function Seek(Offset: Longint; Origin: Word): Longint; overload; override;
+ function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; overload; override;
+ function Write(const Buffer; Count: Longint): Longint; override;
+ function Read(var Buffer; Count: Longint): Longint; override;
+ end;
+
+function TFakeStream.Read(var Buffer; Count: Longint): Longint;
+begin
+ raise Exception.Create('TFakeStream.Read');
+end;
+
+function TFakeStream.Write(const Buffer; Count: Longint): Longint;
+begin
+ FSize := FSize + Count;
+ Result := Count;
+end;
+
+function TFakeStream.Seek(Offset: Longint; Origin: Word): Longint;
+begin
+ Result := Seek(Int64(Offset), TSeekOrigin(Origin));
+end;
+
+function TFakeStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
+begin
+ case Origin of
+ soBeginning: FPosition := Offset;
+ soCurrent: Inc(FPosition, Offset);
+ soEnd: FPosition := FSize + Offset;
+ end;
+ Result := FPosition;
+end;
+
+procedure TFakeStream.SetSize(const NewSize: Int64);
+begin
+ FSize := NewSize;
+end;
+
+//
+// Процедура производит распаковку или проверку архива с учетом маски файла в архиве
+// При проверке архива данные распаковываются, но не сохраняются
+// =============================================================================
+procedure TFWZipReader.ProcessExtractOrCheckAllData(const ExtractMask: string;
+ Path: string; CheckMode: Boolean);
+var
+ I, A: Integer;
+ OldExtractEvent: TZipExtractItemEvent;
+ OldDuplicateEvent: TZipDuplicateEvent;
+ CurrentItem: TFWZipReaderItem;
+ ExtractResult: TExtractResult;
+ CancelExtract, Handled: Boolean;
+ Password: string;
+ FreeAvailable, TotalSpace: TLargeInteger;
+ ExtractList: TList;
+ FakeStream: TFakeStream;
+begin
+ FTotalSizeCount := 0;
+ FTotalProcessedCount := 0;
+ ExtractList := TList.Create;
+ try
+ // Производим поиск файлов для распаковки
+ for I := 0 to Count - 1 do
+ if ExtractMask = '' then
+ begin
+ ExtractList.Add(Pointer(I));
+ Inc(FTotalSizeCount, Item[I].UncompressedSize);
+ end
+ else
+ if MatchesMask(Item[I].FileName, ExtractMask) then
+ begin
+ ExtractList.Add(Pointer(I));
+ Inc(FTotalSizeCount, Item[I].UncompressedSize);
+ end;
+
+ if not CheckMode then
+ begin
+ // Правка пустого и относительного пути
+ Path := PathCanonicalize(Path);
+ if Path = '' then
+ Path := GetCurrentDirUTF8; { *Преобразовано из GetCurrentDir* }
+
+ // Проверка хватит ли места на диске?
+ if GetDiskFreeSpaceEx(PChar(Path), FreeAvailable, TotalSpace, nil) then
+ if FreeAvailable <= FTotalSizeCount then
+ raise EZipReader.CreateFmt('Недостаточно места на диске "%s".' + sLineBreak +
+ 'Необходимо освободить %s.', [Path[1], FileSizeToStr(FTotalSizeCount)]);
+ end;
+
+ FakeStream := TFakeStream.Create;
+ try
+ for I := 0 to ExtractList.Count - 1 do
+ begin
+ FakeStream.Size := 0;
+ CurrentItem := Item[Integer(ExtractList[I])];
+ DoProgress(Self, CurrentItem.FileName, 0, CurrentItem.UncompressedSize, psStart);
+ OldExtractEvent := CurrentItem.OnProgress;
+ try
+ CurrentItem.OnProgress := DoProgress;
+ OldDuplicateEvent := CurrentItem.OnDuplicate;
+ try
+ CurrentItem.OnDuplicate := OnDuplicate;
+ // Пробуем извлечь файл
+ try
+ if CheckMode then
+ ExtractResult := CurrentItem.ExtractToStream(FakeStream, '')
+ else
+ ExtractResult := CurrentItem.Extract(Path, '');
+ if ExtractResult = erNeedPassword then
+ begin
+ // Если произошла обшибка из-за того что файл зашифрован,
+ // пробуем расшифровать его используя список известных паролей
+ for A := 0 to FPasswordList.Count - 1 do
+ begin
+ if CheckMode then
+ ExtractResult := CurrentItem.ExtractToStream(FakeStream, FPasswordList[A])
+ else
+ ExtractResult := CurrentItem.Extract(Path, FPasswordList[A]);
+ if ExtractResult in [erDone, erSkiped] then Break;
+ end;
+ // если не получилось, запрашиваем пароль у пользователя
+ if ExtractResult = erNeedPassword then
+ if Assigned(FOnNeedPwd) then
+ begin
+ CancelExtract := False;
+ while ExtractResult = erNeedPassword do
+ begin
+ Password := '';
+ FOnNeedPwd(Self, CurrentItem.FileName,
+ Password, CancelExtract);
+ if CancelExtract then Exit;
+ if Password <> '' then
+ begin
+ FPasswordList.Add(Password);
+ if CheckMode then
+ ExtractResult := CurrentItem.ExtractToStream(FakeStream, Password)
+ else
+ ExtractResult := CurrentItem.Extract(Path, Password);
+ end;
+ end;
+ end
+ else
+ raise EWrongPasswordException.CreateFmt(
+ 'Ошибка извлечения данных элемента №%d "%s".' + sLineBreak +
+ 'Неверный пароль.', [CurrentItem.ItemIndex, CurrentItem.FileName]);
+ end;
+ except
+
+ // Пользователь отменил распаковку архива
+ on E: EAbort do
+ Exit;
+
+ // Ну не прерывать же распаковку из-за исключения на одном файле?
+ // Пусть решение о прерывании распаковки принимают снаружи
+ on E: Exception do
+ begin
+ Handled := False;
+ if Assigned(FException) then
+ FException(Self, E, Integer(ExtractList[I]), Handled);
+ if not Handled then
+ // Rouse_ 20.02.2012
+ // Неверно перевозбуждено исключение
+ // Спасибо v1ctar за найденый глюк
+ //raise E;
+ raise;
+ end;
+ end;
+ Inc(FTotalProcessedCount, CurrentItem.UncompressedSize);
+ finally
+ CurrentItem.OnDuplicate := OldDuplicateEvent;
+ end;
+ finally
+ CurrentItem.OnProgress := OldExtractEvent;
+ DoProgress(Self, CurrentItem.FileName, 0,
+ CurrentItem.UncompressedSize, psEnd);
+ end;
+ end;
+
+ finally
+ FakeStream.Free;
+ end;
+
+ finally
+ ExtractList.Free;
+ end;
+end;
+
+procedure TFWZipReader.SetDefaultDuplicateAction(const Value: TDuplicateAction);
+begin
+ if Value = daUseNewFilePath then
+ raise EZipReader.Create(
+ 'Действие daUseNewFilePath можно назначать только в обработчике события OnDuplicate.');
+ FDefaultDuplicateAction := Value;
+end;
+
+//
+// Функция возвращает размер центральной директории
+// =============================================================================
+function TFWZipReader.SizeOfCentralDirectory: Int64;
+begin
+ if Zip64Present then
+ Result := FZip64EOFCentralDirectoryRecord.Size
+ else
+ Result := FEndOfCentralDir.SizeOfTheCentralDirectory;
+end;
+
+//
+// Функция возвращает количество элементов архива
+// =============================================================================
+function TFWZipReader.TotalEntryesCount: Integer;
+begin
+ if Zip64Present then
+ Result := FZip64EOFCentralDirectoryRecord.TotalNumber2
+ else
+ Result := FEndOfCentralDir.TotalNumberOfEntries;
+end;
+
+//
+// Вспомогательная функция,
+// указывает из какого блока данных брать валидное значение
+// =============================================================================
+function TFWZipReader.Zip64Present: Boolean;
+begin
+ Result := FZip64EOFCentralDirectoryRecord.Zip64EndOfCentralDirSignature =
+ ZIP64_END_OF_CENTRAL_DIR_SIGNATURE
+end;
+
+end.
diff --git a/prereq/fwzip/FWZipStream.pas b/prereq/fwzip/FWZipStream.pas
new file mode 100644
index 0000000..aaee1de
--- /dev/null
+++ b/prereq/fwzip/FWZipStream.pas
@@ -0,0 +1,263 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ****************************************************************************
+// * Project : FWZip
+// * Unit Name : FWZipStream
+// * Purpose : Вспомогательные стримы для поддержки шифрования на лету,
+// * : и усеченного заголовка ZLib
+// * Author : Александр (Rouse_) Багель
+// * Copyright : © Fangorn Wizards Lab 1998 - 2015.
+// * Version : 1.0.11
+// * Home Page : http://rouse.drkb.ru
+// * Home Blog : http://alexander-bagel.blogspot.ru
+// ****************************************************************************
+// * Stable Release : http://rouse.drkb.ru/components.php#fwzip
+// * Latest Source : https://github.com/AlexanderBagel/FWZip
+// ****************************************************************************
+//
+// Используемые источники:
+// ftp://ftp.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
+// http://zlib.net/zlib-1.2.5.tar.gz
+// http://www.base2ti.com/
+//
+//
+// Описание идеи модуля:
+// При помещении в архив сжатого блока данных методом Deflate у него
+// отрезается двухбайтный заголовок в котором указаны параметры сжатия.
+// Т.е. в архив помещаются сами данные в чистом виде.
+// Для распаковки необходимо данный заголовок восстановить.
+// Данный класс позволяет добавить данный заголовок "на лету"
+// абсолютно прозрачно для внешнего кода.
+// Сам заголовок генерируется в конструкторе и подставляется в методе Read.
+// Так-же класс, выступая посредником между двумя стримами,
+// позволяет производить шифрование и дешифровку передаваемых данных.
+// Шифрование производится в методе Write, в этот момент класс является
+// посредником между TCompressionStream и результирующим стримом.
+// Дешифрование осуществляется в методе Read, в этот момент класс является
+// посредником между стримом со сжатыми и
+// пошифрованными данными и TDecompressionStream.
+//
+
+unit FWZipStream;
+{$mode delphi}
+{$codepage UTF8}
+
+interface
+
+{$I fwzip.inc}
+
+uses
+ Classes,
+ FWZipConsts,
+ FWZipCrypt,
+ FWZipCrc32,
+ FWZipZLib;
+
+type
+ TFWZipItemStream = class(TStream)
+ private
+ FOwner: TStream;
+ FCryptor: TFWZipCryptor;
+ FDecryptor: TFWZipDecryptor;
+ FSize, FStart, FPosition: Int64;
+ {$IFDEF USE_AUTOGENERATED_ZLIB_HEADER}
+ FHeader: Word;
+ {$ENDIF}
+ protected
+ function GetSize: Int64; override;
+ public
+ constructor Create(AOwner: TStream; Cryptor: TFWZipCryptor;
+ Decryptor: TFWZipDecryptor; CompressLevel: Byte; ASize: Int64);
+ function Seek(Offset: Longint; Origin: Word): Longint; overload; override;
+ function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; overload; override;
+ function Read(var Buffer; Count: Longint): Longint; override;
+ function Write(const Buffer; Count: Longint): Longint; override;
+ end;
+
+implementation
+
+{ TFWZipItemStream }
+
+constructor TFWZipItemStream.Create(AOwner: TStream; Cryptor: TFWZipCryptor;
+ Decryptor: TFWZipDecryptor; CompressLevel: Byte; ASize: Int64);
+begin
+ inherited Create;
+ FOwner := AOwner;
+ FCryptor := Cryptor;
+ FDecryptor := Decryptor;
+
+ FSize := ASize;
+ FStart := AOwner.Position;
+ FPosition := 0;
+
+ // Rouse_ 30.10.2013
+ // Устаревший код
+ {$IFDEF USE_AUTOGENERATED_ZLIB_HEADER}
+
+ // Rouse_ 17.03.2011
+ // Размерчик все-же нужно править увеличикая на размер заголовка
+ Inc(FSize, 2);
+ // Восстанавливаем пропущенный заголовок ZLib стрима
+ // см. deflate.c - int ZEXPORT deflate (strm, flush)
+
+ // uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+ FHeader := (Z_DEFLATED + (7 {32k Window size} shl 4)) shl 8;
+
+ // if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
+ // level_flags = 0;
+ // else if (s->level < 6)
+ // level_flags = 1;
+ // else if (s->level == 6)
+ // level_flags = 2;
+ // else
+ // level_flags = 3;
+ //
+ // сам CompressLevel (level_flags)
+ // берется из уже заполненного GeneralPurposeBitFlag
+ // здесь мы из битовой маски восстанавливаем оригинальные значения
+
+ case CompressLevel of
+ PBF_COMPRESS_SUPERFAST:
+ CompressLevel := 0;
+ PBF_COMPRESS_FAST:
+ CompressLevel := 1;
+ PBF_COMPRESS_NORMAL:
+ CompressLevel := 2;
+ PBF_COMPRESS_MAXIMUM:
+ CompressLevel := 3;
+ end;
+
+ // header |= (level_flags << 6);
+ FHeader := FHeader or (CompressLevel shl 6);
+
+ // if (s->strstart != 0) header |= PRESET_DICT;
+ // словарь не используется - оставляем без изменений
+
+ // header += 31 - (header % 31);
+ Inc(FHeader, 31 - (FHeader mod 31));
+
+ // putShortMSB(s, header);
+ FHeader := (FHeader shr 8) + (FHeader and $FF) shl 8;
+ {$ENDIF}
+end;
+
+function TFWZipItemStream.GetSize: Int64;
+begin
+ Result := FSize;
+end;
+
+function TFWZipItemStream.Read(var Buffer; Count: Integer): Longint;
+var
+ P: PByte;
+ DecryptBuff: Pointer;
+begin
+ // Rouse_ 30.10.2013
+ // Устаревший код
+ {$IFDEF USE_AUTOGENERATED_ZLIB_HEADER}
+ if FPosition = 0 then
+ begin
+ // если зачитываются данные с самого начала
+ // необходимо перед ними разместить заголовок ZLib
+ P := @FHeader;
+ Move(P^, Buffer, 2);
+ FOwner.Position := FStart;
+ P := @Buffer;
+ Inc(P, 2);
+ if Count > Size then
+ Count := Size;
+ FOwner.Position := FStart;
+ if FDecryptor <> nil then
+ begin
+ // в случае если файл зашифрован, производим расшифровку блока
+ GetMem(DecryptBuff, Count - 2);
+ try
+ Result := FOwner.Read(DecryptBuff^, Count - 2);
+ FDecryptor.DecryptBuffer(DecryptBuff, Result);
+ Move(DecryptBuff^, P^, Result);
+ finally
+ FreeMem(DecryptBuff);
+ end;
+ end
+ else
+ Result := FOwner.Read(P^, Count - 2);
+ Inc(Result, 2);
+ Inc(FPosition, Result);
+ end
+ else
+ begin
+ FOwner.Position := FStart + Position - 2;
+ {$ELSE}
+ begin
+ FOwner.Position := FStart + Position;
+ {$ENDIF}
+ if Count > Size - Position then
+ Count := Size - Position;
+ if FDecryptor <> nil then
+ begin
+ // в случае если файл зашифрован, производим расшифровку блока
+ GetMem(DecryptBuff, Count);
+ try
+ Result := FOwner.Read(DecryptBuff^, Count);
+ FDecryptor.DecryptBuffer(DecryptBuff, Result);
+ P := @Buffer;
+ Move(DecryptBuff^, P^, Result);
+ finally
+ FreeMem(DecryptBuff);
+ end;
+ end
+ else
+ Result := FOwner.Read(Buffer, Count);
+ Inc(FPosition, Result);
+ end;
+end;
+
+function TFWZipItemStream.Seek(Offset: Integer; Origin: Word): Longint;
+begin
+ Result := Seek(Int64(Offset), TSeekOrigin(Origin));
+end;
+
+function TFWZipItemStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
+begin
+ case Origin of
+ soBeginning: FPosition := Offset;
+ soCurrent: Inc(FPosition, Offset);
+ soEnd: FPosition := Size + Offset;
+ end;
+ Result := FPosition;
+end;
+
+function TFWZipItemStream.Write(const Buffer; Count: Integer): Longint;
+var
+ EncryptBuffer: PByte;
+begin
+ if FCryptor = nil then
+ Result := FOwner.Write(Buffer, Count)
+ else
+ begin
+ // криптуем буфер
+ GetMem(EncryptBuffer, Count);
+ try
+ Move(Buffer, EncryptBuffer^, Count);
+
+ // Rouse_ 31.10.2013
+ // Устаревший код
+ {$IFDEF USE_AUTOGENERATED_ZLIB_HEADER}
+ // Шифровать блок нужно пропустив двубайтный заголовок ZLib
+ if FPosition = 0 then
+ begin
+ Inc(EncryptBuffer, 2);
+ FCryptor.EncryptBuffer(EncryptBuffer, Count - 2);
+ Dec(EncryptBuffer, 2);
+ end
+ else
+ {$ENDIF}
+ FCryptor.EncryptBuffer(EncryptBuffer, Count);
+ Result := FOwner.Write(EncryptBuffer^, Count);
+ finally
+ FreeMem(EncryptBuffer);
+ end;
+ end;
+ Inc(FPosition, Result);
+end;
+
+end.
diff --git a/prereq/fwzip/FWZipWriter.pas b/prereq/fwzip/FWZipWriter.pas
new file mode 100644
index 0000000..ad527c7
--- /dev/null
+++ b/prereq/fwzip/FWZipWriter.pas
@@ -0,0 +1,1822 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ****************************************************************************
+// * Project : FWZip
+// * Unit Name : FWZipWriter
+// * Purpose : Класс для создания ZIP архива
+// * Author : Александр (Rouse_) Багель
+// * Copyright : © Fangorn Wizards Lab 1998 - 2015.
+// * Version : 1.0.11
+// * Home Page : http://rouse.drkb.ru
+// * Home Blog : http://alexander-bagel.blogspot.ru
+// ****************************************************************************
+// * Stable Release : http://rouse.drkb.ru/components.php#fwzip
+// * Latest Source : https://github.com/AlexanderBagel/FWZip
+// ****************************************************************************
+//
+// Используемые источники:
+// ftp://ftp.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
+// http://zlib.net/zlib-1.2.5.tar.gz
+// http://www.base2ti.com/
+//
+
+unit FWZipWriter;
+{$mode delphi}
+{$codepage UTF8}
+
+interface
+
+{$I fwzip.inc}
+
+uses
+ LCLIntf, LCLType, LMessages, windows,
+ SysUtils,
+ Classes,
+ Contnrs,
+ FWZipConsts,
+ FWZipCrc32,
+ FWZipCrypt,
+ FWZipStream,
+ FWZipZLib, FileUtil, LazFileUtils;
+
+type
+ TFWZipWriter = class;
+
+ TFWZipWriterItem = class
+ private
+ FOwner: TFWZipWriter;
+ FComment: string; // коментарий к элементу
+ FFilePath: string; // путь к внешнему файлу (или см. TFWZipWriterItemEx.Data)
+ FFileName: string; // имя элемента в архиве - не может быть пустым
+ FPassword: string; // пароль
+ FCmpLevel: TCompressionLevel; // уровень сжатия
+ FNeedDescriptor: Boolean; // флаг определяет способ хранения данных
+ // о элементе, (дескриптор или локальный заголовок)
+ FSize: Int64;
+ FData: TMemoryStream; // Данные элемента в случае если файл
+ // отсутствует на диске
+ FAttributes: // Внешние аттрибуты файла
+ TWin32FileAttributeData;
+ FTag: Integer;
+ FUseUTF8String: Boolean;
+ FUseExternalData: Boolean; // Флаг указывающий на то что данные будут передаваться снаружи
+ procedure SetBool(const Value: Boolean);
+ procedure SetCmpLevel(const Value: TCompressionLevel);
+ procedure SetString(const Index: Integer; const Value: string);
+ protected
+ property Data: TMemoryStream read FData;
+ property UseExternalData: Boolean read FUseExternalData write FUseExternalData;
+ public
+ constructor Create(Owner: TFWZipWriter;
+ const InitFilePath: string;
+ InitAttributes: TWin32FileAttributeData;
+ const InitFileName: string = ''); virtual;
+ destructor Destroy; override;
+ procedure ChangeDataStream(Value: TStream);
+ procedure ChangeAttributes(Value: TWin32FileAttributeData);
+ function IsFolder: Boolean;
+ property Comment: string index 0 read FComment write SetString;
+ property FilePath: string index 1 read FFilePath write SetString;
+ property FileName: string index 2 read FFileName write SetString;
+ property Password: string index 3 read FPassword write SetString;
+ property CompressionLevel: TCompressionLevel read FCmpLevel write SetCmpLevel;
+ property NeedDescriptor: Boolean read FNeedDescriptor write SetBool;
+ property Size: Int64 read FSize;
+ property Attributes: TWin32FileAttributeData read FAttributes;
+ property Tag: Integer read FTag write FTag;
+ property UseUTF8String: Boolean read FUseUTF8String write FUseUTF8String;
+ end;
+
+ TFWZipWriterItemClass = class of TFWZipWriterItem;
+
+ // Результат создания архива
+ TBuildZipResult =
+ (
+ brDone, // архив создан успешно
+ brFailed, // ошибка создания архива
+ brAborted, // создание архива отменено пользователем
+ brPartialBuild // некоторые элементы пропущены из-за возникших ошибок
+ );
+
+ TFWZipWriter = class
+ private
+ FDefaultDescryptorState: Boolean;
+ FDefaultCompressionLevel: TCompressionLevel;
+ FDefaultPassword: string;
+ FItems: TObjectList;
+ FCD: array of TCentralDirectoryFileHeaderEx;
+ FVersionToExtract: Word;
+ FcdfhOffset, FTotalProgress, FTotalSizeCount, FTotalProcessedCount: Int64;
+ FCompressedStream: TStream;
+ FProcessedItemIndex: Integer;
+ FComment: string;
+ FOnProgress: TZipProgressEvent;
+ FBuildState: Boolean;
+ FSaveExData: TZipSaveExDataEvent;
+ FExceptionCount: Integer;
+ FBuidException: TZipBuildExceptionEvent;
+ FTrimPackedStreamSize: Boolean;
+ FAlwaysAddEmptyFolder: Boolean;
+ FUseUTF8String: Boolean;
+ function GetItem(Index: Integer): TFWZipWriterItem;
+ protected
+ function GetItemClass: TFWZipWriterItemClass; virtual;
+ function AddNewItem(Value: TFWZipWriterItem): Integer;
+ procedure FillItemCDFHeader(CurrentItem: TFWZipWriterItem;
+ var Value: TCentralDirectoryFileHeaderEx); virtual;
+ procedure CompressItem(CurrentItem: TFWZipWriterItem;
+ Index: Integer; StreamSizeBeforeCompress: Int64; Stream: TStream); virtual;
+ procedure FillExData(Stream: TStream; Index: Integer); virtual;
+ protected
+ procedure DoProgress(ProgressState: TProgressState);
+ procedure CompressorOnProcess(Sender: TObject);
+ protected
+ function CheckFileNameSlashes(const Value: string): string;
+ function GetVersionToExtract(Index: Integer): Word;
+ function GetCurrentFileTime: TFileTime;
+ procedure SaveItemToStream(Stream: TStream; Index: Integer); virtual;
+ procedure SaveCentralDirectory(Stream: TStream);
+ procedure SaveEndOfCentralDirectory(Stream: TStream);
+ procedure SaveString(Stream: TStream; const Value: string;
+ UTF8String: Boolean);
+ procedure UpdateLocalHeaders(Stream: TStream);
+ property BuildState: Boolean read FBuildState;
+ function StringLength(const Value: string; UTF8String: Boolean): Integer;
+ public
+ constructor Create; overload;
+ constructor Create(CompressionLevel: TCompressionLevel); overload;
+ constructor Create(UseDescryptors: Boolean;
+ CompressionLevel: TCompressionLevel;
+ const DefaultPassword: string); overload;
+ destructor Destroy; override;
+ function AddEmptyFolder(const FolderRelativeName: string): Integer; overload;
+ function AddEmptyFolder(const FolderRelativeName: string;
+ Attributes: TWin32FileAttributeData): Integer; overload;
+ function AddFile(const FilePath: string;
+ const FileName: string = ''): Integer; overload;
+ function AddFile(const FilePath: string;
+ Attributes: TWin32FileAttributeData;
+ const FileName: string = ''): Integer; overload;
+ function AddStream(const FileName: string; Value: TStream): Integer;
+ function AddFiles(Value: TStringList): Integer;
+ function AddFilesAndFolders(Value: TStringList; SubFolders: Boolean = True): Integer;
+ function AddFolder(const Path: string;
+ SubFolders: Boolean = True): Integer; overload;
+ function AddFolder(const RelativePath, Path, Mask: string;
+ SubFolders: Boolean = True): Integer; overload;
+ function BuildZip(const ZipFilePath: string): TBuildZipResult; overload;
+ function BuildZip(Stream: TStream): TBuildZipResult; overload;
+ function Count: Integer;
+ procedure Clear;
+ procedure DeleteItem(Index: Integer);
+
+ // Свойство отвечает за добавление папки в виде TFWZipWriterItem
+ // непосредственно перед добавлением данных из указаной папки
+ property AlwaysAddEmptyFolder: Boolean read FAlwaysAddEmptyFolder
+ write FAlwaysAddEmptyFolder;
+
+ property Item[Index: Integer]: TFWZipWriterItem read GetItem; default;
+ property Comment: string read FComment write FComment;
+
+ // Свойство работает только при включенной директиве USE_AUTOGENERATED_ZLIB_HEADER
+ // В остальных случаях не влияет на архив и оставлено для совместимости
+ property TrimPackedStreamSize: Boolean read FTrimPackedStreamSize
+ write FTrimPackedStreamSize; // deprecated;
+
+ property OnException: TZipBuildExceptionEvent read FBuidException write FBuidException;
+ property OnProgress: TZipProgressEvent read FOnProgress write FOnProgress;
+ property OnSaveExData: TZipSaveExDataEvent read FSaveExData write FSaveExData;
+ property UseUTF8String: Boolean read FUseUTF8String write FUseUTF8String;
+ end;
+
+ EZipWriterItem = class(Exception);
+ EZipWriter = class(Exception);
+ EZipWriterWrite = class(Exception);
+
+implementation
+
+{ TFWZipWriterItem }
+
+//
+// Процедура изменяет аттрибуты элемента архива
+// =============================================================================
+procedure TFWZipWriterItem.ChangeAttributes(Value: TWin32FileAttributeData);
+begin
+ if not FOwner.BuildState then
+ FAttributes := Value;
+end;
+
+//
+// Процедура изменяет блок данных об элементе. Автоматически чистится имя к файлу.
+// Данные при сжатии будут браться из поля FData
+// =============================================================================
+procedure TFWZipWriterItem.ChangeDataStream(Value: TStream);
+begin
+ if not FOwner.BuildState then
+ if Value.Size <> 0 then
+ begin
+ if FData = nil then
+ FData := TMemoryStream.Create;
+ FData.Clear;
+ FData.CopyFrom(Value, 0);
+ FSize := FData.Size;
+ FFilePath := '';
+ end;
+end;
+
+//
+// Стандартный конструктор класса
+// =============================================================================
+constructor TFWZipWriterItem.Create(Owner: TFWZipWriter;
+ const InitFilePath: string;
+ InitAttributes: TWin32FileAttributeData; const InitFileName: string);
+begin
+ inherited Create;
+ FData := nil;
+ FOwner := Owner;
+ FFilePath := InitFilePath;
+ FAttributes := InitAttributes;
+ FSize :=
+ FileSizeToInt64(FAttributes.nFileSizeLow, FAttributes.nFileSizeHigh);
+ FFileName := InitFileName;
+ UseUTF8String := Owner.UseUTF8String;
+end;
+
+//
+// Стандартный деструктор класса
+// =============================================================================
+destructor TFWZipWriterItem.Destroy;
+begin
+ FData.Free;
+ inherited;
+end;
+
+//
+// Функция проверяет - является ли элемент папкой?
+// =============================================================================
+function TFWZipWriterItem.IsFolder: Boolean;
+begin
+ Result := Attributes.dwFileAttributes and faDirectory <> 0;
+ if not Result then
+ Result := FileName[Length(FileName)] = ZIP_SLASH;
+end;
+
+//
+// Процедура изменяет флаг дескриптора элемента
+// =============================================================================
+procedure TFWZipWriterItem.SetBool(const Value: Boolean);
+begin
+ if not FOwner.BuildState then
+ FNeedDescriptor := Value;
+end;
+
+//
+// Процедура изменяет степень сжатия элемента
+// =============================================================================
+procedure TFWZipWriterItem.SetCmpLevel(const Value: TCompressionLevel);
+begin
+ if not FOwner.BuildState then
+ FCmpLevel := Value;
+end;
+
+//
+// Процедура изменяет строковые свойства элемента.
+// При изменении пути к файлу, автоматически рассчитываются
+// новые аттрибуты файла и очишается стрим FData за ненадобностью
+// =============================================================================
+procedure TFWZipWriterItem.SetString(const Index: Integer;
+ const Value: string);
+var
+ Attributes: TWin32FileAttributeData;
+begin
+ if not FOwner.BuildState then
+ case Index of
+ 0: FComment := Value;
+ 1:
+ begin
+ if FileExistsUTF8(Value) { *Преобразовано из FileExists* } then
+ begin
+ // Изменяем только в том случае если объект доступен
+ // и мы смогли снять его аттрибуты
+ if GetFileAttributesEx(PChar(Value),
+ GetFileExInfoStandard, @Attributes) then
+ begin
+ FAttributes := Attributes;
+ FSize :=
+ FileSizeToInt64(Attributes.nFileSizeLow, Attributes.nFileSizeHigh);
+ FFilePath := Value;
+ FreeAndNil(FData);
+ end;
+ end;
+ end;
+ 2:
+ if Length(Value) >= MAX_PATH then
+ raise EZipWriterItem.Create('Слишком длинный путь.')
+ else
+ FFileName := Value;
+ 3: FPassword := Value;
+ end;
+end;
+
+{ TFWZipWriter }
+
+//
+// Функция добавляет очередной файл в список.
+// В качестве результата возвращает индекс элемента в списке.
+// Параметры:
+// FilePath - путь к файлу
+// FileName - наименование файла в архиве
+// (включая относительный путь от корня архива)
+// =============================================================================
+function TFWZipWriter.AddFile(const FilePath,
+ FileName: string): Integer;
+var
+ Attributes: TWin32FileAttributeData;
+ FullFilePath: string;
+begin
+ Result := -1;
+ FullFilePath := PathCanonicalize(FilePath);
+ // Добавляем только в том случае если объект доступен
+ // и мы смогли снять его аттрибуты
+ if GetFileAttributesEx(PChar(FullFilePath),
+ GetFileExInfoStandard, @Attributes) then
+ Result := AddFile(FullFilePath, Attributes, FileName);
+end;
+
+//
+// Функция добавляет пустую папку в список.
+// В качестве результата возвращает индекс элемента в списке.
+// Параметры:
+// FolderRelativeName - наименование папки в архиве
+// (включая относительный путь от корня архива)
+// =============================================================================
+function TFWZipWriter.AddEmptyFolder(const FolderRelativeName: string): Integer;
+var
+ Attributes: TWin32FileAttributeData;
+begin
+ ZeroMemory(@Attributes, SizeOf(TWin32FileAttributeData));
+ Attributes.dwFileAttributes := faDirectory;
+ Result := AddEmptyFolder(FolderRelativeName, Attributes);
+end;
+
+//
+// Функция добавляет пустую папку в список.
+// В качестве результата возвращает индекс элемента в списке.
+// Параметры:
+// FolderRelativeName - наименование папки в архиве
+// (включая относительный путь от корня архива)
+// Attributes - аттрибуты папки
+// =============================================================================
+function TFWZipWriter.AddEmptyFolder(const FolderRelativeName: string;
+ Attributes: TWin32FileAttributeData): Integer;
+var
+ FolderPath: string;
+ Item: TFWZipWriterItem;
+begin
+ Result := -1;
+ if FolderRelativeName = '' then Exit;
+ FolderPath := CheckFileNameSlashes(FolderRelativeName);
+ if FolderPath[Length(FolderPath)] <> ZIP_SLASH then
+ FolderPath := FolderPath + ZIP_SLASH;
+ Item := GetItemClass.Create(Self, FolderPath, Attributes, FolderPath);
+ Result := AddNewItem(Item);
+end;
+
+//
+// Функция добавляет очередной файл в список.
+// В качестве результата возвращает индекс элемента в списке.
+// Параметры:
+// FilePath - путь к файлу
+// Attributes - аттрибуты файла
+// FileName - наименование файла в архиве
+// (включая относительный путь от корня архива)
+// =============================================================================
+function TFWZipWriter.AddFile(const FilePath: string;
+ Attributes: TWin32FileAttributeData; const FileName: string): Integer;
+var
+ Item: TFWZipWriterItem;
+ InitFileName, FullFilePath: string;
+begin
+ // Проверка что нам передали. папку или файл?
+ Result := -1;
+ FullFilePath := PathCanonicalize(FilePath);
+ if not FileExistsUTF8(FullFilePath) { *Преобразовано из FileExists* } then Exit;
+ if FileName = '' then
+ InitFileName := ExtractFileName(ExcludeTrailingPathDelimiter(FullFilePath))
+ else
+ InitFileName := CheckFileNameSlashes(FileName);
+
+ Item := GetItemClass.Create(Self, FullFilePath, Attributes, InitFileName);
+ Item.CompressionLevel := FDefaultCompressionLevel;
+ Item.Password := FDefaultPassword;
+
+ // в случае наличия дескриптора мы можем
+ // производить расчет контрольной суммы на лету, т.к. при включенном
+ // режиме шифрования она не участвует в генерации заголовка инициализации
+ Item.NeedDescriptor := FDefaultDescryptorState;
+
+ Result := AddNewItem(Item);
+end;
+
+//
+// Функция добавляет набор файлов в список.
+// В качестве результата возвращает количество успешно добавленных элементов.
+// Параметры:
+// Value - пути к файлам
+// Value.ValueFromIndex[I] содержит полный путь к файлу
+// Value.Names[I] содержит имя файла с которым он будет
+// помещен в архив (необязательный параметр)
+// =============================================================================
+function TFWZipWriter.AddFiles(Value: TStringList): Integer;
+var
+ I: Integer;
+begin
+ Result := 0;
+ for I := 0 to Value.Count - 1 do
+ if AddFile(Value.ValueFromIndex[I], Value.Names[I]) >= 0 then
+ Inc(Result);
+end;
+
+//
+// Функция добавляет набор файлов и папок в список.
+// В качестве результата возвращает количество успешно добавленных элементов.
+// Параметры:
+// Value - пути к файлам и папкам из которых будут добавляться данные
+// Value.ValueFromIndex[I] для папки содержит полный путь к папке
+// Value.Names[I] для папки содержит путь относительно корня архива
+// (необязательный параметр)
+// Value.ValueFromIndex[I] для файла содержит полный путь к файлу
+// Value.Names[I] для файла содержит имя файла с которым он будет
+// помещен в архив (необязательный параметр)
+// SubFolders - добавлять данные из подпапок или нет.
+// =============================================================================
+function TFWZipWriter.AddFilesAndFolders(Value: TStringList;
+ SubFolders: Boolean): Integer;
+var
+ I: Integer;
+ Path: string;
+begin
+ Result := 0;
+ for I := 0 to Value.Count - 1 do
+ begin
+ Path := Value.ValueFromIndex[I];
+ if DirectoryExistsUTF8(Path) { *Преобразовано из DirectoryExists* } then
+ Inc(Result, AddFolder(Value.Names[I], Path, '', SubFolders))
+ else
+ if AddFile(Path, Value.Names[I]) >= 0 then
+ Inc(Result);
+ end;
+end;
+
+//
+// Функция добавляет файлы из указаной папки
+// В качестве результата возвращает количество успешно добавленных элементов.
+// Параметры:
+// Path - путь к папке из которой будут добавляться данные
+// SubFolders - добавлять данные из подпапок или нет.
+// =============================================================================
+function TFWZipWriter.AddFolder(const Path: string; SubFolders: Boolean): Integer;
+begin
+ Result := AddFolder(ExtractFileName(
+ ExcludeTrailingPathDelimiter(PathCanonicalize(Path))),
+ Path, '*.*', SubFolders);
+end;
+
+//
+// Расширенный вариант AddFolder
+// Функция добавляет файлы из указаной папки
+// В качестве результата возвращает количество успешно добавленных элементов.
+// Параметры:
+// RelativePath - путь к элементу в архиве относительно корня.
+// Path - путь к папке из которой будут добавляться данные
+// Mask - маска отбора файлов
+// SubFolders - добавлять данные из подпапок или нет.
+// =============================================================================
+function TFWZipWriter.AddFolder(const RelativePath, Path, Mask: string;
+ SubFolders: Boolean): Integer;
+var
+ SR: TSearchRec;
+ TrailingPath, TrailingRelativePath, ResultMask: string;
+ Attributes: TWin32FileAttributeData;
+begin
+ Result := 0;
+ // обычное рекурсивное сканирование папки
+ // единственный нюанс - параметр RelativePath
+ // в котором передается путь к файлу или папке относительно корневой папки
+ if RelativePath = '' then
+ TrailingRelativePath := ''
+ else
+ TrailingRelativePath := IncludeTrailingPathDelimiter(RelativePath);
+ TrailingPath := IncludeTrailingPathDelimiter(PathCanonicalize(Path));
+
+ if Mask = '' then
+ ResultMask := '*.*'
+ else
+ ResultMask := Mask;
+ if FindFirstUTF8(TrailingPath + ResultMask,faAnyFile,SR) { *Преобразовано из FindFirst* } = 0 then
+ try
+ repeat
+
+ {$WARN SYMBOL_PLATFORM OFF}
+ Attributes.dwFileAttributes := SR.FindData.dwFileAttributes;
+ Attributes.ftCreationTime := SR.FindData.ftCreationTime;
+ Attributes.ftLastAccessTime := SR.FindData.ftLastAccessTime;
+ Attributes.ftLastWriteTime := SR.FindData.ftLastWriteTime;
+ Attributes.nFileSizeHigh := SR.FindData.nFileSizeHigh;
+ Attributes.nFileSizeLow := SR.FindData.nFileSizeLow;
+ {$WARN SYMBOL_PLATFORM ON}
+
+ if SR.Name = '.' then
+ begin
+ // Rouse_ 14.02.2013
+ // Если включено добавление пустых папок, то добавляем сначала требуемую запись
+ if AlwaysAddEmptyFolder then
+ AddEmptyFolder(TrailingRelativePath, Attributes);
+ Continue;
+ end;
+
+ if SR.Name = '..' then Continue;
+
+ if SR.Attr and faDirectory <> 0 then
+ begin
+ if SubFolders then
+ Inc(Result, AddFolder(TrailingRelativePath + SR.Name,
+ TrailingPath + SR.Name, ResultMask, SubFolders));
+ end
+ else
+ begin
+ if AddFile(TrailingPath + SR.Name, Attributes,
+ TrailingRelativePath + SR.Name) >= 0 then
+ Inc(Result);
+ end;
+ until FindNextUTF8(SR) { *Преобразовано из FindNext* } <> 0;
+ finally
+ FindCloseUTF8(SR); { *Преобразовано из FindClose* }
+ end;
+end;
+
+//
+// Функция добавляет в архив данные из переданного стрима.
+// В качестве результата возвращает индекс элемента в списке
+// =============================================================================
+function TFWZipWriter.AddStream(const FileName: string;
+ Value: TStream): Integer;
+var
+ Size: Int64;
+ InitFileName: string;
+ Item: TFWZipWriterItem;
+ Attributes: TWin32FileAttributeData;
+begin
+ // проверка на дубли
+ InitFileName := CheckFileNameSlashes(FileName);
+
+ Size := Value.Size;
+ ZeroMemory(@Attributes, SizeOf(TWin32FileAttributeData));
+ Attributes.ftCreationTime := GetCurrentFileTime;
+ Attributes.ftLastAccessTime := Attributes.ftCreationTime;
+ Attributes.ftLastWriteTime := Attributes.ftCreationTime;
+ Attributes.nFileSizeLow := Size and MAXDWORD;
+ Attributes.nFileSizeHigh := Size shr 32;
+ Item := GetItemClass.Create(Self, '', Attributes, InitFileName);
+ Item.CompressionLevel := FDefaultCompressionLevel;
+ Item.Password := FDefaultPassword;
+
+ // в случае наличия дескриптора мы можем
+ // производить расчет контрольной суммы на лету, т.к. при включенном
+ // режиме шифрования она не участвует в генерации заголовка инициализации
+ Item.NeedDescriptor := FDefaultDescryptorState;
+
+ Item.ChangeDataStream(Value);
+ Result := AddNewItem(Item);
+end;
+
+//
+// Вспомогательная функция для доступа к листу из наследников
+// =============================================================================
+function TFWZipWriter.AddNewItem(Value: TFWZipWriterItem): Integer;
+begin
+ Result := FItems.Add(Value);
+end;
+
+//
+// Процедура формирует архив и сохраняет его в указанный стрим.
+// =============================================================================
+function TFWZipWriter.BuildZip(Stream: TStream): TBuildZipResult;
+var
+ I, TotalCount: Integer;
+ BeforeExceptPosition: Int64;
+ ExceptAction: TExceptionAction;
+ OldPathName, NewFilePath: string;
+ NewFileData: TMemoryStream;
+ DeletePackedFile: Boolean;
+begin
+ FVersionToExtract := 0;
+ FTotalProgress := 0;
+ FBuildState := True;
+ try
+ Result := brFailed;
+ if Count > 0 then
+ begin
+ // Выставляем размеры CentralDirectory
+ SetLength(FCD, Count);
+
+ // Рассчитываем общий размер элементов для отображения прогресса
+ FTotalSizeCount := 0;
+ FTotalProcessedCount := 0;
+ for I := 0 to Count - 1 do
+ Inc(FTotalSizeCount, Item[I].Size);
+
+ // Сжимаем все файлы архива и помещаем их в финальный стрим
+ // при этом резервируется место под LocalHeader и DataDescryptor
+ // т.к. размер запакованного файла будет известен только после этапа
+ // архивации и не понятно куда помещать значение:
+ // в LocalHeader, DataDescryptor или в ZIP64 блок данных в CentralDirectory
+ FExceptionCount := 0;
+ BeforeExceptPosition := 0;
+ TotalCount := 0;
+ Result := brDone;
+ I := 0;
+ DeletePackedFile := False;
+ OldPathName := '';
+ while I < Count do
+ begin
+ try
+
+ BeforeExceptPosition := Stream.Position;
+ SaveItemToStream(Stream, I);
+ Inc(TotalCount);
+ Inc(I);
+
+ // в случае если это повторная попытка сжатия и был применен
+ // аттрибут acUseNewFilePathAndDel, то необходимо удалить файл.
+ if DeletePackedFile then
+ begin
+ DeletePackedFile := False;
+ NewFilePath := Item[I - 1].FilePath;
+ SetFileAttributes(PChar(NewFilePath), FILE_ATTRIBUTE_NORMAL);
+ DeleteFileUTF8(NewFilePath); { *Преобразовано из DeleteFile* }
+ end;
+
+ // если путь к файлу был временно изменен из-за применения аттрибутов
+ // acUseNewFilePath или acUseNewFilePathAndDel,
+ // необходимо восстановить старое значение
+ if OldPathName <> '' then
+ begin
+ FBuildState := False;
+ try
+ Item[I - 1].FilePath := OldPathName;
+ finally
+ OldPathName := '';
+ FBuildState := True;
+ end;
+ end;
+
+ except
+
+ // Если пользователь отменил создание архива, выходим из цикла
+ on E: EAbort do
+ begin
+ Result := brAborted;
+ Exit;
+ end;
+
+ on E: Exception do
+ begin
+ // возвращаем позицию в стриме на старое место
+ Stream.Position := BeforeExceptPosition;
+
+ // если элемент использовал кастомные данные,
+ // то снимаем этот вариант заполнения и пусть извне решают
+ // что делать в этом случае
+ Item[I].UseExternalData := False;
+
+ // запрашиваем пользователя, что делать с исключением?
+ ExceptAction := eaSkip;
+ NewFilePath := '';
+
+ NewFileData := TMemoryStream.Create;
+ try
+
+ if Assigned(FBuidException) then
+ FBuidException(Self, E, I, ExceptAction,
+ NewFilePath, NewFileData);
+
+ // обрабатываем выбор польтзователя
+ case ExceptAction of
+
+ // повторить попытку
+ eaRetry:
+ Continue;
+
+ // пропустить элемент
+ eaSkip:
+ begin
+ // то помечаем элемент центральной директории.
+ // Он не будет обрабатываться при сохранениии.
+ FCD[I].ExceptOnWrite := True;
+ // Также увеличим число исключений, для правильной записи
+ // количества элементов архива в корневой директории
+ Inc(FExceptionCount);
+ Inc(I);
+ Result := brPartialBuild;
+ end;
+
+ // остановить создание архива
+ eaAbort:
+ begin
+ Result := brAborted;
+ Exit;
+ end;
+
+ // использовать данные из другого файла
+ eaUseNewFilePath, eaUseNewFilePathAndDel:
+ begin
+ // запоминаем текущий путь к файлу,
+ // для последующего восстановления
+ OldPathName := Item[I].FilePath;
+ FBuildState := False;
+ try
+ Item[I].FilePath := NewFilePath;
+ finally
+ FBuildState := True;
+ end;
+ // выставляем флаг, что при завершени сжатия,
+ // файл слудет удалить
+ DeletePackedFile := ExceptAction = eaUseNewFilePathAndDel;
+ Continue;
+ end;
+
+ // использовать данные из стрима
+ eaUseNewFileData:
+ begin
+ FBuildState := False;
+ try
+ Item[I].ChangeDataStream(NewFileData);
+ finally
+ FBuildState := True;
+ end;
+ Continue;
+ end;
+ end;
+
+ finally
+ NewFileData.Free;
+ end;
+ end;
+
+ end;
+ end;
+
+ // Если в архив не добавлен ни один из элементов,
+ // то возвращаем размер стрима на прежнее значение и выходим с ошибкой
+ if TotalCount = 0 then
+ begin
+ Stream.Size := Stream.Position;
+ Result := brFailed;
+ Exit;
+ end;
+
+ // Теперь размеры сжатых файлов известны,
+ // обновляем LocalHeader и DataDescryptor
+ UpdateLocalHeaders(Stream);
+
+ // Записываем CentralDirectory
+ SaveCentralDirectory(Stream);
+
+ // Пишем структуру EndOfCentralDirectory при этом при необходимости
+ // формируются и пишутся также структуры Zip64EOFCentralDirectoryRecord
+ // и Zip64EOFCentralDirectoryLocator
+ SaveEndOfCentralDirectory(Stream);
+ end;
+ finally
+ FBuildState := False;
+ end;
+end;
+
+//
+// Процедура формирует архив и сохраняет его в указанный файл.
+// =============================================================================
+function TFWZipWriter.BuildZip(const ZipFilePath: string): TBuildZipResult;
+var
+ ZIP: TFileStream;
+begin
+ Result := brFailed;
+ if Count = 0 then Exit;
+ ZIP := TFileStream.Create(ZipFilepath, fmCreate);
+ try
+ Result := BuildZip(ZIP);
+ FlushFileBuffers(ZIP.Handle);
+ finally
+ ZIP.Free;
+ end;
+ if Result in [brFailed, brAborted] then
+ DeleteFileUTF8(ZipFilePath); { *Преобразовано из DeleteFile* }
+end;
+
+//
+// Функция проводит проверку правильности наименования файла в архиве
+// =============================================================================
+function TFWZipWriter.CheckFileNameSlashes(const Value: string): string;
+begin
+ {
+ The name of the file, with optional relative path.
+ The path stored should not contain a drive or
+ device letter, or a leading slash. All slashes
+ should be forward slashes '/' as opposed to
+ backwards slashes '\' for compatibility with Amiga
+ and Unix file systems etc.
+ }
+
+ Result := StringReplace(Value, '\', ZIP_SLASH, [rfReplaceAll]);
+end;
+
+//
+// Очищаем все добавленные в архив элементы
+// =============================================================================
+procedure TFWZipWriter.Clear;
+begin
+ FItems.Clear;
+end;
+
+//
+// Процедура сжимет данные
+// =============================================================================
+procedure TFWZipWriter.CompressItem(CurrentItem: TFWZipWriterItem;
+ Index: Integer; StreamSizeBeforeCompress: Int64; Stream: TStream);
+
+
+ function CopyWithProgress(Src, Dst: TStream;
+ Cryptor: TFWZipCryptor): Cardinal;
+ var
+ Buff: Pointer;
+ Size, TotalSize: Integer;
+ begin
+ Result := $FFFFFFFF;
+ GetMem(Buff, MAXWORD);
+ try
+ Src.Position := 0;
+ FCompressedStream := Src;
+ DoProgress(psInitialization);
+ try
+ TotalSize := 0;
+ while True do
+ begin
+ Size := Src.Read(Buff^, MAXWORD);
+ Result := CRC32Calc(Result, Buff, Size);
+ if Size <> 0 then
+ begin
+ Inc(TotalSize, Size);
+ if Cryptor <> nil then
+ Cryptor.EncryptBuffer(Buff, Size);
+ Dst.WriteBuffer(Buff^, Size);
+ DoProgress(psInProgress);
+ end
+ else
+ Break;
+ end;
+ if TotalSize <> Src.Size then
+ raise EZipWriterWrite.CreateFmt(
+ 'Ошибка записи данных элемента №%d "%s".', [Index, Item[Index].FileName]);
+ except
+ DoProgress(psException);
+ raise;
+ end;
+ DoProgress(psFinalization);
+ finally
+ FreeMem(Buff);
+ end;
+ Result := Result xor $FFFFFFFF;
+ end;
+
+var
+ F: TFileStream;
+ Compressor: TZCompressionStream;
+ Cryptor: TFWZipCryptor;
+ ZipItemStream: TFWZipItemStream;
+ CRC32Stream: TFWZipCRC32Stream;
+ EncryptedHeaderStream: TMemoryStream;
+begin
+ Cryptor := nil;
+ try
+ EncryptedHeaderStream := TMemoryStream.Create;
+ try
+ if CurrentItem.Password <> '' then
+ begin
+ Cryptor := TFWZipCryptor.Create(AnsiString(CurrentItem.Password));
+ Cryptor.GenerateEncryptionHeader(EncryptedHeaderStream,
+ CurrentItem.NeedDescriptor,
+ FCD[Index].Header.Crc32,
+ FCD[Index].Header.LastModFileTimeTime +
+ FCD[Index].Header.LastModFileTimeDate shl 16);
+ // резервируем место под EncryptedHeaderStream
+ Stream.Size := StreamSizeBeforeCompress + EncryptedHeaderSize;
+ Stream.Position := Stream.Size;
+ end;
+
+ // пишем сам сжатый файл
+ case FCD[Index].Header.CompressionMethod of
+ Z_NO_COMPRESSION:
+ begin
+ if CurrentItem.Data <> nil then
+ FCD[Index].Header.Crc32 :=
+ CopyWithProgress(CurrentItem.Data, Stream, Cryptor)
+ else
+ begin
+ try
+ F := TFileStream.Create(CurrentItem.FilePath,
+ fmOpenRead or fmShareDenyWrite);
+ try
+ FCD[Index].Header.Crc32 :=
+ CopyWithProgress(F, Stream, Cryptor)
+ finally
+ F.Free;
+ end;
+ except
+ on E: Exception do
+ raise EZipWriterWrite.CreateFmt(
+ 'Ошибка доступа к данным элемента №%d "%s".' +
+ sLineBreak + E.ClassName + ': ' + E.Message,
+ [Index, CurrentItem.FileName]);
+ end;
+ end;
+ // Получаем размер сжатых данных
+ // В случае если использовалось шифрование в размере срузу будет
+ // учтен 12-ти байтный заголовок инициализации ключа расшифровки
+ FCD[Index].CompressedSize := Stream.Size - StreamSizeBeforeCompress;
+ end;
+ Z_DEFLATED:
+ begin
+ {$IFDEF USE_AUTOGENERATED_ZLIB_HEADER}
+ // позицию сдвигаем на два байта влево,
+ // таким образом мы затрем ненужный нам заголовок ZLib
+ Stream.Position := Stream.Position - 2;
+ {$ENDIF}
+ if CurrentItem.Data <> nil then
+ begin
+ // сохраняем ссылку на стрим с данными для рассчета прогресса
+ FCompressedStream := CurrentItem.Data;
+ ZipItemStream := TFWZipItemStream.Create(Stream, Cryptor, nil,
+ 0, CurrentItem.Size);
+ try
+ Compressor := TZCompressionStream.Create(
+ ZipItemStream, CurrentItem.CompressionLevel,
+ defaultWindowBits, 8, zsDefault);
+ try
+ Compressor.OnProgress := CompressorOnProcess;
+ DoProgress(psInitialization);
+ try
+ CRC32Stream := TFWZipCRC32Stream.Create(CurrentItem.Data);
+ try
+ Compressor.CopyFrom(CRC32Stream, 0);
+ FCD[Index].Header.Crc32 := CRC32Stream.CRC32;
+ finally
+ CRC32Stream.Free;
+ end;
+ except
+ DoProgress(psException);
+ raise;
+ end;
+ DoProgress(psFinalization);
+ finally
+ Compressor.Free;
+ end;
+ finally
+ ZipItemStream.Free;
+ end;
+ end
+ else
+ begin
+ // TFWZipItemStream выступает как посредник между результирующим
+ // стримом и TCompressionStream.
+ // Его задача зашифровать все проходящие через нешго данные
+ ZipItemStream := TFWZipItemStream.Create(Stream, Cryptor, nil,
+ 0, CurrentItem.Size);
+ try
+ Compressor := TZCompressionStream.Create(
+ ZipItemStream, CurrentItem.CompressionLevel,
+ defaultWindowBits, 8, zsDefault);
+ try
+ try
+ F := TFileStream.Create(CurrentItem.FilePath,
+ fmOpenRead or fmShareDenyWrite);
+ try
+ // сохраняем ссылку на стрим с данными для рассчета прогресса
+ FCompressedStream := F;
+ F.Position := 0;
+ Compressor.OnProgress := CompressorOnProcess;
+ // TFWZipCRC32Stream выступает как посредник между
+ // нераспакованными данными и TCompressionStream,
+ // в котором происходит сжатие данных.
+ // Его задача отследить все переданные через него
+ // блоки данных и рассчитать их контрольную сумму
+ // до того как они будут сжаты
+ DoProgress(psInitialization);
+ try
+ CRC32Stream := TFWZipCRC32Stream.Create(F);
+ try
+ Compressor.CopyFrom(CRC32Stream, 0);
+ FCD[Index].Header.Crc32 := CRC32Stream.CRC32;
+ finally
+ CRC32Stream.Free;
+ end;
+ except
+ DoProgress(psException);
+ raise;
+ end;
+ DoProgress(psFinalization);
+ finally
+ F.Free;
+ end;
+ except
+ on E: Exception do
+ raise EZipWriterWrite.CreateFmt(
+ 'Ошибка доступа к данным элемента №%d "%s".' +
+ sLineBreak + E.ClassName + ': ' + E.Message,
+ [Index, CurrentItem.FileName]);
+ end;
+ finally
+ Compressor.Free;
+ end;
+ finally
+ ZipItemStream.Free;
+ end;
+ end;
+
+ {$IFDEF USE_AUTOGENERATED_ZLIB_HEADER}
+ // Rouse_ 14.02.2013
+ // Не знаю почему, но опытным путем установлено,
+ // что размер запакованых данных должен быть меньше на 4 байта
+ // при использовании автогенерируемого заголовка.
+ // Этот момент учитывается в ICSharpCode.SharpZipLibrary
+ // Распаковка в любом случае происходит нормально
+ if TrimPackedStreamSize then
+ Stream.Size := Stream.Size - 4;
+ {$ENDIF}
+
+ // Получаем размер сжатых данных
+ // В случае если использовалось шифрование в размере срузу будет
+ // учтен 12-ти байтный заголовок инициализации ключа расшифровки
+ FCD[Index].CompressedSize := Stream.Size - StreamSizeBeforeCompress;
+
+ end;
+ end;
+
+ // если файл зашифрован,
+ // записываем заголовок инициализации ключа расшифровки
+ if EncryptedHeaderStream.Size > 0 then
+ begin
+ Stream.Position := StreamSizeBeforeCompress;
+ Stream.CopyFrom(EncryptedHeaderStream, 0);
+ end;
+ finally
+ EncryptedHeaderStream.Free;
+ end;
+
+ finally
+ Cryptor.Free;
+ end;
+end;
+
+//
+// Процедура вызывает событие OnProcess
+// =============================================================================
+procedure TFWZipWriter.CompressorOnProcess(Sender: TObject);
+begin
+ DoProgress(psInProgress);
+end;
+
+//
+// Функция возвращает количество добавленных элементов архива
+// =============================================================================
+function TFWZipWriter.Count: Integer;
+begin
+ Result := FItems.Count;
+end;
+
+//
+// Стандартный конструктор класса
+// =============================================================================
+constructor TFWZipWriter.Create;
+begin
+ Create(False, clDefault, '');
+end;
+
+//
+// Расширенный конструктор класса,
+// в котором можно указать степень сжатия,
+// используемую для всех элементов по умолчанию.
+// =============================================================================
+constructor TFWZipWriter.Create(CompressionLevel: TCompressionLevel);
+begin
+ Create(False, CompressionLevel, '');
+end;
+
+//
+// Расширенный конструктор класса,
+// в котором можно изменить настройки элементов будующего архива по умолчнию.
+// =============================================================================
+constructor TFWZipWriter.Create(UseDescryptors: Boolean;
+ CompressionLevel: TCompressionLevel; const DefaultPassword: string);
+begin
+ inherited Create;
+ FDefaultDescryptorState := UseDescryptors;
+ FDefaultCompressionLevel := CompressionLevel;
+ FDefaultPassword := DefaultPassword;
+ FItems := TObjectList.Create;
+ FItems.Capacity := 100000;
+ FTrimPackedStreamSize := True;
+end;
+
+//
+// Процедура удаляет ненужный элемент архива
+// =============================================================================
+procedure TFWZipWriter.DeleteItem(Index: Integer);
+begin
+ FItems.Delete(Index);
+end;
+
+//
+// Стандартный деструктор класса
+// =============================================================================
+destructor TFWZipWriter.Destroy;
+begin
+ FItems.Free;
+ inherited;
+end;
+
+//
+// Вызов внешнего события о прогрессе сжатия
+// =============================================================================
+procedure TFWZipWriter.DoProgress(ProgressState: TProgressState);
+var
+ CurrentProgress: Byte;
+ Cancel: Boolean;
+begin
+ if Assigned(FOnProgress) then
+ begin
+ case ProgressState of
+ psInProgress:
+ begin
+ if FCompressedStream.Size = 0 then
+ CurrentProgress := 100
+ else
+ CurrentProgress :=
+ Round(FCompressedStream.Position / (FCompressedStream.Size / 100));
+ if FTotalSizeCount = 0 then
+ FTotalProgress := 100
+ else
+ FTotalProgress :=
+ Round((FTotalProcessedCount + FCompressedStream.Position) /
+ (FTotalSizeCount / 100));
+ end;
+ psFinalization, psEnd: CurrentProgress := 100;
+ else
+ CurrentProgress := 0;
+ end;
+ Cancel := False;
+ FOnProgress(Self, Item[FProcessedItemIndex].FileName,
+ CurrentProgress, FTotalProgress, Cancel, ProgressState);
+ if Cancel then Abort;
+ end;
+end;
+
+//
+// Рассчитываем длину строки с учетом UTF8
+// =============================================================================
+function TFWZipWriter.StringLength(const Value: string; UTF8String: Boolean): Integer;
+begin
+ if UTF8String then
+ Result := Length(UTF8Encode(Value))
+ else
+ Result := Length(Value);
+end;
+
+//
+// Функция возвращает текущее время в формате TFileTime
+// =============================================================================
+function TFWZipWriter.GetCurrentFileTime: TFileTime;
+var
+ SystemTime: TSystemTime;
+begin
+ DateTimeToSystemTime(Now, SystemTime);
+ SystemTimeToFileTime(SystemTime, Result);
+ FileTimeToLocalFileTime(Result, Result);
+end;
+
+//
+// Обработчик свойства Items
+// =============================================================================
+function TFWZipWriter.GetItem(Index: Integer): TFWZipWriterItem;
+begin
+ Result := TFWZipWriterItem(FItems[Index]);
+end;
+
+//
+// Запрашиваем данные о расширенных блоках данных для каждой записи
+// =============================================================================
+procedure TFWZipWriter.FillExData(Stream: TStream; Index: Integer);
+var
+ ExDataStream: TMemoryStream;
+ EmptyExData: Boolean;
+ UserExDataBlockCount, ExDataSize: Integer;
+ ExDataHeaderTag: Word;
+begin
+ if Assigned(FSaveExData) then
+ begin
+ ExDataStream := TMemoryStream.Create;
+ try
+ EmptyExData := False;
+ UserExDataBlockCount := 0;
+ while not EmptyExData do
+ begin
+ ExDataHeaderTag := 0;
+ ExDataStream.Clear;
+ FSaveExData(Self, Index, UserExDataBlockCount,
+ ExDataHeaderTag, ExDataStream);
+ Inc(UserExDataBlockCount);
+ EmptyExData := ExDataStream.Size = 0;
+ if not EmptyExData then
+ begin
+ if ExDataStream.Size > MAXWORD then
+ raise EZipWriter.Create(
+ 'Размер каждого блока расширенных данных' +
+ ' не может превышать 65535 байт.')
+ else
+ ExDataSize := ExDataStream.Size;
+ if ExDataHeaderTag in
+ [0, SUPPORTED_EXDATA_ZIP64, SUPPORTED_EXDATA_NTFSTIME] then
+ raise EZipWriter.Create(
+ 'Нельзя использовать зарезервированные тэги' +
+ ' блока расширенных данных.');
+ Stream.WriteBuffer(ExDataHeaderTag, 2);
+ Stream.WriteBuffer(ExDataSize, 2);
+ Stream.CopyFrom(ExDataStream, 0);
+ end;
+ end;
+ finally
+ ExDataStream.Free;
+ end;
+ end;
+end;
+
+//
+// Инициализируем CentralDirectoryFileHeader элемента
+// =============================================================================
+procedure TFWZipWriter.FillItemCDFHeader(CurrentItem: TFWZipWriterItem;
+ var Value: TCentralDirectoryFileHeaderEx);
+var
+ SystemTime: TSystemTime;
+ LastWriteTime: TFileTime;
+ FileDate: Cardinal;
+begin
+ Value.Header.CentralFileHeaderSignature := CENTRAL_FILE_HEADER_SIGNATURE;
+ Value.Header.VersionMadeBy := CurrentVersionMadeBy;
+ Value.Header.VersionNeededToExtract := 0; // Рассчитывается позднее
+
+ Value.Header.GeneralPurposeBitFlag := 0;
+ if CurrentItem.Password <> '' then
+ Value.Header.GeneralPurposeBitFlag :=
+ Value.Header.GeneralPurposeBitFlag or PBF_CRYPTED;
+
+ case CurrentItem.CompressionLevel of
+ clNone:; // данный режим компрессии не поддерживается, сразу меняем на Store
+ clFastest:
+ Value.Header.GeneralPurposeBitFlag :=
+ Value.Header.GeneralPurposeBitFlag or PBF_COMPRESS_SUPERFAST;
+ clDefault:
+ Value.Header.GeneralPurposeBitFlag :=
+ Value.Header.GeneralPurposeBitFlag or PBF_COMPRESS_NORMAL;
+ clMax:
+ Value.Header.GeneralPurposeBitFlag :=
+ Value.Header.GeneralPurposeBitFlag or PBF_COMPRESS_MAXIMUM;
+ end;
+ if CurrentItem.NeedDescriptor then
+ Value.Header.GeneralPurposeBitFlag :=
+ Value.Header.GeneralPurposeBitFlag or PBF_DESCRIPTOR;
+
+ if CurrentItem.CompressionLevel = clNone then
+ Value.Header.CompressionMethod := Z_NO_COMPRESSION
+ else
+ Value.Header.CompressionMethod := Z_DEFLATED;
+
+ if not CurrentItem.NeedDescriptor then
+ if CurrentItem.Password <> '' then
+ begin
+ // в случае если дескрипторы отключены и включено шифрование элемента
+ // то необходимо рассчитать его контрольную сумму перед
+ // генерацией заголовка инициализации ключа шифрования
+ if CurrentItem.Data = nil then
+ Value.Header.Crc32 := FileCRC32(CurrentItem.FilePath)
+ else
+ Value.Header.Crc32 :=
+ CRC32Calc(CurrentItem.Data.Memory, CurrentItem.Data.Size);
+ end;
+ Value.UncompressedSize := CurrentItem.Size;
+
+ // Rouse_ 25.10.2013
+ // Правка небольшой ошибки замеченой Владиславом Нечепоренко
+ //FileTimeToSystemTime(CurrentItem.Attributes.ftLastWriteTime, SystemTyme);
+ FileTimeToLocalFileTime(CurrentItem.Attributes.ftLastWriteTime, LastWriteTime);
+ FileTimeToSystemTime(LastWriteTime, SystemTime);
+ FileDate := DateTimeToFileDate(SystemTimeToDateTime(SystemTime));
+
+ Value.Header.LastModFileTimeTime := FileDate and $FFFF;
+ Value.Header.LastModFileTimeDate := FileDate shr 16;
+
+ Value.Filename := CurrentItem.FileName;
+ Value.Header.FilenameLength :=
+ StringLength(CurrentItem.Filename, CurrentItem.UseUTF8String);
+ Value.Header.ExtraFieldLength := 0;
+ Value.FileComment := CurrentItem.Comment;
+ Value.Header.FileCommentLength :=
+ StringLength(CurrentItem.Comment, CurrentItem.UseUTF8String);
+ Value.Header.DiskNumberStart := 0;
+ Value.Header.InternalFileAttributes := 0;
+ Value.Header.ExternalFileAttributes :=
+ CurrentItem.Attributes.dwFileAttributes;
+ Value.Attributes := CurrentItem.Attributes;
+
+ if CurrentItem.UseUTF8String then
+ Value.Header.GeneralPurposeBitFlag :=
+ Value.Header.GeneralPurposeBitFlag or PBF_UTF8;
+end;
+
+//
+// Добавляем возможность создавать наследников от базового класса
+// =============================================================================
+function TFWZipWriter.GetItemClass: TFWZipWriterItemClass;
+begin
+ Result := TFWZipWriterItem;
+end;
+
+//
+// Функция рассчитывает минимальную версию для извлечения
+// указанного элемента архива
+// =============================================================================
+function TFWZipWriter.GetVersionToExtract(Index: Integer): Word;
+begin
+{
+ Current minimum feature versions are as defined below:
+
+ 1.0 - Default value
+ 1.1 - File is a volume label
+ 2.0 - File is a folder (directory)
+ 2.0 - File is compressed using Deflate compression
+ 2.0 - File is encrypted using traditional PKWARE encryption
+ 2.1 - File is compressed using Deflate64(tm)
+ 2.5 - File is compressed using PKWARE DCL Implode
+ 2.7 - File is a patch data set
+ 4.5 - File uses ZIP64 format extensions
+ 4.6 - File is compressed using BZIP2 compression*
+ 5.0 - File is encrypted using DES
+ 5.0 - File is encrypted using 3DES
+ 5.0 - File is encrypted using original RC2 encryption
+ 5.0 - File is encrypted using RC4 encryption
+ 5.1 - File is encrypted using AES encryption
+ 5.1 - File is encrypted using corrected RC2 encryption**
+ 5.2 - File is encrypted using corrected RC2-64 encryption**
+ 6.1 - File is encrypted using non-OAEP key wrapping***
+ 6.2 - Central directory encryption
+}
+
+ // TGSZIPWriter поддерживает следующие расширения стандарта:
+ // 1. использование директорий (версия для извлечения - 2.0)
+ // 2. использование ZIP64 расширения (версия для извлечения - 4.5)
+
+ // Для определения, нужно ли нам использовать ZIP64 необходимо проверить
+ // следующие параметры:
+ // размер каждого элемента архива сжатого и не сжатого,
+ // оффсет на начало блока данных для каждого элемента
+ // если любое из этих значений выходит за значение MAXDWORD,
+ // или количество элементов архива выходит за значение MAXWORD,
+ // нам необходимо применять ZIP64
+
+ Result := 20;
+ if (FCD[Index].UncompressedSize >= MAXDWORD) or
+ (FCD[Index].CompressedSize >= MAXDWORD) or
+ (FCD[Index].RelativeOffsetOfLocalHeader >= MAXDWORD) or
+ (FCD[Index].DiskNumberStart >= MAXWORD) then
+ Result := 45;
+end;
+
+//
+// Процедура проводит сохранение секции CentralDirectory
+// =============================================================================
+procedure TFWZipWriter.SaveCentralDirectory(Stream: TStream);
+var
+ I: Integer;
+ ExDataHeader: TExDataHeaderAndSize;
+ ExDataNTFS: TExDataNTFS;
+ ZIP64Data: TMemoryStream;
+ TotalExDataStream: TMemoryStream;
+begin
+ ZeroMemory(@ExDataNTFS, SizeOf(TExDataNTFS));
+ for I := 0 to Count - 1 do
+ begin
+
+ // пропускаем элементы при записи которых произошло исключение
+ if FCD[I].ExceptOnWrite then Continue;
+
+ // перед записью каждого элемента CentralDirectory
+ // необходимо подготовить буфферы с расширенными данными
+ // и указать их расмер
+ ZIP64Data := TMemoryStream.Create;
+ try
+ // подготавиваем буффер с ZIP64 данными
+
+ {
+ The order of the fields in the ZIP64 extended
+ information record is fixed, but the fields will
+ only appear if the corresponding Local or Central
+ directory record field is set to 0xFFFF or 0xFFFFFFFF.
+ }
+
+ if FCD[I].UncompressedSize >= MAXDWORD then
+ ZIP64Data.WriteBuffer(FCD[I].UncompressedSize, 8);
+ if FCD[I].CompressedSize >= MAXDWORD then
+ ZIP64Data.WriteBuffer(FCD[I].CompressedSize, 8);
+ if FCD[I].RelativeOffsetOfLocalHeader >= MAXDWORD then
+ ZIP64Data.WriteBuffer(FCD[I].RelativeOffsetOfLocalHeader, 8);
+ if FCD[I].DiskNumberStart >= MAXWORD then
+ ZIP64Data.WriteBuffer(FCD[I].DiskNumberStart, 4);
+
+ ZeroMemory(@ExDataNTFS, SizeOf(TExDataHeaderAndSize));
+ if IsAttributesPresent(FCD[I].Attributes) then
+ begin
+ // подготавливаем буффер с NTFS временем
+ FCD[I].Header.ExtraFieldLength := SizeOf(TExDataNTFS);
+
+ // (NTFS) 0x000a Short Tag for this "extra" block type
+ ExDataNTFS.HS.Header := SUPPORTED_EXDATA_NTFSTIME;
+ {
+ In the current implementations, this field has
+ a fixed total data size of 32 bytes and is only stored as local
+ extra field
+ }
+ ExDataNTFS.HS.Size := 32;
+ // Reserved Long for future use
+ ExDataNTFS.Reserved := 0;
+ // Tag1 Short NTFS attribute tag value #1
+ ExDataNTFS.Tag := 1;
+ //Size1 2 bytes Size of attribute #1, in bytes (24)
+ ExDataNTFS.RecordSize := 24;
+ ExDataNTFS.Data.Mtime := FCD[I].Attributes.ftLastWriteTime;
+ ExDataNTFS.Data.Atime := FCD[I].Attributes.ftLastAccessTime;
+ ExDataNTFS.Data.Ctime := FCD[I].Attributes.ftCreationTime;
+ end;
+ if ZIP64Data.Size > 0 then
+ Inc(FCD[I].Header.ExtraFieldLength,
+ ZIP64Data.Size + SizeOf(TExDataHeaderAndSize));
+
+ TotalExDataStream := TMemoryStream.Create;
+ try
+ // Запрашиваем блоки ExData от пользователя
+ FillExData(TotalExDataStream, I);
+
+ // правим общий размер расширенных блоков
+ Inc(FCD[I].Header.ExtraFieldLength, TotalExDataStream.Size);
+
+ // Пишем структуру TCentralDirectoryFileHeader, описывающую элемент
+ Stream.WriteBuffer(FCD[I].Header, SizeOf(TCentralDirectoryFileHeader));
+
+ // Пишем наименование элемента
+ SaveString(Stream, FCD[I].FileName,
+ FCD[I].Header.GeneralPurposeBitFlag and PBF_UTF8 = PBF_UTF8);
+
+ // если нужно - доп информацию в формате ZIP64
+ if ZIP64Data.Size > 0 then
+ begin
+ ExDataHeader.Header := SUPPORTED_EXDATA_ZIP64;
+ ExDataHeader.Size := ZIP64Data.Size;
+ Stream.WriteBuffer(ExDataHeader, SizeOf(TExDataHeaderAndSize));
+ Stream.CopyFrom(ZIP64Data, 0);
+ end;
+
+ // потом информацию о NTFSTime
+ if ExDataNTFS.HS.Header = SUPPORTED_EXDATA_NTFSTIME then
+ Stream.WriteBuffer(ExDataNTFS, SizeOf(TExDataNTFS));
+
+ // и расширенную информацию полученную от пользователя
+ if TotalExDataStream.Size > 0 then
+ Stream.CopyFrom(TotalExDataStream, 0);
+
+ finally
+ TotalExDataStream.Free;
+ end;
+
+ // в завершение, пишем коментарий к элементу
+ SaveString(Stream, FCD[I].FileComment,
+ FCD[I].Header.GeneralPurposeBitFlag and PBF_UTF8 = PBF_UTF8);
+
+ finally
+ ZIP64Data.Free;
+ end;
+ end;
+end;
+
+//
+// Процедура проводит сохранение секции EndOfCentralDirectory
+// =============================================================================
+procedure TFWZipWriter.SaveEndOfCentralDirectory(Stream: TStream);
+var
+ oe64cd: TZip64EOFCentralDirectoryRecord;
+ locator: TZip64EOFCentralDirectoryLocator;
+ eocd: TEndOfCentralDir;
+ oe64cdOffset, SizeOfCentralDir: Int64;
+begin
+ oe64cdOffset := Stream.Position;
+ SizeOfCentralDir := oe64cdOffset - FcdfhOffset;
+ // Исключаем из общего количества элементов архива количество исключений
+ oe64cd.TotalNumber1 := Count - FExceptionCount;
+ // формат ZIP64 используется в случае если количество элементов
+ // архива превышает MAXWORD, или смещение на начало центральной директории
+ // превышает MAXDWORD или ее размер превышает MAXDWORD
+ if (FcdfhOffset > MAXDWORD) or (SizeOfCentralDir > MAXDWORD) or
+ (oe64cd.TotalNumber1 > MAXWORD) then
+ begin
+ // В случае использования формата ZIP64
+ // необходимо записать дополнительные структуры
+
+ // TZip64EOFCentralDirectoryRecord
+ oe64cd.Zip64EndOfCentralDirSignature := ZIP64_END_OF_CENTRAL_DIR_SIGNATURE;
+
+
+ // Rouse_ 20.07.2013
+ // в спецификации 6.3.0 от September 29, 2006 оговорено
+ {
+ The value stored into the "size of zip64 end of central
+ directory record" should be the size of the remaining
+ record and should not include the leading 12 bytes.
+
+ Size = SizeOfFixedFields + SizeOfVariableData - 12.
+ }
+ // FWZip разрабатывался на основе более ранних спецификаций
+ // (изначально на 6.0 потом на 6.2) и не учитывал этот момент
+
+ // Поэтому вместо
+ // oe64cd.SizeOfZip64EOFCentralDirectoryRecord :=
+ // SizeOf(TZip64EOFCentralDirectoryRecord);
+ // пишем:
+
+ oe64cd.SizeOfZip64EOFCentralDirectoryRecord :=
+ SizeOf(TZip64EOFCentralDirectoryRecord) - 12;
+
+
+ oe64cd.VersionMadeBy := CurrentVersionMadeBy;
+ oe64cd.VersionNeededToExtract := FVersionToExtract;
+ oe64cd.Number1 := 0;
+ oe64cd.Number2 := 0;
+ oe64cd.TotalNumber2 := oe64cd.TotalNumber1;
+ oe64cd.Size := SizeOfCentralDir;
+ oe64cd.Offset := FcdfhOffset;
+ Stream.WriteBuffer(oe64cd, SizeOf(TZip64EOFCentralDirectoryRecord));
+
+ // TZip64EOFCentralDirectoryLocator
+ locator.Signature := ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE;
+ locator.NumberOfTheDisk := 0;
+ locator.RelativeOffset := oe64cdOffset;
+ locator.TotalNumberOfDisks := 1;
+ Stream.WriteBuffer(locator, SizeOf(TZip64EOFCentralDirectoryLocator));
+
+ end;
+ eocd.EndOfCentralDirSignature := END_OF_CENTRAL_DIR_SIGNATURE;
+ eocd.NumberOfThisDisk := 0;
+ eocd.NumberOfTheDiskWithTheStart := 0;
+ if oe64cd.TotalNumber1 > MAXWORD then
+ eocd.TotalNumberOfEntriesOnThisDisk := MAXWORD
+ else
+ eocd.TotalNumberOfEntriesOnThisDisk := oe64cd.TotalNumber1;
+ eocd.TotalNumberOfEntries := eocd.TotalNumberOfEntriesOnThisDisk;
+ if SizeOfCentralDir > MAXDWORD then
+ eocd.SizeOfTheCentralDirectory := MAXDWORD
+ else
+ eocd.SizeOfTheCentralDirectory := SizeOfCentralDir;
+ if FcdfhOffset > MAXDWORD then
+ eocd.OffsetOfStartOfCentralDirectory := MAXDWORD
+ else
+ eocd.OffsetOfStartOfCentralDirectory := FcdfhOffset;
+ eocd.ZipfileCommentLength := StringLength(FComment, False);
+ Stream.WriteBuffer(eocd, SizeOf(TEndOfCentralDir));
+ if eocd.ZipfileCommentLength > 0 then
+ SaveString(Stream, FComment, False);
+end;
+
+//
+// Процедура проводит все процедуры подготовки, сжатия и сохранения указанного элемента архива
+// =============================================================================
+procedure TFWZipWriter.SaveItemToStream(Stream: TStream; Index: Integer);
+var
+ CurrentItem: TFWZipWriterItem;
+ FileNameOffset, StreamSizeBeforeCompress: Int64;
+begin
+ CurrentItem := Item[Index];
+
+ // проверка на дуракоустойчивость
+ if not CurrentItem.UseExternalData then
+ if (CurrentItem.FilePath = '') and (CurrentItem.Data = nil) then
+ raise EZipWriter.CreateFmt('Данные элемента №%d "%s" отсутствуют',
+ [Index, CurrentItem.FileName]);
+
+ FProcessedItemIndex := Index;
+
+ // Rouse_ 25.10.2013
+ // Генерируем событие начала распаковки перед тем как результирующий файл будет залочен
+ DoProgress(psStart);
+ try
+
+ // Заполняем информацию в CentralDirectory
+ // ===========================================================================
+ FillItemCDFHeader(CurrentItem, FCD[Index]);
+ FCD[Index].RelativeOffsetOfLocalHeader := Stream.Position;
+
+ // Помещаем данные в результирующий файл
+ // ===========================================================================
+
+ // Запоминаем оффсет по которому необходимо будет писать имя файла
+ FileNameOffset := Stream.Position + SizeOf(TLocalFileHeader);
+
+ // рассчитываем размер резервируемого места под
+ // LocalFileHeader и имя файла
+ StreamSizeBeforeCompress := FileNameOffset +
+ FCD[Index].Header.FilenameLength;
+
+ // резервируем место под ZIP64
+ if FCD[Index].UncompressedSize >= MAXDWORD then
+ Inc(StreamSizeBeforeCompress, SizeOf(TExDataInfo64));
+
+ // выделяем блок данных под LocalFileHeader и имя файла
+ Stream.Size := StreamSizeBeforeCompress;
+ Stream.Position := Stream.Size;
+
+ // сжимаем данные
+ if not CurrentItem.IsFolder then
+ CompressItem(CurrentItem, Index, StreamSizeBeforeCompress, Stream);
+
+ Inc(FTotalProcessedCount, CurrentItem.Size);
+
+ // пишем имя файла
+ Stream.Position := FileNameOffset;
+ SaveString(Stream, FCD[Index].Filename, CurrentItem.UseUTF8String);
+
+ // резервируем место под дескриптор
+ if CurrentItem.NeedDescriptor then
+ Stream.Size := Stream.Size + SizeOf(TDataDescriptor);
+
+ Stream.Position := Stream.Size;
+
+ finally
+ // Rouse_ 25.10.2013
+ // Результирующий файл освобожден, генерируем событие
+ DoProgress(psEnd);
+ end;
+end;
+
+//
+// Процедура проводит преобразование переданной строки в OEM и ее сохранение
+// =============================================================================
+procedure TFWZipWriter.SaveString(Stream: TStream; const Value: string;
+ UTF8String: Boolean);
+var
+ OemString: AnsiString;
+begin
+ if Value <> '' then
+ begin
+ OemString := AnsiString(Value);
+ UniqueString(OemString);
+ if UTF8String then
+ OemString := UTF8Encode(Value)
+ else
+ AnsiToOem(PAnsiChar(OemString), PAnsiChar(OemString));
+ Stream.WriteBuffer(OemString[1], Length(OemString));
+ end;
+end;
+
+//
+// Процедура обновляет секции LocalFileHeader
+// =============================================================================
+procedure TFWZipWriter.UpdateLocalHeaders(Stream: TStream);
+var
+ I: Integer;
+ lfh: TLocalFileHeader;
+ dd: TDataDescriptor;
+ UseDescriptor: Boolean;
+ Info64: TExDataInfo64;
+begin
+ FcdfhOffset := Stream.Position;
+ for I := 0 to Count - 1 do
+ begin
+
+ // пропускаем элементы при записи которых произошло исключение
+ if FCD[I].ExceptOnWrite then Continue;
+
+ // Имея на руках все данные перезаписываем все LocalFileHeader
+ // и DataDescriptor (если требуется)
+ lfh.LocalFileHeaderSignature := LOCAL_FILE_HEADER_SIGNATURE;
+
+ // рассчитываем версию необходимую для распаковки элемента архива
+ lfh.VersionNeededToExtract := GetVersionToExtract(I);
+ lfh.GeneralPurposeBitFlag := FCD[I].Header.GeneralPurposeBitFlag;
+ UseDescriptor := lfh.GeneralPurposeBitFlag and PBF_DESCRIPTOR <> 0;
+ lfh.CompressionMethod := FCD[I].Header.CompressionMethod;
+ lfh.LastModFileTimeTime := FCD[I].Header.LastModFileTimeTime;
+ lfh.LastModFileTimeDate := FCD[I].Header.LastModFileTimeDate;
+ if UseDescriptor then
+ begin
+ dd.DescriptorSignature := DATA_DESCRIPTOR_SIGNATURE;
+ // хоть в стандарте сказано что при использовании дескрипторов
+ // поля Crc32, CompressedSize и UncompressedSize должны быль установлены
+ // в ноль, но большинство архиваторов этого не делают,
+ // поэтому уподобимся им :)
+ lfh.Crc32 := FCD[I].Header.Crc32;
+ dd.Crc32 := lfh.Crc32;
+ if FCD[I].CompressedSize > MAXDWORD then
+ dd.CompressedSize := MAXDWORD
+ else
+ dd.CompressedSize := FCD[I].CompressedSize;
+ lfh.CompressedSize := dd.CompressedSize;
+ if FCD[I].UncompressedSize > MAXDWORD then
+ dd.UncompressedSize := MAXDWORD
+ else
+ dd.UncompressedSize := FCD[I].UncompressedSize;
+ lfh.UncompressedSize := dd.UncompressedSize;
+ end
+ else
+ begin
+ lfh.Crc32 := FCD[I].Header.Crc32;
+ if FCD[I].CompressedSize > MAXDWORD then
+ lfh.CompressedSize := MAXDWORD
+ else
+ lfh.CompressedSize := FCD[I].CompressedSize;
+ if FCD[I].UncompressedSize > MAXDWORD then
+ lfh.UncompressedSize := MAXDWORD
+ else
+ lfh.UncompressedSize := FCD[I].UncompressedSize;
+ end;
+ lfh.FilenameLength := FCD[I].Header.FilenameLength;
+
+ if (FCD[I].UncompressedSize >= MAXDWORD) or
+ (FCD[I].CompressedSize >= MAXDWORD) then
+ lfh.ExtraFieldLength := SizeOf(TExDataInfo64)
+ else
+ lfh.ExtraFieldLength := 0;
+
+ Stream.Position := FCD[I].RelativeOffsetOfLocalHeader;
+
+ Stream.WriteBuffer(lfh, SizeOf(TLocalFileHeader));
+
+ // Rouse_ 20.03.2015
+ // Пишем данные для поддержки ZIP64
+ // а то WinRar, WinZip и 7Zip не будут распаковывать такой архив
+ // (не понятно правда, почему они не читают эту информацию из CentralDirectory)
+ if lfh.ExtraFieldLength > 0 then
+ begin
+ Stream.Position := Stream.Position + lfh.FilenameLength;
+ Info64.HS.Header := SUPPORTED_EXDATA_ZIP64;
+ Info64.HS.Size := SizeOf(TExDataInfo64) - SizeOf(TExDataHeaderAndSize);
+ Info64.UncompressedSize := FCD[I].UncompressedSize;
+ // если CompressedSize меньше MAXDWORD его писать не надо по стандарту,
+ // но место под него уже зарезервированно, поэтому придется писать его в любом случае
+ // как обойти это расхождение со стандартом хорошим способом - я пока не знаю
+ Info64.CompressedSize := FCD[I].CompressedSize;
+ Stream.WriteBuffer(Info64, SizeOf(TExDataInfo64));
+ end;
+
+ if UseDescriptor then
+ begin
+ // дескриптор пишется после сжатого блока данных
+ Stream.Position := FCD[I].RelativeOffsetOfLocalHeader +
+ SizeOf(TLocalFileHeader) + lfh.FilenameLength +
+ lfh.ExtraFieldLength + FCD[I].CompressedSize;
+ Stream.WriteBuffer(dd, SizeOf(TDataDescriptor));
+ end;
+
+ // обновляем информацию в массиве CentralDirectoryFileHeader
+
+ // Rouse_ 14.02.2013
+ // Неверно выставлялась версия для распаковки в CentralDirectoryFileHeader
+ //FCD[I].Header.VersionNeededToExtract := FVersionToExtract;
+ FCD[I].Header.VersionNeededToExtract := lfh.VersionNeededToExtract;
+
+ if UseDescriptor then
+ FCD[I].Header.CompressedSize := dd.CompressedSize
+ else
+ FCD[I].Header.CompressedSize := lfh.CompressedSize;
+ if UseDescriptor then
+ FCD[I].Header.UncompressedSize := dd.UncompressedSize
+ else
+ FCD[I].Header.UncompressedSize := lfh.UncompressedSize;
+ if FCD[I].RelativeOffsetOfLocalHeader > MAXDWORD then
+ FCD[I].Header.RelativeOffsetOfLocalHeader := MAXDWORD
+ else
+ FCD[I].Header.RelativeOffsetOfLocalHeader :=
+ FCD[I].RelativeOffsetOfLocalHeader;
+
+ // Rouse_ 14.02.2013
+ // обновляем глобальную метку версии
+ if FVersionToExtract < lfh.VersionNeededToExtract then
+ FVersionToExtract := lfh.VersionNeededToExtract;
+ end;
+ Stream.Position := FcdfhOffset;
+end;
+
+end.
diff --git a/prereq/fwzip/FWZipZLib.pas b/prereq/fwzip/FWZipZLib.pas
new file mode 100644
index 0000000..e11cd53
--- /dev/null
+++ b/prereq/fwzip/FWZipZLib.pas
@@ -0,0 +1,682 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ****************************************************************************
+// * Project : FWZip
+// * Unit Name : FWZipZLib
+// * Purpose : Базовые стримы сжатия и распаковки.
+// * : Вынесено из ZLibEx в отдельный модуль
+// * : для совместимости со старыми версиями Delphi
+// * Author : Александр (Rouse_) Багель
+// * Copyright : © Fangorn Wizards Lab 1998 - 2015.
+// * Version : 1.0.11
+// * Home Page : http://rouse.drkb.ru
+// * Home Blog : http://alexander-bagel.blogspot.ru
+// ****************************************************************************
+// * Stable Release : http://rouse.drkb.ru/components.php#fwzip
+// * Latest Source : https://github.com/AlexanderBagel/FWZip
+// ****************************************************************************
+//
+// Используемые источники:
+// ftp://ftp.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
+// http://zlib.net/zlib-1.2.5.tar.gz
+// http://www.base2ti.com/
+//
+
+{*************************************************************************************************
+* ZLibEx.pas *
+* *
+* copyright (c) 2000-2013 base2 technologies *
+* copyright (c) 1995-2002 Borland Software Corporation *
+* *
+*************************************************************************************************}
+
+unit FWZipZLib;
+{$mode delphi}
+{$codepage UTF8}
+
+interface
+
+{$I fwzip.inc}
+
+uses
+ Classes,
+ SysUtils,
+ {$IFDEF USE_ZLIB_EX}
+ ZLibExApi
+ {$ELSE}
+ {$IFDEF USE_ZLIB_DLL}
+ ZLib_external
+ {$ELSE}
+ ZLib
+ {$ENDIF}
+ {$ENDIF};
+
+type
+ TStreamPos = Int64;
+
+ TZStrategy = (
+ zsDefault,
+ zsFiltered,
+ zsHuffman,
+ zsRLE,
+ zsFixed
+ );
+
+ TCompressionLevel = (
+ clNone,
+ clFastest,
+ clDefault,
+ clMax,
+ clLevel1,
+ clLevel2,
+ clLevel3,
+ clLevel4,
+ clLevel5,
+ clLevel6,
+ clLevel7,
+ clLevel8,
+ clLevel9
+ );
+
+ TZError = (
+ zeError,
+ zeStreamError,
+ zeDataError,
+ zeMemoryError,
+ zeBufferError,
+ zeVersionError
+ );
+
+ TZFlush = (
+ zfNoFlush,
+ zfPartialFlush,
+ zfSyncFlush,
+ zfFullFlush,
+ zfFinish,
+ zfBlock,
+ zfTrees
+ );
+
+const
+ ZLevels: Array [TCompressionLevel] of Integer = (
+ Z_NO_COMPRESSION, // zcNone
+ Z_BEST_SPEED, // zcFastest
+ Z_DEFAULT_COMPRESSION, // zcDefault
+ Z_BEST_COMPRESSION, // zcMax
+ 1, // zcLevel1
+ 2, // zcLevel2
+ 3, // zcLevel3
+ 4, // zcLevel4
+ 5, // zcLevel5
+ 6, // zcLevel6
+ 7, // zcLevel7
+ 8, // zcLevel8
+ 9 // zcLevel9
+ );
+
+ {** compression methods ***********************************************************************}
+
+ Z_DEFLATED = 8;
+
+ {** compression levels ************************************************************************}
+
+ Z_NO_COMPRESSION = 0;
+ Z_BEST_SPEED = 1;
+ Z_BEST_COMPRESSION = 9;
+ Z_DEFAULT_COMPRESSION = (-1);
+
+ {** flush constants ***************************************************************************}
+
+ Z_NO_FLUSH = 0;
+ Z_PARTIAL_FLUSH = 1;
+ Z_SYNC_FLUSH = 2;
+ Z_FULL_FLUSH = 3;
+ Z_FINISH = 4;
+ Z_BLOCK = 5;
+ Z_TREES = 6;
+
+ {** compression strategies ********************************************************************}
+
+ Z_FILTERED = 1;
+ Z_HUFFMAN_ONLY = 2;
+ Z_RLE = 3;
+ Z_FIXED = 4;
+ Z_DEFAULT_STRATEGY = 0;
+
+ ZStrategies: Array [TZStrategy] of Integer = (
+ Z_DEFAULT_STRATEGY, // zsDefault
+ Z_FILTERED, // zsFiltered
+ Z_HUFFMAN_ONLY, // zsHuffman
+ Z_RLE, // zsRLE
+ Z_FIXED // zsFixed
+ );
+
+ ZErrors: Array [TZError] of Integer = (
+ Z_ERRNO, // zeError
+ Z_STREAM_ERROR, // zeStreamError
+ Z_DATA_ERROR, // zeDataError
+ Z_MEM_ERROR, // zeMemoryError
+ Z_BUF_ERROR, // zeBufferError
+ Z_VERSION_ERROR // zeVersionError
+ );
+
+ ZFlushes: Array [TZFlush] of Integer = (
+ Z_NO_FLUSH, // zfNoFlush
+ Z_PARTIAL_FLUSH, // zfPartialFlush
+ Z_SYNC_FLUSH, // zfSyncFlush
+ Z_FULL_FLUSH, // zfFullFlush
+ Z_FINISH, // zfFinish
+ Z_BLOCK, // zfBlock
+ Z_TREES // zfTrees
+ );
+
+ {** return code messages **********************************************************************}
+
+ z_errmsg: Array [0..9] of String = (
+ 'Need dictionary', // Z_NEED_DICT (2)
+ 'Stream end', // Z_STREAM_END (1)
+ 'OK', // Z_OK (0)
+ 'File error', // Z_ERRNO (-1)
+ 'Stream error', // Z_STREAM_ERROR (-2)
+ 'Data error', // Z_DATA_ERROR (-3)
+ 'Insufficient memory', // Z_MEM_ERROR (-4)
+ 'Buffer error', // Z_BUF_ERROR (-5)
+ 'Incompatible version', // Z_VERSION_ERROR (-6)
+ ''
+ );
+
+type
+
+ {** TCustomZStream ****************************************************************************}
+
+ TCustomZStream = class(TStream)
+ private
+ FStream : TStream;
+ FStreamPos : TStreamPos;
+ FOnProgress: TNotifyEvent;
+
+ FZStream : TZStreamRec;
+ FBuffer : Array [Word] of Byte;
+
+ function GetStreamPosition: TStreamPos;
+ procedure SetStreamPosition(value: TStreamPos);
+ protected
+ constructor Create(stream: TStream);
+
+ function StreamRead(var buffer; count: Longint): Longint;
+ function StreamWrite(const buffer; count: Longint): Longint;
+ function StreamSeek(offset: Longint; origin: Word): Longint;
+
+ procedure StreamReadBuffer(var buffer; count: Longint);
+ procedure StreamWriteBuffer(const buffer; count: Longint);
+
+ procedure DoProgress; dynamic;
+
+ property StreamPosition: TStreamPos read GetStreamPosition write SetStreamPosition;
+
+ property OnProgress: TNotifyEvent read FOnProgress write FOnProgress;
+ end;
+
+ {** TZCompressionStream ***********************************************************************}
+
+ TZCompressionStream = class(TCustomZStream)
+ private
+ function GetCompressionRate: Single;
+ public
+ constructor Create(dest: TStream;
+ compressionLevel: TCompressionLevel = clDefault); overload;
+
+ constructor Create(dest: TStream; compressionLevel: TCompressionLevel;
+ windowBits, memLevel: Integer; strategy: TZStrategy); overload;
+
+ destructor Destroy; override;
+
+ function Read(var buffer; count: Longint): Longint; override;
+ function Write(const buffer; count: Longint): Longint; override;
+ function Seek(offset: Longint; origin: Word): Longint; override;
+
+ property CompressionRate: Single read GetCompressionRate;
+ property OnProgress;
+ end;
+
+ {** TZDecompressionStream *********************************************************************}
+
+ TZDecompressionStream = class(TCustomZStream)
+ public
+ constructor Create(source: TStream); overload;
+ constructor Create(source: TStream; windowBits: Integer); overload;
+
+ destructor Destroy; override;
+
+ function Read(var buffer; count: Longint): Longint; override;
+ function Write(const buffer; count: Longint): Longint; override;
+ function Seek(offset: Longint; origin: Word): Longint; override;
+
+ property OnProgress;
+ end;
+
+type
+ EZLibErrorClass = class of EZlibError;
+
+ EZLibError = class(Exception)
+ private
+ FErrorCode: Integer;
+ public
+ constructor Create(code: Integer; const dummy: String = ''); overload;
+ constructor Create(error: TZError; const dummy: String = ''); overload;
+
+ property ErrorCode: Integer read FErrorCode write FErrorCode;
+ end;
+
+ EZCompressionError = class(EZLibError);
+ EZDecompressionError = class(EZLibError);
+
+implementation
+
+const
+ SZInvalid = 'Invalid ZStream operation!';
+
+function ZCompressCheck(code: Integer): Integer;
+begin
+ result := code;
+
+ if code < 0 then
+ begin
+ raise EZCompressionError.Create(code);
+ end;
+end;
+
+function ZDecompressCheck(code: Integer; raiseBufferError: Boolean = True): Integer;
+begin
+ Result := code;
+
+ if code < 0 then
+ begin
+ if (code <> Z_BUF_ERROR) or raiseBufferError then
+ begin
+ raise EZDecompressionError.Create(code);
+ end;
+ end;
+end;
+
+{** zlib deflate routines ***********************************************************************}
+
+function ZDeflateInit(var stream: TZStreamRec;
+ level: TCompressionLevel): Integer;
+begin
+ result := deflateInit_(stream, ZLevels[level], ZLIB_VERSION,
+ SizeOf(TZStreamRec));
+end;
+
+function ZDeflateInit2(var stream: TZStreamRec;
+ level: TCompressionLevel; windowBits, memLevel: Integer;
+ strategy: TZStrategy): Integer;
+begin
+ {$IFDEF OLDEST_ZLIB}
+ result := ZDeflateInit(stream, level);
+ {$ELSE}
+ result := deflateInit2_(stream, ZLevels[level], Z_DEFLATED, windowBits,
+ memLevel, ZStrategies[strategy], ZLIB_VERSION, SizeOf(TZStreamRec));
+ {$ENDIF}
+end;
+
+function ZDeflate(var stream: TZStreamRec; flush: TZFlush): Integer;
+begin
+ result := deflate(stream, ZFlushes[flush]);
+end;
+
+function ZDeflateEnd(var stream: TZStreamRec): Integer;
+begin
+ result := deflateEnd(stream);
+end;
+
+{** zlib inflate routines ***********************************************************************}
+
+function ZInflateInit(var stream: TZStreamRec): Integer;
+begin
+ result := inflateInit_(stream, ZLIB_VERSION, SizeOf(TZStreamRec));
+end;
+
+function ZInflateInit2(var stream: TZStreamRec;
+ windowBits: Integer): Integer;
+begin
+ {$IFDEF OLDEST_ZLIB}
+ result := ZInflateInit(stream);
+ {$ELSE}
+ result := inflateInit2_(stream, windowBits, ZLIB_VERSION,
+ SizeOf(TZStreamRec));
+ {$ENDIF}
+end;
+
+function ZInflate(var stream: TZStreamRec; flush: TZFlush): Integer;
+begin
+ result := inflate(stream, ZFlushes[flush]);
+end;
+
+function ZInflateEnd(var stream: TZStreamRec): Integer;
+begin
+ result := inflateEnd(stream);
+end;
+
+function ZInflateReset(var stream: TZStreamRec): Integer;
+begin
+ result := inflateReset(stream);
+end;
+
+{** EZLibError **********************************************************************************}
+
+constructor EZLibError.Create(code: Integer; const dummy: String);
+begin
+ inherited Create(z_errmsg[2 - code]);
+
+ FErrorCode := code;
+end;
+
+constructor EZLibError.Create(error: TZError; const dummy: String);
+begin
+ Create(ZErrors[error], dummy);
+end;
+
+{** TCustomZStream ******************************************************************************}
+
+constructor TCustomZStream.Create(stream: TStream);
+begin
+ inherited Create;
+
+ FStream := stream;
+ FStreamPos := stream.Position;
+
+ {$IFDEF OLDEST_ZLIB}
+ FZStream.zalloc := zlibAllocMem;
+ FZStream.zfree := zlibFreeMem;
+ {$ENDIF}
+end;
+
+function TCustomZStream.StreamRead(var buffer; count: Longint): Longint;
+begin
+ if FStream.Position <> FStreamPos then FStream.Position := FStreamPos;
+
+ result := FStream.Read(buffer,count);
+
+ FStreamPos := FStreamPos + result;
+end;
+
+function TCustomZStream.StreamWrite(const buffer; count: Longint): Longint;
+begin
+ if FStream.Position <> FStreamPos then FStream.Position := FStreamPos;
+
+ result := FStream.Write(buffer,count);
+
+ FStreamPos := FStreamPos + result;
+end;
+
+function TCustomZStream.StreamSeek(offset: Longint; origin: Word): Longint;
+begin
+ if FStream.Position <> FStreamPos then FStream.Position := FStreamPos;
+
+ result := FStream.Seek(offset,origin);
+
+ FStreamPos := FStream.Position;
+end;
+
+procedure TCustomZStream.StreamReadBuffer(var buffer; count: Longint);
+begin
+ if FStream.Position <> FStreamPos then FStream.Position := FStreamPos;
+
+ FStream.ReadBuffer(buffer,count);
+
+ FStreamPos := FStreamPos + count;
+end;
+
+procedure TCustomZStream.StreamWriteBuffer(const buffer; count: Longint);
+begin
+ if FStream.Position <> FStreamPos then FStream.Position := FStreamPos;
+
+ FStream.WriteBuffer(buffer,count);
+
+ FStreamPos := FStreamPos + count;
+end;
+
+procedure TCustomZStream.DoProgress;
+begin
+ if Assigned(FOnProgress) then FOnProgress(Self);
+end;
+
+function TCustomZStream.GetStreamPosition: TStreamPos;
+begin
+ result := FStream.Position;
+end;
+
+procedure TCustomZStream.SetStreamPosition(value: TStreamPos);
+begin
+ FStream.Position := value;
+ FStreamPos := FStream.Position;
+end;
+
+{** TZCompressionStream *************************************************************************}
+
+constructor TZCompressionStream.Create(dest: TStream;
+ compressionLevel: TCompressionLevel);
+begin
+ inherited Create(dest);
+
+ FZStream.next_out := @FBuffer;
+ FZStream.avail_out := SizeOf(FBuffer);
+
+ ZCompressCheck(ZDeflateInit(FZStream, compressionLevel));
+end;
+
+constructor TZCompressionStream.Create(dest: TStream;
+ compressionLevel: TCompressionLevel; windowBits, memLevel: Integer;
+ strategy: TZStrategy);
+begin
+ {$IFDEF USE_AUTOGENERATED_ZLIB_HEADER}
+ Create(dest, compressionLevel);
+ {$ELSE}
+ inherited Create(dest);
+
+ FZStream.next_out := @FBuffer;
+ FZStream.avail_out := SizeOf(FBuffer);
+
+ ZCompressCheck(ZDeflateInit2(FZStream, compressionLevel, windowBits,
+ memLevel, strategy));
+ {$ENDIF}
+end;
+
+destructor TZCompressionStream.Destroy;
+begin
+ FZStream.next_in := Nil;
+ FZStream.avail_in := 0;
+
+ try
+ while ZCompressCheck(ZDeflate(FZStream, zfFinish)) <> Z_STREAM_END do
+ begin
+ StreamWriteBuffer(FBuffer, SizeOf(FBuffer) - FZStream.avail_out);
+
+ FZStream.next_out := @FBuffer;
+ FZStream.avail_out := SizeOf(FBuffer);
+ end;
+
+ if FZStream.avail_out < SizeOf(FBuffer) then
+ begin
+ StreamWriteBuffer(FBuffer, SizeOf(FBuffer) - FZStream.avail_out);
+ end;
+ finally
+ ZDeflateEnd(FZStream);
+ end;
+
+ inherited Destroy;
+end;
+
+function TZCompressionStream.Read(var buffer; count: Longint): Longint;
+begin
+ raise EZCompressionError.Create(SZInvalid);
+end;
+
+function TZCompressionStream.Write(const buffer; count: Longint): Longint;
+var
+ writeCount: Longint;
+begin
+ result := count;
+
+ FZStream.next_in := @buffer;
+ FZStream.avail_in := count;
+
+ while FZStream.avail_in > 0 do
+ begin
+ ZCompressCheck(ZDeflate(FZStream, zfNoFlush));
+
+ if FZStream.avail_out = 0 then
+ begin
+ writeCount := StreamWrite(FBuffer,SizeOf(FBuffer));
+
+ if writeCount = SizeOf(FBuffer) then
+ begin
+ FZStream.next_out := @FBuffer;
+ FZStream.avail_out := SizeOf(FBuffer);
+
+ DoProgress;
+ end
+ else
+ begin
+ StreamPosition := StreamPosition - writeCount;
+
+ result := Cardinal(count) - Cardinal(FZStream.avail_in);
+
+ FZStream.avail_in := 0;
+ end;
+ end;
+ end;
+end;
+
+function TZCompressionStream.Seek(offset: Longint; origin: Word): Longint;
+begin
+ if (offset = 0) and (origin = soFromCurrent) then
+ begin
+ result := FZStream.total_in;
+ end
+ else raise EZCompressionError.Create(SZInvalid);
+end;
+
+function TZCompressionStream.GetCompressionRate: Single;
+begin
+ if FZStream.total_in = 0 then result := 0
+ else result := (1.0 - (FZStream.total_out / FZStream.total_in)) * 100.0;
+end;
+
+{** TZDecompressionStream ***********************************************************************}
+
+constructor TZDecompressionStream.Create(source: TStream);
+begin
+ inherited Create(source);
+
+ FZStream.next_in := @FBuffer;
+ FZStream.avail_in := 0;
+
+ ZDecompressCheck(ZInflateInit(FZStream));
+end;
+
+constructor TZDecompressionStream.Create(source: TStream;
+ windowBits: Integer);
+begin
+ {$IFDEF USE_AUTOGENERATED_ZLIB_HEADER}
+ Create(source);
+ {$ELSE}
+ inherited Create(source);
+
+ FZStream.next_in := @FBuffer;
+ FZStream.avail_in := 0;
+
+ ZDecompressCheck(ZInflateInit2(FZStream, windowBits));
+ {$ENDIF}
+end;
+
+destructor TZDecompressionStream.Destroy;
+begin
+ ZInflateEnd(FZStream);
+
+ inherited Destroy;
+end;
+
+function TZDecompressionStream.Read(var buffer; count: Longint): Longint;
+var
+ zresult: Integer;
+begin
+ FZStream.next_out := @buffer;
+ FZStream.avail_out := count;
+
+ zresult := Z_OK;
+
+ while (FZStream.avail_out > 0) and (zresult <> Z_STREAM_END) do
+ begin
+ if FZStream.avail_in = 0 then
+ begin
+ FZStream.avail_in := StreamRead(FBuffer,SizeOf(FBuffer));
+
+ if FZStream.avail_in = 0 then
+ begin
+ result := Cardinal(count) - Cardinal(FZStream.avail_out);
+
+ Exit;
+ end;
+
+ FZStream.next_in := @FBuffer;
+
+ DoProgress;
+ end;
+
+ zresult := ZDecompressCheck(ZInflate(FZStream, zfNoFlush));
+ end;
+
+ if (zresult = Z_STREAM_END) and (FZStream.avail_in > 0) then
+ begin
+ StreamPosition := StreamPosition - FZStream.avail_in;
+
+ FZStream.avail_in := 0;
+ end;
+
+ result := Cardinal(count) - Cardinal(FZStream.avail_out);
+end;
+
+function TZDecompressionStream.Write(const Buffer; Count: Longint): Longint;
+begin
+ raise EZDecompressionError.Create(SZInvalid);
+end;
+
+function TZDecompressionStream.Seek(Offset: Longint; Origin: Word): Longint;
+var
+ buf: Array [0..8191] of Byte;
+ i : Integer;
+begin
+ if (offset = 0) and (origin = soFromBeginning) then
+ begin
+ ZDecompressCheck(ZInflateReset(FZStream));
+
+ FZStream.next_in := @FBuffer;
+ FZStream.avail_in := 0;
+
+ StreamPosition := 0;
+ end
+ else if ((offset >= 0) and (origin = soFromCurrent)) or
+ (((Cardinal(offset) - Cardinal(FZStream.total_out)) > 0) and
+ (origin = soFromBeginning)) then
+ begin
+ if origin = soFromBeginning then Dec(offset, FZStream.total_out);
+
+ if offset > 0 then
+ begin
+ for i := 1 to offset div SizeOf(buf) do ReadBuffer(buf, SizeOf(buf));
+ ReadBuffer(buf, offset mod SizeOf(buf));
+ end;
+ end
+ else if (offset = 0) and (origin = soFromEnd) then
+ begin
+ while Read(buf, SizeOf(buf)) > 0 do ;
+ end
+ else raise EZDecompressionError.Create(SZInvalid);
+
+ result := FZStream.total_out;
+end;
+
+
+end.
diff --git a/prereq/fwzip/Readme.txt b/prereq/fwzip/Readme.txt
new file mode 100644
index 0000000..17739fb
--- /dev/null
+++ b/prereq/fwzip/Readme.txt
@@ -0,0 +1,344 @@
+FWZip 1.0.11 31 2015 .
+: (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: rouse79@yandex.ru
+
+0. :
+
+ .
+ - ZIP .
+ : ( ) .
+ .
+ .
+ - .
+ - .
+ ,
+ (.. XML - .. ) PPMD.
+ - , 400 PPMD (sic).
+ ( PPMD , - )...
+
+1. :
+
+ FWZip ZIP Store Deflate.
+
+ :
+ - ZIP64
+ - DataDescryptors
+ - PKWARE
+ - NTFS
+ - UTF8
+
+ ( ):
+ - Shrunk, Reduced, Imploded, TCA, Deflate64, PKWARE, BZIP2
+ -
+ -
+ - CentralDirectory
+
+ - WinRar ZIP , .
+
+ Delphi XE8 ( 32-, 64).
+ FireMonkey (iOS/Android ).
+
+ !!!
+ Delphi 2007
+ Delphi ZLib. .
+ 11.
+
+ :
+ FWZip ExData , MAXWORD.
+ MAXWORD - ExData .
+ ExData FWZip,
+ .
+
+2. :
+
+ 1.0 ( 22 2011 ):
+
+ -
+
+ 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.2 ( 4 2011 ):
+
+ - (Z_NO_COMPRESSION).
+ erDone .
+ "Romkin", .
+ - EZDecompressionError ExtractToStream.
+ - erWrongCRC32 TExtractResult.
+ CheckCRC32 ExtractToStream False .
+ - EZDecompressionError EZLibError.
+ "@!!ex" .
+
+ 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.4 ( 21 2012 ):
+ - overload ExtractAll TFWZipReader. ExtractMask,
+ , . (. ExctractZIPDemo1)
+ - AddFilesAndFolders TFWZipWriter. (. CreateZIPDemo1)
+ - v1ctar, .
+ - : EZipReader, EZipReaderItem, EZipWriter EZipWriterItem.
+
+ 1.0.5 ( 2 2012 )
+ - TFWZipReader.LoadFromFile TFWZipReader.LoadFromStream.
+ . ( SFX ).
+
+ 1.0.6 ( 14 2013 )
+ - TrimPackedStreamSize TFWZipWriter, ZLib .
+ .
+ , ICSharpCode.SharpZipLibrary, .
+ - VersionNeededToExtract.
+ 'Grighome' .
+ - AddEmptyFolder .
+ - AlwaysAddEmptyFolder. , .
+ - END_OF_CENTRAL_DIR_SIGNATURE.
+ ZIP , .
+ .
+
+ 1.0.7 ( 10 2013 )
+ - FWZipReader .
+ 'Ega23' .
+
+ 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.9 ( 20 2013 )
+ - ( 6.3)
+ - protected (. ZipAnalizer)
+ - TProgressState OnProgress
+ :
+ - PKWARE 6.3 4 . ( 7Zip Zip64EndOfCentralDir SizeOfZip64EOFCentralDirectoryRecord 12 , WinRar/PkZip/WinZip)
+ - AddFolder
+
+ 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.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 .
+
+3. :
+
+ - .\FWZipConsts.pas - ZIP
+ - .\FWZipCrc32.pas -
+ - .\FWZipCrypt.pas - PKWARE
+ - .\FWZipModifier.pas - ZIP .
+ - .\FWZipReader.pas - ZIP
+ - .\FWZipStream.pas - ZLib
+ - .\FWZipWriter.pas - ZIP
+ - .\FWZipZLib.pas - . ZLibEx Delphi
+ - .\fwzip.inc -
+
+ - .\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 - .
+ - .\Modify ZIP\ -
+ - .\Modify ZIP\Merge two ZIP\MergeZip.dpr -
+ - .\Modify ZIP\Replace data in ZIP\ReplaceZipItemData.dpr - .
+ - .\Modify ZIP\Split ZIP\SplitZip.dpr - .
+ - .\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
+
+ - .\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, , :)
+ - .
+
+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
\ No newline at end of file
diff --git a/prereq/fwzip/fwzip.inc b/prereq/fwzip/fwzip.inc
new file mode 100644
index 0000000..54a6d2e
--- /dev/null
+++ b/prereq/fwzip/fwzip.inc
@@ -0,0 +1,72 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ****************************************************************************
+// * Project : FWZip
+// * Unit Name : fwzip.inc
+// * Purpose : Набор классов для распаковки ZIP архива
+// * Author : Александр (Rouse_) Багель
+// * Copyright : © Fangorn Wizards Lab 1998 - 2015.
+// * Version : 1.0.11
+// * Home Page : http://rouse.drkb.ru
+// * Home Blog : http://alexander-bagel.blogspot.ru
+// ****************************************************************************
+// * Stable Release : http://rouse.drkb.ru/components.php#fwzip
+// * Latest Source : https://github.com/AlexanderBagel/FWZip
+// ****************************************************************************
+//
+// Используемые источники:
+// ftp://ftp.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
+// http://zlib.net/zlib-1.2.5.tar.gz
+// http://www.base2ti.com/
+//
+
+// Данный модуль предназначен для глобального включения
+// директив настройки пакета FWZip
+
+// Если необходимо использовать ZLibEx раскоментируйте директиву ниже
+// {$DEFINE USE_ZLIB_EX}
+
+// Если необходимо использовать внешнюю библиотеку раскоментируйте директиву ниже
+// {$DEFINE USE_ZLIB_DLL}
+
+// Если необходима поддержка сжатия/распаковки по старому варианту
+// c генерацией ZLib заголовка раскоментируйте директиву ниже
+// Но есть нюанс - распаковка с автогенерируемым заголовком в очень редких случаях
+// не сможет открыть архивы созданные при помощи 7Zip
+// {$DEFINE USE_AUTOGENERATED_ZLIB_HEADER}
+
+
+
+
+// ВНИМАНИЕ!!!
+// =============================================================================
+
+// КОД СЛЕДУЮЩИЙ НИЖЕ НЕ ПРЕДНАЗНАЧЕН ДЛЯ ИЗМЕНЕНИЯ ПРОГРАММИСТОМ И
+// СОДЕРЖИТ КРИТИЧЕСКИЕ НАСТРОЙКИ ДЛЯ БИБЛИОТЕКИ FWZip
+
+// Если подключена библиотека ZLibEx, отключаем использование внешней библиотеки
+{$IFDEF USE_ZLIB_EX}
+ {$UNDEF USE_ZLIB_DLL}
+{$ENDIF}
+
+// deflateInit2_ и inflateInit2_ отсутствуют в Delphi вплоть до 2009-ой
+// поэтому при использовании старых версий дельфи и стандартного модуля ZLib
+// необходимо отключать использование данных функций
+
+{$UNDEF OLDEST_ZLIB}
+
+// Если подключена библиотека ZLibEx, то использовать deflateInit2_ и inflateInit2_ можно
+{$IFDEF USE_ZLIB_EX}
+ {$UNDEF OLDEST_ZLIB}
+{$ENDIF}
+
+// Если подключена внешняя библиотека, то использовать deflateInit2_ и inflateInit2_ можно
+{$IFDEF USE_ZLIB_DLL}
+ {$UNDEF OLDEST_ZLIB}
+{$ENDIF}
+
+// Если использовать deflateInit2_ и inflateInit2_ нельзя,
+// принудительно переключаемся на старый режим работы с автогенерируемыми заголовками
+{$IFDEF OLDEST_ZLIB}
+ {$DEFINE USE_AUTOGENERATED_ZLIB_HEADER}
+{$ENDIF}
diff --git a/prereq/fwzip/fwzip.lpk b/prereq/fwzip/fwzip.lpk
new file mode 100644
index 0000000..975c4e2
--- /dev/null
+++ b/prereq/fwzip/fwzip.lpk
@@ -0,0 +1,352 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ExternHelp Items="Count"/>
+
+
+
diff --git a/prereq/fwzip/fwzip.pas b/prereq/fwzip/fwzip.pas
new file mode 100644
index 0000000..4857096
--- /dev/null
+++ b/prereq/fwzip/fwzip.pas
@@ -0,0 +1,21 @@
+{ This file was automatically created by Lazarus. Do not edit!
+ This source is only used to compile and install the package.
+ }
+
+unit fwzip;
+
+interface
+
+uses
+ FWZipConsts, FWZipCrc32, FWZipCrypt, FWZipReader, FWZipStream, FWZipWriter,
+ FWZipZLib, LazarusPackageIntf;
+
+implementation
+
+procedure Register;
+begin
+end;
+
+initialization
+ RegisterPackage ('fwzip', @Register );
+end.
diff --git a/prereq/fwzip/zlib_dll/zlib_d2010.dpr b/prereq/fwzip/zlib_dll/zlib_d2010.dpr
new file mode 100644
index 0000000..fbbdbc0
--- /dev/null
+++ b/prereq/fwzip/zlib_dll/zlib_d2010.dpr
@@ -0,0 +1,25 @@
+library zlib_d2010;
+
+uses
+ ZLib;
+
+{$R *.res}
+
+{$IF CompilerVersion < 21}
+ {$MESSAGE FATAL ' Delphi 2010 '}
+{$IFEND}
+
+exports
+ adler32,
+ deflateInit_,
+ DeflateInit2_,
+ deflate,
+ deflateEnd,
+ inflateInit_,
+ inflateInit2_,
+ inflate,
+ inflateEnd,
+ inflateReset;
+
+begin
+end.
diff --git a/prereq/zlib1.rar b/prereq/zlib1.rar
new file mode 100644
index 0000000..3862a1a
Binary files /dev/null and b/prereq/zlib1.rar differ