VPatch 2.0 final

git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@2798 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
joostverburg 2003-08-11 16:42:41 +00:00
parent 2449fbc6bd
commit 6dd280b24f
22 changed files with 3566 additions and 14 deletions

Binary file not shown.

View file

@ -141,23 +141,43 @@ file.</p>
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).</p>
<p class="header">Source code</p>
<p class="subheader">NSIS plug-in (C++)</p>
<p class="text">The source of the NSIS plug-in that applies patches can be found in the
Source\Plugin folder.</p>
<p class="subheader">Patch Generator (Delphi)</p>
<p class="text">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.</p>
<p class="subheader">User interface (Delphi)</p>
<p class="text">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 <a href="http://www.delphi-gems.com">VirtualTreeView</a>
component by Mike Lischke.</p>
<p class="header">Version history</p>
<ul>
<li>2.0 beta 2
<ul>
<li>All new algorithm used in the patch generator: much faster (up to
90%) while using smaller block sizes (higher compression)</li>
<li>Created a NSIS 2 plugin</li>
<li>Works with small files</li>
<li>Replaces existing patch in file if original file CRC is identical</li>
</ul></li>
<li>2.0 final
<ul>
<li>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).</li>
</ul>
</li>
<li>2.0 beta 2
<ul>
<li>All new algorithm used in the patch generator: much faster (up to 90%) while using
smaller block sizes (higher compression)</li>
<li>Created a NSIS 2 plugin</li>
<li>Works with small files</li>
<li>Replaces existing patch in file if original file CRC is identical</li>
</ul>
</li>
</ul>
<p class="header">Credits</p>
<p class="text">Written by Koen van de Sande<br />
C plug-in by Edgewize<br />
New documentation and example by Joost Verburg</p>
<p class="header">License</p>
<pre class="margin">Copyright (C) 2001-2002 Koen van de Sande
<pre class="margin">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.
</pre>
</div></td>
</tr>

Binary file not shown.

View file

@ -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.

View file

@ -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.

View file

@ -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

View file

@ -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.

View file

@ -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 (i<Length(FOld))) then begin
FOld[i].FileName:=FileName;
FOld[i].FriendlyName:=ExtractFileName(FileName);
FOld[i].CRC32:=CalcCRC(FileName);
FOld[i].Size:=GetFileSize(FileName);
ResetCache(i);
end;
end;
procedure TPatchFile.Generate;
var
i: Integer;
begin
//generate all of them into the cache?
for i:=0 to OldVersionCount - 1 do
Generate(i);
end;
procedure TPatchFile.Generate(const Index: Integer);
var
Size: Integer;
fm: TMemoryStream;
begin
fm:=TMemoryStream.Create;
Size:=DoGenerate(FOld[Index].FileName,FNew.FileName,fm,ConfigID);
if not (Size=-1) then begin
if (FOld[Index].Cache.Size>Size) 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<Length(FPat)) and (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.

View file

@ -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

View file

@ -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.

View file

@ -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=

View file

@ -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.

Binary file not shown.

View file

@ -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.

View file

@ -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.

View file

@ -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<ANodeCount,'Tree/GetItem: Index too big');
p:=PTreeNode(Cardinal(ATree)+Index*TREENODE_SIZE);
p^:=New;
end;
function GetItem(ATree: Pointer; Index, ANodeCount: Cardinal): TTreeNode;
var
p: PTreeNode;
begin
Assert(Index<ANodeCount,'Tree/GetItem: Index too big '+IntToStr(Index));
p:=PTreeNode(Cardinal(ATree)+Index*TREENODE_SIZE);
Result:=p^;
end;
procedure SortTree(ATree: Pointer; ANodeCount: Cardinal);
var
compare: Cardinal;
aStack: Array[1..128] of TSortStack;
StackPtr: Integer;
Mid,i,j,low,hi: Integer;
Switcher: TTreeNode;
begin
If ANodeCount = 0 Then Exit;
StackPtr:=1;
aStack[StackPtr].lo:=0;
aStack[StackPtr].hi:=ANodeCount - 1;
Inc(StackPtr);
while not (StackPtr=1) do begin
StackPtr:=StackPtr-1;
low:=aStack[StackPtr].lo;
hi:=aStack[StackPtr].hi;
while true do begin
i:=low;
j:=hi;
Mid:=(low + hi) div 2;
compare:=PTreeNode(Integer(ATree)+Mid*TREENODE_SIZE)^.Checksum;
while true do begin
While PTreeNode(Integer(ATree)+i*TREENODE_SIZE)^.Checksum < compare do begin
Inc(i);
end;
While PTreeNode(Integer(ATree)+j*TREENODE_SIZE)^.Checksum > 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<hi) then break;
end;
if StackPtr=1 then break;
end;
end;
procedure ClearTree(var ATree: Pointer; ANodeCount: Cardinal);
begin
FreeMem(ATree,ANodeCount*TREENODE_SIZE);
ATree:=nil;
end;
function TreeFind(AChecksum: Cardinal; ABlockTree: Pointer; ABlockTreeNodeCount: Integer; var FoundCount: Integer): PTreeNode;
var
lo,mid,hi,m: Integer;
tmp: Cardinal;
begin
lo:=0;
hi:=ABlockTreeNodeCount-1;
while true do begin
mid:=(lo+hi) div 2;
tmp:=PCardinal(Integer(ABlockTree)+mid*TREENODE_SIZE)^;
if tmp = AChecksum then begin
FoundCount:=1;
m:=mid;
Result:=PTreeNode(Integer(ABlockTree)+m*TREENODE_SIZE);
while m > 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.

View file

@ -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.

View file

@ -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)

View file

@ -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.

View file

@ -1,6 +1,6 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "..\ExDLL\exdll.h"
#include "..\..\..\ExDLL\exdll.h"
int DoPatch(HANDLE hPatch, HANDLE hSource, HANDLE hDest);
void strcopy(char *tgt, const char *src);

View file

@ -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"