From 6dd280b24fd77045a1592f66a8d20fb7cda5cc0c Mon Sep 17 00:00:00 2001 From: joostverburg Date: Mon, 11 Aug 2003 16:42:41 +0000 Subject: [PATCH] VPatch 2.0 final git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@2798 212acab6-be3b-0410-9dea-997c60f758d6 --- Contrib/VPatch/GenPat.exe | Bin 68608 -> 68096 bytes Contrib/VPatch/Readme.html | 41 +- Contrib/VPatch/Source/GUI/AboutForm.dfm | Bin 0 -> 1721 bytes Contrib/VPatch/Source/GUI/AboutForm.pas | 31 + Contrib/VPatch/Source/GUI/DLLWrapper.pas | 53 + Contrib/VPatch/Source/GUI/MainForm.dfm | 903 ++++++++++++++++++ Contrib/VPatch/Source/GUI/MainForm.pas | 539 +++++++++++ Contrib/VPatch/Source/GUI/PatchClasses.pas | 548 +++++++++++ Contrib/VPatch/Source/GUI/ProgressForm.dfm | 102 ++ Contrib/VPatch/Source/GUI/ProgressForm.pas | 74 ++ Contrib/VPatch/Source/GUI/VPatchGUI.dof | 87 ++ Contrib/VPatch/Source/GUI/VPatchGUI.dpr | 19 + Contrib/VPatch/Source/GUI/VPatchGUI.res | Bin 0 -> 1636 bytes Contrib/VPatch/Source/GenPat/GenPat2.dpr | 125 +++ .../VPatch/Source/GenPat/PatchGenerator.pas | 591 ++++++++++++ Contrib/VPatch/Source/GenPat/TreeCode.pas | 245 +++++ Contrib/VPatch/Source/GenPat/VAppend.dpr | 77 ++ Contrib/VPatch/Source/GenPat/VPatch2.bpg | 26 + Contrib/VPatch/Source/GenPat/vdsp_crc.pas | 115 +++ .../VPatch/{ => Source/Plugin}/vpatchdll.c | 2 +- .../VPatch/{ => Source/Plugin}/vpatchdll.dsp | 2 +- .../VPatch/{ => Source/Plugin}/vpatchdll.dsw | 0 22 files changed, 3566 insertions(+), 14 deletions(-) create mode 100644 Contrib/VPatch/Source/GUI/AboutForm.dfm create mode 100644 Contrib/VPatch/Source/GUI/AboutForm.pas create mode 100644 Contrib/VPatch/Source/GUI/DLLWrapper.pas create mode 100644 Contrib/VPatch/Source/GUI/MainForm.dfm create mode 100644 Contrib/VPatch/Source/GUI/MainForm.pas create mode 100644 Contrib/VPatch/Source/GUI/PatchClasses.pas create mode 100644 Contrib/VPatch/Source/GUI/ProgressForm.dfm create mode 100644 Contrib/VPatch/Source/GUI/ProgressForm.pas create mode 100644 Contrib/VPatch/Source/GUI/VPatchGUI.dof create mode 100644 Contrib/VPatch/Source/GUI/VPatchGUI.dpr create mode 100644 Contrib/VPatch/Source/GUI/VPatchGUI.res create mode 100644 Contrib/VPatch/Source/GenPat/GenPat2.dpr create mode 100644 Contrib/VPatch/Source/GenPat/PatchGenerator.pas create mode 100644 Contrib/VPatch/Source/GenPat/TreeCode.pas create mode 100644 Contrib/VPatch/Source/GenPat/VAppend.dpr create mode 100644 Contrib/VPatch/Source/GenPat/VPatch2.bpg create mode 100644 Contrib/VPatch/Source/GenPat/vdsp_crc.pas rename Contrib/VPatch/{ => Source/Plugin}/vpatchdll.c (99%) rename Contrib/VPatch/{ => Source/Plugin}/vpatchdll.dsp (98%) rename Contrib/VPatch/{ => Source/Plugin}/vpatchdll.dsw (100%) diff --git a/Contrib/VPatch/GenPat.exe b/Contrib/VPatch/GenPat.exe index 4161e8d541ac2333d2b9bb2b3de479a9d6aa671f..0b3613886d2c0a7d8657523e1b2945b85f58f88d 100644 GIT binary patch delta 5225 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 LGovVo8|4207@kP^ diff --git a/Contrib/VPatch/Readme.html b/Contrib/VPatch/Readme.html index b174935e..3d306310 100644 --- a/Contrib/VPatch/Readme.html +++ b/Contrib/VPatch/Readme.html @@ -141,23 +141,43 @@ file.

patch from file A version 1 to file A version 2 and a patch from file B version 1 to file B version 2. Just call the plug-in multiple times with the same patch file. It will automatically select the right patch (based on the file CRC).

+

Source code

+

NSIS plug-in (C++)

+

The source of the NSIS plug-in that applies patches can be found in the +Source\Plugin folder.

+

Patch Generator (Delphi)

+

The most interesting part of VPatch, the actual patch generation algoritm, +can be found in Source\GenPat\PatchGenerator.pas. The header of that file contains a brief +explanation of the algoritm as well.

+

User interface (Delphi)

+

A user interface is included as well, which you will have to build yourself +because the GUI executable was too large to include. Besides Borland Delphi 6 or higher, +you will also need to install the VirtualTreeView +component by Mike Lischke.

Version history

    -
  • 2.0 beta 2 -
      -
    • All new algorithm used in the patch generator: much faster (up to - 90%) while using smaller block sizes (higher compression)
    • -
    • Created a NSIS 2 plugin
    • -
    • Works with small files
    • -
    • Replaces existing patch in file if original file CRC is identical
    • -
  • +
  • 2.0 final +
      +
    • Cleaned up source code for the patch generator, which is now included (this code is +written in Borland Delphi 6 and compiles with the freely available Personal edition).
    • +
    +
  • +
  • 2.0 beta 2 +
      +
    • All new algorithm used in the patch generator: much faster (up to 90%) while using +smaller block sizes (higher compression)
    • +
    • Created a NSIS 2 plugin
    • +
    • Works with small files
    • +
    • Replaces existing patch in file if original file CRC is identical
    • +
    +

Credits

Written by Koen van de Sande
C plug-in by Edgewize
New documentation and example by Joost Verburg

License

-
Copyright (C) 2001-2002 Koen van de Sande
+
Copyright (C) 2001-2003 Koen van de Sande
 
 This software is provided 'as-is', without any express or implied
 warranty. In no event will the authors be held liable for any damages
@@ -174,9 +194,6 @@ it freely, subject to the following restrictions:
 2. Altered versions must be plainly marked as such,
    and must not be misrepresented as being the original software.
 3. This notice may not be removed or altered from any distribution.
-
-Please note that this version contains the plug-in source only,
-not the source of the patch generator.
 
diff --git a/Contrib/VPatch/Source/GUI/AboutForm.dfm b/Contrib/VPatch/Source/GUI/AboutForm.dfm new file mode 100644 index 0000000000000000000000000000000000000000..6e3ed9c3a8309c68a03eb470d9974d8b1228a40e GIT binary patch literal 1721 zcmb7Fzi-<{6h29@NJ_Hnj_JgugF9G?~b&pI9~dwd%TbD-TU6X`=M0d)+n*|JohImCiv8``5^a6X3L;1 zWr}9GHSX21MM`z*@vEcev$Y&tPX$cxgD zuw?(yB>DyqNq)Q0(L2}+^bTQ8FBva0E~1^LYa5JUPMTthn%bg)BT`p(eA=-XA)W!L z6Sm!QLgEH3D1&DWvfmd3W6HIS@@5Nr#LY|nNLDYa%HpY8$uu8k^6C74L4_I_6Zg>b z2!oo9+t>++oqTMLfJ@Q3<6}A@jM&8%X235iq^TzE$~3bG7!QZIPl_!@`wS1o+T25% zt){HmFG?-P;v+`N2bkl+j}SsJYYrb`e+>OvLuesmXnWA~v}Mo(=z*km(cKklEmMTx zho;ly1sb~O>go#K!myG*v|5QCGLiM0;O~Qd27GEX5yPWg_>&q%7uU)}ivMI5Rc4b{V3(2$ ze|RGtrU{-tnN21UFifRCj1FGEeiN!u;tyt+>nf^1d~gh>DD%D$B>1Gvm+;Ibe~Ooj z<#LVB7t71}rLZf~e7=}3=83<||9r6!9!dT%oeP2IKPTg1I`Lw@yj+N~?%Y6tIQ|>x zzzjIP0T{;+J;m{bz~CTWU{5f7cpJxeu^7JLFHnM$UZSt>EH_d*oDpsfH0>}j;LJ1X zYGP|2<1TT<*0x6$7e_eR+TY3(wVRx%?B};zdwYG|6i!+g!s%a+ockgwCxiuXwl|~g zrO`foH=6diT+w@uhu!;vX$JMrn7Gk4&s{4$?!TjV<9)PeeXKvOR33c_>NEWWd%8`; z#RNK?D(K3G@6Y!ja{u6IZMVBbmy>zwK@De=DIPM6qa zk8s@>5bLEr;N1Ume;+n`d2QMs`?8ij%Jh+M!wngzr|>^;%CP_TdWnl<#5wiU=26l~ uvZP|Ua=)Rp!bi6idAQCp+dNVZNDq%(t`!^9#%`Mg0J53?uDT3tntuU=vy`p? literal 0 HcmV?d00001 diff --git a/Contrib/VPatch/Source/GUI/AboutForm.pas b/Contrib/VPatch/Source/GUI/AboutForm.pas new file mode 100644 index 00000000..3328a61a --- /dev/null +++ b/Contrib/VPatch/Source/GUI/AboutForm.pas @@ -0,0 +1,31 @@ +unit AboutForm; + +interface + +uses Windows, SysUtils, Classes, Graphics, Forms, Controls, StdCtrls, + Buttons, ExtCtrls; + +type + TfrmAbout = class(TForm) + Panel1: TPanel; + ProgramIcon: TImage; + ProductName: TLabel; + Version: TLabel; + Copyright: TLabel; + Comments: TLabel; + OKButton: TButton; + private + { Private declarations } + public + { Public declarations } + end; + +var + frmAbout: TfrmAbout; + +implementation + +{$R *.dfm} + +end. + diff --git a/Contrib/VPatch/Source/GUI/DLLWrapper.pas b/Contrib/VPatch/Source/GUI/DLLWrapper.pas new file mode 100644 index 00000000..5797d906 --- /dev/null +++ b/Contrib/VPatch/Source/GUI/DLLWrapper.pas @@ -0,0 +1,53 @@ +unit DLLWrapper; + +interface + +uses Classes, SysUtils; + + function DoGenerate(const Source, Target: String; Stream: TStream; Config: String): Integer; forward; + +implementation + +uses PatchGenerator; + +function DoGenerate(const Source, Target: String; Stream: TStream; Config: String): Integer; +var + PG: TPatchGenerator; + a: Integer; +begin + WriteLn('Generating '+ExtractFileName(Source)+' to '+ExtractFileName(Target)+'...'); + + PG:=TPatchGenerator.Create; + PG.StartBlockSize:=512; + PG.MinimumBlockSize:=512; + PG.BlockDivider:=2; + PG.StepSize:=256; + try + a:=Pos(',',Config); + if(a=0) then a:=Length(Config)+1; + PG.StartBlockSize:=StrToInt(Copy(Config,1,a-1)); + Config:=Copy(Config,a+1,Length(Config)); + + a:=Pos(',',Config); + if(a=0) then a:=Length(Config)+1; + PG.MinimumBlockSize:=StrToInt(Copy(Config,1,a-1)); + Config:=Copy(Config,a+1,Length(Config)); + + a:=Pos(',',Config); + if(a=0) then a:=Length(Config)+1; + PG.BlockDivider:=StrToInt(Copy(Config,1,a-1)); + Config:=Copy(Config,a+1,Length(Config)); + + a:=Pos(',',Config); + if(a=0) then a:=Length(Config)+1; + PG.StepSize:=StrToInt(Copy(Config,1,a-1)); + finally + end; + + Result:=PG.CreatePatch(Source,Target); + PG.WriteToStream(Stream); + PG.Free; + WriteLn(ExtractFileName(Source)+' -> '+ExtractFileName(Target)+': '+IntToStr(Result)+' bytes'); +end; + +end. diff --git a/Contrib/VPatch/Source/GUI/MainForm.dfm b/Contrib/VPatch/Source/GUI/MainForm.dfm new file mode 100644 index 00000000..84b3725b --- /dev/null +++ b/Contrib/VPatch/Source/GUI/MainForm.dfm @@ -0,0 +1,903 @@ +object frmMain: TfrmMain + Left = 195 + Top = 93 + BorderIcons = [biSystemMenu, biMinimize] + BorderStyle = bsSingle + Caption = 'VG - VPatch GUI' + ClientHeight = 361 + ClientWidth = 689 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + Menu = MainMenu + OldCreateOrder = False + Position = poScreenCenter + ShowHint = True + OnCreate = FormCreate + OnDestroy = FormDestroy + PixelsPerInch = 96 + TextHeight = 13 + object Label1: TLabel + Left = 8 + Top = 32 + Width = 77 + Height = 13 + Caption = 'New versions' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [fsBold] + ParentFont = False + end + object butAdd: TSpeedButton + Left = 24 + Top = 328 + Width = 89 + Height = 25 + Caption = 'Add &new version' + Flat = True + OnClick = butAddClick + end + object grpConfig: TGroupBox + Left = 232 + Top = 43 + Width = 441 + Height = 278 + Enabled = False + TabOrder = 0 + object Label2: TLabel + Left = 16 + Top = 24 + Width = 71 + Height = 13 + Caption = 'New version' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [fsBold] + ParentFont = False + end + object Label3: TLabel + Left = 16 + Top = 80 + Width = 71 + Height = 13 + Caption = 'Old versions' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [fsBold] + ParentFont = False + end + object butOldAdd: TSpeedButton + Left = 368 + Top = 96 + Width = 49 + Height = 25 + Caption = '&Add' + Flat = True + OnClick = butOldAddClick + end + object butOldRemove: TSpeedButton + Left = 368 + Top = 160 + Width = 49 + Height = 25 + Caption = '&Remove' + Flat = True + OnClick = butOldRemoveClick + end + object butNewEdit: TSpeedButton + Left = 368 + Top = 40 + Width = 49 + Height = 25 + Caption = '&Edit' + Flat = True + OnClick = butNewEditClick + end + object Label4: TLabel + Left = 16 + Top = 200 + Width = 176 + Height = 13 + Caption = 'Patch generation configuration' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [fsBold] + ParentFont = False + end + object Label5: TLabel + Left = 32 + Top = 224 + Width = 48 + Height = 13 + Hint = 'Smaller gives smaller patch files, but decreased speed' + Caption = 'Block size' + end + object Label6: TLabel + Left = 32 + Top = 248 + Width = 91 + Height = 13 + Caption = 'Minimum block size' + Visible = False + end + object Label7: TLabel + Left = 232 + Top = 224 + Width = 61 + Height = 13 + Caption = 'Block divider' + Visible = False + end + object Label8: TLabel + Left = 232 + Top = 248 + Width = 43 + Height = 13 + Caption = 'Step size' + Visible = False + end + object txtStartBlockSize: TLabel + Left = 136 + Top = 224 + Width = 65 + Height = 17 + Alignment = taCenter + AutoSize = False + end + object txtNew: TEdit + Left = 32 + Top = 42 + Width = 321 + Height = 21 + ReadOnly = True + TabOrder = 0 + end + object lstOld: TListBox + Left = 32 + Top = 96 + Width = 321 + Height = 89 + ItemHeight = 13 + TabOrder = 1 + end + object txtMinimumBlockSize: TEdit + Left = 136 + Top = 248 + Width = 65 + Height = 21 + TabOrder = 2 + Text = '16' + Visible = False + OnChange = txtMinimumBlockSizeChange + end + object UDMinimumBlockSize: TUpDown + Left = 201 + Top = 248 + Width = 15 + Height = 21 + Associate = txtMinimumBlockSize + Min = 16 + Max = 4096 + Increment = 16 + Position = 16 + TabOrder = 3 + Visible = False + Wrap = False + end + object UDBlockDivider: TUpDown + Left = 401 + Top = 224 + Width = 15 + Height = 21 + Associate = txtBlockDivider + Min = 2 + Max = 512 + Increment = 2 + Position = 16 + TabOrder = 4 + Visible = False + Wrap = False + end + object txtBlockDivider: TEdit + Left = 336 + Top = 224 + Width = 65 + Height = 21 + TabOrder = 5 + Text = '16' + Visible = False + OnChange = txtBlockDividerChange + end + object UDStepSize: TUpDown + Left = 401 + Top = 248 + Width = 15 + Height = 21 + Associate = txtStepSize + Min = 16 + Max = 4096 + Increment = 16 + Position = 16 + TabOrder = 6 + Visible = False + Wrap = False + end + object txtStepSize: TEdit + Left = 336 + Top = 248 + Width = 65 + Height = 21 + TabOrder = 7 + Text = '16' + Visible = False + OnChange = txtStepSizeChange + end + object tbBlockSize: TTrackBar + Left = 200 + Top = 224 + Width = 161 + Height = 25 + Max = 12 + Min = 4 + Orientation = trHorizontal + Frequency = 1 + Position = 6 + SelEnd = 0 + SelStart = 0 + TabOrder = 8 + TickMarks = tmBottomRight + TickStyle = tsAuto + OnChange = tbBlockSizeChange + end + end + object lstNew: TVirtualStringTree + Left = 24 + Top = 48 + Width = 193 + Height = 273 + Header.AutoSizeIndex = 0 + Header.Font.Charset = DEFAULT_CHARSET + Header.Font.Color = clWindowText + Header.Font.Height = -11 + Header.Font.Name = 'MS Sans Serif' + Header.Font.Style = [] + Header.MainColumn = -1 + Header.Options = [hoColumnResize, hoDrag] + HintAnimation = hatNone + Indent = 0 + TabOrder = 1 + TreeOptions.PaintOptions = [toHotTrack, toShowBackground, toShowButtons, toShowDropmark, toShowRoot, toThemeAware, toUseBlendedImages] + TreeOptions.SelectionOptions = [toFullRowSelect] + OnChange = lstNewChange + OnGetText = lstNewGetText + Columns = <> + end + object barCool: TCoolBar + Left = 0 + Top = 0 + Width = 689 + Height = 44 + AutoSize = True + Bands = < + item + BorderStyle = bsSingle + Control = barTool + ImageIndex = -1 + MinHeight = 36 + Width = 689 + end> + EdgeBorders = [ebTop, ebBottom] + object barTool: TToolBar + Left = 9 + Top = 2 + Width = 676 + Height = 36 + AutoSize = True + ButtonHeight = 36 + ButtonWidth = 90 + Caption = 'barTool' + EdgeBorders = [] + Flat = True + Images = IL + ShowCaptions = True + TabOrder = 0 + object toolNew: TToolButton + Left = 0 + Top = 0 + Caption = '&New' + ImageIndex = 0 + MenuItem = mnuNew + end + object toolOpen: TToolButton + Left = 90 + Top = 0 + Caption = '&Open' + ImageIndex = 1 + MenuItem = mnuOpen + end + object toolSave: TToolButton + Left = 180 + Top = 0 + Caption = '&Save' + ImageIndex = 2 + MenuItem = mnuSave + end + object ToolButton1: TToolButton + Left = 270 + Top = 0 + Width = 8 + Caption = 'ToolButton1' + ImageIndex = 7 + Style = tbsSeparator + end + object toolGenGo: TToolButton + Left = 278 + Top = 0 + Caption = '&Generate' + ImageIndex = 3 + MenuItem = mnuGenGo + end + object toolCreateEXE: TToolButton + Left = 368 + Top = 0 + Caption = 'Create &EXE' + ImageIndex = 5 + MenuItem = mnuCreateEXE + end + object toolCreateDLL: TToolButton + Left = 458 + Top = 0 + Caption = 'Create &DLL' + ImageIndex = 6 + MenuItem = mnuCreateDLL + end + object toolCreatePAT: TToolButton + Left = 548 + Top = 0 + Caption = 'Create &patch file' + ImageIndex = 7 + MenuItem = mnuCreatePAT + end + end + end + object chkDebug: TCheckBox + Left = 232 + Top = 336 + Width = 289 + Height = 17 + Caption = 'Show extended information during patch generation' + TabOrder = 3 + OnClick = chkDebugClick + end + object MainMenu: TMainMenu + Images = IL + Left = 160 + Top = 328 + object mnuFile: TMenuItem + Caption = '&File' + object mnuNew: TMenuItem + Caption = '&New' + ImageIndex = 0 + ShortCut = 16462 + OnClick = mnuNewClick + end + object mnuOpen: TMenuItem + Caption = '&Open' + ImageIndex = 1 + ShortCut = 16463 + OnClick = mnuOpenClick + end + object mnuSave: TMenuItem + Caption = '&Save' + ImageIndex = 2 + ShortCut = 16467 + OnClick = mnuSaveClick + end + object mnuSaveas: TMenuItem + Caption = 'Save &as...' + OnClick = mnuSaveasClick + end + object N1: TMenuItem + Caption = '-' + end + object mnuExit: TMenuItem + Caption = 'E&xit' + OnClick = mnuExitClick + end + end + object mnuAction: TMenuItem + Caption = '&Action' + object mnuClearcachedpatches: TMenuItem + Caption = 'Empty &cache' + ImageIndex = 4 + OnClick = mnuClearcachedpatchesClick + end + object mnuGenGo: TMenuItem + Caption = '&Generate' + ImageIndex = 3 + OnClick = mnuGenGoClick + end + object mnuCreateEXE: TMenuItem + Caption = 'Create &EXE' + ImageIndex = 5 + OnClick = mnuCreateEXEClick + end + object mnuCreateDLL: TMenuItem + Caption = 'Create &DLL' + ImageIndex = 6 + OnClick = mnuCreateDLLClick + end + object mnuCreatePAT: TMenuItem + Caption = 'Create &patch file' + ImageIndex = 7 + OnClick = mnuCreatePATClick + end + end + object mnuHelp: TMenuItem + Caption = '&Help' + object mnuAbout: TMenuItem + Caption = '&About' + OnClick = mnuAboutClick + end + end + end + object OD: TOpenDialog + Filter = 'All files (*.*)|*.*' + Options = [ofHideReadOnly, ofPathMustExist, ofFileMustExist, ofEnableSizing, ofDontAddToRecent] + Left = 128 + Top = 328 + end + object dlgOpen: TOpenDialog + DefaultExt = '.vpj' + Filter = 'VPatch ProJects (*.vpj)|*.vpj|All files (*.*)|*.*' + Options = [ofHideReadOnly, ofPathMustExist, ofFileMustExist, ofEnableSizing] + Left = 104 + Top = 24 + end + object dlgSave: TSaveDialog + DefaultExt = '.vpj' + Filter = 'VPatch ProJects (*.vpj)|*.vpj|All files (*.*)|*.*' + Options = [ofOverwritePrompt, ofHideReadOnly, ofPathMustExist, ofNoReadOnlyReturn, ofNoDereferenceLinks, ofEnableSizing] + Left = 136 + Top = 24 + end + object IL: TImageList + Left = 168 + Top = 24 + Bitmap = { + 494C010108000900040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600 + 0000000000003600000028000000400000003000000001002000000000000030 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF000000000000000000000000000000000000FF + FF00000000000000000000000000000000000000000000000000000000000000 + 000000FFFF000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000FFFF0000FF + FF0000FFFF0000000000000000000000000000000000000000000000000000FF + FF0000FFFF0000FFFF0000000000000000000000000000000000FF000000FF00 + 0000FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF00 + 0000FF000000FF000000FF00000000000000000000000000FF000000FF000000 + FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000 + FF000000FF000000FF000000FF00000000000000000000000000008000000080 + 0000008000000080000000800000008000000080000000800000008000000080 + 00000080000000800000008000000000000000000000007F7F0000FFFF0000FF + FF0000FFFF0000FFFF000000000000000000000000000000000000FFFF0000FF + FF0000FFFF0000FFFF00007F7F00000000000000000000000000FF000000FFFF + FF00FFFFFF00FFFFFF00FF000000FFFFFF00FF000000FFFFFF00FF000000FFFF + FF00FFFFFF00FFFFFF00FF00000000000000000000000000FF00FFFFFF00FFFF + FF00FFFFFF000000FF000000FF00FFFFFF00FFFFFF00FFFFFF000000FF00FFFF + FF00FFFFFF00FFFFFF000000FF0000000000000000000000000000800000FFFF + FF00008000000080000000800000FFFFFF0000800000FFFFFF00008000000080 + 0000FFFFFF000080000000800000000000000000000000FFFF0000FFFF0000FF + FF0000FFFF0000FFFF00007F7F000000000000000000007F7F0000FFFF0000FF + FF0000FFFF0000FFFF0000FFFF00000000000000000000000000FF000000FFFF + FF00FF000000FF000000FF000000FFFFFF00FF000000FFFFFF00FF000000FFFF + FF00FF000000FF000000FF00000000000000000000000000FF00FFFFFF000000 + FF000000FF00FFFFFF000000FF00FFFFFF000000FF000000FF000000FF00FFFF + FF000000FF000000FF000000FF0000000000000000000000000000800000FFFF + FF00008000000080000000800000FFFFFF0000800000FFFFFF00008000000080 + 0000FFFFFF000080000000800000000000000000000000FFFF0000FFFF0000FF + FF0000FFFF0000FFFF0000FFFF00000000000000000000FFFF0000FFFF0000FF + FF0000FFFF0000FFFF0000FFFF00000000000000000000000000FF000000FFFF + FF00FFFFFF00FFFFFF00FF000000FF000000FFFFFF00FF000000FF000000FFFF + FF00FFFFFF00FFFFFF00FF00000000000000000000000000FF00FFFFFF000000 + FF000000FF00FFFFFF000000FF00FFFFFF000000FF000000FF000000FF00FFFF + FF000000FF000000FF000000FF0000000000000000000000000000800000FFFF + FF00FFFFFF00FFFFFF0000800000FFFFFF00FFFFFF00FFFFFF00008000000080 + 0000FFFFFF000080000000800000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000FF000000FFFF + FF00FF000000FF000000FF000000FFFFFF00FF000000FFFFFF00FF000000FFFF + FF00FF000000FF000000FF00000000000000000000000000FF00FFFFFF000000 + FF000000FF00FFFFFF000000FF00FFFFFF000000FF000000FF000000FF00FFFF + FF000000FF000000FF000000FF0000000000000000000000000000800000FFFF + FF0000800000FFFFFF0000800000FFFFFF0000800000FFFFFF00008000000080 + 0000FFFFFF000080000000800000000000000000000000000000000000000000 + 000000000000000000000000000000FFFF0000FFFF0000000000000000000000 + 0000000000000000000000000000000000000000000000000000FF000000FFFF + FF00FFFFFF00FFFFFF00FF000000FFFFFF00FF000000FFFFFF00FF000000FFFF + FF00FFFFFF00FFFFFF00FF00000000000000000000000000FF00FFFFFF00FFFF + FF00FFFFFF000000FF000000FF00FFFFFF000000FF000000FF000000FF00FFFF + FF000000FF000000FF000000FF0000000000000000000000000000800000FFFF + FF00FFFFFF00FFFFFF0000800000FFFFFF00FFFFFF00FFFFFF0000800000FFFF + FF00FFFFFF00FFFFFF0000800000000000000000000000000000000000000000 + 000000000000000000000000000000FFFF0000FFFF0000000000000000000000 + 0000000000000000000000000000000000000000000000000000FF000000FF00 + 0000FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF00 + 0000FF000000FF000000FF00000000000000000000000000FF000000FF000000 + FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000 + FF000000FF000000FF000000FF00000000000000000000000000008000000080 + 0000008000000080000000800000008000000080000000800000008000000080 + 0000008000000080000000800000000000000000000000000000000000000000 + 00000000000000000000007F7F0000FFFF0000FFFF00007F7F00000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000FFFF0000FFFF0000FFFF0000FFFF00000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00000000000000000000000000000000000000 + 00000000000000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF000000000000000000000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF000000000000000000000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF000000000000000000000000000000000000000000000000000000 + 000000000000007F7F0000FFFF0000FFFF0000FFFF0000FFFF00007F7F000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF0000000000C0C0C000000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF0000000000C0C0C000000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF0000000000C0C0C000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000008080000080 + 8000000000000000000000000000000000000000000000000000C0C0C000C0C0 + C000000000000080800000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF000000000000000000000000000000000000000000008080000080 + 8000008080000080800000808000008080000080800000808000008080000000 + 0000000000000000000000000000000000000000000000000000008080000080 + 8000000000000000000000000000000000000000000000000000C0C0C000C0C0 + C000000000000080800000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF000000000000000000000000000000000000FFFF00000000000080 + 8000008080000080800000808000008080000080800000808000008080000080 + 8000000000000000000000000000000000000000000000000000008080000080 + 8000000000000000000000000000000000000000000000000000C0C0C000C0C0 + C000000000000080800000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF0000000000000000000000000000000000FFFFFF0000FFFF000000 + 0000008080000080800000808000008080000080800000808000008080000080 + 8000008080000000000000000000000000000000000000000000008080000080 + 8000000000000000000000000000000000000000000000000000000000000000 + 0000000000000080800000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF000000000000000000000000000000000000FFFF00FFFFFF0000FF + FF00000000000080800000808000008080000080800000808000008080000080 + 8000008080000080800000000000000000000000000000000000008080000080 + 8000008080000080800000808000008080000080800000808000008080000080 + 8000008080000080800000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF0000000000000000000000000000000000FFFFFF0000FFFF00FFFF + FF0000FFFF000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000008080000080 + 8000000000000000000000000000000000000000000000000000000000000000 + 0000008080000080800000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF000000000000000000000000000000000000FFFF00FFFFFF0000FF + FF00FFFFFF0000FFFF00FFFFFF0000FFFF00FFFFFF0000FFFF00000000000000 + 0000000000000000000000000000000000000000000000000000008080000000 + 0000C0C0C000C0C0C000C0C0C000C0C0C000C0C0C000C0C0C000C0C0C000C0C0 + C000000000000080800000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF0000000000000000000000000000000000FFFFFF0000FFFF00FFFF + FF0000FFFF00FFFFFF0000FFFF00FFFFFF0000FFFF00FFFFFF00000000000000 + 0000000000000000000000000000000000000000000000000000008080000000 + 0000C0C0C000C0C0C000C0C0C000C0C0C000C0C0C000C0C0C000C0C0C000C0C0 + C000000000000080800000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF000000000000000000000000000000000000FFFF00FFFFFF0000FF + FF00000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000008080000000 + 0000C0C0C000C0C0C000C0C0C000C0C0C000C0C0C000C0C0C000C0C0C000C0C0 + C000000000000080800000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000008080000000 + 0000C0C0C000C0C0C000C0C0C000C0C0C000C0C0C000C0C0C000C0C0C000C0C0 + C000000000000080800000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0000000000FFFF + FF00000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000008080000000 + 0000C0C0C000C0C0C000C0C0C000C0C0C000C0C0C000C0C0C000C0C0C000C0C0 + C000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000008080000000 + 0000C0C0C000C0C0C000C0C0C000C0C0C000C0C0C000C0C0C000C0C0C000C0C0 + C00000000000C0C0C00000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000424D3E000000000000003E000000 + 2800000040000000300000000100010000000000800100000000000000000000 + 000000000000000000000000FFFFFF0000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000F81FE000E000E000E007E000E000E000 + C003E000E000E000800180000000800080018000000080000000800000008000 + 0000800000008000000080000000800000008000000080000000800000008000 + 000080000000800080018000000080008001E000E000E000C003E000E000E000 + E007E001E001E001F81FE003E003E003FFFFFFFFFFFFFFFFFFFFFFFFC001FFFF + E003001F8001FFFFE003000F8001FFFFE00300078001FDFFE00300038001FCFF + E00300018001FC7FE00300008001FC3FE003001F8001FC1FE003001F8001FC3F + E003001F8001FC7FE0038FF18001FCFFE007FFF98001FDFFE00FFF758001FFFF + E01FFF8F8001FFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000 + 000000000000} + end + object dlgSaveExe: TSaveDialog + DefaultExt = '.exe' + Filter = 'Executable files (*.exe)|*.exe|All files (*.*)|*.*' + Options = [ofOverwritePrompt, ofHideReadOnly, ofPathMustExist, ofNoReadOnlyReturn, ofNoDereferenceLinks, ofEnableSizing, ofDontAddToRecent] + Left = 384 + Top = 56 + end + object dlgSaveDLL: TSaveDialog + DefaultExt = '.dll' + Filter = 'DLL files (*.dll)|*.dll|All files (*.*)|*.*' + Options = [ofOverwritePrompt, ofHideReadOnly, ofPathMustExist, ofNoReadOnlyReturn, ofNoDereferenceLinks, ofEnableSizing, ofDontAddToRecent] + Left = 416 + Top = 56 + end + object dlgSavePAT: TSaveDialog + DefaultExt = '.pat' + Filter = 'Patch files (*.pat)|*.pat|All files (*.*)|*.*' + Options = [ofOverwritePrompt, ofHideReadOnly, ofPathMustExist, ofNoReadOnlyReturn, ofNoDereferenceLinks, ofEnableSizing, ofDontAddToRecent] + Left = 448 + Top = 56 + end +end diff --git a/Contrib/VPatch/Source/GUI/MainForm.pas b/Contrib/VPatch/Source/GUI/MainForm.pas new file mode 100644 index 00000000..28133749 --- /dev/null +++ b/Contrib/VPatch/Source/GUI/MainForm.pas @@ -0,0 +1,539 @@ +unit MainForm; + +interface + +uses + Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, + Dialogs, Buttons, StdCtrls, Menus, PatchClasses, VirtualTrees, VDSP_CRC, + ToolWin, ComCtrls, ImgList, ExtCtrls, PatchGenerator, Math; + +const + UntitledFile='Untitled.vpj'; + +type + TfrmMain = class(TForm) + MainMenu: TMainMenu; + mnuFile: TMenuItem; + mnuNew: TMenuItem; + mnuOpen: TMenuItem; + mnuSave: TMenuItem; + mnuSaveas: TMenuItem; + N1: TMenuItem; + mnuExit: TMenuItem; + Label1: TLabel; + grpConfig: TGroupBox; + butAdd: TSpeedButton; + OD: TOpenDialog; + Label2: TLabel; + txtNew: TEdit; + Label3: TLabel; + mnuHelp: TMenuItem; + mnuAbout: TMenuItem; + lstOld: TListBox; + butOldAdd: TSpeedButton; + butOldRemove: TSpeedButton; + butNewEdit: TSpeedButton; + Label4: TLabel; + lstNew: TVirtualStringTree; + dlgOpen: TOpenDialog; + dlgSave: TSaveDialog; + IL: TImageList; + mnuAction: TMenuItem; + mnuGenGo: TMenuItem; + barTool: TToolBar; + toolNew: TToolButton; + toolOpen: TToolButton; + toolSave: TToolButton; + toolGenGo: TToolButton; + mnuCreateEXE: TMenuItem; + dlgSaveExe: TSaveDialog; + toolCreateEXE: TToolButton; + barCool: TCoolBar; + Label5: TLabel; + Label6: TLabel; + txtMinimumBlockSize: TEdit; + UDMinimumBlockSize: TUpDown; + UDBlockDivider: TUpDown; + txtBlockDivider: TEdit; + Label7: TLabel; + UDStepSize: TUpDown; + txtStepSize: TEdit; + Label8: TLabel; + chkDebug: TCheckBox; + tbBlockSize: TTrackBar; + txtStartBlockSize: TLabel; + mnuClearcachedpatches: TMenuItem; + mnuCreateDLL: TMenuItem; + mnuCreatePAT: TMenuItem; + toolCreateDLL: TToolButton; + ToolButton1: TToolButton; + toolCreatePAT: TToolButton; + dlgSaveDLL: TSaveDialog; + dlgSavePAT: TSaveDialog; + procedure butAddClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure mnuExitClick(Sender: TObject); + procedure UpdateStates; + procedure ReloadNewTree; + procedure SelectInNewTree(PatchIndex: Integer); + procedure butNewEditClick(Sender: TObject); + procedure lstNewChange(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure butOldAddClick(Sender: TObject); + procedure butOldRemoveClick(Sender: TObject); + procedure mnuNewClick(Sender: TObject); + procedure mnuOpenClick(Sender: TObject); + procedure mnuSaveClick(Sender: TObject); + procedure mnuSaveasClick(Sender: TObject); + procedure mnuGenGoClick(Sender: TObject); + procedure mnuAboutClick(Sender: TObject); + procedure mnuCreateEXEClick(Sender: TObject); + procedure lstNewGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; + var CellText: WideString); + procedure txtStartBlockSizeChange(Sender: TObject); + procedure txtMinimumBlockSizeChange(Sender: TObject); + procedure txtBlockDividerChange(Sender: TObject); + procedure txtStepSizeChange(Sender: TObject); + procedure chkDebugClick(Sender: TObject); + procedure tbBlockSizeChange(Sender: TObject); + procedure mnuClearcachedpatchesClick(Sender: TObject); + procedure mnuCreateDLLClick(Sender: TObject); + procedure mnuCreatePATClick(Sender: TObject); + private + { Private declarations } +// MS: TModeSelector; + dskName: String; + function DoSave(const FileName: String; const Prompt: Boolean): String; + procedure OpenAFile(FileName: String; AskSave: Boolean=True; PromptNew: Boolean=False); + function CollectConfig: String; + procedure SetConfigTextBoxes(Config: String); + procedure PrintDebug(S: String); + public + { Public declarations } + end; + +var + frmMain: TfrmMain; + PP: TPatchProject = nil; + +implementation + +uses AboutForm; + +{$R *.dfm} + +procedure TfrmMain.butAddClick(Sender: TObject); +begin + OD.Options:=OD.Options-[ofAllowMultiSelect]; + OD.Title:='Open the latest (new) version of a file...'; + OD.FileName:=''; + if OD.Execute then begin + PP.AddNewVersion(OD.FileName); + ReloadNewTree; + SelectInNewTree(PP.PatchFile(OD.FileName).Index); + butOldAdd.Click; + end; +end; + +procedure TfrmMain.FormCreate(Sender: TObject); +begin + grpConfig.Tag:=-1; + dskName:=UntitledFile; + lstNew.NodeDataSize:=SizeOf(Integer); + OpenAFile('',False,False); //don't prompt for New! that'll bug things + ReloadNewTree; + UpdateStates; +end; + +procedure TfrmMain.FormDestroy(Sender: TObject); +begin + PP.Free; +end; + +procedure TfrmMain.mnuExitClick(Sender: TObject); +begin + Close; +end; + +procedure TfrmMain.UpdateStates; +begin + Self.Caption:='VG - VPatch GUI - '+dskName; +// grpConfig.Enabled:=not (lstNew.Tag=-1); +// if not grpConfig.Enabled then grpConfig.Caption:='Select a file first'; + grpConfig.Enabled:=(lstNew.SelectedCount>0); + if grpConfig.Tag=-1 then begin + txtNew.Enabled:=False; + butNewEdit.Enabled:=False; + butNewEdit.Font.Color:=clInactiveCaption; + butOldAdd.Enabled:=False; + butOldAdd.Font.Color:=clInactiveCaption; + butOldRemove.Enabled:=False; + butOldRemove.Font.Color:=clInactiveCaption; + end else begin + txtNew.Enabled:=True; + butNewEdit.Enabled:=True; + butNewEdit.Font.Color:=clWindowText; + butOldAdd.Enabled:=True; + butOldAdd.Font.Color:=clWindowText; +// butOldEdit.Enabled:=True; + butOldRemove.Enabled:=True; + butOldRemove.Font.Color:=clWindowText; + end; +end; + +procedure TfrmMain.ReloadNewTree; +var + i: Integer; + Node: PVirtualNode; +begin + lstNew.BeginUpdate; + lstNew.Clear; + for i:=0 to PP.GetPatchCount - 1 do begin + Node:=lstNew.AddChild(nil); + PInteger(lstNew.GetNodeData(Node))^:=i; + end; + lstNew.EndUpdate; +end; + +procedure TfrmMain.butNewEditClick(Sender: TObject); +var + i: Integer; +begin + OD.Options:=OD.Options-[ofAllowMultiSelect]; + OD.Title:='Select new version of file...'; + OD.FileName:=txtNew.Text; + if OD.Execute then begin + i:=grpConfig.Tag; + PP.PatchFile(i).NewVersion:=OD.FileName; + ReloadNewTree; + lstNew.Selected[lstNew.GetFirstVisible]:=True; + end; +end; + +procedure TfrmMain.lstNewChange(Sender: TBaseVirtualTree; + Node: PVirtualNode); +var + i,j: Integer; +begin + case lstNew.SelectedCount of + 0: Exit; + 1: begin + if lstNew.Selected[Node] then begin + i:=PInteger(lstNew.GetNodeData(Node))^; + grpConfig.Caption:=ExtractFileName(PP.PatchFile(i).NewVersion); + grpConfig.Tag:=i; + txtNew.Text:=PP.PatchFile(i).NewVersion; + lstOld.Clear; + for j:=0 to PP.PatchFile(i).OldVersionCount - 1 do begin + lstOld.Items.Add(PP.PatchFile(i).OldVersions[j]); + end; + SetConfigTextBoxes(PP.PatchFile(i).Config); + end; + end; + else begin + grpConfig.Tag:=-1; //multiple files selected - only allow config changes + txtNew.Text:='(multiple files selected)'; + lstOld.Clear; + end; + end; + UpdateStates; +end; + +procedure TfrmMain.butOldAddClick(Sender: TObject); +var + i,j: Integer; +begin + OD.Options:=OD.Options+[ofAllowMultiSelect]; + OD.Title:='Select old versions of '+grpConfig.Caption+'...'; + OD.FileName:=''; + if OD.Execute then begin + i:=grpConfig.Tag; + for j:=0 to OD.Files.Count - 1 do begin + PP.PatchFile(i).AddOldVersion(OD.Files[j]); + lstOld.Items.Add(OD.Files.Strings[j]); + end; + end; +end; + +procedure TfrmMain.SelectInNewTree(PatchIndex: Integer); +var + Node: PVirtualNode; +begin + Node:=lstNew.GetFirstSelected; + while Node<>nil do begin + lstNew.Selected[Node]:=False; + Node:=lstNew.GetNextSelected(Node); + end; + Node:=lstNew.GetFirst; + while Node<>nil do begin + if PInteger(lstNew.GetNodeData(Node))^=PatchIndex then begin + lstNew.Selected[Node]:=True; + lstNewChange(lstNew,Node); + Exit; + end; + Node:=lstNew.GetNext(Node); + end; +end; + +procedure TfrmMain.butOldRemoveClick(Sender: TObject); +begin + if lstOld.ItemIndex>=0 then begin + PP.PatchFile(grpConfig.Tag).RemoveOldVersion(lstOld.ItemIndex); + lstOld.Items.Delete(lstOld.ItemIndex); + end; +end; + +procedure TfrmMain.OpenAFile(FileName: String; AskSave: Boolean=True; PromptNew: Boolean=False); +var + fs: TFileStream; +begin + PP.Free; //confirm saving first? + PP:=TPatchProject.Create; + ReloadNewTree; + if FileName<>'' then begin + fs:=nil; + try + fs:=TFileStream.Create(FileName,fmOpenRead); + PP.LoadFromStream(fs); + finally + dskName:=FileName; + ReloadNewTree; + fs.Free; + end; + end else begin + dskName:=UntitledFile; + if PromptNew then butAddClick(Self); + end; + + UpdateStates; +end; + +procedure TfrmMain.mnuNewClick(Sender: TObject); +begin + OpenAFile('',True,True); +end; + +procedure TfrmMain.mnuOpenClick(Sender: TObject); +begin + if dlgOpen.Execute then begin + OpenAFile(dlgOpen.FileName,True); + end; +end; + +procedure TfrmMain.mnuSaveClick(Sender: TObject); +begin + dskName:=DoSave(dskName,False); + UpdateStates; +end; + +procedure TfrmMain.mnuSaveasClick(Sender: TObject); +begin + dskName:=DoSave(dskName,True); + UpdateStates; +end; + +function TfrmMain.DoSave(const FileName: String; const Prompt: Boolean): String; +var + FN: String; + fs: TFileStream; +begin + DoSave:=''; + FN:=FileName; + if Prompt or (CompareText(FileName,UntitledFile)=0) then begin + if dlgSave.Execute then begin + FN:=dlgSave.FileName; + if ExtractFileExt(FN)='' then + FN:=FN+'.vpj'; + end else begin + DoSave:=FileName; + Exit; + end; + end; + //do actual saving to this file... + fs:=TFileStream.Create(FN,fmCreate); + PP.SaveToStream(fs); + fs.Free; + DoSave:=FN; +end; + +procedure TfrmMain.mnuGenGoClick(Sender: TObject); +begin + Self.Visible:=False; + Cursor:=crHourGlass; + PP.Generate; + Cursor:=crDefault; + Self.Visible:=True; + SelectInNewTree(0); +end; + +procedure TfrmMain.mnuAboutClick(Sender: TObject); +var + frmAbout: TfrmAbout; +begin + frmAbout:=TfrmAbout.Create(Self); + frmAbout.ShowModal; + frmAbout.Free; +end; + +procedure TfrmMain.mnuCreateEXEClick(Sender: TObject); +var + fs: TFileStream; + fr: TFileStream; +begin + //first, select it on disk (where should the exe go?) + if dlgSaveExe.FileName='' then dlgSaveExe.FileName:='VPatch.exe'; + if dlgSaveExe.Execute then begin + fs:=nil; + try + fs:=TFileStream.Create(dlgSaveExe.FileName,fmCreate); + fr:=nil; + try + fr:=TFileStream.Create(ExtractFilePath(Application.ExeName)+'vpatch.bin',fmOpenRead); + fs.CopyFrom(fr,fr.Size); + finally + fr.Free; + end; + PP.WritePatches(fs); + finally + fs.Free; + end; + end; +end; + +procedure TfrmMain.mnuCreateDLLClick(Sender: TObject); +var + fs: TFileStream; + fr: TFileStream; +begin + //first, select it on disk (where should the exe go?) + if dlgSaveDLL.FileName='' then dlgSaveDLL.FileName:='VPatch.DLL'; + if dlgSaveDLL.Execute then begin + fs:=nil; + try + fs:=TFileStream.Create(dlgSaveDLL.FileName,fmCreate); + fr:=nil; + try + fr:=TFileStream.Create(ExtractFilePath(Application.ExeName)+'vpatchdll.bin',fmOpenRead); + fs.CopyFrom(fr,fr.Size); + finally + fr.Free; + end; + PP.WritePatches(fs); + finally + fs.Free; + end; + end; +end; + +procedure TfrmMain.mnuCreatePATClick(Sender: TObject); +var + fs: TFileStream; +begin + //first, select it on disk (where should the exe go?) + if dlgSavePAT.FileName='' then dlgSavePAT.FileName:='PatchData.pat'; + if dlgSavePAT.Execute then begin + fs:=nil; + try + fs:=TFileStream.Create(dlgSavePAT.FileName,fmCreate); + PP.WritePatches(fs); + finally + fs.Free; + end; + end; +end; + +procedure TfrmMain.lstNewGetText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; + var CellText: WideString); +var + i: Integer; +begin + i:=PInteger(lstNew.GetNodeData(Node))^; + CellText:=ExtractFileName(PP.PatchFile(i).NewVersion); +end; + +procedure TfrmMain.txtStartBlockSizeChange(Sender: TObject); +begin + PP.PatchFile(grpConfig.Tag).Config:=CollectConfig; +end; + +function TfrmMain.CollectConfig: String; +begin + Result:=txtStartBlockSize.Caption+','+txtMinimumBlockSize.Text+','+txtBlockDivider.Text+','+txtStepSize.Text; +end; + +procedure TfrmMain.txtMinimumBlockSizeChange(Sender: TObject); +begin + PP.PatchFile(grpConfig.Tag).Config:=CollectConfig; +end; + +procedure TfrmMain.txtBlockDividerChange(Sender: TObject); +begin + PP.PatchFile(grpConfig.Tag).Config:=CollectConfig; +end; + +procedure TfrmMain.txtStepSizeChange(Sender: TObject); +begin + PP.PatchFile(grpConfig.Tag).Config:=CollectConfig; +end; + +procedure TfrmMain.SetConfigTextBoxes(Config: String); +var + a,i: Integer; +begin + a:=Pos(',',Config); + if(a=0) then a:=Length(Config)+1; + txtStartBlockSize.Caption:=Copy(Config,1,a-1); + Config:=Copy(Config,a+1,Length(Config)); + + a:=StrToInt(txtStartBlockSize.Caption); + i:=-1; + while not (a=0) do begin + a:=a shr 1; + Inc(i); + end; + tbBlockSize.Position := i; + + a:=Pos(',',Config); + if(a=0) then a:=Length(Config)+1; + txtMinimumBlockSize.Text:=Copy(Config,1,a-1); + Config:=Copy(Config,a+1,Length(Config)); + + a:=Pos(',',Config); + if(a=0) then a:=Length(Config)+1; + txtBlockDivider.Text:=Copy(Config,1,a-1); + Config:=Copy(Config,a+1,Length(Config)); + + a:=Pos(',',Config); + if(a=0) then a:=Length(Config)+1; + txtStepSize.Text:=Copy(Config,1,a-1); +end; + +procedure TfrmMain.chkDebugClick(Sender: TObject); +begin + if chkDebug.State = cbUnchecked then + PatchGenerator.DebugEvent:=nil + else + PatchGenerator.DebugEvent:=PrintDebug; +end; + +procedure TfrmMain.PrintDebug(S: String); +begin + WriteLn(S); +end; + +procedure TfrmMain.tbBlockSizeChange(Sender: TObject); +begin + txtStartBlockSize.Caption:=IntToStr(1 shl tbBlockSize.Position); + PP.PatchFile(grpConfig.Tag).Config:=CollectConfig; +end; + +procedure TfrmMain.mnuClearcachedpatchesClick(Sender: TObject); +begin + PP.ResetCache; +end; + +initialization + PP:=TPatchProject.Create; +end. diff --git a/Contrib/VPatch/Source/GUI/PatchClasses.pas b/Contrib/VPatch/Source/GUI/PatchClasses.pas new file mode 100644 index 00000000..73400438 --- /dev/null +++ b/Contrib/VPatch/Source/GUI/PatchClasses.pas @@ -0,0 +1,548 @@ +unit PatchClasses; + +interface + +uses Classes, sysutils, VDSP_CRC, DLLWrapper, Dialogs; + +const + DEFAULT_CONFIG = '64,64,2,32'; + +type + TAbstractFile = record + FileName: String; + FriendlyName: String; + CRC32: LongWord; //the longword/integer sign is going to give problems again... + Size: Integer; + //not sure about this one yet... + Cached: Boolean; //True: we have cached the patch, using latest config + //False: a) we have nothing cached (size and start are -1) + // b) we still have cache (start>0 and size too), but it's not generated using the latest config (we can keep it of course because the new config might be worse) + Cache: TMemoryStream; + end; + + TPatchFile = class (TObject) + private + FIndex: Integer; + ConfigID: String; + FNew: TAbstractFile; + FOld: Array of TAbstractFile; + protected + procedure SetNewFN(Value: String); + function GetNewFN: String; + procedure SetOldFN(i: Integer; FileName: String); + function GetOldFN(Index: Integer): String; + function GetOldVersionCount: Integer; + procedure ResetCache; overload; + procedure ResetCache(OldIndex: Integer); overload; + procedure InvalidateCache; overload; + procedure InvalidateCache(Index: Integer); overload; + function GetCached(Index: Integer): Boolean; + function GetConfig: String; + procedure SetConfig(Value: String); + public + constructor Create(Index: Integer; FileName: String); overload; + constructor Create(Index: Integer; Stream: TStream); overload; + destructor Destroy(); override; + + procedure AddOldVersion(const FileName: String); + procedure RemoveOldVersion(const Index: Integer); + property OldVersions[Index: Integer]: String read GetOldFN write SetOldFN; + + procedure Generate; overload; + procedure Generate(const Index: Integer); overload; + property Generated[Index: Integer]: Boolean read GetCached; + function GetPatchSize(Index: Integer): Integer; + + procedure WritePatch(Index: Integer; Stream: TStream); + +// LoadFromStream not supported: Use Create(Index,Stream) instead! +// procedure LoadFromStream(Stream: TStream); + procedure SaveToStream(Stream: TStream); + published + property NewVersion: String read GetNewFN write SetNewFN; + property OldVersionCount: Integer read GetOldVersionCount; + property Index: Integer read FIndex; + property Config: String read GetConfig write SetConfig; + end; + + TPatchProject = class (TObject) + private + FPat: Array of TPatchFile; + public + procedure LoadFromStream(Stream: TStream); + procedure SaveToStream(Stream: TStream); + constructor Create(); + destructor Destroy(); override; + procedure AddNewVersion(FileName: String); + function PatchFile(FileName: String): TPatchFile; overload; + function PatchFile(Index: Integer): TPatchFile; overload; + function GetPatchCount: Integer; + procedure WritePatches(Stream: TStream); + procedure Generate; + procedure ResetCache; + end; + +implementation + + function ReadStreamString(Stream: TStream): String; + var + Buf: Array[0..512] of Char; + i: LongInt; + S: String; + j: Integer; + begin + Stream.Read(i,SizeOf(i)); + if i>512 then raise Exception.Create('VPJ damaged: String too long (>512)'); + Stream.Read(Buf,i); + for j:=1 to i do + S:=S+Buf[j-1]; + ReadStreamString:=S; + end; + +//a private wrapper for the FileCRC function +function CalcCRC(FileName: String): Integer; +var + fs: TFileStream; +begin + CalcCRC:=0; + fs:=nil; + try + fs:=TFileStream.Create(FileName,fmOpenRead); + CalcCRC:=FileCRC(fs); + finally + fs.Free; + end; +end; + +function GetFileSize(FileName: String): Integer; +var + fs: TFileStream; +begin + GetFileSize:=0; + fs:=nil; + try + fs:=TFileStream.Create(FileName,fmOpenRead); + GetFileSize:=fs.Size; + finally + fs.Free; + end; +end; + +{ TPatchFile } + +procedure TPatchFile.AddOldVersion(const FileName: String); +var + i: Integer; +// fs: TFileStream; +begin + i:=Length(FOld); + SetLength(FOld,i+1); + FOld[i].Cache:=TMemoryStream.Create; + SetOldFN(i,FileName); +end; + +constructor TPatchFile.Create(Index: Integer; FileName: String); +//var +// fs: TFileStream; +begin + inherited Create(); + FIndex:=Index; + SetLength(FOld,0); + FNew.CRC32:=0; + FNew.Size:=-1; + SetNewFN(FileName); + ConfigID:=DEFAULT_CONFIG; + //just to be on the safe side + //following is now done by SetNewFN :) + //no it's not - because that one resets the cache!!! + //doesn't matter, because we're not loading from stream!!! +{ FNew.FileName:=FileName; + FNew.FriendlyName:=ExtractFileName(FileName); + FNew.CRC32:=CalcCRC(FileName); + FNew.Size:=GetFileSize(FileName);} +end; + +constructor TPatchFile.Create(Index: Integer; Stream: TStream); +var + i,q: LongInt; + CSize: Integer; + j: Integer; +begin + inherited Create(); + FIndex:=Index; + SetLength(FOld,0); + FNew.CRC32:=0; + FNew.Size:=-1; //just to be on the safe side + + //read configuration + ConfigID:=ReadStreamString(Stream); + + //now load everything... + FNew.FileName:=ReadStreamString(Stream); + FNew.FriendlyName:=ReadStreamString(Stream); + Stream.Read(FNew.CRC32,SizeOf(FNew.CRC32)); + Stream.Read(FNew.Size,SizeOf(FNew.Size)); + Stream.Read(i,SizeOf(i)); + SetLength(FOld,i); + for j:=0 to i - 1 do begin + FOld[j].FileName:=ReadStreamString(Stream); + FOld[j].FriendlyName:=ReadStreamString(Stream); + Stream.Read(FOld[j].CRC32,SizeOf(FOld[j].CRC32)); + Stream.Read(FOld[j].Size,SizeOf(FOld[j].Size)); + Stream.Read(q,SizeOf(q)); + FOld[j].Cached:=not (q=0); + if FOld[j].Cached then begin + Stream.Read(CSize,SizeOf(CSize)); + FOld[j].Cache:=TMemoryStream.Create; + FOld[j].Cache.CopyFrom(Stream,CSize); + end; + end; +end; + +destructor TPatchFile.Destroy; +begin + SetLength(FOld,0); + inherited; +end; + +function TPatchFile.GetNewFN: String; +begin + GetNewFN:=FNew.FileName; +end; + +function TPatchFile.GetOldFN(Index: Integer): String; +begin + Result:=FOld[Index].FileName; + if FOld[Index].Cached then + if FOld[Index].Cache.Size>0 then begin + Result:=Result + ' ('+IntToStr(FOld[Index].Cache.Size)+' bytes)'; + end; +end; + +function TPatchFile.GetOldVersionCount: Integer; +begin + GetOldVersionCount:=Length(FOld); +end; + +procedure TPatchFile.ResetCache; +var + i: Integer; +begin + for i:=0 to Length(FOld)-1 do + ResetCache(i); +end; + +procedure TPatchFile.RemoveOldVersion(const Index: Integer); +var + i: Integer; +begin + FOld[Index].Cache.Free; + for i:=Index to Length(FOld)-2 do begin + FOld[i]:=FOld[i+1]; + end; + SetLength(FOld,Length(FOld)-1); +end; + +procedure TPatchFile.ResetCache(OldIndex: Integer); +begin + FOld[OldIndex].Cached:=False; + FOld[OldIndex].Size:=-1; + FOld[OldIndex].Cache.Clear; +end; + +procedure TPatchFile.SaveToStream(Stream: TStream); + procedure WriteStreamString(Stream: TStream; const S: String); + var + i: LongInt; + j: Integer; + Buf: Array[0..512] of Char; + begin + i:=Length(S); + Stream.Write(i,SizeOf(i)); + for j:=1 to i do + Buf[j-1]:=S[j]; + Buf[i]:=#0; + Stream.Write(Buf,i); + end; +var + i,q: LongInt; + j: Integer; + tmp: Integer; +begin + //write config ID + WriteStreamString(Stream,ConfigID); + + WriteStreamString(Stream,FNew.FileName); + WriteStreamString(Stream,FNew.FriendlyName); + Stream.Write(FNew.CRC32,SizeOf(FNew.CRC32)); + Stream.Write(FNew.Size,SizeOf(FNew.Size)); + + i:=Length(FOld); + Stream.Write(i,SizeOf(i)); + + for j:=0 to i - 1 do begin + WriteStreamString(Stream,FOld[j].FileName); + WriteStreamString(Stream,FOld[j].FriendlyName); + Stream.Write(FOld[j].CRC32,SizeOf(FOld[j].CRC32)); + Stream.Write(FOld[j].Size,SizeOf(FOld[j].Size)); + if FOld[j].Cached then q:=1 else q:=0; + Stream.Write(q,SizeOf(q)); + if FOld[j].Cached then begin + tmp:=FOld[j].Cache.Size; + Stream.Write(tmp,SizeOf(tmp)); + FOld[j].Cache.Seek(0,soFromBeginning); + Stream.CopyFrom(FOld[j].Cache,tmp); + end; + end; +end; + +procedure TPatchFile.SetNewFN(Value: String); +var + NewSize: Integer; + NewCRC: LongWord; +begin + FNew.FileName:=Value; + FNew.Friendlyname:=ExtractFileName(Value); + NewCRC:=CalcCRC(Value); + NewSize:=GetFileSize(Value); + //if any changes, then reset cache :) + if not ((FNew.CRC32=NewCRC) and (FNew.Size=NewSize)) then begin + FNew.CRC32:=NewCRC; + FNew.Size:=NewSize; + ResetCache; + end; +end; + +procedure TPatchFile.SetOldFN(i: Integer; FileName: String); +begin + if((i>=0) and (iSize) or (not FOld[Index].Cached) then begin //the new one is better + FOld[Index].Cache.Clear; + fm.Seek(8,soFromBeginning); + FOld[Index].Cache.CopyFrom(fm,fm.Size-8); + end; + FOld[Index].Cached:=True; + end; + fm.Free; +end; + +function TPatchFile.GetCached(Index: Integer): Boolean; +begin + GetCached:=FOld[Index].Cached; +end; + +function TPatchFile.GetConfig: String; +begin + GetConfig:=ConfigID; +end; + +procedure TPatchFile.SetConfig(Value: String); +begin + if not Assigned(Self) then Exit; + if not SameText(Value,ConfigID) then begin + InvalidateCache; //configuration changed, invalidate cache + end; + ConfigID:=Value; +end; + +function TPatchFile.GetPatchSize(Index: Integer): Integer; +begin + if Generated[Index] then begin + GetPatchSize:=FOld[Index].Cache.Size; + end else + GetPatchSize:=-1; +end; + +procedure TPatchFile.InvalidateCache; +var + i: Integer; +begin + for i:=0 to Length(FOld)-1 do + InvalidateCache(i); +end; + +procedure TPatchFile.InvalidateCache(Index: Integer); +begin + FOld[Index].Cached:=False; +end; + +procedure TPatchFile.WritePatch(Index: Integer; Stream: TStream); +begin + if not FOld[Index].Cached then + Generate(Index); + if not FOld[Index].Cached then + raise Exception.Create('Writing of patch failed: Could not generate all patches'); + FOld[Index].Cache.Seek(0,soFromBeginning); + Stream.CopyFrom(FOld[Index].Cache,FOld[Index].Cache.Size); +end; + +{ TPatchProject } + +procedure TPatchProject.AddNewVersion(FileName: String); +var + i: Integer; +begin + i:=Length(FPat); + SetLength(FPat,i+1); + FPat[i]:=TPatchFile.Create(i,FileName); + FPat[i].SetConfig(DEFAULT_CONFIG); +end; + +constructor TPatchProject.Create; +begin + inherited; + SetLength(FPat,0); +end; + +destructor TPatchProject.Destroy; +var + i: Integer; +begin + for i:=0 to Length(FPat)-1 do begin + FPat[i].Free; + end; + SetLength(FPat,0); + inherited; +end; + +procedure TPatchProject.Generate; +var + i: Integer; +begin + for i:=0 to GetPatchCount - 1 do + FPat[i].Generate; +end; + +function TPatchProject.GetPatchCount: Integer; +begin + GetPatchCount:=Length(FPat); +end; + +procedure TPatchProject.LoadFromStream(Stream: TStream); +var + i: LongInt; + j: Integer; +begin + //first free all patchfiles + for j:=0 to Length(FPat)-1 do begin + FPat[j].Free; + FPat[j]:=nil; + end; + Stream.Read(i,SizeOf(i)); + if(i=$1A4A5056) then begin //still read old files + Stream.Read(i,SizeOf(i)); //16 dummy bytes + Stream.Read(i,SizeOf(i)); + Stream.Read(i,SizeOf(i)); + Stream.Read(i,SizeOf(i)); + + Stream.Read(i,SizeOf(i)); + end; + SetLength(FPat,i); + for j:=0 to i - 1 do begin + FPat[j]:=TPatchFile.Create(j,Stream); + end; +end; + +function TPatchProject.PatchFile(FileName: String): TPatchFile; +var + i: Integer; +begin + PatchFile:=nil; + for i:=0 to Length(FPat) - 1 do begin + if(CompareText(FPat[i].FNew.FileName,FileName)=0) then begin + PatchFile:=FPat[i]; + end; + end; + for i:=0 to Length(FPat) - 1 do begin + if(CompareText(FPat[i].FNew.FriendlyName,FileName)=0) then begin + PatchFile:=FPat[i]; + end; + end; +end; + +function TPatchProject.PatchFile(Index: Integer): TPatchFile; +begin + if (Index=0) then + PatchFile:=FPat[Index] + else + PatchFile:=nil; +end; + +procedure TPatchProject.ResetCache; +var + i: Integer; +begin + for i:=0 to Pred(Length(FPat)) do + FPat[i].ResetCache; +end; + +procedure TPatchProject.SaveToStream(Stream: TStream); +var + HeadID: Array[0..3] of Char; + i: LongInt; + j: Integer; +begin + HeadID:='VPJ'+#26; + Stream.Write(HeadID,SizeOf(HeadID)); + //16 dummy bytes + i:=0; + Stream.Write(i,SizeOf(i)); + Stream.Write(i,SizeOf(i)); + Stream.Write(i,SizeOf(i)); + Stream.Write(i,SizeOf(i)); + i:=Length(FPat); + Stream.Write(i,SizeOf(i)); + for j:=0 to i - 1 do begin + FPat[j].SaveToStream(Stream); + end; +end; + +procedure TPatchProject.WritePatches(Stream: TStream); +var + i,j,k,o: LongInt; +begin + k:=$54415056; + o:=Stream.Position; + Stream.Write(k,SizeOf(k)); + k:=0; + Stream.Write(k,SizeOf(k)); + k:=0; + for i:=0 to Length(FPat)-1 do begin + for j:=0 to FPat[i].GetOldVersionCount - 1 do begin + FPat[i].WritePatch(j,Stream); + Inc(k); + end; + end; + Stream.Seek(o+4,soFromBeginning); + Stream.Write(k,SizeOf(k)); + Stream.Seek(Stream.Size,soFromBeginning); + Stream.Write(o,SizeOf(o)); +end; + +end. + \ No newline at end of file diff --git a/Contrib/VPatch/Source/GUI/ProgressForm.dfm b/Contrib/VPatch/Source/GUI/ProgressForm.dfm new file mode 100644 index 00000000..787fec9d --- /dev/null +++ b/Contrib/VPatch/Source/GUI/ProgressForm.dfm @@ -0,0 +1,102 @@ +object frmProg: TfrmProg + Left = 328 + Top = 266 + BorderIcons = [biSystemMenu, biMinimize] + BorderStyle = bsSingle + Caption = 'Progress...' + ClientHeight = 193 + ClientWidth = 385 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + OldCreateOrder = False + Position = poScreenCenter + OnCreate = FormCreate + PixelsPerInch = 96 + TextHeight = 13 + object lblStatus: TLabel + Left = 8 + Top = 8 + Width = 369 + Height = 17 + AutoSize = False + Transparent = True + end + object lblSize: TLabel + Left = 152 + Top = 8 + Width = 225 + Height = 17 + Alignment = taRightJustify + AutoSize = False + Transparent = True + end + object lblFile: TLabel + Left = 8 + Top = 48 + Width = 369 + Height = 17 + AutoSize = False + Caption = '(filename)' + end + object lblNewFile: TLabel + Left = 8 + Top = 96 + Width = 369 + Height = 17 + AutoSize = False + Caption = '(filename)' + end + object lblTotal: TLabel + Left = 8 + Top = 144 + Width = 369 + Height = 17 + AutoSize = False + Caption = 'Total progress' + end + object shpFull: TShape + Left = 8 + Top = 24 + Width = 369 + Height = 17 + Brush.Color = clGray + end + object shpLeft: TShape + Left = 8 + Top = 24 + Width = 369 + Height = 17 + Brush.Color = clRed + end + object prgFile: TProgressBar + Left = 8 + Top = 64 + Width = 369 + Height = 25 + Min = 0 + Max = 100 + TabOrder = 0 + end + object prgNewFile: TProgressBar + Left = 8 + Top = 112 + Width = 369 + Height = 25 + Min = 0 + Max = 100 + TabOrder = 1 + end + object prgAll: TProgressBar + Left = 8 + Top = 160 + Width = 369 + Height = 25 + Min = 0 + Max = 100 + TabOrder = 2 + end +end diff --git a/Contrib/VPatch/Source/GUI/ProgressForm.pas b/Contrib/VPatch/Source/GUI/ProgressForm.pas new file mode 100644 index 00000000..b2fca0ac --- /dev/null +++ b/Contrib/VPatch/Source/GUI/ProgressForm.pas @@ -0,0 +1,74 @@ +unit ProgressForm; + +interface + +uses + Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, + Dialogs, StdCtrls, ComCtrls, ExtCtrls, Math; + +type + TfrmProg = class(TForm) + prgFile: TProgressBar; + lblFile: TLabel; + lblNewFile: TLabel; + prgNewFile: TProgressBar; + lblTotal: TLabel; + prgAll: TProgressBar; + lblStatus: TLabel; + shpFull: TShape; + shpLeft: TShape; + lblSize: TLabel; + procedure GetStatusProc(S: PChar; Point, Total, + CurrentSavings: Integer); stdcall; + procedure FormCreate(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + FilePos,FileRange,AllPos,AllRange: Byte; + CTotal: Integer; + t2: TDateTime; + end; + +var + frmProg: TfrmProg; + +implementation + +{$R *.dfm} + +procedure TfrmProg.GetStatusProc(S: PChar; Point, Total, CurrentSavings: Integer); stdcall; +var + a,b: Integer; + j: Single; +begin + if Length(S)>0 then + lblStatus.Caption:=S; + if (Total<0) then begin + Total:=CTotal; + if (Now-t2)*24*3600*10<8 then Exit; //update only every 800 milliseconds + end; + if (Total>=0) then CTotal:=Total; + if (Total>=0) and (Point>=0) then begin + a:=(Point*100) div Total; + prgFile.Position:=a; + b:=FilePos+(a*FileRange) div 100; + prgNewFile.Position:=b; + prgAll.Position:=AllPos+(b*AllRange) div 100; + end; + if (CurrentSavings>=0) and (Total>=0) then begin + j:=(Total-CurrentSavings)*shpFull.Width/Total; + shpLeft.Width:=Max(Round(j),3); + lblSize.Caption:=IntToStr(Total-CurrentSavings)+' of '+IntToStr(Total)+' ('+IntToStr(CurrentSavings*100 div Total)+'%)'; + end; + Refresh; + t2:=Now; +end; + +procedure TfrmProg.FormCreate(Sender: TObject); +begin + FilePos:=0; FileRange:=100; AllPos:=0; AllRange:=100; CTotal:=-1; + t2:=0; +end; + +end. diff --git a/Contrib/VPatch/Source/GUI/VPatchGUI.dof b/Contrib/VPatch/Source/GUI/VPatchGUI.dof new file mode 100644 index 00000000..f34f36b6 --- /dev/null +++ b/Contrib/VPatch/Source/GUI/VPatchGUI.dof @@ -0,0 +1,87 @@ +[FileVersion] +Version=6.0 +[Compiler] +A=8 +B=0 +C=1 +D=1 +E=0 +F=0 +G=1 +H=1 +I=1 +J=0 +K=0 +L=1 +M=0 +N=1 +O=1 +P=1 +Q=0 +R=0 +S=0 +T=0 +U=0 +V=1 +W=0 +X=1 +Y=1 +Z=1 +ShowHints=1 +ShowWarnings=1 +UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; +[Linker] +MapFile=0 +OutputObjs=0 +ConsoleApp=0 +DebugInfo=0 +RemoteSymbols=0 +MinStackSize=16384 +MaxStackSize=1048576 +ImageBase=4194304 +ExeDescription= +[Directories] +OutputDir= +UnitOutputDir= +PackageDLLOutputDir= +PackageDCPOutputDir= +SearchPath= +Packages=vcl;rtl;dbrtl;adortl;vcldb;vclx;bdertl;vcldbx;ibxpress;dsnap;cds;bdecds;qrpt;teeui;teedb;tee;dss;teeqr;visualclx;visualdbclx;dsnapcrba;dsnapcon;VclSmp;vclshlctrls;vclie;xmlrtl;inet;inetdbbde;inetdbxpress;nmfast;webdsnap;websnap;dbexpress;dbxcds;indy;dclOffice2k;VirtualTreesD6;packageTib;inetdb +Conditionals= +DebugSourceDirs= +UsePackages=0 +[Parameters] +RunParams= +HostApplication= +Launcher= +UseLauncher=0 +DebugCWD= +[Language] +ActiveLang= +ProjectLang= +RootDir= +[Version Info] +IncludeVerInfo=1 +AutoIncBuild=1 +MajorVer=2 +MinorVer=0 +Release=0 +Build=10 +Debug=0 +PreRelease=0 +Special=0 +Private=0 +DLL=0 +Locale=1043 +CodePage=1252 +[Version Info Keys] +CompanyName=Van de Sande Productions +FileDescription=VG - VPatch GUI +FileVersion=2.0.0.10 +InternalName=VPatchGUI +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion=2.0 final +Comments= diff --git a/Contrib/VPatch/Source/GUI/VPatchGUI.dpr b/Contrib/VPatch/Source/GUI/VPatchGUI.dpr new file mode 100644 index 00000000..6043f94a --- /dev/null +++ b/Contrib/VPatch/Source/GUI/VPatchGUI.dpr @@ -0,0 +1,19 @@ +program VPatchGUI; + +uses + Forms, + MainForm in 'MainForm.pas' {frmMain}, + PatchClasses in 'PatchClasses.pas', + VDSP_CRC in '..\VDSP_CRC.pas', + DLLWrapper in 'DLLWrapper.pas', + AboutForm in 'AboutForm.pas' {frmAbout}, + PatchGenerator in '..\PatchGenerator.pas', + TreeCode in '..\TreeCode.pas'; + +{$R *.res} + +begin + Application.Initialize; + Application.CreateForm(TfrmMain, frmMain); + Application.Run; +end. diff --git a/Contrib/VPatch/Source/GUI/VPatchGUI.res b/Contrib/VPatch/Source/GUI/VPatchGUI.res new file mode 100644 index 0000000000000000000000000000000000000000..0aa15975d21574dcc95872bccc19ac7a3d5edb61 GIT binary patch literal 1636 zcmaJ=O;1xn6g`hNeUXK<;zC`>i!sKSXv#;_gasO~NTNbOyQPgXl@v-tE7h>Dt8PgA zGbGUD#iT2L14|Yz+{uy!VLbQFd;LIk();c`ch3EoI~@QBDAqcmIk0{W#rp|zJl#vD zN0Tw>K8=9#jN&13Gv@Nu1o%U<=@h>-DNS@b9d1YyqO4Q=y1vBeRwk2 zpWeg1x_fvx3p60u1^D|&WOKwja1Ig;Rb$Goo-vYu*eEWy6sNlQU;yuy+XMXFFl_b56SoB;ivJw8Lp>3( z$9@`n2YXMr?Wat^8=XAN+-RA7;j5pO%qm$IMDI zp#&|d&C$i>Bgb7W9?g`_hHm}!u^r!bYeSu|K3tC}S>*Z+6`kwrKF8P2V46DcK8MT2VwR@?N zgX*!q$raSGjdfH|LXLU^Ys_4M!4^5!l#|62#xcp$PO%5+Xc;$|Zt1rL@;($F1!`Vx$wnh6B-m~&L?Fwod^Ac(1jC+`4WQ`o@t=eS@F^_rXd`QV- ziJ9wUeI%O4J9Z9C;7VVfJo9WbldB~06L`dvI2qR)1kW_g7&&)c`4#5f=sQt=rMS*L zMtFEdeo5IfjVk9L9hcZqU5ar%xWIc$Mp37+NxhA7bp9T9G0GvgB7MX&5fo1txTARo z=h=S;lJBXWYmjqsB5oc5Z#=FC+|u0cex;(!#oZDxCy6c7pMQtozx N%=o4yay0of`3E#IF1G*x literal 0 HcmV?d00001 diff --git a/Contrib/VPatch/Source/GenPat/GenPat2.dpr b/Contrib/VPatch/Source/GenPat/GenPat2.dpr new file mode 100644 index 00000000..d2a5bbb6 --- /dev/null +++ b/Contrib/VPatch/Source/GenPat/GenPat2.dpr @@ -0,0 +1,125 @@ +program GenPat2; + +{ + VPatch 2 - Patch Generator + =============================== + + (c) 2001-2003 Van de Sande Productions + + This is the main program unit for the commandline version. It implements + commandline options (like /b=) and displays help if no options are given. + + What's new + ---------- + 2.0 20030811 Koen Initial documentation +} + +{$APPTYPE CONSOLE} +uses + PatchGenerator in 'PatchGenerator.pas', + VDSP_CRC in 'VDSP_CRC.pas', + Sysutils, + TreeCode in 'TreeCode.pas'; + +type + TEventHandler = class + procedure PrintDebug(S: String); + end; + + procedure TEventhandler.PrintDebug(S: String); + begin + WriteLn(S); + end; + +{$DEFINE READCONFIG} //try to read genpat.ini? +{.$DEFINE AUTOWAIT} //have /wait command line switch on by default? + //useful when debugging + +var + Config: TextFile; + T1,T2: TDateTime; + d: Integer; + S,Key: String; + ShowDebug: Boolean; + PG: TPatchGenerator; + EV: TEventHandler; +begin + EV:=TEventHandler.Create; + PG:=TPatchGenerator.Create; + PG.StartBlockSize:=64; + + WriteLn('GenPat v2.0 final'); + WriteLn('================='); + WriteLn; + WriteLn('(c) 2001-2003 Van de Sande Productions'); + WriteLn('Website: http://www.tibed.net/vpatch'); + WriteLn('E-mail: koen@tibed.net'); + WriteLn; + ShowDebug:=FindCmdLineSwitch('debug',['/'],True); + if ShowDebug then + DebugEvent:=EV.PrintDebug; + +{$IFDEF READCONFIG} + if FileExists('genpat.ini') then begin + AssignFile(Config,'genpat.ini'); + Reset(Config); + while not eof(Config) do begin + ReadLn(Config,S); + d:=Pos('=',S); + if not (d=0) then begin + Key:=LowerCase(Copy(S,1,d-1)); + S:=Copy(S,d+1,Length(S)); + if CompareStr(Key,'startblocksize')=0 then PG.StartBlockSize:=StrToInt(S); + end; + end; + CloseFile(Config); + end; +{$ENDIF} + for d:=1 to ParamCount do begin + if CompareStr(LowerCase(Copy(ParamStr(d),1,3)),'/b=')=0 then begin + PG.StartBlockSize:=StrToInt(Copy(ParamStr(d),4,10)); + end; + end; + + if (CompareStr(ParamStr(1),'')=0) or (CompareStr(ParamStr(2),'')=0) or (CompareStr(ParamStr(3),'')=0) then begin + WriteLn('This program will take (sourcefile) as input and create a (patchfile).'); + WriteLn('With this patchfile, you can convert a (sourcefile) into (targetfile).'); + WriteLn; + WriteLn('Command line info:'); + WriteLn(' GENPAT (sourcefile) (targetfile) (patchfile)'); + WriteLn; + WriteLn('Command line options (you do not need them):'); + WriteLn('/B=(BlockSize) Set blocksize (def=64), multiple of 2'); + WriteLn('/WAIT Wait for a keypress after program complete'); + WriteLn('/DEBUG Show runtime debug information'); + WriteLn('Note: all these parameters must be *after* the filenames!'); + WriteLn; + Write('Press a enter to exit '); + ReadLn(S); + Exit; + end; + + if FileExists(ParamStr(3)) then begin + WriteLn('Using existing file to include patches in: '+ParamStr(3)); + PG.LoadFromFile(ParamStr(3)); + end; + + T1:=Now; + WriteLn('Patch body size: '+IntToStr(PG.CreatePatch(ParamStr(1),ParamStr(2)))); + PG.WriteToFile(ParamStr(3)); + + T2:=Now; + Write('GenPat.exe finished execution in: '); + WriteLn(FloatToStr((T2-T1)*24*60*60),'s'); + WriteLn; +{$IFNDEF AUTOWAIT} + if FindCmdLineSwitch('wait',['/'],True) then begin +{$ENDIF} + WriteLn; + WriteLn('Press a key'); + ReadLn(S); +{$IFNDEF AUTOWAIT} + end; +{$ENDIF} + PG.Free; +end. diff --git a/Contrib/VPatch/Source/GenPat/PatchGenerator.pas b/Contrib/VPatch/Source/GenPat/PatchGenerator.pas new file mode 100644 index 00000000..c4e99ce9 --- /dev/null +++ b/Contrib/VPatch/Source/GenPat/PatchGenerator.pas @@ -0,0 +1,591 @@ +unit PatchGenerator; + +{ + VPatch 2 - Patch Generator + ========================== + + (c) 2002-2003 Van de Sande Productions + + This unit contains the 'core' functionality of VPatch. TPatchGenerator can + load/create/save .PAT files and supports CreatePatch(Old, New) to generate + new patches. The only configurable parameter is StartBlockSize. + Though I cleaned up the code a little bit, there is very little documentation. + That's why I will briefly explain the general workings of the current VPatch + algoritm. + There is a source file, which is divided into blocks of BlockSize. Block 1 + spans bytes 0-15, block 2 16-31, etc if blocksize = 16. For every block, a + checksum is calculated and then the block is inserted into a binary search + tree, which is sorted on this checksum. + Now, the target file (new version) is traversed linearly. For a block at a + certain position, the checksum is calculated. Then, a lookup is performed in + the binary search tree to find all blocks in the source file which match this + checksum. For every occurence, it is checked how many consecutive bytes match + with this block (note: since the checksum is not unique, this can be 0 as well, + but since all occurences are checked, the largest match is selected). Note also + that this match length is not limited to BlockSize but can be larger as well; + everything beyond the block end is checked as well (the block is merely used + as a starting position for checking the match). + For those biggest block matches between source/target files, a copy instruction + will be generated in the patch file. For 'inbetween' or unmatchable blocks, the + data of the new file is placed in the patch file. This involves some + housekeeping, which is what most of the other code does. + + What's new + ---------- + 2.0 20030811 Koen Initial documentation +} + +interface + +uses + Classes, + Sysutils, + TreeCode, + VDSP_CRC; + +type + TStatusNotifyEvent = procedure(S: String; Current, Total, Savings: Integer) of object; + TDebugNotifyEvent = procedure(S: String) of object; + PDataBlock = ^TDataBlock; + TDataBlock = record + SourceOffset: Integer; + TargetOffset: Integer; + Size: Integer; + Next: PDataBlock; + end; + //internal structure for FindBlock + TBlock = record + Offset: Integer; + Size: Integer; + end; + TPatchGenerator = class + private + noPat: Integer; + PRay: Array of TDataBlock; + NRay: Array of TDataBlock; + + FPatchData: TMemoryStream; + FStartBlockSize: Integer; //initial block size + FBlockDivider: Integer; //... block size is divided by this + FMinimumBlockSize: Integer;//until this minimum is reached + FStepSize: Integer; + + //input: ASubBlock, which is a pointer to the start of the block to look + //for in ABlock. The entire ABlock is searched. The function returns the + //offset of the block, when it is found. The ASize parameter contains the + //size of this block + procedure ShowDebug(S: String); + + function FindBlock(ASubBlock, ABlock, ABlockTree: Pointer; + var ASubBlockStart: Integer; ASubBlockSize, ABlockSize, + AMatchSize, ABlockTreeNodeCount: Integer; var ASize: Integer): Integer; + + procedure FindBlockSize(ASubBlock, ABlock: Pointer; ASubBlockSize, + ABlockSize: Integer; var ASubStart, AStart, AFoundSize: Integer); + function WritePatchToStream(Target: Pointer; SourceCRC, + TargetCRC: Integer): Integer; + + procedure RemoveExistingPatch(ACRC: Integer); + public + constructor Create; + destructor Destroy; override; + procedure Clear; + function CreatePatch(SourceFileName, TargetFileName: String): Integer; + property StartBlockSize: Integer read FStartBlockSize write FStartBlockSize; + property BlockDivider: Integer read FBlockDivider write FBlockDivider; + property MinimumBlockSize: Integer read FMinimumBlockSize write FMinimumBlockSize; + property StepSize: Integer read FStepSize write FStepSize; + function Size: Integer; + procedure WriteToFile(AFileName: String); + procedure WriteToStream(AStream: TStream); + procedure LoadFromFile(AFileName: String); + end; + + +const + BUF_BLOCK_SIZE = 4096; + INIT_BLOCK_COUNT=10000; + +var + DebugEvent: TDebugNotifyEvent = nil; + +implementation + +{ TPatchGenerator } + +procedure TPatchGenerator.Clear; +begin + FPatchData.Clear; +end; + +constructor TPatchGenerator.Create; +begin + inherited; + FPatchData:=TMemoryStream.Create; +end; + +function TPatchGenerator.CreatePatch(SourceFileName, + TargetFileName: String): Integer; +var + fsSource, fsTarget: TFileStream; + fm: TMemoryStream; + Source, Target: Pointer; + SourceSize, TargetSize: Integer; + SourceCRC, TargetCRC: Integer; + SourceTree: Pointer; + SourceTreeNodeCount: Cardinal; + cBlockSize: Integer; + + o,i,lastO: Integer; + Start,Siz,BetweenSiz: Integer; + retTO: Integer; + noN: Integer; +begin + fsSource:=TFileStream.Create(SourceFileName,fmOpenRead); + fsTarget:=TFileStream.Create(TargetFileName,fmOpenRead); + fm:=TMemoryStream.Create; + + SetLength(PRay,INIT_BLOCK_COUNT); + SetLength(NRay,INIT_BLOCK_COUNT); + + //Load those files into memory! + SourceSize:=fsSource.Size; + GetMem(Source,SourceSize); + fm.CopyFrom(fsSource,SourceSize); + Move(fm.Memory^,Source^,SourceSize); + SourceCRC:=FileCRC(fsSource); + fsSource.Free; + + fm.Clear; + TargetSize:=fsTarget.Size; + GetMem(Target,TargetSize); + fm.CopyFrom(fsTarget,TargetSize); + Move(fm.Memory^,Target^,TargetSize); + TargetCRC:=FileCRC(fsTarget); + fsTarget.Free; + fm.Free; + + PRay[0].TargetOffset:=0; + PRay[0].SourceOffset:=0; + PRay[0].Size:=0; + noPat:=1; + + //termination block + + PRay[noPat].SourceOffset:=0; + PRay[noPat].TargetOffset:=TargetSize; + PRay[noPat].Size:=0; + + //we only have one pass in this mode +// StartBlockSize:=16; + MinimumBlockSize:=StartBlockSize; + StepSize:=1; + BlockDivider:=2; + + //because we are dividing first inside. + cBlockSize:=StartBlockSize*BlockDivider; + + SourceTree:=nil; + SourceTreeNodeCount:=BuildTree(Source,SourceTree,SourceSize,cBlockSize div BlockDivider); + SortTree(SourceTree,SourceTreeNodeCount); + + //now, we must do the above again - with a smaller block size + repeat + if cBlockSize<=MinimumBlockSize then break; + cBlockSize:=cBlockSize div BlockDivider; + noN:=0; + for i:=1 to noPat do begin + //calculate location of the inbetween parts + Start:=PRay[i-1].TargetOffset+PRay[i-1].Size; + BetweenSiz:=PRay[i].TargetOffset-Start; + + NRay[noN].SourceOffset:=PRay[i-1].SourceOffset; + NRay[noN].TargetOffset:=PRay[i-1].TargetOffset; + NRay[noN].Size:=PRay[i-1].Size; + Inc(noN); + if BetweenSiz>0 then begin + + o:=Start; + repeat + //ShowDebug(PChar('DoFind '+IntToStr(o))); + LastO:=o; + retTO:=FindBlock(Target,Source,SourceTree,o,TargetSize,SourceSize,cBlockSize,SourceTreeNodeCount,Siz); + if not (Siz=0) then + ShowDebug(IntToStr(LastO)+' -> Source='+IntToStr(retTO)+' Target='+IntToStr(o)+' Size='+IntToStr(Siz)); + + if Siz=0 then begin + o:=LastO+StepSize; + end else begin + //we have found a block, let's add it! + NRay[noN].SourceOffset:=retTO; + NRay[noN].TargetOffset:=o; + NRay[noN].Size:=Siz; + Inc(noN); + if noN>=Length(NRay) then begin + SetLength(NRay,Length(NRay)*2); + SetLength(PRay,Length(PRay)*2); + end; + Inc(o,Siz); + end; + + //check to see if we're not inside another one. + Siz:=NRay[noN].TargetOffset-NRay[noN-1].TargetOffset-NRay[noN-1].Size; + If Siz<0 then begin //that's impossible! (overlapping should be eliminated) + NRay[noN].TargetOffset:=NRay[noN].TargetOffset-Siz; + NRay[noN].Size:=NRay[noN].Size+Siz; + NRay[noN].SourceOffset:=NRay[noN].SourceOffset-Siz; + end; + until o>Start+BetweenSiz; + + end; + end; + //I think the last termination block isn't copied: do so now. + NRay[noN].SourceOffset:=PRay[noPat].SourceOffset; + NRay[noN].TargetOffset:=PRay[noPat].TargetOffset; + NRay[noN].Size:=PRay[noPat].Size; + //copy back into PRay + for i:=0 to noN do begin + PRay[i].SourceOffset:=NRay[i].SourceOffset; + PRay[i].TargetOffset:=NRay[i].TargetOffset; + PRay[i].Size:=NRay[i].Size; + end; + noPat:=noN; + until false; + + //writing is next! + ShowDebug('Writing patch'); + + Result:=WritePatchToStream(Target, SourceCRC, TargetCRC); + + ClearTree(SourceTree,SourceTreeNodeCount); + FreeMem(Source,SourceSize); + FreeMem(Target,TargetSize); + ShowDebug('Done'); +end; + +destructor TPatchGenerator.Destroy; +begin + FPatchData.Free; + inherited; +end; + +function TPatchGenerator.FindBlock(ASubBlock, ABlock, ABlockTree: Pointer; var ASubBlockStart: Integer; + ASubBlockSize, ABlockSize, AMatchSize, ABlockTreeNodeCount: Integer; var ASize: Integer): Integer; +//This procedure locates location of a block in the target file +//Then, it calls FindBlockSize to determine size of this block +var + MatchSize, FoundSize: Integer; + q,r,i: Integer; + FoundCache_SubOffset, FoundCache_Size, FoundCache_Offset: Integer; + Checksum: Cardinal; + PFound: PTreeNode; + FoundCount: Integer; +begin + //if we find nothing... + + FoundCache_Size:=0; + FoundCache_Offset:=0; + FoundCache_SubOffset:=ASubBlockStart; + + FindBlock:=0; + ASize:=0; + + MatchSize:=AMatchSize; + + //we can only find MatchSize sized blocks in the tree! + if MatchSize > ASubBlockSize - ASubBlockStart then Exit; + if MatchSize = 0 then Exit; + + Checksum:=0; + calculateChecksum(ASubBlock,ASubBlockStart,MatchSize,Checksum); + PFound:=TreeFind(Checksum,ABlockTree,ABlockTreeNodeCount,FoundCount); + + for i:=0 to Pred(FoundCount) do begin + FoundSize:=MatchSize; + //q = offset in Block + q:=PFound^.Offset; + //r = offset in SubBlock + r:=ASubBlockStart; + FindBlockSize(ASubBlock, ABlock, ASubBlockSize, ABlockSize, r, q, FoundSize); + if FoundSize>FoundCache_Size then begin + FoundCache_SubOffset:=r; + FoundCache_Offset:=q; + FoundCache_Size:=FoundSize; + end; + ShowDebug(' Block Size Start='+IntToStr(r)+' tarStart='+IntToStr(q)+' Size='+IntToStr(FoundSize)); + PFound:=PTreeNode(Integer(PFound)+SizeOf(TTreeNode)); + end; + + FindBlock:=FoundCache_Offset; + ASize:=FoundCache_Size; + ASubBlockStart:=FoundCache_SubOffset; +end; + +procedure TPatchGenerator.FindBlockSize(ASubBlock, ABlock: Pointer; ASubBlockSize, ABlockSize: Integer; var ASubStart,AStart,AFoundSize: Integer); +var + FoundSize: Integer; + a,c,d,i: Integer; + f1p,f2p,f1Size,f2Size: Integer; + beforeSize: Integer; + CurBufSize: Integer; +begin + //OK, now let's go... + //Trace after -> how long does this go on? + f1p:=Integer(ASubBlock)+ASubStart; + f2p:=Integer(ABlock)+AStart; + f1Size:=ASubBlockSize-ASubStart; + f2Size:=ABlockSize-AStart; + FoundSize:=0; + CurBufSize := BUF_BLOCK_SIZE; //size of the block we're checking + while not (CurBufSize = 0) do begin + //we need equal bytes from both... so if one of them EOF, it's the end. + if FoundSize+CurBufSize>f1Size then CurBufSize:=f1Size - FoundSize; + if FoundSize+CurBufSize>f2Size then CurBufSize:=f2Size - FoundSize; + if CompareMem(Pointer(f1p),Pointer(f2p),CurBufSize) then begin + Inc(FoundSize,CurBufSize); + Inc(f1p,CurBufSize); + Inc(f2p,CurBufSize); + end + else begin + CurBufSize:=CurBufSize div 2; + end; + end; + + if FoundSize = 0 then begin AFoundSize:=0; Exit; end; + + //Trace before -> how much bytes are still the same before the block? + //First, read 1 block from source and 1 block from target, start from back to compare how much they differ + //just take BUF_BLOCK_SIZE as maximum size for the block before - that's surely + //big enough! + beforeSize:=BUF_BLOCK_SIZE; + a:=ASubStart-beforeSize; + if a<0 then begin + a:=0; + beforeSize:=ASubStart; + end; + //b is the current before block size + c:=AStart-beforeSize; + if c<0 then begin + c:=0; + beforeSize:=AStart; + a:=ASubStart-beforeSize; + end; + //a=Offset in source + //b=Size of beforeblock + //c=offset in target + + d:=0; + for i:=beforeSize-1 downto 0 do begin + //if not (f1^[a+i]=f2^[c+i]) then begin + if not (PByte(Integer(ASubBlock)+a+i)^=PByte(Integer(ABlock)+c+i)^) then begin + //d=how many bytes before are the same? + Break; + end; + Inc(d); + end; + Inc(FoundSize,d); + Dec(ASubStart,d); + Dec(AStart,d); + AFoundSize:=FoundSize; +end; + +function TPatchGenerator.Size: Integer; +begin + Result:=FPatchData.Size; +end; + +procedure TPatchGenerator.ShowDebug(S: String); +begin + if Assigned(DebugEvent) then DebugEvent(S); +end; + +function TPatchGenerator.WritePatchToStream(Target: Pointer; SourceCRC, TargetCRC: Integer): Integer; +var + HeadID: Array[0..3] of Char; + NoBlocks, NoBlocksOffset, BodySize, BodySizeOffset: Integer; + b: Byte; + w: Word; + i, j: Integer; + l: LongWord; + Start, Siz: Integer; + PTarget: Pointer; +begin + RemoveExistingPatch(SourceCRC); + with FPatchData do begin + Seek(0,soFromEnd); + if Size = 0 then begin + HeadID:='VPAT'; + Write(HeadID,SizeOf(HeadID)); + l:=0; + Write(l,SizeOf(l)); //NoFiles + end; + l:=0; + NoBlocksOffset:=Position; + Write(l,SizeOf(l)); //should become NoBlocks later + Write(SourceCRC,SizeOf(SourceCRC)); //source CRC + Write(TargetCRC,SizeOf(TargetCRC)); //target CRC + BodySizeOffset:=Position; + Write(l,SizeOf(l)); //should become BodySize (of this patch) + + NoBlocks:=0; + BodySize:=0; + //Write the patch... + for i:=0 to noPat - 1 do begin + //write char 1 - integer/copysource + //write char 2 - long/copysource + //write char 5 - integer/insidepatch + //write char 6 - long/insidepatch + + Start:=PRay[i].TargetOffset+PRay[i].Size; + Siz:= PRay[i+1].TargetOffset-Start; + + If Siz<0 then begin //that's impossible! (overlapping should be eliminated) + PRay[i+1].TargetOffset:=PRay[i+1].TargetOffset-Siz; + PRay[i+1].Size:=PRay[i+1].Size+Siz; + PRay[i+1].SourceOffset:=PRay[i+1].SourceOffset-Siz; + Siz:=0; + end; + + if not (PRay[i].Size=0) then begin + if (PRay[i].Size<=255) then begin + b:=1; + Write(b,SizeOf(b)); + b:=PRay[i].Size; + Write(b,SizeOf(b)); + Inc(BodySize,2); + end else if PRay[i].Size<=65535 then begin + b:=2; + Write(b,SizeOf(b)); + w:=PRay[i].Size; + Write(w,SizeOf(w)); + Inc(BodySize,3); + end else begin + b:=3; + Write(b,SizeOf(b)); + Write(PRay[i].Size,SizeOf(Integer)); + Inc(BodySize,5); + end; + Write(PRay[i].SourceOffset,SizeOf(Integer)); + Inc(BodySize,SizeOf(Integer)); + Inc(NoBlocks); + end; + //Now write the writeblock + If Not (Siz = 0) Then begin + if Siz<=255 then begin + b:=5; + Write(b,SizeOf(b)); + b:=Siz; + Write(b,SizeOf(b)); + Inc(BodySize,2); + end else if Siz<=65535 then begin + b:=6; + Write(b,1); + w:=Siz; + Write(w,2); + Inc(BodySize,3); + end else begin + b:=7; + Write(b,1); + Write(Siz,4); + Inc(BodySize,5); + end; + PTarget:=Pointer(Integer(Target)+Start); + j:=Start; + repeat + //read + if (j+4096>Start+Siz) then begin + Write(PTarget^,Start+Siz-j); + break; + end; + Write(PTarget^,4096); + Inc(j,4096); + PTarget:=Pointer(Integer(PTarget)+4096); + until false; + Inc(BodySize,Siz); + Inc(NoBlocks); + end; + end; + Seek(NoBlocksOffset,soFromBeginning); + Write(NoBlocks,SizeOf(NoBlocks)); + Seek(BodySizeOffset,soFromBeginning); + Write(BodySize,SizeOf(BodySize)); + ShowDebug('Patch body size: '+IntToStr(BodySize)); + ShowDebug('Total patch size:'+IntToStr(Size)); + //now increase file count + Seek(4,soFromBeginning); + Read(i,SizeOf(i)); + Inc(i); + Seek(4,soFromBeginning); + Write(i,SizeOf(i)); + Seek(0,soFromEnd); + Result:=BodySize; + end; +end; + +procedure TPatchGenerator.WriteToFile(AFileName: String); +var + fs: TFileStream; +begin + fs:=TFileStream.Create(AFileName,fmCreate); + FPatchData.Seek(0,soFromBeginning); + fs.CopyFrom(FPatchData,FPatchData.Size); + fs.Free; +end; + +procedure TPatchGenerator.LoadFromFile(AFileName: String); +var + fs: TFileStream; +begin + fs:=TFileStream.Create(AFileName,fmOpenRead); + FPatchData.Clear; + FPatchData.CopyFrom(fs,fs.Size); + fs.Free; +end; + +procedure TPatchGenerator.RemoveExistingPatch(ACRC: Integer); +var + HeadID: Array[0..3] of Char; + NoFiles, i, j, SourceCRC, MSize: Integer; + StartPos: Integer; + ms: TMemoryStream; +begin + with FPatchData do begin + if Size = 0 then Exit; + Seek(0,soFromBeginning); + Read(HeadID,SizeOf(HeadID)); + if HeadID = 'VPAT' then begin + Read(NoFiles,SizeOf(NoFiles)); + for i:=0 to Pred(NoFiles) do begin + if Position >= Size then Break; + StartPos:=Position; + Read(j,SizeOf(j)); //NoBlocks + Read(SourceCRC,SizeOf(SourceCRC)); //SourceCRC + Read(j,SizeOf(j)); //TargetCRC + Read(j,SizeOf(j)); //BodySize + Seek(j,soFromCurrent); + if SourceCRC = ACRC then begin + ms:=TMemoryStream.Create; + MSize:=Size-Position; + if MSize > 0 then ms.CopyFrom(FPatchData,MSize); + ms.Seek(0, soFromBeginning); + FPatchData.Seek(StartPos,soFromBeginning); + FPatchData.SetSize(Size - j - SizeOf(Integer) * 4); + FPatchData.CopyFrom(ms,ms.Size); + ms.Free; + Dec(NoFiles); + Seek(4,soFromBeginning); + Write(NoFiles,SizeOf(NoFiles)); + Break; + end; + end; + end; + end; +end; + +procedure TPatchGenerator.WriteToStream(AStream: TStream); +begin + FPatchData.Seek(0,soFromBeginning); + AStream.CopyFrom(FPatchData,FPatchData.Size); +end; + +end. diff --git a/Contrib/VPatch/Source/GenPat/TreeCode.pas b/Contrib/VPatch/Source/GenPat/TreeCode.pas new file mode 100644 index 00000000..3d6c5f62 --- /dev/null +++ b/Contrib/VPatch/Source/GenPat/TreeCode.pas @@ -0,0 +1,245 @@ +unit TreeCode; + +{ + VPatch 2 - Binary Checksum Tree + =============================== + + (c) 2002-2003 Van de Sande Productions + + This unit implements a binary search tree, which is constructed from a memory + block by BuildTree. This memory block is divided into equal-sized blocks of + BlockSize, and for every block a checksum is calculated. Then, it is inserted + in the binary tree, which is sorted on the checksum. + The patch generator will search for the checksums using a binary search, which + is O(log n) (much better than the old 1.x algoritm, which was O(n)). + + What's new + ---------- + 2.0 20030811 Koen Initial documentation +} + +interface + +type + TSortStack=record + lo,hi: Integer; + end; + PTreeNode = ^TTreeNode; + TTreeNode = record + Checksum: Cardinal; + Offset: Cardinal; + end; + +const + TREENODE_SIZE = SizeOf(TTreeNode); + +procedure calculateChecksum(AData: Pointer; AStart, ASize: Cardinal; var K: Cardinal); +procedure calculateNext(AData: Pointer; AStart, ASize: Cardinal; var K: Cardinal); +function BuildTree(ASource: Pointer; var ATree: Pointer; ASourceSize, ABLOCKSIZE: Cardinal): Cardinal; +procedure SortTree(ATree: Pointer; ANodeCount: Cardinal); +procedure ClearTree(var ATree: Pointer; ANodeCount: Cardinal); +function TreeFind(AChecksum: Cardinal; ABlockTree: Pointer; ABlockTreeNodeCount: Integer; var FoundCount: Integer): PTreeNode; +function GetItem(ATree: Pointer; Index, ANodeCount: Cardinal): TTreeNode; + +procedure Test; + +implementation + +uses SysUtils; + +procedure calculateChecksum(AData: Pointer; AStart, ASize: Cardinal; var K: Cardinal); +var + A,B,i,j: Cardinal; +begin + A:=K and $0000FFFF; + B:=(K and $FFFF0000) shr 16; + j:=Cardinal(AData)+AStart; + for i:=1 to ASize do begin + A:=A + PByte(j)^; + B:=B + (ASize-i+1)*PByte(j)^; + Inc(j); + end; + K:=(A and $0000FFFF) or ((B and $0000FFFF) shl 16); +end; + +procedure calculateNext(AData: Pointer; AStart, ASize: Cardinal; var K: Cardinal); +var + A,B,j: Cardinal; +begin + j:=Cardinal(AData)+AStart; + A:=(K-PByte(j-1)^+PByte(j+ASize-1)^) and $0000FFFF; + B:=((K shr 16)-ASize*PByte(j-1)^+A) and $0000FFFF; + K:=A or (B shl 16); +end; + +function BuildTree(ASource: Pointer; var ATree: Pointer; ASourceSize, ABLOCKSIZE: Cardinal): Cardinal; +var + i, NodeCount: Cardinal; + Node: TTreeNode; +begin + Assert(not Assigned(ATree),'Cannot use initialized tree in BuildTree!'); + NodeCount:=ASourceSize div ABLOCKSIZE; + GetMem(ATree,NodeCount*TREENODE_SIZE); + if NodeCount > 0 then begin + for i:=0 to Pred(NodeCount) do begin + Node.Offset:=i*ABLOCKSIZE; + Node.Checksum:=0; + calculateChecksum(ASource,Node.Offset,ABLOCKSIZE,Node.Checksum); + Move(Node,Pointer(Cardinal(ATree)+i*TREENODE_SIZE)^,TREENODE_SIZE); + end; + end; + Result:=NodeCount; +end; + +procedure SetItem(ATree: Pointer; Index, ANodeCount: Cardinal; New: TTreeNode); +var + p: PTreeNode; +begin + Assert(Index compare do begin + j:=j-1; + end; + If (i <= j) Then begin + Move(Pointer(Integer(ATree)+j*TREENODE_SIZE)^,Switcher,TREENODE_SIZE); + Move(Pointer(Integer(ATree)+i*TREENODE_SIZE)^,Pointer(Integer(ATree)+j*TREENODE_SIZE)^,TREENODE_SIZE); + Move(Switcher,Pointer(Integer(ATree)+i*TREENODE_SIZE)^,TREENODE_SIZE); + Inc(i); + Dec(j); + End; + if not (i <= j) then break; + end; + If j - low < hi - i Then begin + If i < hi Then begin + aStack[StackPtr].lo:=i; + aStack[StackPtr].hi:=hi; + Inc(StackPtr); + End; + hi:=j; + end Else begin + If low < j Then begin + aStack[StackPtr].lo:=low; + aStack[StackPtr].hi:=j; + Inc(StackPtr); + End; + low:=i; + End; + if not (low 0 do begin + Dec(m); + if PCardinal(Integer(ABlockTree)+m*TREENODE_SIZE)^ = tmp then begin + Result:=PTreeNode(Integer(ABlockTree)+m*TREENODE_SIZE); + Inc(FoundCount); + end else + Break; + end; + m:=mid; + while m < ABlockTreeNodeCount-1 do begin + Inc(m); + if PCardinal(Integer(ABlockTree)+m*TREENODE_SIZE)^ = tmp then begin + Inc(FoundCount); + end else + Break; + end; + Exit; + end; + if lo>=hi then Break; + if AChecksum < tmp then begin + hi:=mid-1; + end else begin + lo:=mid+1; + end; + end; + FoundCount:=0; Result:=nil; +end; + +procedure Test; +var + p: Pointer; + t: TTreeNode; + r: PTreeNode; + i,q: Integer; + NC: Integer; +begin + NC:=100; + GetMem(p,800); + for i:=0 to 99 do begin + t.Offset:=i*100; + t.Checksum:=i div 2; + SetItem(p,i,NC,t); + end; + SortTree(p,NC); + for i:=0 to 99 do begin + t:=GetItem(p,i,NC); + Write(IntToStr(t.Checksum)+' '); + end; + r:=TreeFind(7,p,NC,q); + WriteLn(IntToStr(q)); + t:=r^; + WriteLn(IntToStr(t.Checksum)+' '); +end; + +end. diff --git a/Contrib/VPatch/Source/GenPat/VAppend.dpr b/Contrib/VPatch/Source/GenPat/VAppend.dpr new file mode 100644 index 00000000..4bed790d --- /dev/null +++ b/Contrib/VPatch/Source/GenPat/VAppend.dpr @@ -0,0 +1,77 @@ +program VAppend; + +{$APPTYPE CONSOLE} + +uses + SysUtils; + +var + fs, fo: File; + Patch: String; + OutFile: String = 'VPATCH.EXE'; + Runtime: String = 'VPATCH.BIN'; + o: LongWord; + Buf: Array[0..4095] of Byte; + Size, BufSize: Integer; + +begin + WriteLn('VAppend v2.0'); + WriteLn('============'); + WriteLn; + WriteLn('(c) 2001-2002 Van de Sande Productions'); + WriteLn('Website: http://www.tibed.net/vpatch'); + WriteLn('E-mail: koen@tibed.net'); + WriteLn; + if ParamCount = 0 then begin + WriteLn('Use this program to append .PAT files to the VPatch runtime.'); + WriteLn; + WriteLn(' VAPPEND (patch file) [output file] [runtime]'); + WriteLn; + WriteLn('By default, the output file is VPATCH.EXE and the runtime is VPATCH.BIN'); + end; + if not FileExists(ParamStr(1)) then begin + WriteLn('ERROR: Patch file not found'); + Exit; + end; + Patch := ParamStr(1); + if ParamCount > 1 then OutFile := ParamStr(2); + if ParamCount > 2 then Runtime := ParamStr(3); + WriteLn('Patch: '+Patch); + WriteLn('Runtime: '+Runtime); + WriteLn('Output: '+OutFile); + + AssignFile(fo,OutFile); + Rewrite(fo,1); + //copy the runtime + AssignFile(fs,Runtime); + FileMode:=fmOpenRead; + Reset(fs,1); + BufSize:=4096; + o:=FileSize(fs); //patch start offset + Size:=FileSize(fs); + while Size>0 do begin + if Size-BufSize<0 then BufSize:=Size; + BlockRead(fs,Buf,BufSize); + BlockWrite(fo,Buf,BufSize); + Dec(Size,BufSize); + end; + CloseFile(fs); + //do the patch + AssignFile(fs,Patch); + FileMode:=fmOpenRead; + Reset(fs,1); + BufSize:=4096; + Size:=FileSize(fs); + while Size>0 do begin + if Size-BufSize<0 then BufSize:=Size; + BlockRead(fs,Buf,BufSize); + BlockWrite(fo,Buf,BufSize); + Dec(Size,BufSize); + end; + CloseFile(fs); + + BlockWrite(fo,o,SizeOf(o)); + CloseFile(fo); + WriteLn('Created.'); +end. + \ No newline at end of file diff --git a/Contrib/VPatch/Source/GenPat/VPatch2.bpg b/Contrib/VPatch/Source/GenPat/VPatch2.bpg new file mode 100644 index 00000000..536fe3d1 --- /dev/null +++ b/Contrib/VPatch/Source/GenPat/VPatch2.bpg @@ -0,0 +1,26 @@ +#------------------------------------------------------------------------------ +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 = GenPat2.exe VAppend.exe VPatchGUI.exe +#------------------------------------------------------------------------------ +default: $(PROJECTS) +#------------------------------------------------------------------------------ + +GenPat2.exe: GenPat2.dpr + $(DCC) + +VAppend.exe: VAppend.dpr + $(DCC) + +VPatchGUI.exe: gui\VPatchGUI.dpr + $(DCC) + + diff --git a/Contrib/VPatch/Source/GenPat/vdsp_crc.pas b/Contrib/VPatch/Source/GenPat/vdsp_crc.pas new file mode 100644 index 00000000..209b7098 --- /dev/null +++ b/Contrib/VPatch/Source/GenPat/vdsp_crc.pas @@ -0,0 +1,115 @@ +unit VDSP_CRC; + +{ + VPatch 2 - CRC + ============== + + (c) 2002-2003 Van de Sande Productions + + This unit can calculate the standard ZIP CRC32 for a filestream. + + What's new + ---------- + 2.0 20030811 Koen Initial documentation +} + +interface + +uses Classes; + +//var +//this is the CRC32 table +// CRCTable: Array[0..255] of LongWord; + {= ( +//this table used to be inside the exe, but now it has been replaced by a calculation routine which saves 1 KB +$0,$77073096,$EE0E612C,$990951BA,$76DC419, +$706AF48F,$E963A535,$9E6495A3,$EDB8832,$79DCB8A4, +$E0D5E91E,$97D2D988,$9B64C2B,$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, +$1DB7106,$98D220BC,$EFD5102A,$71B18589,$6B6B51F, +$9FBFE4A5,$E8B8D433,$7807C9A2,$F00F934,$9609A88E, +$E10E9818,$7F6A0DBB,$86D3D2D,$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, +$3B6E20C,$74B1D29A,$EAD54739,$9DD277AF,$4DB2615, +$73DC1683,$E3630B12,$94643B84,$D6D6A3E,$7A6A5AA8, +$E40ECF0B,$9309FF9D,$A00AE27,$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, +$26D930A,$9C0906A9,$EB0E363F,$72076785,$5005713, +$95BF4A82,$E2B87A14,$7BB12BAE,$CB61B38,$92D28E9B, +$E5D5BE0D,$7CDCEFB7,$BDBDF21,$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} + +function FileCRC(fs: TFileStream): Integer; + +implementation + +function FileCRC(fs: TFileStream): Integer; +const + CRCBlock = 4096; +var + CRCTable: Array[0..255] of LongWord; + c: LongWord; //!!! this must be an unsigned 32-bits var! + Block: Array[0..CRCBlock-1] of Byte; + i,j,bytesread: Integer; +begin + //this used to be the InitCRC procedure + For i:= 0 To 255 do begin + c:= i; + For j:= 0 To 7 do begin + If (c And 1)=0 Then begin + c:= (c div 2); + end Else begin + c:= (c div 2) Xor $EDB88320; + End; + end; + CRCTable[i]:= c; + end; +// InitCRC procedure end; + c:=$FFFFFFFF; + fs.Seek(0,soFromBeginning); + for i:=0 to (fs.Size div CRCBlock)+1 do begin + bytesread:=fs.Read(Block,CRCBlock); + for j:=0 to bytesread-1 do begin + c:=CRCTable[(c and $FF) xor Block[j]] xor (((c and $FFFFFF00) div 256) and $FFFFFF); + end; + end; + FileCRC:=c xor $FFFFFFFF; +end; + +end. diff --git a/Contrib/VPatch/vpatchdll.c b/Contrib/VPatch/Source/Plugin/vpatchdll.c similarity index 99% rename from Contrib/VPatch/vpatchdll.c rename to Contrib/VPatch/Source/Plugin/vpatchdll.c index 79baa84a..064c77ce 100644 --- a/Contrib/VPatch/vpatchdll.c +++ b/Contrib/VPatch/Source/Plugin/vpatchdll.c @@ -1,6 +1,6 @@ #define WIN32_LEAN_AND_MEAN #include -#include "..\ExDLL\exdll.h" +#include "..\..\..\ExDLL\exdll.h" int DoPatch(HANDLE hPatch, HANDLE hSource, HANDLE hDest); void strcopy(char *tgt, const char *src); diff --git a/Contrib/VPatch/vpatchdll.dsp b/Contrib/VPatch/Source/Plugin/vpatchdll.dsp similarity index 98% rename from Contrib/VPatch/vpatchdll.dsp rename to Contrib/VPatch/Source/Plugin/vpatchdll.dsp index 8617263d..8f75f620 100644 --- a/Contrib/VPatch/vpatchdll.dsp +++ b/Contrib/VPatch/Source/Plugin/vpatchdll.dsp @@ -53,7 +53,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /entry:"_DllMainCRTStartup" /dll /machine:I386 /nodefaultlib /out:"..\..\Plugins\VPatch.dll" /opt:nowin98 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /entry:"_DllMainCRTStartup" /dll /machine:I386 /nodefaultlib /out:"..\..\..\..\Plugins\VPatch.dll" /opt:nowin98 # SUBTRACT LINK32 /pdb:none !ELSEIF "$(CFG)" == "vpatchdll - Win32 Debug" diff --git a/Contrib/VPatch/vpatchdll.dsw b/Contrib/VPatch/Source/Plugin/vpatchdll.dsw similarity index 100% rename from Contrib/VPatch/vpatchdll.dsw rename to Contrib/VPatch/Source/Plugin/vpatchdll.dsw