VPatch 3.0
git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@4271 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
parent
9929eb7120
commit
4bf6509225
53 changed files with 3918 additions and 1782 deletions
Binary file not shown.
|
@ -2,7 +2,7 @@
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
<head>
|
<head>
|
||||||
<title>VPatch 2</title>
|
<title>VPatch 3</title>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
|
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
/*<![CDATA[*/
|
/*<![CDATA[*/
|
||||||
|
@ -97,12 +97,13 @@ a:hover
|
||||||
<table width="750" class="maintable" cellspacing="0" cellpadding="0" align="center">
|
<table width="750" class="maintable" cellspacing="0" cellpadding="0" align="center">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<h1>VPatch 2</h1>
|
|
||||||
|
<h1>VPatch 3.0</h1>
|
||||||
<div>
|
<div>
|
||||||
<h2>Introduction</h2>
|
<h2>Introduction</h2>
|
||||||
<div>
|
<div>
|
||||||
<p>VPatch allows to create a patch file to update previous versions
|
<p>VPatch allows to create a patch file to update previous versions
|
||||||
of your software. The GenPat utility generates the patch file. The
|
of your software. The GenPat utitily generates the patch file. The
|
||||||
plug-in can use the patch to update a file. Using a patch, you can
|
plug-in can use the patch to update a file. Using a patch, you can
|
||||||
reduce the download size of your updates, because only the differences
|
reduce the download size of your updates, because only the differences
|
||||||
between the files are included in the patch file.</p>
|
between the files are included in the patch file.</p>
|
||||||
|
@ -116,35 +117,41 @@ a:hover
|
||||||
system) and DATA_20.DTA (version 2.0 of this data file). Now call
|
system) and DATA_20.DTA (version 2.0 of this data file). Now call
|
||||||
the command line tool GenPat.exe:</p>
|
the command line tool GenPat.exe:</p>
|
||||||
<pre>
|
<pre>
|
||||||
GENPAT data.dta data_20.dta data.pat
|
GENPAT oldfile.txt newfile.txt patch.pat
|
||||||
</pre>
|
</pre>
|
||||||
<p>Now, the patch will be generated, this will take some time.</p>
|
<p>Now, the patch will be generated, this will take some time.</p>
|
||||||
<p>Using the /B=(BlockSize) parameter of the GenPat utility (put it
|
<p>Using the /B=(BlockSize) parameter of the GenPat utility (put it
|
||||||
after the filenames), you can use a different block size. A smaller
|
after the filenames), you can use a different block size. A smaller
|
||||||
block size may result in a smaller patch, but the generation will
|
block size may result in a smaller patch, but the generation will
|
||||||
take more time (the default blocksize is 64).</p>
|
take more time (the default blocksize is 64).</p>
|
||||||
|
<p>If you have trouble using this command-line utility, you can download
|
||||||
|
a GUI (graphical user interface) for VPatch from its own website:
|
||||||
|
<a href="http://www.tibed.net/vpatch">http://www.tibed.net/vpatch</a>.</p>
|
||||||
</div>
|
</div>
|
||||||
<h3>Update the file during installation</h3>
|
<h3>Update the file during installation</h3>
|
||||||
<div>
|
<div>
|
||||||
<p>Use the VPatch plug-in to update a file using a patch file:</p>
|
<p>Use the VPatch plug-in to update a file using a patch file:</p>
|
||||||
<pre>
|
<pre>
|
||||||
vpatch::vpatchfile "pathfile.pat" "source.file" "new.file"
|
vpatch::vpatchfile "patch.pat" "oldfile.txt" "temporary_newfile.txt"
|
||||||
</pre>
|
</pre>
|
||||||
<p>The result of the patch operating will be added to the stack and
|
<p>The result of the patch operating will be added to the stack and
|
||||||
can be one of the following texts:</p>
|
can be one of the following texts:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>OK</li>
|
<li>OK</li>
|
||||||
<li>OK, new version already installed</li>
|
<li>OK, new version already installed</li>
|
||||||
<li>An error occurred while patching</li>
|
<li>An error occured while patching</li>
|
||||||
<li>Patch data is invalid or corrupt</li>
|
<li>Patch data is invalid or corrupt</li>
|
||||||
<li>No suitable patches were found</li>
|
<li>No suitable patches were found</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Check <a href="../../Examples/VPatch/example.nsi">example.nsi</a> for an example.</p>
|
<p>Check <a href="example.nsi">example.nsi</a> for an example. You
|
||||||
|
should check whether the stack string starts with "OK"
|
||||||
|
because then the patch has succeeded and you can rename "temporary_newfile.txt"
|
||||||
|
to "oldfile.txt" to replace the original, if you want.</p>
|
||||||
</div>
|
</div>
|
||||||
<h3>Multiple patches in one file</h3>
|
<h3>Multiple patches in one file</h3>
|
||||||
<div>
|
<div>
|
||||||
<p>GenPat appends a patch to the file you specified. If there is already
|
<p>GenPat appends a patch to the file you specified. If there is already
|
||||||
a patch for the same original file in the patch file, the patch will
|
a patch for the same orginal file in the patch file, the patch will
|
||||||
be replaced. For example, if you want to be able to upgrade version
|
be replaced. For example, if you want to be able to upgrade version
|
||||||
1 and 2 to version 3, you can put a 1 > 3 and 2 > 3 patch in
|
1 and 2 to version 3, you can put a 1 > 3 and 2 > 3 patch in
|
||||||
one file.</p>
|
one file.</p>
|
||||||
|
@ -154,76 +161,55 @@ vpatch::vpatchfile "pathfile.pat" "source.file" "new.file"
|
||||||
times with the same patch file. It will automatically select the right
|
times with the same patch file. It will automatically select the right
|
||||||
patch (based on the file CRC).</p>
|
patch (based on the file CRC).</p>
|
||||||
</div>
|
</div>
|
||||||
<h3>GenPat exit codes</h3>
|
<h3>Patch generator (GenPat) exit codes</h3>
|
||||||
<div>
|
<div>
|
||||||
<p>In version 2.1 support was added for exit codes (known as error levels
|
<p>In version 3 the following exit codes (known as error levels in
|
||||||
in the DOS period) to GenPat. GenPat will return an exit code based
|
the DOS period) can be returned by GenPat. GenPat will return an
|
||||||
on success of the patch generation. Here is a list of the possible
|
exit code based on succes of the patch generation. Here is a list
|
||||||
exit codes:</p>
|
of the possible exit codes:</p>
|
||||||
<table width="547" border="0" cellspacing="0" cellpadding="0">
|
<table width="547" border="0" cellspacing="0" cellpadding="0">
|
||||||
<tr>
|
<tr>
|
||||||
<td><b>Exit code</b></td>
|
<td><b>Exit code</b></td>
|
||||||
<td><b>Description</b></td>
|
<td><b>Description</b></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>0</td>
|
<td>0</td>
|
||||||
<td>Success</td>
|
<td>Success</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>1</td>
|
<td>1</td>
|
||||||
<td>Arguments missing</td>
|
<td>Arguments missing</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>2</td>
|
<td>2</td>
|
||||||
<td>Source file not found</td>
|
<td>Other error</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>3</td>
|
<td>3</td>
|
||||||
<td>Target file not found</td>
|
<td>Source file already has a patch in specified patch file (ERROR),
|
||||||
</tr>
|
use /R switch to override</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td>4</td>
|
</table>
|
||||||
<td>Unknown error while reading existing patch file</td>
|
<p>These exit codes can be useful when you generate patch files through
|
||||||
</tr>
|
a NSIS script.</p>
|
||||||
<tr>
|
|
||||||
<td>5</td>
|
|
||||||
<td>Unknown error while generating patch</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>6</td>
|
|
||||||
<td>Unknown error while writing patch file to disk</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>10</td>
|
|
||||||
<td>CRC of source and target file are equal</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>11</td>
|
|
||||||
<td>Not enough memory for source file</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>12</td>
|
|
||||||
<td>Not enough memory for target file</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>These exit codes can be useful when you generate patch files through
|
|
||||||
a script.</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h2>Source code</h2>
|
<h2>Source code</h2>
|
||||||
<div>
|
<div>
|
||||||
|
<p>Source code is available in the original package and in the CVS repository of NSIS.</p>
|
||||||
<h3>NSIS plug-in (C++)</h3>
|
<h3>NSIS plug-in (C++)</h3>
|
||||||
<div>
|
<div>
|
||||||
<p>The source of the NSIS plug-in that applies patches can be found
|
<p>The source of the NSIS plug-in that applies patches can be found
|
||||||
in the Source\Plugin folder.</p>
|
in the Source\Plugin folder.</p>
|
||||||
</div>
|
</div>
|
||||||
<h3>Patch Generator (Delphi)</h3>
|
<h3>Patch Generator (C++)</h3>
|
||||||
<div>
|
<div>
|
||||||
<p>The most interesting part of VPatch, the actual patch generation
|
<p>The most interesting part of VPatch, the actual patch generation
|
||||||
algorithm, can be found in Source\GenPat\PatchGenerator.pas. The header
|
algoritm, can be found in Source\GenPat\PatchGenerator.cpp. The
|
||||||
of that file contains a brief explanation of the algorithm as well.</p>
|
header of that file contains a brief explanation of the algorithm
|
||||||
|
as well.</p>
|
||||||
</div>
|
</div>
|
||||||
<h3>User interface (Delphi)</h3>
|
<h3>User interface (Delphi)</h3>
|
||||||
<div>
|
<div>
|
||||||
|
@ -233,10 +219,54 @@ vpatch::vpatchfile "pathfile.pat" "source.file" "new.file"
|
||||||
edition), you will also need to install the <a href=
|
edition), you will also need to install the <a href=
|
||||||
"http://www.delphi-gems.com">VirtualTreeView</a> component by Mike Lischke.</p>
|
"http://www.delphi-gems.com">VirtualTreeView</a> component by Mike Lischke.</p>
|
||||||
</div>
|
</div>
|
||||||
|
<h3>Test framework (Python)</h3>
|
||||||
|
<div>
|
||||||
|
<p>Run the <i>VPatch_tests.py</i> script (if you have <a href="http://www.python.org">Python</a>
|
||||||
|
installed) to perform basic functionality tests on VPatch.</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h2>Version history</h2>
|
<h2>Version history</h2>
|
||||||
<div>
|
<div>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li>3.0
|
||||||
|
<ul>
|
||||||
|
<li><b>Final</b>: Updates to the GUI, installer</li>
|
||||||
|
<li><b>RC8</b>: GenPat will now flag replacement of a patch (e.g.
|
||||||
|
the source file has the same contents as a previous patch inside
|
||||||
|
a patch file) as an error. You can specifically allow it using
|
||||||
|
the /R switch. Added license to source files.</li>
|
||||||
|
<li><b>RC7</b>: Fixed critical bug in GenPat with multiple patches
|
||||||
|
in a single file. Fixed serious bug in stand-alone EXE runtime:
|
||||||
|
process kept on running forever. Included case testing through
|
||||||
|
a Python script to test common usage (and prevent bugs like
|
||||||
|
the one in GenPat in the future).</li>
|
||||||
|
<li><b>RC6</b>: Upgraded to non-beta compiler. Added /A switch
|
||||||
|
to change block match limit and /O to deactivate the limit.
|
||||||
|
Updated GUI to support the /O switch.</li>
|
||||||
|
<li><b>RC4a to RC5a</b>: input block size is now checked for power
|
||||||
|
of 2 and fixed if incorrect. When patch file does not yet exist,
|
||||||
|
no longer forgets to create the header. No longer tries to allocate
|
||||||
|
memory when there are no chunks. Fixed memory leaks.</li>
|
||||||
|
<li>Target file date is now preserved inside a patch and restored
|
||||||
|
on the user system.</li>
|
||||||
|
<li>MD5 checksums are now used instead of CRC32 checksums, unless
|
||||||
|
existing patches in a file already are in CRC32 mode.</li>
|
||||||
|
<li>The patch generator, GenPat, has been completely rewritten
|
||||||
|
in C++. It no longer needs to keep the entire files in memory,
|
||||||
|
instead memory usage is a certain percentage of the source file
|
||||||
|
size. The percentage is based on the block size, larger block
|
||||||
|
sizes will reduce memory usage.</li>
|
||||||
|
<li>All runtimes now share a common codebase, perform proper error
|
||||||
|
checking and don't leave behind files if the input file was
|
||||||
|
already up to date.</li>
|
||||||
|
<li>Bug Fix: The patch generator algorithm no longer reduces to
|
||||||
|
a quadratic runtime if there are many blocks with the same content
|
||||||
|
in the files to patch.</li>
|
||||||
|
<li>Bug Fix: The documentation of the command-line utilities was
|
||||||
|
incorrect and no warnings would be given by the runtimes, causing
|
||||||
|
the patch not to work (this does not apply to NSIS patches).</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
<li>2.1
|
<li>2.1
|
||||||
<ul>
|
<ul>
|
||||||
<li>Added argument checking and error handling to GenPat. Now
|
<li>Added argument checking and error handling to GenPat. Now
|
||||||
|
@ -269,13 +299,13 @@ vpatch::vpatchfile "pathfile.pat" "source.file" "new.file"
|
||||||
<h2>Credits</h2>
|
<h2>Credits</h2>
|
||||||
<div>
|
<div>
|
||||||
<p>Written by Koen van de Sande<br />
|
<p>Written by Koen van de Sande<br />
|
||||||
C plug-in by Edgewize<br />
|
C plug-in initially by Edgewize, updated by Koen van de Sande<br />
|
||||||
New documentation and example by Joost Verburg</p>
|
New documentation and example by Joost Verburg and Koen van de Sande</p>
|
||||||
</div>
|
</div>
|
||||||
<h2>License</h2>
|
<h2>License</h2>
|
||||||
<div>
|
<div>
|
||||||
<pre>
|
<pre>
|
||||||
Copyright (C) 2001-2003 Koen van de Sande
|
Copyright (C) 2001-2005 Koen van de Sande / Van de Sande Productions
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied
|
This software is provided 'as-is', without any express or implied
|
||||||
warranty. In no event will the authors be held liable for any damages
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
|
22
Contrib/VPatch/SConscript
Normal file
22
Contrib/VPatch/SConscript
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
target = 'VPatch'
|
||||||
|
|
||||||
|
examples = Split("""
|
||||||
|
example.nsi
|
||||||
|
newfile.txt
|
||||||
|
oldfile.txt
|
||||||
|
patch.pat
|
||||||
|
""")
|
||||||
|
|
||||||
|
docs = Split("""
|
||||||
|
Readme.html
|
||||||
|
""")
|
||||||
|
|
||||||
|
includes = Split("""
|
||||||
|
VPatchLib.nsh
|
||||||
|
""")
|
||||||
|
|
||||||
|
Import('defenv')
|
||||||
|
|
||||||
|
defenv.DistributeExamples(target, examples)
|
||||||
|
defenv.DistributeDocs(target, docs)
|
||||||
|
defenv.Distribute('Include', includes)
|
Binary file not shown.
|
@ -6,48 +6,46 @@ uses Classes, SysUtils;
|
||||||
|
|
||||||
function DoGenerate(const Source, Target: String; Stream: TStream; Config: String): Integer; forward;
|
function DoGenerate(const Source, Target: String; Stream: TStream; Config: String): Integer; forward;
|
||||||
|
|
||||||
|
var
|
||||||
|
WaitAfterGenerate: Boolean = False;
|
||||||
|
OptimalPatches: Boolean = False;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses PatchGenerator;
|
uses
|
||||||
|
OSUtil, Forms;
|
||||||
|
|
||||||
function DoGenerate(const Source, Target: String; Stream: TStream; Config: String): Integer;
|
function DoGenerate(const Source, Target: String; Stream: TStream; Config: String): Integer;
|
||||||
var
|
var
|
||||||
PG: TPatchGenerator;
|
F: TextFile;
|
||||||
a: Integer;
|
Temp, BatchFile: String;
|
||||||
|
fs: TFileStream;
|
||||||
begin
|
begin
|
||||||
WriteLn('Generating '+ExtractFileName(Source)+' to '+ExtractFileName(Target)+'...');
|
BatchFile:=ExcludeTrailingPathDelimiter(ExtractFilePath(Application.ExeName)) + PathDelim +'~generate_patch.bat';
|
||||||
|
AssignFile(F,BatchFile);
|
||||||
PG:=TPatchGenerator.Create;
|
Rewrite(F);
|
||||||
PG.StartBlockSize:=512;
|
Temp:=GetTempFile;
|
||||||
PG.MinimumBlockSize:=512;
|
WriteLn(F,'@cls');
|
||||||
PG.BlockDivider:=2;
|
WriteLn(F,'@echo Generating '+ExtractFileName(Source)+' to '+ExtractFileName(Target)+'...');
|
||||||
PG.StepSize:=256;
|
Write(F,'genpat.exe "', Source, '" "', Target, '" "', Temp, '" /b='+Config);
|
||||||
try
|
if OptimalPatches then begin
|
||||||
a:=Pos(',',Config);
|
Write(F,' /o');
|
||||||
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;
|
end;
|
||||||
|
WriteLn(F,'');
|
||||||
|
if WaitAfterGenerate then begin
|
||||||
|
WriteLn(F,'@echo.');
|
||||||
|
WriteLn(F,'@pause');
|
||||||
|
end;
|
||||||
|
CloseFile(F);
|
||||||
|
|
||||||
Result:=PG.CreatePatch(Source,Target);
|
ExecWaitBatchFile(ExtractFilePath(BatchFile),BatchFile);
|
||||||
PG.WriteToStream(Stream);
|
|
||||||
PG.Free;
|
fs:=TFileStream.Create(Temp,fmOpenRead);
|
||||||
WriteLn(ExtractFileName(Source)+' -> '+ExtractFileName(Target)+': '+IntToStr(Result)+' bytes');
|
Stream.CopyFrom(fs,fs.Size);
|
||||||
|
Result:=fs.Size;
|
||||||
|
fs.Free;
|
||||||
|
DeleteFile(Temp);
|
||||||
|
DeleteFile(BatchFile);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
|
@ -4,7 +4,7 @@ object frmMain: TfrmMain
|
||||||
BorderIcons = [biSystemMenu, biMinimize]
|
BorderIcons = [biSystemMenu, biMinimize]
|
||||||
BorderStyle = bsSingle
|
BorderStyle = bsSingle
|
||||||
Caption = 'VG - VPatch GUI'
|
Caption = 'VG - VPatch GUI'
|
||||||
ClientHeight = 361
|
ClientHeight = 385
|
||||||
ClientWidth = 689
|
ClientWidth = 689
|
||||||
Color = clBtnFace
|
Color = clBtnFace
|
||||||
Font.Charset = DEFAULT_CHARSET
|
Font.Charset = DEFAULT_CHARSET
|
||||||
|
@ -12,6 +12,121 @@ object frmMain: TfrmMain
|
||||||
Font.Height = -11
|
Font.Height = -11
|
||||||
Font.Name = 'MS Sans Serif'
|
Font.Name = 'MS Sans Serif'
|
||||||
Font.Style = []
|
Font.Style = []
|
||||||
|
Icon.Data = {
|
||||||
|
000001000200101000000100080068050000260000002020000001000800A808
|
||||||
|
00008E0500002800000010000000200000000100080000000000000100000000
|
||||||
|
0000000000000001000000010000000000000000800000800000008080008000
|
||||||
|
00008000800080800000C0C0C000C0DCC000F0CAA60000003E0000005D000000
|
||||||
|
7C0000009B000000BA000000D9000000F0002424FF004848FF006C6CFF009090
|
||||||
|
FF00B4B4FF0000143E00001E5D0000287C0000329B00003CBA000046D9000055
|
||||||
|
F000246DFF004885FF006C9DFF0090B5FF00B4CDFF00002A3E00003F5D000054
|
||||||
|
7C0000699B00007EBA000093D90000AAF00024B6FF0048C2FF006CCEFF0090DA
|
||||||
|
FF00B4E6FF00003E3E00005D5D00007C7C00009B9B0000BABA0000D9D90000F0
|
||||||
|
F00024FFFF0048FFFF006CFFFF0090FFFF00B4FFFF00003E2A00005D3F00007C
|
||||||
|
5400009B690000BA7E0000D9930000F0AA0024FFB60048FFC2006CFFCE0090FF
|
||||||
|
DA00B4FFE600003E1400005D1E00007C2800009B320000BA3C0000D9460000F0
|
||||||
|
550024FF6D0048FF85006CFF9D0090FFB500B4FFCD00003E0000005D0000007C
|
||||||
|
0000009B000000BA000000D9000000F0000024FF240048FF48006CFF6C0090FF
|
||||||
|
9000B4FFB400143E00001E5D0000287C0000329B00003CBA000046D9000055F0
|
||||||
|
00006DFF240085FF48009DFF6C00B5FF9000CDFFB4002A3E00003F5D0000547C
|
||||||
|
0000699B00007EBA000093D90000AAF00000B6FF2400C2FF4800CEFF6C00DAFF
|
||||||
|
9000E6FFB4003E3E00005D5D00007C7C00009B9B0000BABA0000D9D90000F0F0
|
||||||
|
0000FFFF2400FFFF4800FFFF6C00FFFF9000FFFFB4003E2A00005D3F00007C54
|
||||||
|
00009B690000BA7E0000D9930000F0AA0000FFB62400FFC24800FFCE6C00FFDA
|
||||||
|
9000FFE6B4003E1400005D1E00007C2800009B320000BA3C0000D9460000F055
|
||||||
|
0000FF6D2400FF854800FF9D6C00FFB59000FFCDB4003E0000005D0000007C00
|
||||||
|
00009B000000BA000000D9000000F0000000FF242400FF484800FF6C6C00FF90
|
||||||
|
9000FFB4B4003E0014005D001E007C0028009B003200BA003C00D9004600F000
|
||||||
|
5500FF246D00FF488500FF6C9D00FF90B500FFB4CD003E002A005D003F007C00
|
||||||
|
54009B006900BA007E00D9009300F000AA00FF24B600FF48C200FF6CCE00FF90
|
||||||
|
DA00FFB4E6003E003E005D005D007C007C009B009B00BA00BA00D900D900F000
|
||||||
|
F000FF24FF00FF48FF00FF6CFF00FF90FF00FFB4FF002A003E003F005D005400
|
||||||
|
7C0069009B007E00BA009300D900AA00F000B624FF00C248FF00CE6CFF00DA90
|
||||||
|
FF00E6B4FF0014003E001E005D0028007C0032009B003C00BA004600D9005500
|
||||||
|
F0006D24FF008548FF009D6CFF00B590FF00CDB4FF0006060600121212001F1F
|
||||||
|
1F002C2C2C003939390045454500525252005F5F5F006C6C6C00787878008585
|
||||||
|
8500929292009F9F9F00ABABAB00B8B8B800C5C5C500D2D2D200DEDEDE00EBEB
|
||||||
|
EB00F8F8F800F0FBFF00A4A0A000808080000000FF0000FF000000FFFF00FF00
|
||||||
|
0000FF00FF00FFFF0000FFFFFF00000000000000000000000000000000000000
|
||||||
|
EAE7858586868796ECEBEA00000000919185858686868787888B8DF8000000E9
|
||||||
|
99858586868687878B8B8C8A000000F8FF968686878787878D8B8B97000000EB
|
||||||
|
F4F48B8A888887879809870000000000EFFF8B8A8888878A9796850000000000
|
||||||
|
EDF48D8B8A8A8A09099800000000000000F7F4EFF2F2F2F20700000000000000
|
||||||
|
00EDF3F0F0F0079800000000000000000000EBF307F0F7970000000000000000
|
||||||
|
0000EAF5FFF4F78600000000000000000000F8F4FFF4F7960000000000000000
|
||||||
|
0000EAF3F4F379F80000000000000000008D868585858585EA00000000000000
|
||||||
|
009996EF07F19896980000000000FFFF0000C007000080030000800300008003
|
||||||
|
000080070000C0070000C00F0000E01F0000E03F0000F03F0000F03F0000F03F
|
||||||
|
0000F03F0000E01F0000E01F0000280000002000000040000000010008000000
|
||||||
|
0000000400000000000000000000000100000001000000000000000080000080
|
||||||
|
000000808000800000008000800080800000C0C0C000C0DCC000F0CAA6000000
|
||||||
|
3E0000005D0000007C0000009B000000BA000000D9000000F0002424FF004848
|
||||||
|
FF006C6CFF009090FF00B4B4FF0000143E00001E5D0000287C0000329B00003C
|
||||||
|
BA000046D9000055F000246DFF004885FF006C9DFF0090B5FF00B4CDFF00002A
|
||||||
|
3E00003F5D0000547C0000699B00007EBA000093D90000AAF00024B6FF0048C2
|
||||||
|
FF006CCEFF0090DAFF00B4E6FF00003E3E00005D5D00007C7C00009B9B0000BA
|
||||||
|
BA0000D9D90000F0F00024FFFF0048FFFF006CFFFF0090FFFF00B4FFFF00003E
|
||||||
|
2A00005D3F00007C5400009B690000BA7E0000D9930000F0AA0024FFB60048FF
|
||||||
|
C2006CFFCE0090FFDA00B4FFE600003E1400005D1E00007C2800009B320000BA
|
||||||
|
3C0000D9460000F0550024FF6D0048FF85006CFF9D0090FFB500B4FFCD00003E
|
||||||
|
0000005D0000007C0000009B000000BA000000D9000000F0000024FF240048FF
|
||||||
|
48006CFF6C0090FF9000B4FFB400143E00001E5D0000287C0000329B00003CBA
|
||||||
|
000046D9000055F000006DFF240085FF48009DFF6C00B5FF9000CDFFB4002A3E
|
||||||
|
00003F5D0000547C0000699B00007EBA000093D90000AAF00000B6FF2400C2FF
|
||||||
|
4800CEFF6C00DAFF9000E6FFB4003E3E00005D5D00007C7C00009B9B0000BABA
|
||||||
|
0000D9D90000F0F00000FFFF2400FFFF4800FFFF6C00FFFF9000FFFFB4003E2A
|
||||||
|
00005D3F00007C5400009B690000BA7E0000D9930000F0AA0000FFB62400FFC2
|
||||||
|
4800FFCE6C00FFDA9000FFE6B4003E1400005D1E00007C2800009B320000BA3C
|
||||||
|
0000D9460000F0550000FF6D2400FF854800FF9D6C00FFB59000FFCDB4003E00
|
||||||
|
00005D0000007C0000009B000000BA000000D9000000F0000000FF242400FF48
|
||||||
|
4800FF6C6C00FF909000FFB4B4003E0014005D001E007C0028009B003200BA00
|
||||||
|
3C00D9004600F0005500FF246D00FF488500FF6C9D00FF90B500FFB4CD003E00
|
||||||
|
2A005D003F007C0054009B006900BA007E00D9009300F000AA00FF24B600FF48
|
||||||
|
C200FF6CCE00FF90DA00FFB4E6003E003E005D005D007C007C009B009B00BA00
|
||||||
|
BA00D900D900F000F000FF24FF00FF48FF00FF6CFF00FF90FF00FFB4FF002A00
|
||||||
|
3E003F005D0054007C0069009B007E00BA009300D900AA00F000B624FF00C248
|
||||||
|
FF00CE6CFF00DA90FF00E6B4FF0014003E001E005D0028007C0032009B003C00
|
||||||
|
BA004600D9005500F0006D24FF008548FF009D6CFF00B590FF00CDB4FF000606
|
||||||
|
0600121212001F1F1F002C2C2C003939390045454500525252005F5F5F006C6C
|
||||||
|
6C007878780085858500929292009F9F9F00ABABAB00B8B8B800C5C5C500D2D2
|
||||||
|
D200DEDEDE00EBEBEB00F8F8F800F0FBFF00A4A0A000808080000000FF0000FF
|
||||||
|
000000FFFF00FF000000FF00FF00FFFF0000FFFFFF0000000000000000000000
|
||||||
|
00000000000000000000000000000000000000000000000000000000000000ED
|
||||||
|
EBEBEAEAEAEAEAEAEAEBF8ED000000000000000000000000000000ECE9E7E791
|
||||||
|
85858586868686868585E7E7E8EAEBED000000000000000000EAE79191918585
|
||||||
|
8686868687878788898A8B8C98A3E8E8EA00000000000000E791919185858585
|
||||||
|
8586868686868787878787898C8DF409E9E90000000000E99191918585858585
|
||||||
|
8686868686868787878788888A8B8BF5F484EB00000000919191989785858585
|
||||||
|
868686868687878787878A8B8C8B898A8A8AEA00000000919109FFF485858585
|
||||||
|
868686868687878787878B8C88F5FF8D8A8AF800000000EA91F3FFFF97858585
|
||||||
|
868686868687878787888AFF888DF58B8C96EF00000000009198FFFF99858586
|
||||||
|
868787878787878787878C8D88F58B898AEA000000000000EA85F4FFFF098B8B
|
||||||
|
8A898888888887878786F58A8A8D898A85F0000000000000009109FFFF8D8B8B
|
||||||
|
8A89888888888787878AF4868D968686EB0000000000000000F8A4F5FFF58B8B
|
||||||
|
8A8988888888878787090996F38585E700000000000000000000918DFFFF8C8B
|
||||||
|
8A89888888888787878D86098686EAED00000000000000000000F8EDF4FFF48B
|
||||||
|
8A89888888888787878D8AF3EFF7EC00000000000000000000000091F1FFFFF0
|
||||||
|
0709098B8B98090909F1F307F0EB00000000000000000000000000F8EBF4FFF2
|
||||||
|
F707F2F2F2F2F2F20807F3F0EDEB00000000000000000000000000009107FFF5
|
||||||
|
EEF0F1F2F2F2F2F109F107EFE9000000000000000000000000000000F7EAF3FF
|
||||||
|
F0F707F1F1F1F109F009EFEAEC0000000000000000000000000000000091F7F5
|
||||||
|
F3EDF7EFEFEFEF8B989886E80000000000000000000000000000000000F7E909
|
||||||
|
FFED79797979798B979791ED00000000000000000000000000000000000091F8
|
||||||
|
FFF2FFFFFFF379979785E900000000000000000000000000000000000000EA85
|
||||||
|
FFFFFFFFFFF379979791EB00000000000000000000000000000000000000EAEA
|
||||||
|
FFF4FFFFFFF379979791ED00000000000000000000000000000000000000EDEA
|
||||||
|
FFF3FFFFFFF379979791EE00000000000000000000000000000000000000ED85
|
||||||
|
FFF3FFFFFFF379979785EF00000000000000000000000000000000000000ED85
|
||||||
|
F3F3FFFFFFF379979785F700000000000000000000000000000000000000EC85
|
||||||
|
F3F2F3F3F20906797985EB00000000000000000000000000000000000000EB85
|
||||||
|
86858585858585858585E8F800000000000000000000000000000000008A8786
|
||||||
|
858585F8EC868585858585EB00000000000000000000000000000000008685F7
|
||||||
|
EF07F1F1F1F1F107EF8686EF0000000000000000000000000000000000F29797
|
||||||
|
97979809090997979796090000000000000000000000FFFFFFFFFF8003FFF800
|
||||||
|
003FE000001FC000000F80000007800000078000000780000007C000000FC000
|
||||||
|
000FE000001FE000003FF000003FF000007FF80000FFF80000FFFC0001FFFC00
|
||||||
|
01FFFE0003FFFE0003FFFF0007FFFF0007FFFF0007FFFF0007FFFF0007FFFF00
|
||||||
|
07FFFF0007FFFF0003FFFE0003FFFE0003FFFE0007FF}
|
||||||
Menu = MainMenu
|
Menu = MainMenu
|
||||||
OldCreateOrder = False
|
OldCreateOrder = False
|
||||||
Position = poScreenCenter
|
Position = poScreenCenter
|
||||||
|
@ -36,17 +151,59 @@ object frmMain: TfrmMain
|
||||||
object butAdd: TSpeedButton
|
object butAdd: TSpeedButton
|
||||||
Left = 24
|
Left = 24
|
||||||
Top = 328
|
Top = 328
|
||||||
Width = 89
|
Width = 193
|
||||||
Height = 25
|
Height = 25
|
||||||
Caption = 'Add &new version'
|
Caption = 'Add &new version'
|
||||||
Flat = True
|
Glyph.Data = {
|
||||||
|
36050000424D3605000000000000360400002800000010000000100000000100
|
||||||
|
08000000000000010000000000000000000000010000000100004A004A006200
|
||||||
|
6200780178009F019F00BC01BC00D301D300E200E200EF00EF00F700F700FB00
|
||||||
|
FB00FD00FD00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00
|
||||||
|
FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00
|
||||||
|
FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00
|
||||||
|
FE00FE00FE00FE00FE00FD00FD00FC00FC00FA00FA00F701F700F202F200EC03
|
||||||
|
EC00E305E300D708D700C60BC600AF11AF008F188F007E1D7E006C226C006125
|
||||||
|
6100572857004C2C4C0040304000353535003636360037373700383838003939
|
||||||
|
39003A3A3A003B3B3B003C3C3C003D3D3D003E3E3E003F3F3F00404040004141
|
||||||
|
4100424242004343430044444400454545004646460047474700484848004949
|
||||||
|
49004A4A4A004B4B4B004C4C4C004D4D4D004E4E4E004F4F4F00505050005151
|
||||||
|
5100525252005353530054545400555555005656560057575700585858005959
|
||||||
|
59005A5A5A005B5B5B005C5C5C005D5D5D005E5E5E005F5F5F00606060006161
|
||||||
|
6100626262006363630064646400656565006666660067676700686868006969
|
||||||
|
69006A6A6A006B6B6B006C6C6C006D6D6D006E6E6E006F6F6F00707070007171
|
||||||
|
7100727272007373730074747400757575007676760077777700787878007979
|
||||||
|
79007A7A7A007B7B7B007C7C7C007D7D7D007E7E7E007F7F7F00808080008181
|
||||||
|
8100828282008383830084848400858585008686860087878700888888008989
|
||||||
|
89008A8A8A008B8B8B008C8C8C008D8D8D008E8E8E008F8F8F00909090009191
|
||||||
|
9100929292009393930094949400959595009696960097979700989898009999
|
||||||
|
99009A9A9A009B9B9B009C9C9C009D9D9D009E9E9E009F9F9F00A0A0A000A1A1
|
||||||
|
A100A2A2A200A3A3A300A4A4A400A5A5A500A6A6A600A7A7A700A8A8A800A9A9
|
||||||
|
A900AAAAAA00ABABAB00ACACAC00ADADAD00AEAEAE00B3B3B300BFC1BF00C8CC
|
||||||
|
C900D0D5D200D7DDD900DEE6E100E6EDE800ECF3EE00F1F7F300F5FAF600F7FB
|
||||||
|
F900F9FCFA00FBFDFB00FBFDFC00FBFDFC00F9FDFA00F6FCF800F4FBF600F0FA
|
||||||
|
F300ECFAF100E9F9EF00E6F8ED00E2F7EA00DDF6E700D7F4E300D3F3E000D0F2
|
||||||
|
DD00CEF1DB00CCF1D900C9EFD600C0EDCF00B9EBC900ADE7C000A3E4B80098E0
|
||||||
|
AF008DDDA50085DAA0007DD89A0075D694006DD38F0067D18B0060CF84005BCE
|
||||||
|
800055CC7B004DCA780047C8750042C672003DC46E0039C36B0036C2680033C0
|
||||||
|
640030BE61002EBC5C002CBA590029B9550027B8510027B74E0025B5490023B5
|
||||||
|
440023B3420022B13D0020B03B001EB1360019B2310016B32D0012B327000EB4
|
||||||
|
21000BB41D000AB41B0009B31A0009B0190009AD19000AA318000A9717000A8C
|
||||||
|
1700097D14000872120007680E0006640D0006650D0007690F001515151515FD
|
||||||
|
FDFFFFFDFD1515151515151515FDFDF9F5F4F4F5F8FCFC1515151515FFFAF2F4
|
||||||
|
F4F5F4F4F4F4FAFD151515FFF9EFF0F2F5F5F5F5F5F4F4FAFE1515FFE8E9EFF2
|
||||||
|
EDC6C2D9F5F5F4F4FE15FBECE3E9F1F3F1D1BCBFDAF5F5F4F8FDFBE4E1E7F1F4
|
||||||
|
F2F5D2BCBFDAF5F4F6FDFADFDFCACCCCCCCDCDBEBCC1D6F4F4FEF9D9DCBCBCBC
|
||||||
|
BCBCBCBCBCBCCEF3F4FFF9D6D7D6D5D5D5D7D2BBBCD0E7F0F5FDF9D8D0DEE0DE
|
||||||
|
DED5C4BCD1E8EBF0F7FD15ECCDD3E1E0DAB9BCD1E8E9EEEFF91515ECD6C8D3DF
|
||||||
|
DECDCFE1E5E7E9EEF9151515ECD3C6CFD6DADCDBDBDFE8FA1515151515ECECCF
|
||||||
|
C9CDCFD1D6E4E41515151515151515E7ECECECECEA1515151515}
|
||||||
OnClick = butAddClick
|
OnClick = butAddClick
|
||||||
end
|
end
|
||||||
object grpConfig: TGroupBox
|
object grpConfig: TGroupBox
|
||||||
Left = 232
|
Left = 232
|
||||||
Top = 43
|
Top = 51
|
||||||
Width = 441
|
Width = 441
|
||||||
Height = 278
|
Height = 270
|
||||||
Enabled = False
|
Enabled = False
|
||||||
TabOrder = 0
|
TabOrder = 0
|
||||||
object Label2: TLabel
|
object Label2: TLabel
|
||||||
|
@ -123,14 +280,6 @@ object frmMain: TfrmMain
|
||||||
Hint = 'Smaller gives smaller patch files, but decreased speed'
|
Hint = 'Smaller gives smaller patch files, but decreased speed'
|
||||||
Caption = 'Block size'
|
Caption = 'Block size'
|
||||||
end
|
end
|
||||||
object Label6: TLabel
|
|
||||||
Left = 32
|
|
||||||
Top = 248
|
|
||||||
Width = 91
|
|
||||||
Height = 13
|
|
||||||
Caption = 'Minimum block size'
|
|
||||||
Visible = False
|
|
||||||
end
|
|
||||||
object Label7: TLabel
|
object Label7: TLabel
|
||||||
Left = 232
|
Left = 232
|
||||||
Top = 224
|
Top = 224
|
||||||
|
@ -139,14 +288,6 @@ object frmMain: TfrmMain
|
||||||
Caption = 'Block divider'
|
Caption = 'Block divider'
|
||||||
Visible = False
|
Visible = False
|
||||||
end
|
end
|
||||||
object Label8: TLabel
|
|
||||||
Left = 232
|
|
||||||
Top = 248
|
|
||||||
Width = 43
|
|
||||||
Height = 13
|
|
||||||
Caption = 'Step size'
|
|
||||||
Visible = False
|
|
||||||
end
|
|
||||||
object txtStartBlockSize: TLabel
|
object txtStartBlockSize: TLabel
|
||||||
Left = 136
|
Left = 136
|
||||||
Top = 224
|
Top = 224
|
||||||
|
@ -171,78 +312,6 @@ object frmMain: TfrmMain
|
||||||
ItemHeight = 13
|
ItemHeight = 13
|
||||||
TabOrder = 1
|
TabOrder = 1
|
||||||
end
|
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
|
object tbBlockSize: TTrackBar
|
||||||
Left = 200
|
Left = 200
|
||||||
Top = 224
|
Top = 224
|
||||||
|
@ -250,22 +319,16 @@ object frmMain: TfrmMain
|
||||||
Height = 25
|
Height = 25
|
||||||
Max = 12
|
Max = 12
|
||||||
Min = 4
|
Min = 4
|
||||||
Orientation = trHorizontal
|
|
||||||
Frequency = 1
|
|
||||||
Position = 6
|
Position = 6
|
||||||
SelEnd = 0
|
TabOrder = 2
|
||||||
SelStart = 0
|
|
||||||
TabOrder = 8
|
|
||||||
TickMarks = tmBottomRight
|
|
||||||
TickStyle = tsAuto
|
|
||||||
OnChange = tbBlockSizeChange
|
OnChange = tbBlockSizeChange
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
object lstNew: TVirtualStringTree
|
object lstNew: TVirtualStringTree
|
||||||
Left = 24
|
Left = 24
|
||||||
Top = 48
|
Top = 56
|
||||||
Width = 193
|
Width = 193
|
||||||
Height = 273
|
Height = 265
|
||||||
Header.AutoSizeIndex = 0
|
Header.AutoSizeIndex = 0
|
||||||
Header.Font.Charset = DEFAULT_CHARSET
|
Header.Font.Charset = DEFAULT_CHARSET
|
||||||
Header.Font.Color = clWindowText
|
Header.Font.Color = clWindowText
|
||||||
|
@ -371,14 +434,25 @@ object frmMain: TfrmMain
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
object chkDebug: TCheckBox
|
object chkOutputWait: TCheckBox
|
||||||
Left = 232
|
Left = 232
|
||||||
Top = 336
|
Top = 336
|
||||||
Width = 289
|
Width = 305
|
||||||
Height = 17
|
Height = 17
|
||||||
Caption = 'Show extended information during patch generation'
|
Caption = 'Leave console window open after generating patches'
|
||||||
TabOrder = 3
|
TabOrder = 3
|
||||||
OnClick = chkDebugClick
|
OnClick = chkOutputWaitClick
|
||||||
|
end
|
||||||
|
object chkOptimal: TCheckBox
|
||||||
|
Left = 232
|
||||||
|
Top = 360
|
||||||
|
Width = 441
|
||||||
|
Height = 17
|
||||||
|
Caption =
|
||||||
|
'"Optimal" patch generation (can be very slow when generating pat' +
|
||||||
|
'ches for big files)'
|
||||||
|
TabOrder = 4
|
||||||
|
OnClick = chkOptimalClick
|
||||||
end
|
end
|
||||||
object MainMenu: TMainMenu
|
object MainMenu: TMainMenu
|
||||||
Images = IL
|
Images = IL
|
||||||
|
@ -446,6 +520,21 @@ object frmMain: TfrmMain
|
||||||
end
|
end
|
||||||
object mnuHelp: TMenuItem
|
object mnuHelp: TMenuItem
|
||||||
Caption = '&Help'
|
Caption = '&Help'
|
||||||
|
object mnuWebsite: TMenuItem
|
||||||
|
Caption = '&Website'
|
||||||
|
OnClick = mnuWebsiteClick
|
||||||
|
end
|
||||||
|
object Readme1: TMenuItem
|
||||||
|
Caption = '&Readme'
|
||||||
|
OnClick = Readme1Click
|
||||||
|
end
|
||||||
|
object ReadmeincludedwithNSIS1: TMenuItem
|
||||||
|
Caption = 'Readme included with NSIS'
|
||||||
|
OnClick = ReadmeincludedwithNSIS1Click
|
||||||
|
end
|
||||||
|
object N2: TMenuItem
|
||||||
|
Caption = '-'
|
||||||
|
end
|
||||||
object mnuAbout: TMenuItem
|
object mnuAbout: TMenuItem
|
||||||
Caption = '&About'
|
Caption = '&About'
|
||||||
OnClick = mnuAboutClick
|
OnClick = mnuAboutClick
|
||||||
|
|
|
@ -5,7 +5,7 @@ interface
|
||||||
uses
|
uses
|
||||||
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
|
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
|
||||||
Dialogs, Buttons, StdCtrls, Menus, PatchClasses, VirtualTrees, VDSP_CRC,
|
Dialogs, Buttons, StdCtrls, Menus, PatchClasses, VirtualTrees, VDSP_CRC,
|
||||||
ToolWin, ComCtrls, ImgList, ExtCtrls, PatchGenerator, Math;
|
ToolWin, ComCtrls, ImgList, ExtCtrls, Math, OSUtil;
|
||||||
|
|
||||||
const
|
const
|
||||||
UntitledFile='Untitled.vpj';
|
UntitledFile='Untitled.vpj';
|
||||||
|
@ -50,16 +50,7 @@ type
|
||||||
toolCreateEXE: TToolButton;
|
toolCreateEXE: TToolButton;
|
||||||
barCool: TCoolBar;
|
barCool: TCoolBar;
|
||||||
Label5: TLabel;
|
Label5: TLabel;
|
||||||
Label6: TLabel;
|
|
||||||
txtMinimumBlockSize: TEdit;
|
|
||||||
UDMinimumBlockSize: TUpDown;
|
|
||||||
UDBlockDivider: TUpDown;
|
|
||||||
txtBlockDivider: TEdit;
|
|
||||||
Label7: TLabel;
|
Label7: TLabel;
|
||||||
UDStepSize: TUpDown;
|
|
||||||
txtStepSize: TEdit;
|
|
||||||
Label8: TLabel;
|
|
||||||
chkDebug: TCheckBox;
|
|
||||||
tbBlockSize: TTrackBar;
|
tbBlockSize: TTrackBar;
|
||||||
txtStartBlockSize: TLabel;
|
txtStartBlockSize: TLabel;
|
||||||
mnuClearcachedpatches: TMenuItem;
|
mnuClearcachedpatches: TMenuItem;
|
||||||
|
@ -70,6 +61,12 @@ type
|
||||||
toolCreatePAT: TToolButton;
|
toolCreatePAT: TToolButton;
|
||||||
dlgSaveDLL: TSaveDialog;
|
dlgSaveDLL: TSaveDialog;
|
||||||
dlgSavePAT: TSaveDialog;
|
dlgSavePAT: TSaveDialog;
|
||||||
|
chkOutputWait: TCheckBox;
|
||||||
|
mnuWebsite: TMenuItem;
|
||||||
|
Readme1: TMenuItem;
|
||||||
|
N2: TMenuItem;
|
||||||
|
ReadmeincludedwithNSIS1: TMenuItem;
|
||||||
|
chkOptimal: TCheckBox;
|
||||||
procedure butAddClick(Sender: TObject);
|
procedure butAddClick(Sender: TObject);
|
||||||
procedure FormCreate(Sender: TObject);
|
procedure FormCreate(Sender: TObject);
|
||||||
procedure FormDestroy(Sender: TObject);
|
procedure FormDestroy(Sender: TObject);
|
||||||
|
@ -95,11 +92,15 @@ type
|
||||||
procedure txtMinimumBlockSizeChange(Sender: TObject);
|
procedure txtMinimumBlockSizeChange(Sender: TObject);
|
||||||
procedure txtBlockDividerChange(Sender: TObject);
|
procedure txtBlockDividerChange(Sender: TObject);
|
||||||
procedure txtStepSizeChange(Sender: TObject);
|
procedure txtStepSizeChange(Sender: TObject);
|
||||||
procedure chkDebugClick(Sender: TObject);
|
|
||||||
procedure tbBlockSizeChange(Sender: TObject);
|
procedure tbBlockSizeChange(Sender: TObject);
|
||||||
procedure mnuClearcachedpatchesClick(Sender: TObject);
|
procedure mnuClearcachedpatchesClick(Sender: TObject);
|
||||||
procedure mnuCreateDLLClick(Sender: TObject);
|
procedure mnuCreateDLLClick(Sender: TObject);
|
||||||
procedure mnuCreatePATClick(Sender: TObject);
|
procedure mnuCreatePATClick(Sender: TObject);
|
||||||
|
procedure chkOutputWaitClick(Sender: TObject);
|
||||||
|
procedure mnuWebsiteClick(Sender: TObject);
|
||||||
|
procedure Readme1Click(Sender: TObject);
|
||||||
|
procedure ReadmeincludedwithNSIS1Click(Sender: TObject);
|
||||||
|
procedure chkOptimalClick(Sender: TObject);
|
||||||
private
|
private
|
||||||
{ Private declarations }
|
{ Private declarations }
|
||||||
// MS: TModeSelector;
|
// MS: TModeSelector;
|
||||||
|
@ -108,7 +109,6 @@ type
|
||||||
procedure OpenAFile(FileName: String; AskSave: Boolean=True; PromptNew: Boolean=False);
|
procedure OpenAFile(FileName: String; AskSave: Boolean=True; PromptNew: Boolean=False);
|
||||||
function CollectConfig: String;
|
function CollectConfig: String;
|
||||||
procedure SetConfigTextBoxes(Config: String);
|
procedure SetConfigTextBoxes(Config: String);
|
||||||
procedure PrintDebug(S: String);
|
|
||||||
public
|
public
|
||||||
{ Public declarations }
|
{ Public declarations }
|
||||||
end;
|
end;
|
||||||
|
@ -119,7 +119,7 @@ var
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses AboutForm;
|
uses AboutForm, DLLWrapper;
|
||||||
|
|
||||||
{$R *.dfm}
|
{$R *.dfm}
|
||||||
|
|
||||||
|
@ -292,15 +292,15 @@ begin
|
||||||
PP:=TPatchProject.Create;
|
PP:=TPatchProject.Create;
|
||||||
ReloadNewTree;
|
ReloadNewTree;
|
||||||
if FileName<>'' then begin
|
if FileName<>'' then begin
|
||||||
fs:=nil;
|
|
||||||
try
|
|
||||||
fs:=TFileStream.Create(FileName,fmOpenRead);
|
fs:=TFileStream.Create(FileName,fmOpenRead);
|
||||||
PP.LoadFromStream(fs);
|
try
|
||||||
finally
|
PP.LoadFromStream(fs);
|
||||||
|
except
|
||||||
|
on E: Exception do ShowMessage(E.Message);
|
||||||
|
end;
|
||||||
dskName:=FileName;
|
dskName:=FileName;
|
||||||
ReloadNewTree;
|
ReloadNewTree;
|
||||||
fs.Free;
|
fs.Free;
|
||||||
end;
|
|
||||||
end else begin
|
end else begin
|
||||||
dskName:=UntitledFile;
|
dskName:=UntitledFile;
|
||||||
if PromptNew then butAddClick(Self);
|
if PromptNew then butAddClick(Self);
|
||||||
|
@ -318,6 +318,8 @@ procedure TfrmMain.mnuOpenClick(Sender: TObject);
|
||||||
begin
|
begin
|
||||||
if dlgOpen.Execute then begin
|
if dlgOpen.Execute then begin
|
||||||
OpenAFile(dlgOpen.FileName,True);
|
OpenAFile(dlgOpen.FileName,True);
|
||||||
|
if lstNew.GetFirst <> nil then
|
||||||
|
lstNew.Selected[lstNew.GetFirst]:=True;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -460,7 +462,7 @@ end;
|
||||||
|
|
||||||
function TfrmMain.CollectConfig: String;
|
function TfrmMain.CollectConfig: String;
|
||||||
begin
|
begin
|
||||||
Result:=txtStartBlockSize.Caption+','+txtMinimumBlockSize.Text+','+txtBlockDivider.Text+','+txtStepSize.Text;
|
Result:=txtStartBlockSize.Caption;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TfrmMain.txtMinimumBlockSizeChange(Sender: TObject);
|
procedure TfrmMain.txtMinimumBlockSizeChange(Sender: TObject);
|
||||||
|
@ -494,33 +496,6 @@ begin
|
||||||
Inc(i);
|
Inc(i);
|
||||||
end;
|
end;
|
||||||
tbBlockSize.Position := i;
|
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;
|
end;
|
||||||
|
|
||||||
procedure TfrmMain.tbBlockSizeChange(Sender: TObject);
|
procedure TfrmMain.tbBlockSizeChange(Sender: TObject);
|
||||||
|
@ -534,6 +509,31 @@ begin
|
||||||
PP.ResetCache;
|
PP.ResetCache;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TfrmMain.chkOutputWaitClick(Sender: TObject);
|
||||||
|
begin
|
||||||
|
WaitAfterGenerate:=chkOutputWait.Checked;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TfrmMain.mnuWebsiteClick(Sender: TObject);
|
||||||
|
begin
|
||||||
|
OpenLink('http://www.tibed.net/vpatch');
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TfrmMain.Readme1Click(Sender: TObject);
|
||||||
|
begin
|
||||||
|
OpenLink('VPatch.htm');
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TfrmMain.ReadmeincludedwithNSIS1Click(Sender: TObject);
|
||||||
|
begin
|
||||||
|
OpenLink('Readme.html');
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TfrmMain.chkOptimalClick(Sender: TObject);
|
||||||
|
begin
|
||||||
|
OptimalPatches:=chkOptimal.Checked;
|
||||||
|
end;
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
PP:=TPatchProject.Create;
|
PP:=TPatchProject.Create;
|
||||||
end.
|
end.
|
||||||
|
|
114
Contrib/VPatch/Source/GUI/OSUtil.pas
Normal file
114
Contrib/VPatch/Source/GUI/OSUtil.pas
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
unit OSUtil;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
procedure OpenLink(ALink: String); forward;
|
||||||
|
function GetTempDir: String; forward;
|
||||||
|
function GetTempFile: String; forward;
|
||||||
|
procedure ExecProgram(GameFolder: String; S: String; JustEXE: String; AWaitUntilFinish: Boolean); forward;
|
||||||
|
procedure ExecWaitBatchFile(AFolder: String; AName: String); forward;
|
||||||
|
procedure OSMoveFile(ASource,ADest: String); forward;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
Windows, SysUtils, ShellAPI, Forms, Dialogs;
|
||||||
|
|
||||||
|
// does not support command-line arguments right now
|
||||||
|
procedure ExecWaitBatchFile(AFolder: String; AName: String);
|
||||||
|
var
|
||||||
|
S, JustEXE: String;
|
||||||
|
StartUp: STARTUPINFO;
|
||||||
|
ProcInfo: PROCESS_INFORMATION;
|
||||||
|
begin
|
||||||
|
S:='"'+AName+'"';
|
||||||
|
JustExe:=AName;
|
||||||
|
StartUp.lpReserved:=nil;
|
||||||
|
StartUp.lpDesktop:=nil;
|
||||||
|
StartUp.lpTitle:=nil;
|
||||||
|
StartUp.dwFlags:=STARTF_USESHOWWINDOW;
|
||||||
|
StartUp.wShowWindow:=SW_SHOWMAXIMIZED;
|
||||||
|
StartUp.cbReserved2:=0;
|
||||||
|
StartUp.lpReserved2:=nil;
|
||||||
|
|
||||||
|
//it works now... but don't ask me how - it's taken me hours just to get this working :)
|
||||||
|
if not CreateProcess(PChar(JustEXE),PChar(S),nil,nil,False,NORMAL_PRIORITY_CLASS,nil,PChar(AFolder),StartUp,ProcInfo) then
|
||||||
|
raise Exception.Create('CreateProcess error:'+IntToStr(GetLastError));
|
||||||
|
if not (ProcInfo.hThread=0) then CloseHandle(ProcInfo.hThread);
|
||||||
|
if not (ProcInfo.hProcess=0) then begin
|
||||||
|
WaitForSingleObject(ProcInfo.hProcess,INFINITE);
|
||||||
|
CloseHandle(ProcInfo.hProcess);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure OSMoveFile(ASource,ADest: String);
|
||||||
|
begin
|
||||||
|
if not MoveFileEx(@ASource[1],@ADest[1],MOVEFILE_COPY_ALLOWED+MOVEFILE_REPLACE_EXISTING+MOVEFILE_WRITE_THROUGH) then
|
||||||
|
raise Exception.Create('File movement failed in OSMoveFile: '+ASource+'; '+ADest);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure OpenLink(ALink: String);
|
||||||
|
var
|
||||||
|
StartDoc: Integer;
|
||||||
|
begin
|
||||||
|
StartDoc:=ShellExecute(Application.Handle, 'open', PChar(ALink), nil, nil, SW_SHOWNORMAL);
|
||||||
|
If StartDoc <= 32 Then begin
|
||||||
|
MessageDlg('Error occured while opening link: '+ALink,mtWarning,[mbOK],0);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ExecProgram(GameFolder: String; S: String; JustEXE: String; AWaitUntilFinish: Boolean);
|
||||||
|
var
|
||||||
|
StartUp: STARTUPINFO;
|
||||||
|
ProcInfo: PROCESS_INFORMATION;
|
||||||
|
begin
|
||||||
|
StartUp.lpReserved:=nil;
|
||||||
|
StartUp.lpDesktop:=nil;
|
||||||
|
StartUp.lpTitle:=nil;
|
||||||
|
StartUp.dwFlags:=STARTF_USESHOWWINDOW;
|
||||||
|
StartUp.wShowWindow:=SW_SHOWMAXIMIZED;
|
||||||
|
StartUp.cbReserved2:=0;
|
||||||
|
StartUp.lpReserved2:=nil;
|
||||||
|
|
||||||
|
//it works now... but don't ask me how - it's taken me hours just to get this working :)
|
||||||
|
if not CreateProcess(PChar(JustEXE),PChar(S),nil,nil,False,NORMAL_PRIORITY_CLASS,nil,PChar(GameFolder),StartUp,ProcInfo) then
|
||||||
|
raise Exception.Create('CreateProcess error:'+IntToStr(GetLastError));
|
||||||
|
if not (ProcInfo.hThread=0) then CloseHandle(ProcInfo.hThread);
|
||||||
|
if not (ProcInfo.hProcess=0) then begin
|
||||||
|
if AWaitUntilFinish then
|
||||||
|
WaitForSingleObject(ProcInfo.hProcess,INFINITE);
|
||||||
|
CloseHandle(ProcInfo.hProcess);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
TempDir: String;
|
||||||
|
strBuffer: Array[0..1024] of Char;
|
||||||
|
nBufferLength: Cardinal;
|
||||||
|
|
||||||
|
function GetTempFile;
|
||||||
|
var
|
||||||
|
Prefix: String;
|
||||||
|
lngLength: Integer;
|
||||||
|
begin
|
||||||
|
PreFix:='TMP';
|
||||||
|
strBuffer:='';
|
||||||
|
lngLength:=GetTempFileName(PChar(TempDir),PChar(PreFix),0,strBuffer);
|
||||||
|
if not (lngLength=0) then begin
|
||||||
|
GetTempFile:=strBuffer;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetTempDir: String;
|
||||||
|
begin
|
||||||
|
GetTempDir:=TempDir;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
// get temporary folder
|
||||||
|
nBufferLength:=1024;
|
||||||
|
strBuffer:='';
|
||||||
|
GetTempPath(nBufferLength,strBuffer);
|
||||||
|
TempDir:=strBuffer;
|
||||||
|
end.
|
|
@ -5,7 +5,7 @@ interface
|
||||||
uses Classes, sysutils, VDSP_CRC, DLLWrapper, Dialogs;
|
uses Classes, sysutils, VDSP_CRC, DLLWrapper, Dialogs;
|
||||||
|
|
||||||
const
|
const
|
||||||
DEFAULT_CONFIG = '64,64,2,32';
|
DEFAULT_CONFIG = '64';
|
||||||
|
|
||||||
type
|
type
|
||||||
TAbstractFile = record
|
TAbstractFile = record
|
||||||
|
@ -215,7 +215,7 @@ begin
|
||||||
Result:=FOld[Index].FileName;
|
Result:=FOld[Index].FileName;
|
||||||
if FOld[Index].Cached then
|
if FOld[Index].Cached then
|
||||||
if FOld[Index].Cache.Size>0 then begin
|
if FOld[Index].Cache.Size>0 then begin
|
||||||
Result:=Result + ' ('+IntToStr(FOld[Index].Cache.Size)+' bytes)';
|
Result:=Result + ' ('+IntToStr(FOld[Index].Cache.Size)+' bytes to patch)';
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -445,6 +445,7 @@ end;
|
||||||
|
|
||||||
procedure TPatchProject.LoadFromStream(Stream: TStream);
|
procedure TPatchProject.LoadFromStream(Stream: TStream);
|
||||||
var
|
var
|
||||||
|
MagicWord: Array[0..15] of Char;
|
||||||
i: LongInt;
|
i: LongInt;
|
||||||
j: Integer;
|
j: Integer;
|
||||||
begin
|
begin
|
||||||
|
@ -453,15 +454,13 @@ begin
|
||||||
FPat[j].Free;
|
FPat[j].Free;
|
||||||
FPat[j]:=nil;
|
FPat[j]:=nil;
|
||||||
end;
|
end;
|
||||||
Stream.Read(i,SizeOf(i));
|
Stream.Read(MagicWord,SizeOf(MagicWord));
|
||||||
if(i=$1A4A5056) then begin //still read old files
|
if SameText('VPatchProject 3'#26,MagicWord) then begin
|
||||||
Stream.Read(i,SizeOf(i)); //16 dummy bytes
|
Stream.Read(i,SizeOf(i)); //4 dummy bytes
|
||||||
Stream.Read(i,SizeOf(i));
|
end else
|
||||||
Stream.Read(i,SizeOf(i));
|
raise Exception.Create('Error: file format incompatible (only version 3 and newer are supported).');
|
||||||
Stream.Read(i,SizeOf(i));
|
|
||||||
|
|
||||||
Stream.Read(i,SizeOf(i));
|
Stream.Read(i,SizeOf(i)); // file count
|
||||||
end;
|
|
||||||
SetLength(FPat,i);
|
SetLength(FPat,i);
|
||||||
for j:=0 to i - 1 do begin
|
for j:=0 to i - 1 do begin
|
||||||
FPat[j]:=TPatchFile.Create(j,Stream);
|
FPat[j]:=TPatchFile.Create(j,Stream);
|
||||||
|
@ -503,18 +502,15 @@ end;
|
||||||
|
|
||||||
procedure TPatchProject.SaveToStream(Stream: TStream);
|
procedure TPatchProject.SaveToStream(Stream: TStream);
|
||||||
var
|
var
|
||||||
HeadID: Array[0..3] of Char;
|
HeadID: Array[0..15] of Char;
|
||||||
i: LongInt;
|
i: LongInt;
|
||||||
j: Integer;
|
j: Integer;
|
||||||
begin
|
begin
|
||||||
HeadID:='VPJ'+#26;
|
HeadID:='VPatchProject 3'+#26;
|
||||||
Stream.Write(HeadID,SizeOf(HeadID));
|
Stream.Write(HeadID,SizeOf(HeadID));
|
||||||
//16 dummy bytes
|
//4 dummy bytes left
|
||||||
i:=0;
|
i:=0;
|
||||||
Stream.Write(i,SizeOf(i));
|
Stream.Write(i,SizeOf(i));
|
||||||
Stream.Write(i,SizeOf(i));
|
|
||||||
Stream.Write(i,SizeOf(i));
|
|
||||||
Stream.Write(i,SizeOf(i));
|
|
||||||
i:=Length(FPat);
|
i:=Length(FPat);
|
||||||
Stream.Write(i,SizeOf(i));
|
Stream.Write(i,SizeOf(i));
|
||||||
for j:=0 to i - 1 do begin
|
for j:=0 to i - 1 do begin
|
||||||
|
@ -525,6 +521,7 @@ end;
|
||||||
procedure TPatchProject.WritePatches(Stream: TStream);
|
procedure TPatchProject.WritePatches(Stream: TStream);
|
||||||
var
|
var
|
||||||
i,j,k,o: LongInt;
|
i,j,k,o: LongInt;
|
||||||
|
q: LongWord;
|
||||||
begin
|
begin
|
||||||
k:=$54415056;
|
k:=$54415056;
|
||||||
o:=Stream.Position;
|
o:=Stream.Position;
|
||||||
|
@ -539,7 +536,10 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
Stream.Seek(o+4,soFromBeginning);
|
Stream.Seek(o+4,soFromBeginning);
|
||||||
Stream.Write(k,SizeOf(k));
|
q:=k;
|
||||||
|
// set the MD5 flag
|
||||||
|
q:=q or $80000000;
|
||||||
|
Stream.Write(q,SizeOf(q));
|
||||||
Stream.Seek(Stream.Size,soFromBeginning);
|
Stream.Seek(Stream.Size,soFromBeginning);
|
||||||
Stream.Write(o,SizeOf(o));
|
Stream.Write(o,SizeOf(o));
|
||||||
end;
|
end;
|
||||||
|
|
BIN
Contrib/VPatch/Source/GUI/VPatch.ico
Normal file
BIN
Contrib/VPatch/Source/GUI/VPatch.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
163
Contrib/VPatch/Source/GUI/VPatchGUI.bdsproj
Normal file
163
Contrib/VPatch/Source/GUI/VPatchGUI.bdsproj
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<BorlandProject>
|
||||||
|
<PersonalityInfo>
|
||||||
|
<Option>
|
||||||
|
<Option Name="Personality">Delphi.Personality</Option>
|
||||||
|
<Option Name="ProjectType"></Option>
|
||||||
|
<Option Name="Version">1.0</Option>
|
||||||
|
<Option Name="GUID">{F68A969B-E8BB-4D72-9FB4-216CA54EACE0}</Option>
|
||||||
|
</Option>
|
||||||
|
</PersonalityInfo>
|
||||||
|
<Delphi.Personality>
|
||||||
|
<Source>
|
||||||
|
<Source Name="MainSource">VPatchGUI.dpr</Source>
|
||||||
|
</Source>
|
||||||
|
<FileVersion>
|
||||||
|
<FileVersion Name="Version">7.0</FileVersion>
|
||||||
|
</FileVersion>
|
||||||
|
<Compiler>
|
||||||
|
<Compiler Name="A">8</Compiler>
|
||||||
|
<Compiler Name="B">0</Compiler>
|
||||||
|
<Compiler Name="C">1</Compiler>
|
||||||
|
<Compiler Name="D">1</Compiler>
|
||||||
|
<Compiler Name="E">0</Compiler>
|
||||||
|
<Compiler Name="F">0</Compiler>
|
||||||
|
<Compiler Name="G">1</Compiler>
|
||||||
|
<Compiler Name="H">1</Compiler>
|
||||||
|
<Compiler Name="I">1</Compiler>
|
||||||
|
<Compiler Name="J">0</Compiler>
|
||||||
|
<Compiler Name="K">0</Compiler>
|
||||||
|
<Compiler Name="L">1</Compiler>
|
||||||
|
<Compiler Name="M">0</Compiler>
|
||||||
|
<Compiler Name="N">1</Compiler>
|
||||||
|
<Compiler Name="O">1</Compiler>
|
||||||
|
<Compiler Name="P">1</Compiler>
|
||||||
|
<Compiler Name="Q">0</Compiler>
|
||||||
|
<Compiler Name="R">0</Compiler>
|
||||||
|
<Compiler Name="S">0</Compiler>
|
||||||
|
<Compiler Name="T">0</Compiler>
|
||||||
|
<Compiler Name="U">0</Compiler>
|
||||||
|
<Compiler Name="V">1</Compiler>
|
||||||
|
<Compiler Name="W">0</Compiler>
|
||||||
|
<Compiler Name="X">1</Compiler>
|
||||||
|
<Compiler Name="Y">1</Compiler>
|
||||||
|
<Compiler Name="Z">1</Compiler>
|
||||||
|
<Compiler Name="ShowHints">True</Compiler>
|
||||||
|
<Compiler Name="ShowWarnings">True</Compiler>
|
||||||
|
<Compiler Name="UnitAliases">WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;</Compiler>
|
||||||
|
<Compiler Name="NamespacePrefix"></Compiler>
|
||||||
|
<Compiler Name="GenerateDocumentation">False</Compiler>
|
||||||
|
<Compiler Name="DefaultNamespace"></Compiler>
|
||||||
|
<Compiler Name="SymbolDeprecated">True</Compiler>
|
||||||
|
<Compiler Name="SymbolLibrary">True</Compiler>
|
||||||
|
<Compiler Name="SymbolPlatform">True</Compiler>
|
||||||
|
<Compiler Name="SymbolExperimental">True</Compiler>
|
||||||
|
<Compiler Name="UnitLibrary">True</Compiler>
|
||||||
|
<Compiler Name="UnitPlatform">True</Compiler>
|
||||||
|
<Compiler Name="UnitDeprecated">True</Compiler>
|
||||||
|
<Compiler Name="UnitExperimental">True</Compiler>
|
||||||
|
<Compiler Name="HResultCompat">True</Compiler>
|
||||||
|
<Compiler Name="HidingMember">True</Compiler>
|
||||||
|
<Compiler Name="HiddenVirtual">True</Compiler>
|
||||||
|
<Compiler Name="Garbage">True</Compiler>
|
||||||
|
<Compiler Name="BoundsError">True</Compiler>
|
||||||
|
<Compiler Name="ZeroNilCompat">True</Compiler>
|
||||||
|
<Compiler Name="StringConstTruncated">True</Compiler>
|
||||||
|
<Compiler Name="ForLoopVarVarPar">True</Compiler>
|
||||||
|
<Compiler Name="TypedConstVarPar">True</Compiler>
|
||||||
|
<Compiler Name="AsgToTypedConst">True</Compiler>
|
||||||
|
<Compiler Name="CaseLabelRange">True</Compiler>
|
||||||
|
<Compiler Name="ForVariable">True</Compiler>
|
||||||
|
<Compiler Name="ConstructingAbstract">True</Compiler>
|
||||||
|
<Compiler Name="ComparisonFalse">True</Compiler>
|
||||||
|
<Compiler Name="ComparisonTrue">True</Compiler>
|
||||||
|
<Compiler Name="ComparingSignedUnsigned">True</Compiler>
|
||||||
|
<Compiler Name="CombiningSignedUnsigned">True</Compiler>
|
||||||
|
<Compiler Name="UnsupportedConstruct">True</Compiler>
|
||||||
|
<Compiler Name="FileOpen">True</Compiler>
|
||||||
|
<Compiler Name="FileOpenUnitSrc">True</Compiler>
|
||||||
|
<Compiler Name="BadGlobalSymbol">True</Compiler>
|
||||||
|
<Compiler Name="DuplicateConstructorDestructor">True</Compiler>
|
||||||
|
<Compiler Name="InvalidDirective">True</Compiler>
|
||||||
|
<Compiler Name="PackageNoLink">True</Compiler>
|
||||||
|
<Compiler Name="PackageThreadVar">True</Compiler>
|
||||||
|
<Compiler Name="ImplicitImport">True</Compiler>
|
||||||
|
<Compiler Name="HPPEMITIgnored">True</Compiler>
|
||||||
|
<Compiler Name="NoRetVal">True</Compiler>
|
||||||
|
<Compiler Name="UseBeforeDef">True</Compiler>
|
||||||
|
<Compiler Name="ForLoopVarUndef">True</Compiler>
|
||||||
|
<Compiler Name="UnitNameMismatch">True</Compiler>
|
||||||
|
<Compiler Name="NoCFGFileFound">True</Compiler>
|
||||||
|
<Compiler Name="MessageDirective">True</Compiler>
|
||||||
|
<Compiler Name="ImplicitVariants">True</Compiler>
|
||||||
|
<Compiler Name="UnicodeToLocale">True</Compiler>
|
||||||
|
<Compiler Name="LocaleToUnicode">True</Compiler>
|
||||||
|
<Compiler Name="ImagebaseMultiple">True</Compiler>
|
||||||
|
<Compiler Name="SuspiciousTypecast">True</Compiler>
|
||||||
|
<Compiler Name="PrivatePropAccessor">True</Compiler>
|
||||||
|
<Compiler Name="UnsafeType">False</Compiler>
|
||||||
|
<Compiler Name="UnsafeCode">False</Compiler>
|
||||||
|
<Compiler Name="UnsafeCast">False</Compiler>
|
||||||
|
<Compiler Name="OptionTruncated">True</Compiler>
|
||||||
|
<Compiler Name="WideCharReduced">True</Compiler>
|
||||||
|
<Compiler Name="DuplicatesIgnored">True</Compiler>
|
||||||
|
</Compiler>
|
||||||
|
<Linker>
|
||||||
|
<Linker Name="MapFile">0</Linker>
|
||||||
|
<Linker Name="OutputObjs">0</Linker>
|
||||||
|
<Linker Name="ConsoleApp">1</Linker>
|
||||||
|
<Linker Name="DebugInfo">False</Linker>
|
||||||
|
<Linker Name="RemoteSymbols">False</Linker>
|
||||||
|
<Linker Name="GenerateDRC">False</Linker>
|
||||||
|
<Linker Name="MinStackSize">16384</Linker>
|
||||||
|
<Linker Name="MaxStackSize">1048576</Linker>
|
||||||
|
<Linker Name="ImageBase">4194304</Linker>
|
||||||
|
<Linker Name="ExeDescription"></Linker>
|
||||||
|
</Linker>
|
||||||
|
<Directories>
|
||||||
|
<Directories Name="OutputDir">..\..</Directories>
|
||||||
|
<Directories Name="UnitOutputDir"></Directories>
|
||||||
|
<Directories Name="PackageDLLOutputDir"></Directories>
|
||||||
|
<Directories Name="PackageDCPOutputDir"></Directories>
|
||||||
|
<Directories Name="SearchPath"></Directories>
|
||||||
|
<Directories Name="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</Directories>
|
||||||
|
<Directories Name="Conditionals"></Directories>
|
||||||
|
<Directories Name="DebugSourceDirs"></Directories>
|
||||||
|
<Directories Name="UsePackages">False</Directories>
|
||||||
|
</Directories>
|
||||||
|
<Parameters>
|
||||||
|
<Parameters Name="RunParams"></Parameters>
|
||||||
|
<Parameters Name="HostApplication"></Parameters>
|
||||||
|
<Parameters Name="Launcher"></Parameters>
|
||||||
|
<Parameters Name="UseLauncher">False</Parameters>
|
||||||
|
<Parameters Name="DebugCWD"></Parameters>
|
||||||
|
</Parameters>
|
||||||
|
<VersionInfo>
|
||||||
|
<VersionInfo Name="IncludeVerInfo">True</VersionInfo>
|
||||||
|
<VersionInfo Name="AutoIncBuild">True</VersionInfo>
|
||||||
|
<VersionInfo Name="MajorVer">3</VersionInfo>
|
||||||
|
<VersionInfo Name="MinorVer">0</VersionInfo>
|
||||||
|
<VersionInfo Name="Release">0</VersionInfo>
|
||||||
|
<VersionInfo Name="Build">28</VersionInfo>
|
||||||
|
<VersionInfo Name="Debug">False</VersionInfo>
|
||||||
|
<VersionInfo Name="PreRelease">False</VersionInfo>
|
||||||
|
<VersionInfo Name="Special">False</VersionInfo>
|
||||||
|
<VersionInfo Name="Private">False</VersionInfo>
|
||||||
|
<VersionInfo Name="DLL">False</VersionInfo>
|
||||||
|
<VersionInfo Name="Locale">1043</VersionInfo>
|
||||||
|
<VersionInfo Name="CodePage">1252</VersionInfo>
|
||||||
|
</VersionInfo>
|
||||||
|
<VersionInfoKeys>
|
||||||
|
<VersionInfoKeys Name="CompanyName">Van de Sande Productions</VersionInfoKeys>
|
||||||
|
<VersionInfoKeys Name="FileDescription">VG - VPatch GUI</VersionInfoKeys>
|
||||||
|
<VersionInfoKeys Name="FileVersion">3.0.0.28</VersionInfoKeys>
|
||||||
|
<VersionInfoKeys Name="InternalName">VPatchGUI</VersionInfoKeys>
|
||||||
|
<VersionInfoKeys Name="LegalCopyright"></VersionInfoKeys>
|
||||||
|
<VersionInfoKeys Name="LegalTrademarks"></VersionInfoKeys>
|
||||||
|
<VersionInfoKeys Name="OriginalFilename">VPatchGUI.exe</VersionInfoKeys>
|
||||||
|
<VersionInfoKeys Name="ProductName">VPatch Graphical User Interface</VersionInfoKeys>
|
||||||
|
<VersionInfoKeys Name="ProductVersion">3.0</VersionInfoKeys>
|
||||||
|
<VersionInfoKeys Name="Comments">Official website: http://www.tibed.net/vpatch</VersionInfoKeys>
|
||||||
|
</VersionInfoKeys>
|
||||||
|
</Delphi.Personality>
|
||||||
|
</BorlandProject>
|
39
Contrib/VPatch/Source/GUI/VPatchGUI.cfg
Normal file
39
Contrib/VPatch/Source/GUI/VPatchGUI.cfg
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
-$A8
|
||||||
|
-$B-
|
||||||
|
-$C+
|
||||||
|
-$D+
|
||||||
|
-$E-
|
||||||
|
-$F-
|
||||||
|
-$G+
|
||||||
|
-$H+
|
||||||
|
-$I+
|
||||||
|
-$J-
|
||||||
|
-$K-
|
||||||
|
-$L+
|
||||||
|
-$M-
|
||||||
|
-$N+
|
||||||
|
-$O+
|
||||||
|
-$P+
|
||||||
|
-$Q-
|
||||||
|
-$R-
|
||||||
|
-$S-
|
||||||
|
-$T-
|
||||||
|
-$U-
|
||||||
|
-$V+
|
||||||
|
-$W-
|
||||||
|
-$X+
|
||||||
|
-$YD
|
||||||
|
-$Z1
|
||||||
|
-cg
|
||||||
|
-AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
|
||||||
|
-H+
|
||||||
|
-W+
|
||||||
|
-M
|
||||||
|
-$M16384,1048576
|
||||||
|
-K$00400000
|
||||||
|
-E"..\.."
|
||||||
|
-LE"K:\Documents and Settings\Koen van de Sande\My Documents\Borland Studio Projects\Bpl"
|
||||||
|
-LN"K:\Documents and Settings\Koen van de Sande\My Documents\Borland Studio Projects\Bpl"
|
||||||
|
-w-UNSAFE_TYPE
|
||||||
|
-w-UNSAFE_CODE
|
||||||
|
-w-UNSAFE_CAST
|
|
@ -1,87 +0,0 @@
|
||||||
[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=
|
|
|
@ -4,16 +4,16 @@ uses
|
||||||
Forms,
|
Forms,
|
||||||
MainForm in 'MainForm.pas' {frmMain},
|
MainForm in 'MainForm.pas' {frmMain},
|
||||||
PatchClasses in 'PatchClasses.pas',
|
PatchClasses in 'PatchClasses.pas',
|
||||||
VDSP_CRC in '..\GenPat\VDSP_CRC.pas',
|
|
||||||
DLLWrapper in 'DLLWrapper.pas',
|
DLLWrapper in 'DLLWrapper.pas',
|
||||||
AboutForm in 'AboutForm.pas' {frmAbout},
|
AboutForm in 'AboutForm.pas' {frmAbout},
|
||||||
PatchGenerator in '..\GenPat\PatchGenerator.pas',
|
VDSP_CRC in 'vdsp_crc.pas',
|
||||||
TreeCode in '..\GenPat\TreeCode.pas';
|
OSUtil in 'OSUtil.pas';
|
||||||
|
|
||||||
{$R *.res}
|
{$R *.res}
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Application.Initialize;
|
Application.Initialize;
|
||||||
|
Application.Title := 'VPatch GUI';
|
||||||
Application.CreateForm(TfrmMain, frmMain);
|
Application.CreateForm(TfrmMain, frmMain);
|
||||||
Application.Run;
|
Application.Run;
|
||||||
end.
|
end.
|
||||||
|
|
Binary file not shown.
5
Contrib/VPatch/Source/GUI/clean.bat
Normal file
5
Contrib/VPatch/Source/GUI/clean.bat
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
@echo off
|
||||||
|
echo Cleaning up all non-source files
|
||||||
|
del /S *.~*
|
||||||
|
del /S *.dcu
|
||||||
|
echo done.
|
120
Contrib/VPatch/Source/GenPat/Checksums.cpp
Normal file
120
Contrib/VPatch/Source/GenPat/Checksums.cpp
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Checksums.cpp
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// -=* VPatch *=-
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2001-2005 Koen van de Sande / Van de Sande Productions
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Website: http://www.tibed.net/vpatch
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source 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 source distribution.
|
||||||
|
|
||||||
|
#include "Checksums.h"
|
||||||
|
|
||||||
|
/* ------------------------ CRC32 checksum calculation ----------------- */
|
||||||
|
|
||||||
|
uint32_t CRCTable[256];
|
||||||
|
bool bInitCRC = false;
|
||||||
|
|
||||||
|
void InitCRC() {
|
||||||
|
int i, j; unsigned long c;
|
||||||
|
for (c = i = 0; i < 256; c = ++i) {
|
||||||
|
for (j = 0; j < 8; j++) {
|
||||||
|
if (c & 1) c = (c>>1) ^ 0xEDB88320;
|
||||||
|
else c >>= 1;
|
||||||
|
}
|
||||||
|
CRCTable[i] = c;
|
||||||
|
}
|
||||||
|
bInitCRC = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
crc32_t streamCRC32(bistream& data) {
|
||||||
|
if(!bInitCRC) InitCRC();
|
||||||
|
|
||||||
|
const int CRCBLOCKSIZE = 16384;
|
||||||
|
|
||||||
|
uint8_t block[CRCBLOCKSIZE];
|
||||||
|
unsigned int read;
|
||||||
|
uint8_t *p;
|
||||||
|
|
||||||
|
crc32_t crc = 0xFFFFFFFF;
|
||||||
|
while(data.good()) {
|
||||||
|
data.read(reinterpret_cast<char*>(block), CRCBLOCKSIZE);
|
||||||
|
read = data.gcount();
|
||||||
|
for (p = block; p < block + read; p++)
|
||||||
|
crc = CRCTable[(crc & 0xFF) ^ *p] ^ (crc >> 8);
|
||||||
|
}
|
||||||
|
crc = (crc ^ 0xFFFFFFFF);
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------ MD5 checksum calculation ----------------- */
|
||||||
|
|
||||||
|
void streamMD5(bistream& data, md5_byte_t digest[16]) {
|
||||||
|
const int MD5BLOCKSIZE = 16384;
|
||||||
|
uint8_t md5block[MD5BLOCKSIZE];
|
||||||
|
unsigned int read;
|
||||||
|
|
||||||
|
md5_state_t state;
|
||||||
|
|
||||||
|
md5_init(&state);
|
||||||
|
|
||||||
|
while(data.good()) {
|
||||||
|
data.read(reinterpret_cast<char*>(md5block), MD5BLOCKSIZE);
|
||||||
|
read = data.gcount();
|
||||||
|
md5_append(&state, md5block, read);
|
||||||
|
}
|
||||||
|
|
||||||
|
md5_finish(&state, digest);
|
||||||
|
}
|
||||||
|
|
||||||
|
TChecksum::TChecksum(std::string& fileName) : mode(MD5) {
|
||||||
|
bifstream data;
|
||||||
|
data.open(fileName.c_str(), ios::binary | ios::in);
|
||||||
|
data.seekg(0, ios::beg);
|
||||||
|
crc = streamCRC32(data);
|
||||||
|
data.close();
|
||||||
|
|
||||||
|
bifstream data2;
|
||||||
|
data2.open(fileName.c_str(), ios::binary | ios::in);
|
||||||
|
data2.seekg(0, ios::beg);
|
||||||
|
streamMD5(data2, digest);
|
||||||
|
data2.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TChecksum::loadMD5(md5_byte_t newdigest[16]) {
|
||||||
|
mode = MD5;
|
||||||
|
for(int i = 0; i < 16; i++) {
|
||||||
|
digest[i] = newdigest[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void TChecksum::loadCRC32(crc32_t newcrc) {
|
||||||
|
mode = CRC32;
|
||||||
|
crc = newcrc;
|
||||||
|
}
|
||||||
|
bool TChecksum::operator==(const TChecksum& b) {
|
||||||
|
if(mode != b.mode) throw "Checksums in different mode: MD5/CRC32";
|
||||||
|
if(mode == MD5) {
|
||||||
|
for(int md5index = 0; md5index < 16; md5index++) {
|
||||||
|
if(digest[md5index] != b.digest[md5index]) break;
|
||||||
|
if(md5index == 15) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return (crc == b.crc);
|
||||||
|
}
|
||||||
|
}
|
50
Contrib/VPatch/Source/GenPat/Checksums.h
Normal file
50
Contrib/VPatch/Source/GenPat/Checksums.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Checksums.h
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// -=* VPatch *=-
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2001-2005 Koen van de Sande / Van de Sande Productions
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Website: http://www.tibed.net/vpatch
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source 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 source distribution.
|
||||||
|
|
||||||
|
#if !defined(Checksums_H)
|
||||||
|
#define Checksums_H
|
||||||
|
|
||||||
|
#include "md5.h"
|
||||||
|
#include <string>
|
||||||
|
#include "GlobalTypes.h"
|
||||||
|
|
||||||
|
typedef uint32_t crc32_t;
|
||||||
|
|
||||||
|
class TChecksum {
|
||||||
|
public:
|
||||||
|
md5_byte_t digest[16];
|
||||||
|
crc32_t crc;
|
||||||
|
enum { CRC32, MD5 } mode;
|
||||||
|
|
||||||
|
TChecksum() : mode(MD5) { }
|
||||||
|
TChecksum(std::string& fileName);
|
||||||
|
|
||||||
|
void loadMD5(md5_byte_t newdigest[16]);
|
||||||
|
void loadCRC32(crc32_t newcrc);
|
||||||
|
|
||||||
|
bool operator==(const TChecksum& b);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // Checksums_H
|
95
Contrib/VPatch/Source/GenPat/ChunkedFile.cpp
Normal file
95
Contrib/VPatch/Source/GenPat/ChunkedFile.cpp
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// ChunkedFile.cpp
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// -=* VPatch *=-
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2001-2005 Koen van de Sande / Van de Sande Productions
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Website: http://www.tibed.net/vpatch
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source 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 source distribution.
|
||||||
|
|
||||||
|
|
||||||
|
#include "ChunkedFile.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
ChunkedFile::ChunkedFile(bistream& f, TFileOffset fSize, TFileOffset chunkSize) :
|
||||||
|
chunks(NULL) {
|
||||||
|
|
||||||
|
chunkCount = fSize / chunkSize;
|
||||||
|
cout << "[ChunkedFile] Filesize of " << static_cast<unsigned int>(fSize) << " gives " << static_cast<unsigned int>(chunkCount) << " chunks.\n";
|
||||||
|
|
||||||
|
cout << "[ChunkedFile] Memory to be used by those chunks: " << sizeof(FileChunk) * chunkCount << " bytes...";
|
||||||
|
if(chunkCount == 0) {
|
||||||
|
chunks = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
chunks = new FileChunk[chunkCount];
|
||||||
|
cout << " allocated.\n";
|
||||||
|
|
||||||
|
unsigned char* data = new unsigned char[chunkSize];
|
||||||
|
for(TFileOffset i = 0; i < chunkCount; i++) {
|
||||||
|
f.read(reinterpret_cast<char*>(data),chunkSize);
|
||||||
|
chunks[i].offset = i * chunkSize;
|
||||||
|
calculateChecksum(data,chunkSize,chunks[i].checksum);
|
||||||
|
}
|
||||||
|
delete[] data;
|
||||||
|
|
||||||
|
cout << "[ChunkedFile] Sorting chunks... ";
|
||||||
|
std::sort(chunks,chunks + chunkCount);
|
||||||
|
cout << "done.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool ChunkedFile::search(TChunkChecksum key, TFileOffset* start) {
|
||||||
|
// function:
|
||||||
|
// Searches sortedArray[first]..sortedArray[last] for key.
|
||||||
|
// returns: index of the matching element if it finds key,
|
||||||
|
// otherwise -(index where it could be inserted)-1.
|
||||||
|
// parameters:
|
||||||
|
// sortedArray in array of sorted (ascending) values.
|
||||||
|
// first, last in lower and upper subscript bounds
|
||||||
|
// key in value to search for.
|
||||||
|
// returns:
|
||||||
|
// index of key, or -insertion_position -1 if key is not
|
||||||
|
// in the array. This value can easily be
|
||||||
|
// transformed into the position to insert it.
|
||||||
|
if(chunkCount == 0) return false;
|
||||||
|
int first = 0;
|
||||||
|
int last = chunkCount - 1;
|
||||||
|
while (first <= last) {
|
||||||
|
int mid = (first + last) / 2; // compute mid point.
|
||||||
|
if(key == chunks[mid].checksum) {
|
||||||
|
while(true) {
|
||||||
|
if(mid == 0) break;
|
||||||
|
mid--;
|
||||||
|
if(!(key == chunks[mid].checksum)) {
|
||||||
|
mid++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*start = mid;
|
||||||
|
return true; // found it. return position
|
||||||
|
}
|
||||||
|
if (key < chunks[mid].checksum)
|
||||||
|
last = mid - 1; // repeat search in bottom half.
|
||||||
|
else
|
||||||
|
first = mid + 1; // repeat search in top half.
|
||||||
|
}
|
||||||
|
return false; // failed to find key
|
||||||
|
}
|
77
Contrib/VPatch/Source/GenPat/ChunkedFile.h
Normal file
77
Contrib/VPatch/Source/GenPat/ChunkedFile.h
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// ChunkedFile.h
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// -=* VPatch *=-
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2001-2005 Koen van de Sande / Van de Sande Productions
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Website: http://www.tibed.net/vpatch
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source 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 source distribution.
|
||||||
|
|
||||||
|
#if !defined(ChunkedFile_H)
|
||||||
|
#define ChunkedFile_H
|
||||||
|
|
||||||
|
#include "GlobalTypes.h"
|
||||||
|
#include "adler32.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
// private data type: the data tree information
|
||||||
|
typedef struct TChunkChecksum {
|
||||||
|
Checksum::uLong adler32;
|
||||||
|
CHECKSUM_BLOCK v;
|
||||||
|
} TChunkChecksum;
|
||||||
|
|
||||||
|
inline bool operator<(const TChunkChecksum& a, const TChunkChecksum& b) {
|
||||||
|
return (a.adler32 < b.adler32) ? true : (
|
||||||
|
(a.adler32 == b.adler32) ? (a.v < b.v) : false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
inline bool operator==(const TChunkChecksum& a, const TChunkChecksum& b) {
|
||||||
|
return (a.v == b.v) && (a.adler32 == b.adler32);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct FileChunk {
|
||||||
|
TFileOffset offset;
|
||||||
|
TChunkChecksum checksum;
|
||||||
|
} FileChunk;
|
||||||
|
|
||||||
|
inline bool operator<(const FileChunk& a, const FileChunk& b) {
|
||||||
|
return a.checksum < b.checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChunkedFile {
|
||||||
|
public:
|
||||||
|
TFileOffset chunkCount;
|
||||||
|
FileChunk* chunks;
|
||||||
|
|
||||||
|
ChunkedFile(bistream& f, TFileOffset fSize, TFileOffset chunkSize);
|
||||||
|
|
||||||
|
~ChunkedFile() {
|
||||||
|
if(chunks != NULL) delete[] chunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool search(TChunkChecksum key, TFileOffset* start);
|
||||||
|
|
||||||
|
inline void calculateChecksum(unsigned char* data, TFileOffset size, TChunkChecksum& K) {
|
||||||
|
K.v = *reinterpret_cast<CHECKSUM_BLOCK*>(data);
|
||||||
|
K.adler32 = Checksum::adler32(1L,data,size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ChunkedFile_H
|
243
Contrib/VPatch/Source/GenPat/FileFormat1.cpp
Normal file
243
Contrib/VPatch/Source/GenPat/FileFormat1.cpp
Normal file
|
@ -0,0 +1,243 @@
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// FileFormat1.cpp
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// -=* VPatch *=-
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2001-2005 Koen van de Sande / Van de Sande Productions
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Website: http://www.tibed.net/vpatch
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source 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 source distribution.
|
||||||
|
|
||||||
|
#include "FileFormat1.h"
|
||||||
|
#include "GlobalTypes.h"
|
||||||
|
|
||||||
|
#define MAGIC_VPAT 0x54415056
|
||||||
|
|
||||||
|
namespace FileFormat1 {
|
||||||
|
void writeByte(bostream& patch, TFileOffset dw) {
|
||||||
|
unsigned char b = dw & 0xFF;
|
||||||
|
patch.write(reinterpret_cast<char*>(&b),sizeof(b));
|
||||||
|
}
|
||||||
|
void writeWord(bostream& patch, TFileOffset dw) {
|
||||||
|
unsigned char b = dw & 0xFF;
|
||||||
|
patch.write(reinterpret_cast<char*>(&b),sizeof(b));
|
||||||
|
b = (dw & 0xFF00) >> 8;
|
||||||
|
patch.write(reinterpret_cast<char*>(&b),sizeof(b));
|
||||||
|
}
|
||||||
|
void writeDword(bostream& patch, TFileOffset dw) {
|
||||||
|
unsigned char b = dw & 0xFF;
|
||||||
|
patch.write(reinterpret_cast<char*>(&b),sizeof(b));
|
||||||
|
b = (dw & 0xFF00) >> 8;
|
||||||
|
patch.write(reinterpret_cast<char*>(&b),sizeof(b));
|
||||||
|
b = (dw & 0xFF0000) >> 16;
|
||||||
|
patch.write(reinterpret_cast<char*>(&b),sizeof(b));
|
||||||
|
b = (dw & 0xFF000000) >> 24;
|
||||||
|
patch.write(reinterpret_cast<char*>(&b),sizeof(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeMD5(bostream& patch, md5_byte_t digest[16]) {
|
||||||
|
for(int i = 0; i < 16; i++) {
|
||||||
|
writeByte(patch, digest[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TFileOffset readDword(bistream& patch) {
|
||||||
|
unsigned char b;
|
||||||
|
patch.read(reinterpret_cast<char*>(&b),sizeof(b));
|
||||||
|
TFileOffset dw = b;
|
||||||
|
patch.read(reinterpret_cast<char*>(&b),sizeof(b));
|
||||||
|
dw = dw | (b << 8);
|
||||||
|
patch.read(reinterpret_cast<char*>(&b),sizeof(b));
|
||||||
|
dw = dw | (b << 16);
|
||||||
|
patch.read(reinterpret_cast<char*>(&b),sizeof(b));
|
||||||
|
dw = dw | (b << 24);
|
||||||
|
return dw;
|
||||||
|
}
|
||||||
|
|
||||||
|
void readMD5(bistream& patch, md5_byte_t digest[16]) {
|
||||||
|
unsigned char b;
|
||||||
|
for(int i = 0; i < 16; i++) {
|
||||||
|
patch.read(reinterpret_cast<char*>(&b),sizeof(b));
|
||||||
|
digest[i] = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeFileCount(bostream& f, TFileOffset currentCount) {
|
||||||
|
f.seekp(4,ios::beg);
|
||||||
|
writeDword(f,currentCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
TFileOffset removeExistingPatch(bistream& in, TFileOffset inSize, bostream& out, TChecksum* removeCRC, bool existanceIsError) {
|
||||||
|
TFileOffset fileCount = 0x80000000; // MD5 mode
|
||||||
|
if(in.bad() || in.eof() || (inSize == 0)) { // empty file/does not yet exist
|
||||||
|
writeDword(out,MAGIC_VPAT);
|
||||||
|
writeDword(out,fileCount); // noFiles
|
||||||
|
return fileCount;
|
||||||
|
}
|
||||||
|
// copy and do stuff
|
||||||
|
if(readDword(in) != MAGIC_VPAT) {
|
||||||
|
writeDword(out,MAGIC_VPAT);
|
||||||
|
writeDword(out,fileCount); // noFiles
|
||||||
|
return fileCount;
|
||||||
|
}
|
||||||
|
fileCount = readDword(in);
|
||||||
|
writeDword(out,MAGIC_VPAT);
|
||||||
|
writeDword(out,fileCount); // noFiles
|
||||||
|
bool MD5Mode = (fileCount & 0x80000000) != 0;
|
||||||
|
|
||||||
|
if(MD5Mode) removeCRC->mode = TChecksum::MD5;
|
||||||
|
if(!MD5Mode) removeCRC->mode = TChecksum::CRC32;
|
||||||
|
|
||||||
|
// top byte is reserved for extensions
|
||||||
|
fileCount = fileCount & 0x00FFFFFF;
|
||||||
|
|
||||||
|
TFileOffset tempCount = fileCount;
|
||||||
|
for(TFileOffset i = 0; i < tempCount; i++) {
|
||||||
|
TFileOffset startOffset = in.tellg();
|
||||||
|
readDword(in); // noBlocks
|
||||||
|
TChecksum sourceChecksum;
|
||||||
|
if(!MD5Mode) {
|
||||||
|
crc32_t sourceCRC = readDword(in); // SourceCRC
|
||||||
|
readDword(in); // TargetCRC
|
||||||
|
sourceChecksum.loadCRC32(sourceCRC);
|
||||||
|
} else {
|
||||||
|
md5_byte_t digest[16];
|
||||||
|
readMD5(in, digest); // SourceCRC
|
||||||
|
sourceChecksum.loadMD5(digest);
|
||||||
|
readMD5(in, digest); // TargetCRC
|
||||||
|
}
|
||||||
|
TFileOffset bodySize = readDword(in); // bodySize
|
||||||
|
in.seekg(bodySize,ios::cur);
|
||||||
|
TFileOffset endOffset = in.tellg();
|
||||||
|
if(sourceChecksum == *removeCRC) {
|
||||||
|
if(existanceIsError) {
|
||||||
|
throw "Source file with the exact same contents already exists in patch!\nUse /R option (replace) to replace it with this patch!";
|
||||||
|
}
|
||||||
|
fileCount--;
|
||||||
|
} else {
|
||||||
|
// copy this patch to out
|
||||||
|
in.seekg(startOffset,ios::beg);
|
||||||
|
TFileOffset size = endOffset-startOffset;
|
||||||
|
char* buffer = new char[size];
|
||||||
|
in.read(buffer,size);
|
||||||
|
out.write(buffer,size);
|
||||||
|
delete[] buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TFileOffset curPos = out.tellp();
|
||||||
|
if(MD5Mode) fileCount = fileCount | 0x80000000;
|
||||||
|
writeFileCount(out,fileCount);
|
||||||
|
out.seekp(curPos,ios::beg);
|
||||||
|
return fileCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writePatch(bostream& patch, bistream& target, vector<SameBlock*>& sameBlocks, TChecksum* sourceCRC, TChecksum* targetCRC, TFileOffset currentFileCount, POSIX::ALT_FILETIME targetTime) {
|
||||||
|
TFileOffset bodySize = 0;
|
||||||
|
TFileOffset noBlocks = 0;
|
||||||
|
TFileOffset noBlocksOffset = patch.tellp();
|
||||||
|
writeDword(patch,noBlocks);
|
||||||
|
if(sourceCRC->mode == TChecksum::MD5) {
|
||||||
|
writeMD5(patch,sourceCRC->digest); // sourceCRC
|
||||||
|
writeMD5(patch,targetCRC->digest); // targetCRC
|
||||||
|
} else {
|
||||||
|
writeDword(patch,sourceCRC->crc); // sourceCRC
|
||||||
|
writeDword(patch,targetCRC->crc); // targetCRC
|
||||||
|
}
|
||||||
|
TFileOffset bodySizeOffset = patch.tellp();
|
||||||
|
writeDword(patch,bodySize);
|
||||||
|
|
||||||
|
for(vector<SameBlock*>::iterator iter = sameBlocks.begin(); iter != sameBlocks.end(); iter++) {
|
||||||
|
SameBlock* current = *iter;
|
||||||
|
|
||||||
|
// store current block
|
||||||
|
if(current->size > 0) {
|
||||||
|
// copy block from sourceFile
|
||||||
|
if(current->size < 256) {
|
||||||
|
writeByte(patch,1);
|
||||||
|
writeByte(patch,current->size);
|
||||||
|
bodySize += 2;
|
||||||
|
} else if(current->size < 65536) {
|
||||||
|
writeByte(patch,2);
|
||||||
|
writeWord(patch,current->size);
|
||||||
|
bodySize += 3;
|
||||||
|
} else {
|
||||||
|
writeByte(patch,3);
|
||||||
|
writeDword(patch,current->size);
|
||||||
|
bodySize += 5;
|
||||||
|
}
|
||||||
|
writeDword(patch,current->sourceOffset);
|
||||||
|
bodySize += 4;
|
||||||
|
noBlocks++;
|
||||||
|
}
|
||||||
|
iter++;
|
||||||
|
if(iter == sameBlocks.end()) break;
|
||||||
|
SameBlock* next = *iter;
|
||||||
|
iter--;
|
||||||
|
|
||||||
|
// calculate area inbetween this block and the next
|
||||||
|
TFileOffset notFoundStart = current->targetOffset+current->size;
|
||||||
|
if(notFoundStart > next->targetOffset) {
|
||||||
|
throw "makeBinaryPatch input problem: there was overlap";
|
||||||
|
}
|
||||||
|
TFileOffset notFoundSize = next->targetOffset - notFoundStart;
|
||||||
|
if(notFoundSize > 0) {
|
||||||
|
// we need to include this area in the patch directly
|
||||||
|
if(notFoundSize < 256) {
|
||||||
|
writeByte(patch,5);
|
||||||
|
writeByte(patch,notFoundSize);
|
||||||
|
bodySize += 2;
|
||||||
|
} else if(notFoundSize < 65536) {
|
||||||
|
writeByte(patch,6);
|
||||||
|
writeWord(patch,notFoundSize);
|
||||||
|
bodySize += 3;
|
||||||
|
} else {
|
||||||
|
writeByte(patch,7);
|
||||||
|
writeDword(patch,notFoundSize);
|
||||||
|
bodySize += 5;
|
||||||
|
}
|
||||||
|
// copy from target...
|
||||||
|
target.seekg(notFoundStart,ios::beg);
|
||||||
|
#define COPY_BUF_SIZE 4096
|
||||||
|
char copyBuffer[COPY_BUF_SIZE];
|
||||||
|
for(TFileOffset i = 0; i < notFoundSize; i += COPY_BUF_SIZE) {
|
||||||
|
TFileOffset j = notFoundSize - i;
|
||||||
|
if(j > COPY_BUF_SIZE) j = COPY_BUF_SIZE;
|
||||||
|
target.read(copyBuffer,j);
|
||||||
|
patch.write(copyBuffer,j);
|
||||||
|
}
|
||||||
|
bodySize += notFoundSize;
|
||||||
|
noBlocks++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// we are done, now add just one extra block with the target file time
|
||||||
|
writeByte(patch,255);
|
||||||
|
writeDword(patch,targetTime.dwLowDateTime);
|
||||||
|
writeDword(patch,targetTime.dwHighDateTime);
|
||||||
|
noBlocks++;
|
||||||
|
bodySize += 9;
|
||||||
|
|
||||||
|
TFileOffset curPos = patch.tellp();
|
||||||
|
patch.seekp(noBlocksOffset,ios::beg);
|
||||||
|
writeDword(patch,noBlocks);
|
||||||
|
patch.seekp(bodySizeOffset,ios::beg);
|
||||||
|
writeDword(patch,bodySize);
|
||||||
|
// do this at the end because it messes up file position
|
||||||
|
writeFileCount(patch,++currentFileCount);
|
||||||
|
patch.seekp(curPos,ios::beg);
|
||||||
|
}
|
||||||
|
}
|
41
Contrib/VPatch/Source/GenPat/FileFormat1.h
Normal file
41
Contrib/VPatch/Source/GenPat/FileFormat1.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// FileFormat1
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// -=* VPatch *=-
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2001-2005 Koen van de Sande / Van de Sande Productions
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Website: http://www.tibed.net/vpatch
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source 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 source distribution.
|
||||||
|
|
||||||
|
#if !defined(FileFormat1_H)
|
||||||
|
#define FileFormat1_H
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include "Checksums.h"
|
||||||
|
#include "PatchGenerator.h"
|
||||||
|
#include "POSIXUtil.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace FileFormat1 {
|
||||||
|
TFileOffset removeExistingPatch(bistream& in, TFileOffset inSize, bostream& out, TChecksum* removeCRC, bool existanceIsError);
|
||||||
|
void writePatch(bostream& patch, bistream& target, vector<SameBlock*>& sameBlocks, TChecksum* sourceCRC, TChecksum* targetCRC, TFileOffset currentFileCount, POSIX::ALT_FILETIME targetTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FileFormat1_H
|
|
@ -1,226 +0,0 @@
|
||||||
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.1 20031219 Koen Added error checking, handling, shouldn't
|
|
||||||
crash when invalid arguments, returns
|
|
||||||
exit codes now.
|
|
||||||
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, i: Integer;
|
|
||||||
S,Key: String;
|
|
||||||
SourceFile, TargetFile, PatchFile: String;
|
|
||||||
ShowDebug, ShowHelp: Boolean;
|
|
||||||
PG: TPatchGenerator;
|
|
||||||
EV: TEventHandler;
|
|
||||||
|
|
||||||
begin
|
|
||||||
EV:=TEventHandler.Create;
|
|
||||||
PG:=TPatchGenerator.Create;
|
|
||||||
PG.StartBlockSize:=64;
|
|
||||||
|
|
||||||
WriteLn('GenPat v2.1');
|
|
||||||
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}
|
|
||||||
i:=0;
|
|
||||||
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 else begin
|
|
||||||
// not a parameter?
|
|
||||||
if not (ParamStr(d)[1] = '/') then begin
|
|
||||||
if i = 2 then begin
|
|
||||||
PatchFile:=ParamStr(d);
|
|
||||||
Inc(i);
|
|
||||||
end;
|
|
||||||
if i = 1 then begin
|
|
||||||
TargetFile:=ParamStr(d);
|
|
||||||
Inc(i);
|
|
||||||
end;
|
|
||||||
if i = 0 then begin
|
|
||||||
SourceFile:=ParamStr(d);
|
|
||||||
Inc(i);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
ShowHelp:=False;
|
|
||||||
if(CompareStr(PatchFile,'')=0) then ShowHelp:=True;
|
|
||||||
if SourceFile = '' then ShowHelp:=True;
|
|
||||||
if TargetFile = '' then ShowHelp:=True;
|
|
||||||
|
|
||||||
if ShowHelp 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('/NOEQUALERROR Exit code becomes 0 instead of 10 when');
|
|
||||||
WriteLn(' two files with equal CRC are encountered');
|
|
||||||
WriteLn(' (patch file will remain unchanged)');
|
|
||||||
WriteLn('/DEBUG Show runtime debug information');
|
|
||||||
WriteLn;
|
|
||||||
WriteLn('Note: filenames should never start with / character!');
|
|
||||||
WriteLn;
|
|
||||||
WriteLn('Possible exit codes:');
|
|
||||||
WriteLn(' 0 Success');
|
|
||||||
WriteLn(' 1 Arguments missing');
|
|
||||||
WriteLn(' 2 Source file not found');
|
|
||||||
WriteLn(' 3 Target file not found');
|
|
||||||
WriteLn(' 4 Unknown error while reading existing patch file');
|
|
||||||
WriteLn(' 5 Unknown error while generating patch');
|
|
||||||
WriteLn(' 6 Unknown error while writing patch file to disk');
|
|
||||||
WriteLn(' 10 CRC of source and target file are equal (impossible with /NOEQUALERROR)');
|
|
||||||
WriteLn(' 11 Not enough memory for source file');
|
|
||||||
WriteLn(' 12 Not enough memory for target file');
|
|
||||||
PG.Free;
|
|
||||||
ExitCode:=1;
|
|
||||||
Exit;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// stop if file error, result shown above
|
|
||||||
if not FileExists(SourceFile) then begin
|
|
||||||
WriteLn('Error: Source file not found');
|
|
||||||
PG.Free;
|
|
||||||
ExitCode:=2;
|
|
||||||
Exit;
|
|
||||||
end;
|
|
||||||
if not FileExists(TargetFile) then begin
|
|
||||||
WriteLn('Error: Target file not found');
|
|
||||||
PG.Free;
|
|
||||||
ExitCode:=3;
|
|
||||||
Exit;
|
|
||||||
end;
|
|
||||||
|
|
||||||
if FileExists(PatchFile) then begin
|
|
||||||
WriteLn('Using existing file to include patches in: '+PatchFile);
|
|
||||||
try
|
|
||||||
PG.LoadFromFile(PatchFile);
|
|
||||||
except
|
|
||||||
on E: Exception do begin
|
|
||||||
WriteLn('Error: Reading existing patch file failed');
|
|
||||||
WriteLn('Error message: ', E.ClassName, ': ', E.Message);
|
|
||||||
PG.Free;
|
|
||||||
ExitCode:=4;
|
|
||||||
Exit;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
WriteLn('Source (original) file: ', SourceFile);
|
|
||||||
WriteLn('Target (newer) file: ', TargetFile);
|
|
||||||
|
|
||||||
T1:=Now;
|
|
||||||
|
|
||||||
// create patch file, with error handling
|
|
||||||
try
|
|
||||||
i:=PG.CreatePatch(SourceFile,TargetFile);
|
|
||||||
except
|
|
||||||
on E: Exception do begin
|
|
||||||
WriteLn('Error: Generating patch failed');
|
|
||||||
WriteLn('Error message: ', E.ClassName, ': ', E.Message);
|
|
||||||
PG.Free;
|
|
||||||
ExitCode:=5;
|
|
||||||
Exit;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
if(i < 0) then begin
|
|
||||||
if(i = -1) then begin
|
|
||||||
if not FindCmdLineSwitch('noequalerror',['/'],True) then
|
|
||||||
WriteLn('Error: CRC of source and target file are equal');
|
|
||||||
end;
|
|
||||||
if(i = -2) then WriteLn('Error: Not enough memory for source file');
|
|
||||||
if(i = -3) then WriteLn('Error: Not enough memory for target file');
|
|
||||||
ExitCode:=9 - i;
|
|
||||||
|
|
||||||
if(i = -1) and (FindCmdLineSwitch('noequalerror',['/'],True)) then begin
|
|
||||||
WriteLn('Equal CRCs ignored (no patch will be written and exit code is 0)');
|
|
||||||
ExitCode:=0;
|
|
||||||
end;
|
|
||||||
end else begin
|
|
||||||
WriteLn('Patch body size: '+IntToStr(i));
|
|
||||||
try
|
|
||||||
PG.WriteToFile(PatchFile);
|
|
||||||
except
|
|
||||||
on E: Exception do begin
|
|
||||||
WriteLn('Error: Writing patch to file ' + PatchFile + ' failed');
|
|
||||||
WriteLn('Error message: ', E.ClassName, ': ', E.Message);
|
|
||||||
PG.Free;
|
|
||||||
ExitCode:=6;
|
|
||||||
Exit;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
T2:=Now;
|
|
||||||
Write('Time taken for generation: ');
|
|
||||||
WriteLn(FloatToStr((T2-T1)*24*60*60),'s');
|
|
||||||
WriteLn;
|
|
||||||
|
|
||||||
ExitCode:=0;
|
|
||||||
end;
|
|
||||||
|
|
||||||
PG.Free;
|
|
||||||
end.
|
|
28
Contrib/VPatch/Source/GenPat/GlobalTypes.cpp
Normal file
28
Contrib/VPatch/Source/GenPat/GlobalTypes.cpp
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// GlobalTypes.cpp
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// -=* VPatch *=-
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2001-2005 Koen van de Sande / Van de Sande Productions
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Website: http://www.tibed.net/vpatch
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source 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 source distribution.
|
||||||
|
|
||||||
|
|
||||||
|
#include "GlobalTypes.h"
|
||||||
|
|
54
Contrib/VPatch/Source/GenPat/GlobalTypes.h
Normal file
54
Contrib/VPatch/Source/GenPat/GlobalTypes.h
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// GlobalTypes.h
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// -=* VPatch *=-
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2001-2005 Koen van de Sande / Van de Sande Productions
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Website: http://www.tibed.net/vpatch
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source 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 source distribution.
|
||||||
|
|
||||||
|
#if !defined(GlobalTypes_H)
|
||||||
|
#define GlobalTypes_H
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <ios>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
typedef unsigned char uint8_t;
|
||||||
|
typedef unsigned __int32 uint32_t;
|
||||||
|
typedef unsigned __int64 uint64_t;
|
||||||
|
#define CHECKSUM_BLOCK unsigned __int64
|
||||||
|
#define __WIN32__
|
||||||
|
#else
|
||||||
|
#define CHECKSUM_BLOCK unsigned long long
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef uint32_t TFileOffset;
|
||||||
|
typedef ifstream bifstream;
|
||||||
|
typedef istream bistream;
|
||||||
|
typedef ofstream bofstream;
|
||||||
|
typedef ostream bostream;
|
||||||
|
#endif // GlobalTypes_H
|
128
Contrib/VPatch/Source/GenPat/POSIXUtil.cpp
Normal file
128
Contrib/VPatch/Source/GenPat/POSIXUtil.cpp
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// POSIXUtil.cpp
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// -=* VPatch *=-
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2001-2005 Koen van de Sande / Van de Sande Productions
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Website: http://www.tibed.net/vpatch
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source 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 source distribution.
|
||||||
|
|
||||||
|
|
||||||
|
#include "POSIXUtil.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
/* My Borland/VC++ compiler do not have this file */
|
||||||
|
#if !defined(__BORLANDC__) && !defined(_MSC_VER)
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __WIN32__ /* The Windows way of getting a temp file needs windows.h*/
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace POSIX {
|
||||||
|
|
||||||
|
void TimeT_To_FILETIME(time_t t, ALT_FILETIME *pft ) {
|
||||||
|
uint64_t ll = (((uint64_t)t) *10000000L) + (((uint64_t)116444736L) * 1000000000L);
|
||||||
|
pft->dwLowDateTime = (uint32_t)(ll & 0xFFFFFFFF);
|
||||||
|
pft->dwHighDateTime = (uint32_t)((ll>>32)&0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __WIN32__
|
||||||
|
/* do it the old way on Win32, because POSIX does not get timezone stuff right */
|
||||||
|
ALT_FILETIME getFileTime(const char* sFileName) {
|
||||||
|
FILETIME temp;
|
||||||
|
GetSystemTimeAsFileTime(&temp);
|
||||||
|
HANDLE h = CreateFile(sFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
|
||||||
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
|
if (h == INVALID_HANDLE_VALUE) {
|
||||||
|
cerr << "Cannot read file time of " << sFileName << "\n";
|
||||||
|
} else {
|
||||||
|
GetFileTime(h, NULL, NULL, &temp);
|
||||||
|
CloseHandle(h);
|
||||||
|
}
|
||||||
|
ALT_FILETIME result;
|
||||||
|
result.dwHighDateTime = temp.dwHighDateTime;
|
||||||
|
result.dwLowDateTime = temp.dwLowDateTime;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ALT_FILETIME getFileTime(const char* sFileName) {
|
||||||
|
struct stat buf;
|
||||||
|
/* get current time first as a fall-back */
|
||||||
|
time_t currentTime = time(NULL);
|
||||||
|
|
||||||
|
if(stat(sFileName, &buf)) {
|
||||||
|
cerr << "Cannot read file time of " << sFileName << "\n";
|
||||||
|
} else {
|
||||||
|
/* get the time from the file */
|
||||||
|
currentTime = buf.st_mtime;
|
||||||
|
}
|
||||||
|
ALT_FILETIME result;
|
||||||
|
TimeT_To_FILETIME(currentTime, &result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t getFileSize(const char* sFileName) {
|
||||||
|
std::ifstream f;
|
||||||
|
f.open(sFileName, std::ios_base::binary | std::ios_base::in);
|
||||||
|
if (!f.good() || f.eof() || !f.is_open()) {
|
||||||
|
throw "File could not be read (getFileSize)";
|
||||||
|
}
|
||||||
|
f.seekg(0, std::ios_base::beg);
|
||||||
|
std::ifstream::pos_type begin_pos = f.tellg();
|
||||||
|
f.seekg(0, std::ios_base::end);
|
||||||
|
return static_cast<int>(f.tellg() - begin_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __WIN32__
|
||||||
|
string getTempFile() {
|
||||||
|
char buffer[MAX_PATH];
|
||||||
|
if(GetTempFileName(".","vpatch",0,buffer) == 0) {
|
||||||
|
cerr << "Cannot create temporary filename";
|
||||||
|
}
|
||||||
|
return string(buffer);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
//#ifdef POSIX
|
||||||
|
// This is a POSIX version of the function, together with #include <stdio.h>
|
||||||
|
// but I will not add it in a final release version.
|
||||||
|
string getTempFile() {
|
||||||
|
char filebuf [L_tmpnam];
|
||||||
|
|
||||||
|
// create a temporary filename
|
||||||
|
const char *fname = tmpnam (filebuf);
|
||||||
|
|
||||||
|
if (!fname)
|
||||||
|
cerr << "Cannot create temporary filename";
|
||||||
|
|
||||||
|
return string(fname);
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
44
Contrib/VPatch/Source/GenPat/POSIXUtil.h
Normal file
44
Contrib/VPatch/Source/GenPat/POSIXUtil.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// POSIXUtil.h
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// -=* VPatch *=-
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2001-2005 Koen van de Sande / Van de Sande Productions
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Website: http://www.tibed.net/vpatch
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source 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 source distribution.
|
||||||
|
|
||||||
|
#if !defined(POSIXUtil_H)
|
||||||
|
#define POSIXUtil_H
|
||||||
|
#include "GlobalTypes.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace POSIX {
|
||||||
|
typedef struct ALT_FILETIME {
|
||||||
|
uint32_t dwLowDateTime;
|
||||||
|
uint32_t dwHighDateTime;
|
||||||
|
} ALT_FILETIME;
|
||||||
|
|
||||||
|
ALT_FILETIME getFileTime(const char* sFileName);
|
||||||
|
uint32_t getFileSize(const char* sFileName);
|
||||||
|
string getTempFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // POSIXUtil_H
|
247
Contrib/VPatch/Source/GenPat/PatchGenerator.cpp
Normal file
247
Contrib/VPatch/Source/GenPat/PatchGenerator.cpp
Normal file
|
@ -0,0 +1,247 @@
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// PatchGenerator.cpp
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// -=* VPatch *=-
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2001-2005 Koen van de Sande / Van de Sande Productions
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Website: http://www.tibed.net/vpatch
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source 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 source distribution.
|
||||||
|
|
||||||
|
#include "PatchGenerator.h"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#define TARGET_BUFFER_SIZE 65536
|
||||||
|
#define TARGET_LOOKAHEAD_SIZE 4096
|
||||||
|
#define MAX_BLOCK_SIZE 16384
|
||||||
|
#define DEFAULT_MAX_MATCHES 500
|
||||||
|
|
||||||
|
PatchGenerator::PatchGenerator(bistream& source, TFileOffset sourceSize, bistream& target, TFileOffset targetSize, bostream& patch) :
|
||||||
|
source(source), sourceSize(sourceSize), target(target), targetSize(targetSize), patch(patch),
|
||||||
|
targetCData(NULL), targetCDataBaseOffset(0), targetCDataSize(0), blockSize(64), maxMatches(DEFAULT_MAX_MATCHES), beVerbose(false) {
|
||||||
|
targetCData = new unsigned char[TARGET_BUFFER_SIZE];
|
||||||
|
}
|
||||||
|
|
||||||
|
PatchGenerator::~PatchGenerator() {
|
||||||
|
if(targetCData != NULL) delete[] targetCData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PatchGenerator::execute(vector<SameBlock*>& sameBlocks) {
|
||||||
|
ChunkedFile* sourceTree = new ChunkedFile(source,sourceSize,blockSize);
|
||||||
|
|
||||||
|
// sameBlocks: this vector will store blocks that have been found to be the same
|
||||||
|
// between files
|
||||||
|
|
||||||
|
// the vector needs an 'empty' first block so checking for overlap with the
|
||||||
|
// 'previous' block never fails
|
||||||
|
SameBlock* firstBlock = new SameBlock;
|
||||||
|
firstBlock->sourceOffset = 0;
|
||||||
|
firstBlock->targetOffset = 0;
|
||||||
|
firstBlock->size = 0;
|
||||||
|
sameBlocks.push_back(firstBlock);
|
||||||
|
|
||||||
|
targetCDataBaseOffset = 0;
|
||||||
|
targetCDataSize = 0;
|
||||||
|
bool firstRun = true;
|
||||||
|
|
||||||
|
// currentOffset is in the target file
|
||||||
|
for(TFileOffset currentOffset = 0; currentOffset < targetSize; ) {
|
||||||
|
bool reloadTargetCData = true;
|
||||||
|
if((currentOffset >= targetCDataBaseOffset) &&
|
||||||
|
(currentOffset + TARGET_LOOKAHEAD_SIZE < targetCDataBaseOffset + TARGET_BUFFER_SIZE)) {
|
||||||
|
|
||||||
|
if(firstRun) {
|
||||||
|
firstRun = false;
|
||||||
|
} else {
|
||||||
|
reloadTargetCData = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(reloadTargetCData) {
|
||||||
|
// at least support looking back blockSize, if possible (findBlock relies on this!)
|
||||||
|
targetCDataBaseOffset = currentOffset - blockSize;
|
||||||
|
|
||||||
|
// handle start of file correctly
|
||||||
|
if(currentOffset < blockSize) targetCDataBaseOffset = 0;
|
||||||
|
|
||||||
|
targetCDataSize = TARGET_BUFFER_SIZE;
|
||||||
|
// check if this does not extend beyond EOF
|
||||||
|
if(targetCDataBaseOffset + targetCDataSize > targetSize) {
|
||||||
|
targetCDataSize = targetSize - targetCDataBaseOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we need to update the memory cache of target
|
||||||
|
cout << "[CacheReload] File position = " << static_cast<unsigned int>(targetCDataBaseOffset) << "\n";
|
||||||
|
|
||||||
|
target.seekg(targetCDataBaseOffset,ios::beg);
|
||||||
|
target.read(reinterpret_cast<char*>(targetCData),targetCDataSize);
|
||||||
|
}
|
||||||
|
//cout << currentOffset << " ";
|
||||||
|
|
||||||
|
SameBlock* currentSameBlock = findBlock(sourceTree,currentOffset);
|
||||||
|
|
||||||
|
if(currentSameBlock) {
|
||||||
|
// we have a match
|
||||||
|
SameBlock* previousBlock = sameBlocks.back();
|
||||||
|
if(previousBlock->targetOffset + previousBlock->size > currentSameBlock->targetOffset) {
|
||||||
|
// there is overlap, resolve it
|
||||||
|
TFileOffset difference = previousBlock->targetOffset + previousBlock->size - currentSameBlock->targetOffset;
|
||||||
|
currentSameBlock->sourceOffset += difference;
|
||||||
|
currentSameBlock->targetOffset += difference;
|
||||||
|
currentSameBlock->size -= difference;
|
||||||
|
}
|
||||||
|
sameBlocks.push_back(currentSameBlock);
|
||||||
|
|
||||||
|
// debug info
|
||||||
|
if(beVerbose) {
|
||||||
|
cout << "Block found: " << static_cast<unsigned int>(currentSameBlock->targetOffset)
|
||||||
|
<< " " << static_cast<unsigned int>(currentSameBlock->size)
|
||||||
|
<< " (source offset=" << static_cast<unsigned int>(currentSameBlock->sourceOffset) << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
currentOffset = currentSameBlock->targetOffset + currentSameBlock->size;
|
||||||
|
} else {
|
||||||
|
// no match, advance one byte
|
||||||
|
currentOffset++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add a block at the end, again to prevent bounds checking hassle
|
||||||
|
SameBlock* lastBlock = new SameBlock;
|
||||||
|
lastBlock->sourceOffset = 0;
|
||||||
|
lastBlock->targetOffset = targetSize;
|
||||||
|
lastBlock->size = 0;
|
||||||
|
sameBlocks.push_back(lastBlock);
|
||||||
|
delete sourceTree;
|
||||||
|
}
|
||||||
|
|
||||||
|
SameBlock* PatchGenerator::findBlock(ChunkedFile* sourceTree,
|
||||||
|
TFileOffset targetFileStartOffset) {
|
||||||
|
if(targetSize - targetFileStartOffset < blockSize) return NULL;
|
||||||
|
|
||||||
|
TFileOffset preDataSize = targetFileStartOffset - targetCDataBaseOffset;
|
||||||
|
//unsigned char* p = &(targetCData[preDataSize]);
|
||||||
|
// SameBlock* currentSameBlock = findBlock(sourceTree,p,preDataSize,
|
||||||
|
// targetCDataSize - preDataSize,
|
||||||
|
// currentOffset);
|
||||||
|
//unsigned char* targetData, // target data contains a memory part of target stream
|
||||||
|
//TFileOffset targetDataPreSize, // this specifies how many bytes we can access in front (required to be at least blockSize)
|
||||||
|
//TFileOffset targetDataSize, // this specifies how many bytes we can acces in the pointer (must be at least blockSize)
|
||||||
|
|
||||||
|
// read the current data part into memory
|
||||||
|
TChunkChecksum checksum;
|
||||||
|
sourceTree->calculateChecksum(&(targetCData[preDataSize]),blockSize,checksum);
|
||||||
|
|
||||||
|
TFileOffset foundIndex; // location into sourceTree chunks array of found chunk
|
||||||
|
if(sourceTree->search(checksum,&foundIndex)) {
|
||||||
|
// we found something
|
||||||
|
SameBlock* bestMatch = new SameBlock;
|
||||||
|
bestMatch->sourceOffset = sourceTree->chunks[foundIndex].offset;
|
||||||
|
bestMatch->targetOffset = targetFileStartOffset;
|
||||||
|
bestMatch->size = 0; // default to 0, because they can all be mismatches as well
|
||||||
|
|
||||||
|
// increase match size if possible, also check if it is a match at all
|
||||||
|
int matchCount = 0;
|
||||||
|
while((sourceTree->chunks[foundIndex].checksum == checksum) && ((maxMatches == 0) || (matchCount < maxMatches))) {
|
||||||
|
// check if this one is better than the current match
|
||||||
|
SameBlock match;
|
||||||
|
match.sourceOffset = sourceTree->chunks[foundIndex].offset;
|
||||||
|
match.targetOffset = targetFileStartOffset;
|
||||||
|
match.size = 0; // default to 0, could be a mismatch with the same key
|
||||||
|
improveSameBlockMatch(match,bestMatch->size);
|
||||||
|
if(match.size > bestMatch->size) {
|
||||||
|
*bestMatch = match;
|
||||||
|
}
|
||||||
|
foundIndex++;
|
||||||
|
matchCount++;
|
||||||
|
}
|
||||||
|
if(beVerbose) {
|
||||||
|
if(maxMatches != 0) {
|
||||||
|
if(matchCount == maxMatches) {
|
||||||
|
cout << "[FindBlock] Abort due to >" << static_cast<unsigned int>(maxMatches)
|
||||||
|
<< " matches; file position = " << static_cast<unsigned int>(targetFileStartOffset) << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(bestMatch->size == 0)
|
||||||
|
return NULL;
|
||||||
|
else
|
||||||
|
return bestMatch;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define COMPARISON_SIZE 2048
|
||||||
|
|
||||||
|
void PatchGenerator::improveSameBlockMatch(SameBlock& match, TFileOffset currentBest) {
|
||||||
|
// we should now try to make the match longer by reading big chunks of the
|
||||||
|
// files to come
|
||||||
|
source.seekg(match.sourceOffset + match.size,ios::beg);
|
||||||
|
target.seekg(match.targetOffset + match.size,ios::beg);
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
unsigned char sourceData[COMPARISON_SIZE];
|
||||||
|
unsigned char targetData[COMPARISON_SIZE];
|
||||||
|
|
||||||
|
TFileOffset startTarget = match.targetOffset + match.size;
|
||||||
|
TFileOffset startSource = match.sourceOffset + match.size;
|
||||||
|
TFileOffset checkSize = COMPARISON_SIZE;
|
||||||
|
if(checkSize > targetSize - startTarget) checkSize = targetSize - startTarget;
|
||||||
|
if(checkSize > sourceSize - startSource) checkSize = sourceSize - startSource;
|
||||||
|
if(checkSize == 0) break;
|
||||||
|
source.read(reinterpret_cast<char*>(sourceData),checkSize);
|
||||||
|
target.read(reinterpret_cast<char*>(targetData),checkSize);
|
||||||
|
TFileOffset i = 0;
|
||||||
|
while((sourceData[i] == targetData[i]) && (i < checkSize )) {
|
||||||
|
match.size++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
// check if we stopped because we had a mismatch
|
||||||
|
if(i < checkSize) break;
|
||||||
|
}
|
||||||
|
if(match.size < blockSize) {
|
||||||
|
match.size = 0;
|
||||||
|
} else {
|
||||||
|
// try to improve before match if this is useful
|
||||||
|
if(match.size + blockSize <= currentBest) return;
|
||||||
|
// do not do if there is no more data in the target...
|
||||||
|
if(match.targetOffset == 0) return;
|
||||||
|
|
||||||
|
// we know it is stored in the cache... so we just need the source one
|
||||||
|
unsigned char sourceData[MAX_BLOCK_SIZE];
|
||||||
|
|
||||||
|
TFileOffset startSource = match.sourceOffset - blockSize;
|
||||||
|
TFileOffset checkSize = blockSize;
|
||||||
|
if(checkSize > match.sourceOffset) {
|
||||||
|
checkSize = match.sourceOffset;
|
||||||
|
startSource = 0;
|
||||||
|
}
|
||||||
|
if(checkSize == 0) return;
|
||||||
|
source.seekg(startSource,ios::beg);
|
||||||
|
source.read(reinterpret_cast<char*>(sourceData),checkSize);
|
||||||
|
checkSize--;
|
||||||
|
while(sourceData[checkSize] == targetCData[match.targetOffset - targetCDataBaseOffset - 1]) {
|
||||||
|
match.targetOffset--;
|
||||||
|
match.sourceOffset--;
|
||||||
|
match.size++;
|
||||||
|
checkSize--;
|
||||||
|
if(checkSize == 0) break;
|
||||||
|
if(match.targetOffset == 0) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
72
Contrib/VPatch/Source/GenPat/PatchGenerator.h
Normal file
72
Contrib/VPatch/Source/GenPat/PatchGenerator.h
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// PatchGenerator.h
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// -=* VPatch *=-
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2001-2005 Koen van de Sande / Van de Sande Productions
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Website: http://www.tibed.net/vpatch
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source 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 source distribution.
|
||||||
|
|
||||||
|
#if !defined(PatchGenerator_H)
|
||||||
|
#define PatchGenerator_H
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include "GlobalTypes.h"
|
||||||
|
#include "ChunkedFile.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
typedef struct SameBlock {
|
||||||
|
TFileOffset sourceOffset;
|
||||||
|
TFileOffset targetOffset;
|
||||||
|
TFileOffset size;
|
||||||
|
} SameBlock;
|
||||||
|
|
||||||
|
class PatchGenerator {
|
||||||
|
protected:
|
||||||
|
bistream& source;
|
||||||
|
TFileOffset sourceSize;
|
||||||
|
bistream& target;
|
||||||
|
TFileOffset targetSize;
|
||||||
|
bostream& patch;
|
||||||
|
|
||||||
|
// cache
|
||||||
|
unsigned char* targetCData;
|
||||||
|
TFileOffset targetCDataBaseOffset;
|
||||||
|
TFileOffset targetCDataSize;
|
||||||
|
|
||||||
|
SameBlock* PatchGenerator::findBlock(ChunkedFile* sourceTree,
|
||||||
|
TFileOffset targetFileStartOffset);
|
||||||
|
// SameBlock* findBlock(ChunkedFile* sourceTree, unsigned char* targetData, TFileOffset targetStartOffset);
|
||||||
|
void improveSameBlockMatch(SameBlock& match, TFileOffset currentBest = 0);
|
||||||
|
public:
|
||||||
|
TFileOffset blockSize;
|
||||||
|
int maxMatches;
|
||||||
|
bool beVerbose;
|
||||||
|
|
||||||
|
// load in the source, target streams
|
||||||
|
PatchGenerator(bistream& source, TFileOffset sourceSize, bistream& target, TFileOffset targetSize, bostream& patch);
|
||||||
|
~PatchGenerator();
|
||||||
|
|
||||||
|
// construct the actual patch
|
||||||
|
void execute(vector<SameBlock*>& sameBlocks);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PatchGenerator_H
|
|
@ -1,615 +0,0 @@
|
||||||
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.1 20031219 Koen Added error checking to CreatePatch, returns
|
|
||||||
negative numbers when there are errors.
|
|
||||||
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+fmShareDenyNone);
|
|
||||||
fsTarget:=TFileStream.Create(TargetFileName,fmOpenRead+fmShareDenyNone);
|
|
||||||
fm:=TMemoryStream.Create;
|
|
||||||
|
|
||||||
SetLength(PRay,INIT_BLOCK_COUNT);
|
|
||||||
SetLength(NRay,INIT_BLOCK_COUNT);
|
|
||||||
|
|
||||||
//Load those files into memory!
|
|
||||||
SourceSize:=fsSource.Size;
|
|
||||||
try
|
|
||||||
GetMem(Source,SourceSize);
|
|
||||||
except
|
|
||||||
on EOutOfMemory do begin
|
|
||||||
Result:=-2; // not enough memory for source file
|
|
||||||
Exit;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
fm.CopyFrom(fsSource,SourceSize);
|
|
||||||
Move(fm.Memory^,Source^,SourceSize);
|
|
||||||
SourceCRC:=FileCRC(fsSource);
|
|
||||||
fsSource.Free;
|
|
||||||
|
|
||||||
fm.Clear;
|
|
||||||
TargetSize:=fsTarget.Size;
|
|
||||||
try
|
|
||||||
GetMem(Target,TargetSize);
|
|
||||||
except
|
|
||||||
on EOutOfMemory do begin
|
|
||||||
FreeMem(Source,SourceSize);
|
|
||||||
Result:=-3; // not enough memory for target file
|
|
||||||
Exit;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
fm.CopyFrom(fsTarget,TargetSize);
|
|
||||||
Move(fm.Memory^,Target^,TargetSize);
|
|
||||||
TargetCRC:=FileCRC(fsTarget);
|
|
||||||
fsTarget.Free;
|
|
||||||
fm.Free;
|
|
||||||
|
|
||||||
if(SourceCRC = TargetCRC) then begin
|
|
||||||
FreeMem(Source,SourceSize);
|
|
||||||
FreeMem(Target,TargetSize);
|
|
||||||
Result:=-1;
|
|
||||||
Exit;
|
|
||||||
end;
|
|
||||||
|
|
||||||
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.
|
|
20
Contrib/VPatch/Source/GenPat/SConscript
Normal file
20
Contrib/VPatch/Source/GenPat/SConscript
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
target = "GenPat"
|
||||||
|
|
||||||
|
files = Split("""
|
||||||
|
adler32.cpp
|
||||||
|
Checksums.cpp
|
||||||
|
ChunkedFile.cpp
|
||||||
|
FileFormat1.cpp
|
||||||
|
GlobalTypes.cpp
|
||||||
|
main.cpp
|
||||||
|
md5.c
|
||||||
|
PatchGenerator.cpp
|
||||||
|
POSIXUtil.cpp
|
||||||
|
""")
|
||||||
|
|
||||||
|
libs = Split("""
|
||||||
|
""")
|
||||||
|
|
||||||
|
Import('BuildUtil defenv')
|
||||||
|
|
||||||
|
BuildUtil(target, files, libs, flags = ['$EXCEPTION_FLAG'], install = 'Bin')
|
|
@ -1,251 +0,0 @@
|
||||||
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.1 20031219 Koen Fixed bug in TreeFind: when tree was a nil
|
|
||||||
pointer, now returns instead of AVing
|
|
||||||
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
|
|
||||||
if not Assigned(ABlockTree) then begin
|
|
||||||
FoundCount:=0; Result:=nil;
|
|
||||||
Exit;
|
|
||||||
end;
|
|
||||||
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.
|
|
|
@ -1,77 +0,0 @@
|
||||||
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.
|
|
||||||
|
|
92
Contrib/VPatch/Source/GenPat/adler32.cpp
Normal file
92
Contrib/VPatch/Source/GenPat/adler32.cpp
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
/* adler32.c -- compute the Adler-32 checksum of a data stream
|
||||||
|
* Copyright (C) 1995-2003 Mark Adler
|
||||||
|
|
||||||
|
THIS IS A MODIFIED VERSION OF THE ORIGINAL ZLIB adler32.c!
|
||||||
|
|
||||||
|
The following was copied from zlib.h:
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source 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 source distribution.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "adler32.h"
|
||||||
|
|
||||||
|
#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
|
||||||
|
|
||||||
|
#define BASE 65521UL /* largest prime smaller than 65536 */
|
||||||
|
#define NMAX 5552
|
||||||
|
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
|
||||||
|
|
||||||
|
#define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
|
||||||
|
#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
|
||||||
|
#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
|
||||||
|
#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
|
||||||
|
#define DO16(buf) DO8(buf,0); DO8(buf,8);
|
||||||
|
|
||||||
|
#ifdef NO_DIVIDE
|
||||||
|
# define MOD(a) \
|
||||||
|
do { \
|
||||||
|
if (a >= (BASE << 16)) a -= (BASE << 16); \
|
||||||
|
if (a >= (BASE << 15)) a -= (BASE << 15); \
|
||||||
|
if (a >= (BASE << 14)) a -= (BASE << 14); \
|
||||||
|
if (a >= (BASE << 13)) a -= (BASE << 13); \
|
||||||
|
if (a >= (BASE << 12)) a -= (BASE << 12); \
|
||||||
|
if (a >= (BASE << 11)) a -= (BASE << 11); \
|
||||||
|
if (a >= (BASE << 10)) a -= (BASE << 10); \
|
||||||
|
if (a >= (BASE << 9)) a -= (BASE << 9); \
|
||||||
|
if (a >= (BASE << 8)) a -= (BASE << 8); \
|
||||||
|
if (a >= (BASE << 7)) a -= (BASE << 7); \
|
||||||
|
if (a >= (BASE << 6)) a -= (BASE << 6); \
|
||||||
|
if (a >= (BASE << 5)) a -= (BASE << 5); \
|
||||||
|
if (a >= (BASE << 4)) a -= (BASE << 4); \
|
||||||
|
if (a >= (BASE << 3)) a -= (BASE << 3); \
|
||||||
|
if (a >= (BASE << 2)) a -= (BASE << 2); \
|
||||||
|
if (a >= (BASE << 1)) a -= (BASE << 1); \
|
||||||
|
if (a >= BASE) a -= BASE; \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
# define MOD(a) a %= BASE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Checksum {
|
||||||
|
|
||||||
|
/* ========================================================================= */
|
||||||
|
uLong adler32(uLong adler, const Byte *buf, uInt len) {
|
||||||
|
unsigned long s1 = adler & 0xffff;
|
||||||
|
unsigned long s2 = (adler >> 16) & 0xffff;
|
||||||
|
int k;
|
||||||
|
|
||||||
|
if (buf == Z_NULL) return 1L;
|
||||||
|
|
||||||
|
while (len > 0) {
|
||||||
|
k = len < NMAX ? (int)len : NMAX;
|
||||||
|
len -= k;
|
||||||
|
while (k >= 16) {
|
||||||
|
DO16(buf);
|
||||||
|
buf += 16;
|
||||||
|
k -= 16;
|
||||||
|
}
|
||||||
|
if (k != 0) do {
|
||||||
|
s1 += *buf++;
|
||||||
|
s2 += s1;
|
||||||
|
} while (--k);
|
||||||
|
MOD(s1);
|
||||||
|
MOD(s2);
|
||||||
|
}
|
||||||
|
return (s2 << 16) | s1;
|
||||||
|
}
|
||||||
|
}
|
18
Contrib/VPatch/Source/GenPat/adler32.h
Normal file
18
Contrib/VPatch/Source/GenPat/adler32.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Adler32
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#if !defined(Adler32_H)
|
||||||
|
#define Adler32_H
|
||||||
|
|
||||||
|
namespace Checksum {
|
||||||
|
typedef unsigned int uInt; /* 16 bits or more */
|
||||||
|
typedef unsigned long uLong; /* 32 bits or more */
|
||||||
|
typedef unsigned char Byte; /* 8 bits */
|
||||||
|
|
||||||
|
uLong adler32(uLong adler, const Byte *buf, uInt len);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // Adler32_H
|
||||||
|
|
||||||
|
|
292
Contrib/VPatch/Source/GenPat/main.cpp
Normal file
292
Contrib/VPatch/Source/GenPat/main.cpp
Normal file
|
@ -0,0 +1,292 @@
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// main.cpp
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// -=* VPatch *=-
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2001-2005 Koen van de Sande / Van de Sande Productions
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Website: http://www.tibed.net/vpatch
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source 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 source distribution.
|
||||||
|
|
||||||
|
#ifdef __BORLANDC__
|
||||||
|
#pragma argsused
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__BORLANDC__) && !defined(_MSC_VER)
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "GlobalTypes.h"
|
||||||
|
#include "POSIXUtil.h"
|
||||||
|
#include "Checksums.h"
|
||||||
|
#include "PatchGenerator.h"
|
||||||
|
#include "FileFormat1.h"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
int main( int argc, char * argv[] ) {
|
||||||
|
cout << "GenPat v3.1\n";
|
||||||
|
cout << "===========\n\n(c) 2001-2005 Van de Sande Productions\n";
|
||||||
|
cout << "Website: http://www.tibed.net/vpatch\n\n";
|
||||||
|
|
||||||
|
string sourceFileName;
|
||||||
|
string targetFileName;
|
||||||
|
string patchFileName;
|
||||||
|
|
||||||
|
bool showHelp = true;
|
||||||
|
|
||||||
|
int blockSize = 64;
|
||||||
|
int maxMatches = 500;
|
||||||
|
bool beVerbose = false;
|
||||||
|
bool beOptimal = false;
|
||||||
|
bool existanceIsError = true; // flag error if patch already has source's MD5/CRC32?
|
||||||
|
int fileNameArgument = 0;
|
||||||
|
if(argc > 1) {
|
||||||
|
for(int i = 1; i < argc; i++) {
|
||||||
|
string s(argv[i]);
|
||||||
|
if(s.size() > 0) {
|
||||||
|
if(s[0] == '/') {
|
||||||
|
if(s.size() > 1) {
|
||||||
|
if((s[1] == 'v') || (s[1] == 'V')) {
|
||||||
|
beVerbose = true;
|
||||||
|
}
|
||||||
|
if((s[1] == 'o') || (s[1] == 'O')) {
|
||||||
|
beOptimal = true;
|
||||||
|
}
|
||||||
|
if((s[1] == 'r') || (s[1] == 'R')) {
|
||||||
|
existanceIsError = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(s.size() > 2) {
|
||||||
|
if((s[1] == 'b') || (s[1] == 'B')) {
|
||||||
|
if(s[2] == '=') {
|
||||||
|
istringstream ss(s.substr(3));
|
||||||
|
ss >> blockSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if((s[1] == 'a') || (s[1] == 'A')) {
|
||||||
|
if(s[2] == '=') {
|
||||||
|
istringstream ss(s.substr(3));
|
||||||
|
ss >> maxMatches;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (fileNameArgument) {
|
||||||
|
case 0:
|
||||||
|
sourceFileName = s;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
targetFileName = s;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
patchFileName = s;
|
||||||
|
showHelp = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cerr << "WARNING: extra filename argument not used: " << s << "\n";
|
||||||
|
}
|
||||||
|
fileNameArgument++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(beOptimal) {
|
||||||
|
maxMatches = 0;
|
||||||
|
}
|
||||||
|
if(showHelp) {
|
||||||
|
cout << "This program will take (sourcefile) as input and create a (patchfile).\n";
|
||||||
|
cout << "With this patchfile, you can convert a (sourcefile) into (targetfile).\n\n";
|
||||||
|
cout << "Command line info:\n";
|
||||||
|
cout << " GENPAT (sourcefile) (targetfile) (patchfile)\n\n";
|
||||||
|
|
||||||
|
cout << "Command line option (optional):\n";
|
||||||
|
cout << "/R Replace a patch with same contents as source silently if it\n already exists.\n";
|
||||||
|
cout << "/B=64 Set blocksize (default=64), multiple of 2 is required.\n";
|
||||||
|
cout << "/V More verbose information during patch creation.\n";
|
||||||
|
cout << "/O Deactivate match limit of the /A switch (sometimes smaller patches).\n";
|
||||||
|
cout << "/A=500 Maximum number of block matches per block (improves performance).\n";
|
||||||
|
cout << " Default is 500, larger is slower. Use /V to see the cut-off aborts.\n\n";
|
||||||
|
cout << "Note: filenames should never start with / character!\n\n";
|
||||||
|
cout << "Possible exit codes:\n";
|
||||||
|
cout << " 0 Success\n";
|
||||||
|
cout << " 1 Arguments missing\n";
|
||||||
|
cout << " 2 Other error\n";
|
||||||
|
cout << " 3 Source file already has a patch in specified patch file (=error)\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << "[Source] " << sourceFileName.c_str() << "\n";
|
||||||
|
cout << "[Target] " << targetFileName.c_str() << "\n[PatchFile] " << patchFileName.c_str() << "\n";
|
||||||
|
|
||||||
|
// get the file sizes
|
||||||
|
TFileOffset sourceSize = 0;
|
||||||
|
try {
|
||||||
|
sourceSize = POSIX::getFileSize(sourceFileName.c_str());
|
||||||
|
}
|
||||||
|
catch(char* s) {
|
||||||
|
cerr << "Source file size reading failed: " << s << "\n";
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
TFileOffset targetSize;
|
||||||
|
try {
|
||||||
|
targetSize = POSIX::getFileSize(targetFileName.c_str());
|
||||||
|
}
|
||||||
|
catch(const char* s) {
|
||||||
|
cerr << "Target file size reading failed: " << s << "\n";
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate CRCs
|
||||||
|
TChecksum* sourceCRC = new TChecksum(sourceFileName);
|
||||||
|
sourceCRC->mode = TChecksum::MD5; // default
|
||||||
|
TChecksum* targetCRC = new TChecksum(targetFileName);
|
||||||
|
targetCRC->mode = TChecksum::MD5; // default
|
||||||
|
|
||||||
|
string tempFileName = POSIX::getTempFile();
|
||||||
|
|
||||||
|
// open the files
|
||||||
|
bifstream source;
|
||||||
|
source.open(sourceFileName.c_str(), std::ios_base::binary | std::ios_base::in);
|
||||||
|
bifstream target;
|
||||||
|
target.open(targetFileName.c_str(), std::ios_base::binary | std::ios_base::in);
|
||||||
|
bofstream patch;
|
||||||
|
patch.open(tempFileName.c_str(), std::ios_base::binary | std::ios_base::out);
|
||||||
|
|
||||||
|
// remove existing patch with sourceCRC
|
||||||
|
TFileOffset fileCount = 0;
|
||||||
|
while(true) {
|
||||||
|
TFileOffset previousPatchSize;
|
||||||
|
try {
|
||||||
|
previousPatchSize = POSIX::getFileSize(patchFileName.c_str());
|
||||||
|
} catch(const char* s) {
|
||||||
|
cout << "Patch file does not yet exist: " << s << ", it will be created.\n";
|
||||||
|
std::ofstream newfile;
|
||||||
|
newfile.open(patchFileName.c_str(), std::ios_base::binary | std::ios_base::out);
|
||||||
|
newfile.close();
|
||||||
|
}
|
||||||
|
bifstream previousPatch;
|
||||||
|
previousPatch.open(patchFileName.c_str(), std::ios_base::binary | std::ios_base::in);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// this will copy the contents of previousPatch to patch, but without sourceCRC
|
||||||
|
fileCount = FileFormat1::removeExistingPatch(previousPatch,previousPatchSize,patch,sourceCRC,existanceIsError);
|
||||||
|
} catch(const char* s) {
|
||||||
|
cerr << "ERROR: " << s << "\n";
|
||||||
|
patch.close();
|
||||||
|
unlink(tempFileName.c_str());
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set them to the same checksum mode
|
||||||
|
targetCRC->mode = sourceCRC->mode;
|
||||||
|
cout << "[Checksum] Kind of checksums used: ";
|
||||||
|
if(targetCRC->mode == TChecksum::MD5) cout << "MD5\n";
|
||||||
|
if(targetCRC->mode == TChecksum::CRC32) cout << "CRC32\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(source.good() && target.good() && patch.good()) {
|
||||||
|
PatchGenerator* gen = new PatchGenerator(source,sourceSize,target,targetSize,patch);
|
||||||
|
try {
|
||||||
|
// clean up the blocksize to be a multiple of 2
|
||||||
|
int orgBlockSize = blockSize;
|
||||||
|
int bs_counter = 0;
|
||||||
|
while(blockSize != 0) {
|
||||||
|
bs_counter++;
|
||||||
|
blockSize >>= 1;
|
||||||
|
}
|
||||||
|
blockSize = 1;
|
||||||
|
while(bs_counter != 0) {
|
||||||
|
blockSize <<= 1;
|
||||||
|
bs_counter--;
|
||||||
|
}
|
||||||
|
if((blockSize >> 1) == orgBlockSize) blockSize = orgBlockSize;
|
||||||
|
if(blockSize != orgBlockSize) {
|
||||||
|
cout << "[BlockSizeFix] Your blocksize had to be fixed since it is not a multiple of 2\n";
|
||||||
|
}
|
||||||
|
if(blockSize < 16) {
|
||||||
|
blockSize = 16;
|
||||||
|
cout << "[BlockSizeFix] Your blocksize had to be fixed since it is smaller than 16\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
gen->blockSize = blockSize;
|
||||||
|
cout << "[BlockSize] " << static_cast<unsigned int>(gen->blockSize) << " bytes\n";
|
||||||
|
|
||||||
|
gen->maxMatches = maxMatches;
|
||||||
|
if(gen->maxMatches == 0) {
|
||||||
|
cout << "[FindBlockMatchLimit] Unlimited matches\n";
|
||||||
|
} else {
|
||||||
|
cout << "[FindBlockMatchLimit] " << gen->maxMatches << " matches\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
gen->beVerbose = beVerbose;
|
||||||
|
if(beVerbose) {
|
||||||
|
cout << "[Debug] Verbose output during patch generation activated.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// create sameBlock storage
|
||||||
|
vector<SameBlock*> sameBlocks;
|
||||||
|
// run the patch generator to find similar blocks
|
||||||
|
gen->execute(sameBlocks);
|
||||||
|
// construct the actual patch in FileFormat1
|
||||||
|
FileFormat1::writePatch(patch,target,sameBlocks,sourceCRC,targetCRC,fileCount,POSIX::getFileTime(targetFileName.c_str()));
|
||||||
|
// cleanup sameblocks
|
||||||
|
for(vector<SameBlock*>::iterator iter = sameBlocks.begin(); iter != sameBlocks.end(); iter++) {
|
||||||
|
delete *iter;
|
||||||
|
*iter = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
patch.close();
|
||||||
|
TFileOffset patchSize = POSIX::getFileSize(tempFileName.c_str());
|
||||||
|
|
||||||
|
// finally: copy the temporary file to the actual patch
|
||||||
|
bifstream tempF;
|
||||||
|
tempF.open(tempFileName.c_str(), std::ios_base::binary | std::ios_base::in);
|
||||||
|
bofstream patchF;
|
||||||
|
patchF.open(patchFileName.c_str(), std::ios_base::binary | std::ios_base::out);
|
||||||
|
char* buf = new char[patchSize];
|
||||||
|
tempF.read(buf,patchSize);
|
||||||
|
patchF.write(buf,patchSize);
|
||||||
|
delete[] buf;
|
||||||
|
tempF.close();
|
||||||
|
|
||||||
|
// now empty the temporary file
|
||||||
|
std::ofstream clearF;
|
||||||
|
clearF.open(tempFileName.c_str(), std::ios_base::binary | std::ios_base::out);
|
||||||
|
}
|
||||||
|
catch(string s) {
|
||||||
|
cerr << "Error thrown: " << s.c_str();
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
catch(const char* s) {
|
||||||
|
cerr << "Error thrown: " << s;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cerr << "There was a problem opening the files.\n";
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if(*sourceCRC == *targetCRC)
|
||||||
|
cerr << "WARNING: source and target file have equal CRCs!";
|
||||||
|
delete sourceCRC;
|
||||||
|
delete targetCRC;
|
||||||
|
unlink(tempFileName.c_str());
|
||||||
|
return 0;
|
||||||
|
}
|
389
Contrib/VPatch/Source/GenPat/md5.c
Normal file
389
Contrib/VPatch/Source/GenPat/md5.c
Normal file
|
@ -0,0 +1,389 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source 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 source distribution.
|
||||||
|
|
||||||
|
L. Peter Deutsch
|
||||||
|
ghost@aladdin.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
|
||||||
|
/*
|
||||||
|
Independent implementation of MD5 (RFC 1321).
|
||||||
|
|
||||||
|
This code implements the MD5 Algorithm defined in RFC 1321, whose
|
||||||
|
text is available at
|
||||||
|
http://www.ietf.org/rfc/rfc1321.txt
|
||||||
|
The code is derived from the text of the RFC, including the test suite
|
||||||
|
(section A.5) but excluding the rest of Appendix A. It does not include
|
||||||
|
any code or documentation that is identified in the RFC as being
|
||||||
|
copyrighted.
|
||||||
|
|
||||||
|
The original and principal author of md5.c is L. Peter Deutsch
|
||||||
|
<ghost@aladdin.com>. Other authors are noted in the change history
|
||||||
|
that follows (in reverse chronological order):
|
||||||
|
|
||||||
|
2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
|
||||||
|
either statically or dynamically; added missing #include <string.h>
|
||||||
|
in library.
|
||||||
|
2002-03-11 lpd Corrected argument list for main(), and added int return
|
||||||
|
type, in test program and T value program.
|
||||||
|
2002-02-21 lpd Added missing #include <stdio.h> in test program.
|
||||||
|
2000-07-03 lpd Patched to eliminate warnings about "constant is
|
||||||
|
unsigned in ANSI C, signed in traditional"; made test program
|
||||||
|
self-checking.
|
||||||
|
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
|
||||||
|
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
|
||||||
|
1999-05-03 lpd Original version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "md5.h"
|
||||||
|
|
||||||
|
void memcpy2( void *dest, const void *src, int count ) {
|
||||||
|
md5_byte_t* bDest = (md5_byte_t*)dest;
|
||||||
|
md5_byte_t* bSrc = (md5_byte_t*)src;
|
||||||
|
int i = 0;
|
||||||
|
for(; i < count; i++) {
|
||||||
|
bDest[i] = bSrc[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
|
||||||
|
#ifdef ARCH_IS_BIG_ENDIAN
|
||||||
|
# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
|
||||||
|
#else
|
||||||
|
# define BYTE_ORDER 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define T_MASK ((md5_word_t)~0)
|
||||||
|
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
|
||||||
|
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
|
||||||
|
#define T3 0x242070db
|
||||||
|
#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
|
||||||
|
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
|
||||||
|
#define T6 0x4787c62a
|
||||||
|
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
|
||||||
|
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
|
||||||
|
#define T9 0x698098d8
|
||||||
|
#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
|
||||||
|
#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
|
||||||
|
#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
|
||||||
|
#define T13 0x6b901122
|
||||||
|
#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
|
||||||
|
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
|
||||||
|
#define T16 0x49b40821
|
||||||
|
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
|
||||||
|
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
|
||||||
|
#define T19 0x265e5a51
|
||||||
|
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
|
||||||
|
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
|
||||||
|
#define T22 0x02441453
|
||||||
|
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
|
||||||
|
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
|
||||||
|
#define T25 0x21e1cde6
|
||||||
|
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
|
||||||
|
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
|
||||||
|
#define T28 0x455a14ed
|
||||||
|
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
|
||||||
|
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
|
||||||
|
#define T31 0x676f02d9
|
||||||
|
#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
|
||||||
|
#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
|
||||||
|
#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
|
||||||
|
#define T35 0x6d9d6122
|
||||||
|
#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
|
||||||
|
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
|
||||||
|
#define T38 0x4bdecfa9
|
||||||
|
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
|
||||||
|
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
|
||||||
|
#define T41 0x289b7ec6
|
||||||
|
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
|
||||||
|
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
|
||||||
|
#define T44 0x04881d05
|
||||||
|
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
|
||||||
|
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
|
||||||
|
#define T47 0x1fa27cf8
|
||||||
|
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
|
||||||
|
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
|
||||||
|
#define T50 0x432aff97
|
||||||
|
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
|
||||||
|
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
|
||||||
|
#define T53 0x655b59c3
|
||||||
|
#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
|
||||||
|
#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
|
||||||
|
#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
|
||||||
|
#define T57 0x6fa87e4f
|
||||||
|
#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
|
||||||
|
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
|
||||||
|
#define T60 0x4e0811a1
|
||||||
|
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
|
||||||
|
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
|
||||||
|
#define T63 0x2ad7d2bb
|
||||||
|
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
|
||||||
|
{
|
||||||
|
md5_word_t
|
||||||
|
a = pms->abcd[0], b = pms->abcd[1],
|
||||||
|
c = pms->abcd[2], d = pms->abcd[3];
|
||||||
|
md5_word_t t;
|
||||||
|
#if BYTE_ORDER > 0
|
||||||
|
/* Define storage only for big-endian CPUs. */
|
||||||
|
md5_word_t X[16];
|
||||||
|
#else
|
||||||
|
/* Define storage for little-endian or both types of CPUs. */
|
||||||
|
md5_word_t xbuf[16];
|
||||||
|
const md5_word_t *X;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
{
|
||||||
|
#if BYTE_ORDER == 0
|
||||||
|
/*
|
||||||
|
* Determine dynamically whether this is a big-endian or
|
||||||
|
* little-endian machine, since we can use a more efficient
|
||||||
|
* algorithm on the latter.
|
||||||
|
*/
|
||||||
|
static const int w = 1;
|
||||||
|
|
||||||
|
if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
|
||||||
|
#endif
|
||||||
|
#if BYTE_ORDER <= 0 /* little-endian */
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* On little-endian machines, we can process properly aligned
|
||||||
|
* data without copying it.
|
||||||
|
*/
|
||||||
|
if (!((data - (const md5_byte_t *)0) & 3)) {
|
||||||
|
/* data are properly aligned */
|
||||||
|
X = (const md5_word_t *)data;
|
||||||
|
} else {
|
||||||
|
/* not aligned */
|
||||||
|
memcpy2(xbuf, data, 64);
|
||||||
|
X = xbuf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if BYTE_ORDER == 0
|
||||||
|
else /* dynamic big-endian */
|
||||||
|
#endif
|
||||||
|
#if BYTE_ORDER >= 0 /* big-endian */
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* On big-endian machines, we must arrange the bytes in the
|
||||||
|
* right order.
|
||||||
|
*/
|
||||||
|
const md5_byte_t *xp = data;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
# if BYTE_ORDER == 0
|
||||||
|
X = xbuf; /* (dynamic only) */
|
||||||
|
# else
|
||||||
|
# define xbuf X /* (static only) */
|
||||||
|
# endif
|
||||||
|
for (i = 0; i < 16; ++i, xp += 4)
|
||||||
|
xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||||
|
|
||||||
|
/* Round 1. */
|
||||||
|
/* Let [abcd k s i] denote the operation
|
||||||
|
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
|
||||||
|
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
|
||||||
|
#define SET(a, b, c, d, k, s, Ti)\
|
||||||
|
t = a + F(b,c,d) + X[k] + Ti;\
|
||||||
|
a = ROTATE_LEFT(t, s) + b
|
||||||
|
/* Do the following 16 operations. */
|
||||||
|
SET(a, b, c, d, 0, 7, T1);
|
||||||
|
SET(d, a, b, c, 1, 12, T2);
|
||||||
|
SET(c, d, a, b, 2, 17, T3);
|
||||||
|
SET(b, c, d, a, 3, 22, T4);
|
||||||
|
SET(a, b, c, d, 4, 7, T5);
|
||||||
|
SET(d, a, b, c, 5, 12, T6);
|
||||||
|
SET(c, d, a, b, 6, 17, T7);
|
||||||
|
SET(b, c, d, a, 7, 22, T8);
|
||||||
|
SET(a, b, c, d, 8, 7, T9);
|
||||||
|
SET(d, a, b, c, 9, 12, T10);
|
||||||
|
SET(c, d, a, b, 10, 17, T11);
|
||||||
|
SET(b, c, d, a, 11, 22, T12);
|
||||||
|
SET(a, b, c, d, 12, 7, T13);
|
||||||
|
SET(d, a, b, c, 13, 12, T14);
|
||||||
|
SET(c, d, a, b, 14, 17, T15);
|
||||||
|
SET(b, c, d, a, 15, 22, T16);
|
||||||
|
#undef SET
|
||||||
|
|
||||||
|
/* Round 2. */
|
||||||
|
/* Let [abcd k s i] denote the operation
|
||||||
|
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
|
||||||
|
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
|
||||||
|
#define SET(a, b, c, d, k, s, Ti)\
|
||||||
|
t = a + G(b,c,d) + X[k] + Ti;\
|
||||||
|
a = ROTATE_LEFT(t, s) + b
|
||||||
|
/* Do the following 16 operations. */
|
||||||
|
SET(a, b, c, d, 1, 5, T17);
|
||||||
|
SET(d, a, b, c, 6, 9, T18);
|
||||||
|
SET(c, d, a, b, 11, 14, T19);
|
||||||
|
SET(b, c, d, a, 0, 20, T20);
|
||||||
|
SET(a, b, c, d, 5, 5, T21);
|
||||||
|
SET(d, a, b, c, 10, 9, T22);
|
||||||
|
SET(c, d, a, b, 15, 14, T23);
|
||||||
|
SET(b, c, d, a, 4, 20, T24);
|
||||||
|
SET(a, b, c, d, 9, 5, T25);
|
||||||
|
SET(d, a, b, c, 14, 9, T26);
|
||||||
|
SET(c, d, a, b, 3, 14, T27);
|
||||||
|
SET(b, c, d, a, 8, 20, T28);
|
||||||
|
SET(a, b, c, d, 13, 5, T29);
|
||||||
|
SET(d, a, b, c, 2, 9, T30);
|
||||||
|
SET(c, d, a, b, 7, 14, T31);
|
||||||
|
SET(b, c, d, a, 12, 20, T32);
|
||||||
|
#undef SET
|
||||||
|
|
||||||
|
/* Round 3. */
|
||||||
|
/* Let [abcd k s t] denote the operation
|
||||||
|
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
|
||||||
|
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||||
|
#define SET(a, b, c, d, k, s, Ti)\
|
||||||
|
t = a + H(b,c,d) + X[k] + Ti;\
|
||||||
|
a = ROTATE_LEFT(t, s) + b
|
||||||
|
/* Do the following 16 operations. */
|
||||||
|
SET(a, b, c, d, 5, 4, T33);
|
||||||
|
SET(d, a, b, c, 8, 11, T34);
|
||||||
|
SET(c, d, a, b, 11, 16, T35);
|
||||||
|
SET(b, c, d, a, 14, 23, T36);
|
||||||
|
SET(a, b, c, d, 1, 4, T37);
|
||||||
|
SET(d, a, b, c, 4, 11, T38);
|
||||||
|
SET(c, d, a, b, 7, 16, T39);
|
||||||
|
SET(b, c, d, a, 10, 23, T40);
|
||||||
|
SET(a, b, c, d, 13, 4, T41);
|
||||||
|
SET(d, a, b, c, 0, 11, T42);
|
||||||
|
SET(c, d, a, b, 3, 16, T43);
|
||||||
|
SET(b, c, d, a, 6, 23, T44);
|
||||||
|
SET(a, b, c, d, 9, 4, T45);
|
||||||
|
SET(d, a, b, c, 12, 11, T46);
|
||||||
|
SET(c, d, a, b, 15, 16, T47);
|
||||||
|
SET(b, c, d, a, 2, 23, T48);
|
||||||
|
#undef SET
|
||||||
|
|
||||||
|
/* Round 4. */
|
||||||
|
/* Let [abcd k s t] denote the operation
|
||||||
|
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
|
||||||
|
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
|
||||||
|
#define SET(a, b, c, d, k, s, Ti)\
|
||||||
|
t = a + I(b,c,d) + X[k] + Ti;\
|
||||||
|
a = ROTATE_LEFT(t, s) + b
|
||||||
|
/* Do the following 16 operations. */
|
||||||
|
SET(a, b, c, d, 0, 6, T49);
|
||||||
|
SET(d, a, b, c, 7, 10, T50);
|
||||||
|
SET(c, d, a, b, 14, 15, T51);
|
||||||
|
SET(b, c, d, a, 5, 21, T52);
|
||||||
|
SET(a, b, c, d, 12, 6, T53);
|
||||||
|
SET(d, a, b, c, 3, 10, T54);
|
||||||
|
SET(c, d, a, b, 10, 15, T55);
|
||||||
|
SET(b, c, d, a, 1, 21, T56);
|
||||||
|
SET(a, b, c, d, 8, 6, T57);
|
||||||
|
SET(d, a, b, c, 15, 10, T58);
|
||||||
|
SET(c, d, a, b, 6, 15, T59);
|
||||||
|
SET(b, c, d, a, 13, 21, T60);
|
||||||
|
SET(a, b, c, d, 4, 6, T61);
|
||||||
|
SET(d, a, b, c, 11, 10, T62);
|
||||||
|
SET(c, d, a, b, 2, 15, T63);
|
||||||
|
SET(b, c, d, a, 9, 21, T64);
|
||||||
|
#undef SET
|
||||||
|
|
||||||
|
/* Then perform the following additions. (That is increment each
|
||||||
|
of the four registers by the value it had before this block
|
||||||
|
was started.) */
|
||||||
|
pms->abcd[0] += a;
|
||||||
|
pms->abcd[1] += b;
|
||||||
|
pms->abcd[2] += c;
|
||||||
|
pms->abcd[3] += d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
md5_init(md5_state_t *pms)
|
||||||
|
{
|
||||||
|
pms->count[0] = pms->count[1] = 0;
|
||||||
|
pms->abcd[0] = 0x67452301;
|
||||||
|
pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
|
||||||
|
pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
|
||||||
|
pms->abcd[3] = 0x10325476;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
|
||||||
|
{
|
||||||
|
const md5_byte_t *p = data;
|
||||||
|
int left = nbytes;
|
||||||
|
int offset = (pms->count[0] >> 3) & 63;
|
||||||
|
md5_word_t nbits = (md5_word_t)(nbytes << 3);
|
||||||
|
|
||||||
|
if (nbytes <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Update the message length. */
|
||||||
|
pms->count[1] += nbytes >> 29;
|
||||||
|
pms->count[0] += nbits;
|
||||||
|
if (pms->count[0] < nbits)
|
||||||
|
pms->count[1]++;
|
||||||
|
|
||||||
|
/* Process an initial partial block. */
|
||||||
|
if (offset) {
|
||||||
|
int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
|
||||||
|
|
||||||
|
memcpy2(pms->buf + offset, p, copy);
|
||||||
|
if (offset + copy < 64)
|
||||||
|
return;
|
||||||
|
p += copy;
|
||||||
|
left -= copy;
|
||||||
|
md5_process(pms, pms->buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process full blocks. */
|
||||||
|
for (; left >= 64; p += 64, left -= 64)
|
||||||
|
md5_process(pms, p);
|
||||||
|
|
||||||
|
/* Process a final partial block. */
|
||||||
|
if (left)
|
||||||
|
memcpy2(pms->buf, p, left);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
md5_finish(md5_state_t *pms, md5_byte_t digest[16])
|
||||||
|
{
|
||||||
|
static const md5_byte_t pad[64] = {
|
||||||
|
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
|
};
|
||||||
|
md5_byte_t data[8];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Save the length before padding. */
|
||||||
|
for (i = 0; i < 8; ++i)
|
||||||
|
data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
|
||||||
|
/* Pad to 56 bytes mod 64. */
|
||||||
|
md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
|
||||||
|
/* Append the length. */
|
||||||
|
md5_append(pms, data, 8);
|
||||||
|
for (i = 0; i < 16; ++i)
|
||||||
|
digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
|
||||||
|
}
|
91
Contrib/VPatch/Source/GenPat/md5.h
Normal file
91
Contrib/VPatch/Source/GenPat/md5.h
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source 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 source distribution.
|
||||||
|
|
||||||
|
L. Peter Deutsch
|
||||||
|
ghost@aladdin.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
|
||||||
|
/*
|
||||||
|
Independent implementation of MD5 (RFC 1321).
|
||||||
|
|
||||||
|
This code implements the MD5 Algorithm defined in RFC 1321, whose
|
||||||
|
text is available at
|
||||||
|
http://www.ietf.org/rfc/rfc1321.txt
|
||||||
|
The code is derived from the text of the RFC, including the test suite
|
||||||
|
(section A.5) but excluding the rest of Appendix A. It does not include
|
||||||
|
any code or documentation that is identified in the RFC as being
|
||||||
|
copyrighted.
|
||||||
|
|
||||||
|
The original and principal author of md5.h is L. Peter Deutsch
|
||||||
|
<ghost@aladdin.com>. Other authors are noted in the change history
|
||||||
|
that follows (in reverse chronological order):
|
||||||
|
|
||||||
|
2002-04-13 lpd Removed support for non-ANSI compilers; removed
|
||||||
|
references to Ghostscript; clarified derivation from RFC 1321;
|
||||||
|
now handles byte order either statically or dynamically.
|
||||||
|
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
|
||||||
|
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
|
||||||
|
added conditionalization for C++ compilation from Martin
|
||||||
|
Purschke <purschke@bnl.gov>.
|
||||||
|
1999-05-03 lpd Original version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef md5_INCLUDED
|
||||||
|
# define md5_INCLUDED
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This package supports both compile-time and run-time determination of CPU
|
||||||
|
* byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
|
||||||
|
* compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
|
||||||
|
* defined as non-zero, the code will be compiled to run only on big-endian
|
||||||
|
* CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
|
||||||
|
* run on either big- or little-endian CPUs, but will run slightly less
|
||||||
|
* efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef unsigned char md5_byte_t; /* 8-bit byte */
|
||||||
|
typedef unsigned int md5_word_t; /* 32-bit word */
|
||||||
|
|
||||||
|
/* Define the state of the MD5 Algorithm. */
|
||||||
|
typedef struct md5_state_s {
|
||||||
|
md5_word_t count[2]; /* message length in bits, lsw first */
|
||||||
|
md5_word_t abcd[4]; /* digest buffer */
|
||||||
|
md5_byte_t buf[64]; /* accumulate block */
|
||||||
|
} md5_state_t;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Initialize the algorithm. */
|
||||||
|
void md5_init(md5_state_t *pms);
|
||||||
|
|
||||||
|
/* Append a string to the message. */
|
||||||
|
void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
|
||||||
|
|
||||||
|
/* Finish the message and return the digest. */
|
||||||
|
void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* end extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* md5_INCLUDED */
|
|
@ -1,6 +1,9 @@
|
||||||
target = 'VPatch'
|
target = 'VPatch'
|
||||||
|
|
||||||
files = Split("""
|
files = Split("""
|
||||||
|
apply_patch.c
|
||||||
|
checksum.c
|
||||||
|
md5.c
|
||||||
vpatchdll.c
|
vpatchdll.c
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
@ -8,19 +11,6 @@ libs = Split("""
|
||||||
kernel32
|
kernel32
|
||||||
""")
|
""")
|
||||||
|
|
||||||
examples = Split("""
|
|
||||||
#Contrib/VPatch/example.nsi
|
|
||||||
#Contrib/VPatch/newfile.txt
|
|
||||||
#Contrib/VPatch/oldfile.txt
|
|
||||||
#Contrib/VPatch/patch.pat
|
|
||||||
""")
|
|
||||||
|
|
||||||
docs = Split("""
|
|
||||||
#Contrib/VPatch/Readme.html
|
|
||||||
""")
|
|
||||||
|
|
||||||
Import('BuildPlugin env')
|
Import('BuildPlugin env')
|
||||||
|
|
||||||
BuildPlugin(target, files, libs, examples, docs)
|
BuildPlugin(target, files, libs)
|
||||||
|
|
||||||
env.Distribute('Bin', '#Contrib/VPatch/GenPat.exe')
|
|
||||||
|
|
239
Contrib/VPatch/Source/Plugin/apply_patch.c
Normal file
239
Contrib/VPatch/Source/Plugin/apply_patch.c
Normal file
|
@ -0,0 +1,239 @@
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// apply_patch.c
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// -=* VPatch *=-
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2001-2005 Koen van de Sande / Van de Sande Productions
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Website: http://www.tibed.net/vpatch
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source 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 source distribution.
|
||||||
|
|
||||||
|
#include "apply_patch.h"
|
||||||
|
#include "checksum.h"
|
||||||
|
|
||||||
|
/* ------------------------ patch application ----------------- */
|
||||||
|
|
||||||
|
#define BLOCKSIZE 16384
|
||||||
|
|
||||||
|
int DoPatch(HANDLE hPatch, HANDLE hSource, HANDLE hDest) {
|
||||||
|
|
||||||
|
static char block[BLOCKSIZE];
|
||||||
|
|
||||||
|
unsigned long temp = 0;
|
||||||
|
unsigned long read;
|
||||||
|
unsigned long source_crc = 0;
|
||||||
|
md5_byte_t source_md5[16];
|
||||||
|
unsigned long patch_dest_crc = 0;
|
||||||
|
md5_byte_t patch_dest_md5[16];
|
||||||
|
int MD5Mode = 0;
|
||||||
|
unsigned long patches = 0;
|
||||||
|
int already_uptodate = 0;
|
||||||
|
|
||||||
|
FILETIME targetModifiedTime;
|
||||||
|
|
||||||
|
// special 'addition' for the dll: since the patch file is now
|
||||||
|
// in a seperate file, the VPAT header might be right at the start
|
||||||
|
// of the file, and a pointer at the end of the file is probably missing
|
||||||
|
// (because all patch generator versions don't append it, the linker/gui
|
||||||
|
// does this).
|
||||||
|
SetFilePointer(hPatch, 0, NULL, FILE_BEGIN);
|
||||||
|
ReadFile(hPatch, &temp, 4, &read, NULL);
|
||||||
|
// it's not at the start of file -> there must be a pointer at the end of
|
||||||
|
// file then
|
||||||
|
if (temp != 0x54415056) {
|
||||||
|
SetFilePointer(hPatch, -4, NULL, FILE_END);
|
||||||
|
ReadFile(hPatch, &temp, 4, &read, NULL);
|
||||||
|
|
||||||
|
SetFilePointer(hPatch, temp, NULL, FILE_BEGIN);
|
||||||
|
ReadFile(hPatch, &temp, 4, &read, NULL);
|
||||||
|
if (temp != 0x54415056)
|
||||||
|
return PATCH_CORRUPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// target file date is by default the current system time
|
||||||
|
GetSystemTimeAsFileTime(&targetModifiedTime);
|
||||||
|
|
||||||
|
// read the number of patches in the file
|
||||||
|
ReadFile(hPatch, &patches, 4, &read, NULL);
|
||||||
|
if(patches & 0x80000000) MD5Mode = 1;
|
||||||
|
// MSB is now reserved for future extensions, anyone wanting more than
|
||||||
|
// 16 million patches in a single file is nuts anyway
|
||||||
|
patches = patches & 0x00FFFFFF;
|
||||||
|
|
||||||
|
if(!MD5Mode) {
|
||||||
|
if (!FileCRC(hSource, &source_crc))
|
||||||
|
return PATCH_ERROR;
|
||||||
|
} else {
|
||||||
|
if (!FileMD5(hSource, source_md5))
|
||||||
|
return PATCH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (patches--) {
|
||||||
|
long patch_blocks = 0, patch_size = 0;
|
||||||
|
|
||||||
|
// flag which needs to be set by one of the checksum checks
|
||||||
|
int currentPatchMatchesChecksum = 0;
|
||||||
|
|
||||||
|
// read the number of blocks this patch has
|
||||||
|
if(!ReadFile(hPatch, &patch_blocks, 4, &read, NULL)) {
|
||||||
|
return PATCH_CORRUPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read checksums
|
||||||
|
if(!MD5Mode) {
|
||||||
|
unsigned long patch_source_crc = 0;
|
||||||
|
if(!ReadFile(hPatch, &patch_source_crc, 4, &read, NULL)) {
|
||||||
|
return PATCH_CORRUPT;
|
||||||
|
}
|
||||||
|
if(!ReadFile(hPatch, &patch_dest_crc, 4, &read, NULL)) {
|
||||||
|
return PATCH_CORRUPT;
|
||||||
|
}
|
||||||
|
// check to see if it's already up-to-date for some patch
|
||||||
|
if (source_crc == patch_dest_crc) {
|
||||||
|
already_uptodate = 1;
|
||||||
|
}
|
||||||
|
if (source_crc == patch_source_crc) {
|
||||||
|
currentPatchMatchesChecksum = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int md5index;
|
||||||
|
md5_byte_t patch_source_md5[16];
|
||||||
|
if(!ReadFile(hPatch, patch_source_md5, 16, &read, NULL)) {
|
||||||
|
return PATCH_CORRUPT;
|
||||||
|
}
|
||||||
|
if(!ReadFile(hPatch, patch_dest_md5, 16, &read, NULL)) {
|
||||||
|
return PATCH_CORRUPT;
|
||||||
|
}
|
||||||
|
// check to see if it's already up-to-date for some patch
|
||||||
|
for(md5index = 0; md5index < 16; md5index++) {
|
||||||
|
if(source_md5[md5index] != patch_dest_md5[md5index]) break;
|
||||||
|
if(md5index == 15) already_uptodate = 1;
|
||||||
|
}
|
||||||
|
for(md5index = 0; md5index < 16; md5index++) {
|
||||||
|
if(source_md5[md5index] != patch_source_md5[md5index]) break;
|
||||||
|
if(md5index == 15) currentPatchMatchesChecksum = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// read the size of the patch, we can use this to skip over it
|
||||||
|
if(!ReadFile(hPatch, &patch_size, 4, &read, NULL)) {
|
||||||
|
return PATCH_CORRUPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(currentPatchMatchesChecksum) {
|
||||||
|
while (patch_blocks--) {
|
||||||
|
unsigned char blocktype = 0;
|
||||||
|
unsigned long blocksize = 0;
|
||||||
|
if(!ReadFile(hPatch, &blocktype, 1, &read, NULL)) {
|
||||||
|
return PATCH_CORRUPT;
|
||||||
|
}
|
||||||
|
switch (blocktype) {
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
if (blocktype == 1)
|
||||||
|
{ unsigned char x; blocksize = ReadFile(hPatch,&x,1,&read,NULL)? x: 0; }
|
||||||
|
else if (blocktype == 2)
|
||||||
|
{ unsigned short x; blocksize = ReadFile(hPatch,&x,2,&read,NULL)? x: 0; }
|
||||||
|
else
|
||||||
|
{ unsigned long x; blocksize = ReadFile(hPatch,&x,4,&read,NULL)? x:0; }
|
||||||
|
|
||||||
|
if (!blocksize || !ReadFile(hPatch, &temp, 4, &read, NULL) || read != 4)
|
||||||
|
return PATCH_CORRUPT;
|
||||||
|
|
||||||
|
SetFilePointer(hSource, temp, 0, FILE_BEGIN);
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(!ReadFile(hSource, block, min(BLOCKSIZE, blocksize), &read, NULL)) {
|
||||||
|
return PATCH_ERROR;
|
||||||
|
}
|
||||||
|
WriteFile(hDest, block, read, &temp, NULL);
|
||||||
|
if (temp != min(BLOCKSIZE, blocksize))
|
||||||
|
return PATCH_ERROR;
|
||||||
|
blocksize -= temp;
|
||||||
|
} while (temp);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
case 7:
|
||||||
|
if (blocktype == 5)
|
||||||
|
{ unsigned char x; blocksize = ReadFile(hPatch,&x,1,&read,NULL)? x:0; }
|
||||||
|
else if (blocktype == 6)
|
||||||
|
{ unsigned short x; blocksize = ReadFile(hPatch,&x,2,&read,NULL)? x:0; }
|
||||||
|
else
|
||||||
|
{ unsigned long x; blocksize = ReadFile(hPatch,&x,4,&read,NULL)? x:0; }
|
||||||
|
|
||||||
|
if (!blocksize)
|
||||||
|
return PATCH_CORRUPT;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(!ReadFile(hPatch, block, min(BLOCKSIZE, blocksize), &read, NULL)) {
|
||||||
|
return PATCH_CORRUPT;
|
||||||
|
}
|
||||||
|
WriteFile(hDest, block, read, &temp, NULL);
|
||||||
|
if (temp != min(BLOCKSIZE, blocksize))
|
||||||
|
return PATCH_ERROR;
|
||||||
|
blocksize -= temp;
|
||||||
|
} while (temp);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 255: // read the file modified time from the patch
|
||||||
|
if(!ReadFile(hPatch,&targetModifiedTime,sizeof(targetModifiedTime),&read,NULL)) {
|
||||||
|
return PATCH_CORRUPT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return PATCH_CORRUPT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!MD5Mode) {
|
||||||
|
unsigned long dest_crc = 0;
|
||||||
|
if(!FileCRC(hDest, &dest_crc)) {
|
||||||
|
return PATCH_ERROR;
|
||||||
|
}
|
||||||
|
if (dest_crc != patch_dest_crc)
|
||||||
|
return PATCH_ERROR;
|
||||||
|
} else {
|
||||||
|
int md5index;
|
||||||
|
md5_byte_t dest_md5[16];
|
||||||
|
if(!FileMD5(hDest, dest_md5)) {
|
||||||
|
return PATCH_ERROR;
|
||||||
|
}
|
||||||
|
for(md5index = 0; md5index < 16; md5index++) {
|
||||||
|
if(dest_md5[md5index] != patch_dest_md5[md5index]) return PATCH_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// set file time
|
||||||
|
SetFileTime(hDest, NULL, NULL, &targetModifiedTime);
|
||||||
|
|
||||||
|
return PATCH_SUCCESS;
|
||||||
|
} else {
|
||||||
|
SetFilePointer(hPatch, patch_size, NULL, FILE_CURRENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if already up to date, it doesn't matter that we didn't match
|
||||||
|
if(already_uptodate) {
|
||||||
|
return PATCH_UPTODATE;
|
||||||
|
} else {
|
||||||
|
return PATCH_NOMATCH;
|
||||||
|
}
|
||||||
|
}
|
45
Contrib/VPatch/Source/Plugin/apply_patch.h
Normal file
45
Contrib/VPatch/Source/Plugin/apply_patch.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// apply_patch.h
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// -=* VPatch *=-
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2001-2005 Koen van de Sande / Van de Sande Productions
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Website: http://www.tibed.net/vpatch
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source 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 source distribution.
|
||||||
|
|
||||||
|
#ifndef apply_patch_INCLUDED
|
||||||
|
#define apply_patch_INCLUDED
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
/* ------------------------ patch application ----------------- */
|
||||||
|
|
||||||
|
// possible return values
|
||||||
|
#define PATCH_SUCCESS 0
|
||||||
|
#define PATCH_ERROR 1
|
||||||
|
#define PATCH_CORRUPT 2
|
||||||
|
#define PATCH_NOMATCH 3
|
||||||
|
#define PATCH_UPTODATE 4
|
||||||
|
#define FILE_ERR_PATCH 5
|
||||||
|
#define FILE_ERR_SOURCE 6
|
||||||
|
#define FILE_ERR_DEST 7
|
||||||
|
|
||||||
|
int DoPatch(HANDLE hPatch, HANDLE hSource, HANDLE hDest);
|
||||||
|
|
||||||
|
#endif
|
115
Contrib/VPatch/Source/Plugin/checksum.c
Normal file
115
Contrib/VPatch/Source/Plugin/checksum.c
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// checksum.c
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// -=* VPatch *=-
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2001-2005 Koen van de Sande / Van de Sande Productions
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Website: http://www.tibed.net/vpatch
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source 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 source distribution.
|
||||||
|
|
||||||
|
#include "checksum.h"
|
||||||
|
|
||||||
|
/* ------------------------ CRC32 checksum calculation ----------------- */
|
||||||
|
|
||||||
|
UINT CRCTable[256];
|
||||||
|
BOOL bInitCRC = FALSE;
|
||||||
|
|
||||||
|
_inline void InitCRC() {
|
||||||
|
int i, j; unsigned long c;
|
||||||
|
for (c = i = 0; i < 256; c = ++i) {
|
||||||
|
for (j = 0; j < 8; j++) {
|
||||||
|
if (c & 1) c = (c>>1) ^ 0xEDB88320;
|
||||||
|
else c >>= 1;
|
||||||
|
}
|
||||||
|
CRCTable[i] = c;
|
||||||
|
}
|
||||||
|
bInitCRC = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CRCBLOCKSIZE 4096
|
||||||
|
|
||||||
|
BOOL FileCRC(HANDLE hFile, DWORD *crc) {
|
||||||
|
static BYTE crcblock[CRCBLOCKSIZE];
|
||||||
|
DWORD read;
|
||||||
|
BYTE *p;
|
||||||
|
|
||||||
|
UINT c = 0xFFFFFFFF;
|
||||||
|
if (bInitCRC == FALSE)
|
||||||
|
InitCRC();
|
||||||
|
|
||||||
|
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
|
||||||
|
do {
|
||||||
|
if (ReadFile(hFile, crcblock, CRCBLOCKSIZE, &read, NULL) == FALSE)
|
||||||
|
return FALSE;
|
||||||
|
for (p = crcblock; p < crcblock + read; p++)
|
||||||
|
c = CRCTable[(c & 0xFF) ^ *p] ^ (c >> 8);
|
||||||
|
} while (read);
|
||||||
|
|
||||||
|
*crc = (c ^ 0xFFFFFFFF);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CRC32ToString(char* string, DWORD crc) {
|
||||||
|
int i = 0;
|
||||||
|
int j = 7;
|
||||||
|
int a1, a2;
|
||||||
|
for(i = 0; i < 4; i++) {
|
||||||
|
a1 = (crc >> 4) % 16;
|
||||||
|
a2 = crc % 16;
|
||||||
|
string[j--] = a2 < 10 ? ('0' + a2) : ('A' + a2 - 10);
|
||||||
|
string[j--] = a1 < 10 ? ('0' + a1) : ('A' + a1 - 10);
|
||||||
|
crc = crc >> 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------ MD5 checksum calculation ----------------- */
|
||||||
|
|
||||||
|
#define MD5BLOCKSIZE 16384
|
||||||
|
|
||||||
|
BOOL FileMD5(HANDLE hFile, md5_byte_t digest[16]) {
|
||||||
|
static BYTE md5block[MD5BLOCKSIZE];
|
||||||
|
DWORD read;
|
||||||
|
|
||||||
|
md5_state_t state;
|
||||||
|
|
||||||
|
md5_init(&state);
|
||||||
|
|
||||||
|
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
|
||||||
|
do {
|
||||||
|
if (ReadFile(hFile, md5block, MD5BLOCKSIZE, &read, NULL) == FALSE)
|
||||||
|
return FALSE;
|
||||||
|
md5_append(&state, md5block, read);
|
||||||
|
} while (read);
|
||||||
|
|
||||||
|
md5_finish(&state, digest);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MD5ToString(char* string, md5_byte_t checksum[16]) {
|
||||||
|
int i = 0;
|
||||||
|
int j = 0;
|
||||||
|
int a1, a2;
|
||||||
|
for(i = 0; i < 16; i++) {
|
||||||
|
a1 = (checksum[i] >> 4) % 16;
|
||||||
|
a2 = checksum[i] % 16;
|
||||||
|
string[j++] = a1 < 10 ? ('0' + a1) : ('A' + a1 - 10);
|
||||||
|
string[j++] = a2 < 10 ? ('0' + a2) : ('A' + a2 - 10);
|
||||||
|
}
|
||||||
|
}
|
42
Contrib/VPatch/Source/Plugin/checksum.h
Normal file
42
Contrib/VPatch/Source/Plugin/checksum.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// checksum.h
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// -=* VPatch *=-
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2001-2005 Koen van de Sande / Van de Sande Productions
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Website: http://www.tibed.net/vpatch
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source 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 source distribution.
|
||||||
|
|
||||||
|
#ifndef checksum_INCLUDED
|
||||||
|
#define checksum_INCLUDED
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include "md5.h"
|
||||||
|
|
||||||
|
/* ------------------------ CRC32 checksum calculation ----------------- */
|
||||||
|
|
||||||
|
BOOL FileCRC(HANDLE hFile, DWORD *crc);
|
||||||
|
void CRC32ToString(char* string, DWORD crc);
|
||||||
|
|
||||||
|
/* ------------------------ MD5 checksum calculation ----------------- */
|
||||||
|
|
||||||
|
BOOL FileMD5(HANDLE hFile, md5_byte_t digest[16]);
|
||||||
|
void MD5ToString(char* string, md5_byte_t checksum[16]);
|
||||||
|
|
||||||
|
#endif
|
389
Contrib/VPatch/Source/Plugin/md5.c
Normal file
389
Contrib/VPatch/Source/Plugin/md5.c
Normal file
|
@ -0,0 +1,389 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source 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 source distribution.
|
||||||
|
|
||||||
|
L. Peter Deutsch
|
||||||
|
ghost@aladdin.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
|
||||||
|
/*
|
||||||
|
Independent implementation of MD5 (RFC 1321).
|
||||||
|
|
||||||
|
This code implements the MD5 Algorithm defined in RFC 1321, whose
|
||||||
|
text is available at
|
||||||
|
http://www.ietf.org/rfc/rfc1321.txt
|
||||||
|
The code is derived from the text of the RFC, including the test suite
|
||||||
|
(section A.5) but excluding the rest of Appendix A. It does not include
|
||||||
|
any code or documentation that is identified in the RFC as being
|
||||||
|
copyrighted.
|
||||||
|
|
||||||
|
The original and principal author of md5.c is L. Peter Deutsch
|
||||||
|
<ghost@aladdin.com>. Other authors are noted in the change history
|
||||||
|
that follows (in reverse chronological order):
|
||||||
|
|
||||||
|
2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
|
||||||
|
either statically or dynamically; added missing #include <string.h>
|
||||||
|
in library.
|
||||||
|
2002-03-11 lpd Corrected argument list for main(), and added int return
|
||||||
|
type, in test program and T value program.
|
||||||
|
2002-02-21 lpd Added missing #include <stdio.h> in test program.
|
||||||
|
2000-07-03 lpd Patched to eliminate warnings about "constant is
|
||||||
|
unsigned in ANSI C, signed in traditional"; made test program
|
||||||
|
self-checking.
|
||||||
|
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
|
||||||
|
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
|
||||||
|
1999-05-03 lpd Original version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "md5.h"
|
||||||
|
|
||||||
|
void memcpy( void *dest, const void *src, int count ) {
|
||||||
|
md5_byte_t* bDest = (md5_byte_t*)dest;
|
||||||
|
md5_byte_t* bSrc = (md5_byte_t*)src;
|
||||||
|
int i = 0;
|
||||||
|
for(; i < count; i++) {
|
||||||
|
bDest[i] = bSrc[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
|
||||||
|
#ifdef ARCH_IS_BIG_ENDIAN
|
||||||
|
# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
|
||||||
|
#else
|
||||||
|
# define BYTE_ORDER 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define T_MASK ((md5_word_t)~0)
|
||||||
|
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
|
||||||
|
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
|
||||||
|
#define T3 0x242070db
|
||||||
|
#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
|
||||||
|
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
|
||||||
|
#define T6 0x4787c62a
|
||||||
|
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
|
||||||
|
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
|
||||||
|
#define T9 0x698098d8
|
||||||
|
#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
|
||||||
|
#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
|
||||||
|
#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
|
||||||
|
#define T13 0x6b901122
|
||||||
|
#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
|
||||||
|
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
|
||||||
|
#define T16 0x49b40821
|
||||||
|
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
|
||||||
|
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
|
||||||
|
#define T19 0x265e5a51
|
||||||
|
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
|
||||||
|
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
|
||||||
|
#define T22 0x02441453
|
||||||
|
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
|
||||||
|
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
|
||||||
|
#define T25 0x21e1cde6
|
||||||
|
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
|
||||||
|
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
|
||||||
|
#define T28 0x455a14ed
|
||||||
|
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
|
||||||
|
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
|
||||||
|
#define T31 0x676f02d9
|
||||||
|
#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
|
||||||
|
#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
|
||||||
|
#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
|
||||||
|
#define T35 0x6d9d6122
|
||||||
|
#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
|
||||||
|
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
|
||||||
|
#define T38 0x4bdecfa9
|
||||||
|
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
|
||||||
|
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
|
||||||
|
#define T41 0x289b7ec6
|
||||||
|
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
|
||||||
|
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
|
||||||
|
#define T44 0x04881d05
|
||||||
|
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
|
||||||
|
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
|
||||||
|
#define T47 0x1fa27cf8
|
||||||
|
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
|
||||||
|
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
|
||||||
|
#define T50 0x432aff97
|
||||||
|
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
|
||||||
|
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
|
||||||
|
#define T53 0x655b59c3
|
||||||
|
#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
|
||||||
|
#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
|
||||||
|
#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
|
||||||
|
#define T57 0x6fa87e4f
|
||||||
|
#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
|
||||||
|
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
|
||||||
|
#define T60 0x4e0811a1
|
||||||
|
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
|
||||||
|
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
|
||||||
|
#define T63 0x2ad7d2bb
|
||||||
|
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
|
||||||
|
{
|
||||||
|
md5_word_t
|
||||||
|
a = pms->abcd[0], b = pms->abcd[1],
|
||||||
|
c = pms->abcd[2], d = pms->abcd[3];
|
||||||
|
md5_word_t t;
|
||||||
|
#if BYTE_ORDER > 0
|
||||||
|
/* Define storage only for big-endian CPUs. */
|
||||||
|
md5_word_t X[16];
|
||||||
|
#else
|
||||||
|
/* Define storage for little-endian or both types of CPUs. */
|
||||||
|
md5_word_t xbuf[16];
|
||||||
|
const md5_word_t *X;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
{
|
||||||
|
#if BYTE_ORDER == 0
|
||||||
|
/*
|
||||||
|
* Determine dynamically whether this is a big-endian or
|
||||||
|
* little-endian machine, since we can use a more efficient
|
||||||
|
* algorithm on the latter.
|
||||||
|
*/
|
||||||
|
static const int w = 1;
|
||||||
|
|
||||||
|
if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
|
||||||
|
#endif
|
||||||
|
#if BYTE_ORDER <= 0 /* little-endian */
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* On little-endian machines, we can process properly aligned
|
||||||
|
* data without copying it.
|
||||||
|
*/
|
||||||
|
if (!((data - (const md5_byte_t *)0) & 3)) {
|
||||||
|
/* data are properly aligned */
|
||||||
|
X = (const md5_word_t *)data;
|
||||||
|
} else {
|
||||||
|
/* not aligned */
|
||||||
|
memcpy(xbuf, data, 64);
|
||||||
|
X = xbuf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if BYTE_ORDER == 0
|
||||||
|
else /* dynamic big-endian */
|
||||||
|
#endif
|
||||||
|
#if BYTE_ORDER >= 0 /* big-endian */
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* On big-endian machines, we must arrange the bytes in the
|
||||||
|
* right order.
|
||||||
|
*/
|
||||||
|
const md5_byte_t *xp = data;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
# if BYTE_ORDER == 0
|
||||||
|
X = xbuf; /* (dynamic only) */
|
||||||
|
# else
|
||||||
|
# define xbuf X /* (static only) */
|
||||||
|
# endif
|
||||||
|
for (i = 0; i < 16; ++i, xp += 4)
|
||||||
|
xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||||
|
|
||||||
|
/* Round 1. */
|
||||||
|
/* Let [abcd k s i] denote the operation
|
||||||
|
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
|
||||||
|
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
|
||||||
|
#define SET(a, b, c, d, k, s, Ti)\
|
||||||
|
t = a + F(b,c,d) + X[k] + Ti;\
|
||||||
|
a = ROTATE_LEFT(t, s) + b
|
||||||
|
/* Do the following 16 operations. */
|
||||||
|
SET(a, b, c, d, 0, 7, T1);
|
||||||
|
SET(d, a, b, c, 1, 12, T2);
|
||||||
|
SET(c, d, a, b, 2, 17, T3);
|
||||||
|
SET(b, c, d, a, 3, 22, T4);
|
||||||
|
SET(a, b, c, d, 4, 7, T5);
|
||||||
|
SET(d, a, b, c, 5, 12, T6);
|
||||||
|
SET(c, d, a, b, 6, 17, T7);
|
||||||
|
SET(b, c, d, a, 7, 22, T8);
|
||||||
|
SET(a, b, c, d, 8, 7, T9);
|
||||||
|
SET(d, a, b, c, 9, 12, T10);
|
||||||
|
SET(c, d, a, b, 10, 17, T11);
|
||||||
|
SET(b, c, d, a, 11, 22, T12);
|
||||||
|
SET(a, b, c, d, 12, 7, T13);
|
||||||
|
SET(d, a, b, c, 13, 12, T14);
|
||||||
|
SET(c, d, a, b, 14, 17, T15);
|
||||||
|
SET(b, c, d, a, 15, 22, T16);
|
||||||
|
#undef SET
|
||||||
|
|
||||||
|
/* Round 2. */
|
||||||
|
/* Let [abcd k s i] denote the operation
|
||||||
|
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
|
||||||
|
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
|
||||||
|
#define SET(a, b, c, d, k, s, Ti)\
|
||||||
|
t = a + G(b,c,d) + X[k] + Ti;\
|
||||||
|
a = ROTATE_LEFT(t, s) + b
|
||||||
|
/* Do the following 16 operations. */
|
||||||
|
SET(a, b, c, d, 1, 5, T17);
|
||||||
|
SET(d, a, b, c, 6, 9, T18);
|
||||||
|
SET(c, d, a, b, 11, 14, T19);
|
||||||
|
SET(b, c, d, a, 0, 20, T20);
|
||||||
|
SET(a, b, c, d, 5, 5, T21);
|
||||||
|
SET(d, a, b, c, 10, 9, T22);
|
||||||
|
SET(c, d, a, b, 15, 14, T23);
|
||||||
|
SET(b, c, d, a, 4, 20, T24);
|
||||||
|
SET(a, b, c, d, 9, 5, T25);
|
||||||
|
SET(d, a, b, c, 14, 9, T26);
|
||||||
|
SET(c, d, a, b, 3, 14, T27);
|
||||||
|
SET(b, c, d, a, 8, 20, T28);
|
||||||
|
SET(a, b, c, d, 13, 5, T29);
|
||||||
|
SET(d, a, b, c, 2, 9, T30);
|
||||||
|
SET(c, d, a, b, 7, 14, T31);
|
||||||
|
SET(b, c, d, a, 12, 20, T32);
|
||||||
|
#undef SET
|
||||||
|
|
||||||
|
/* Round 3. */
|
||||||
|
/* Let [abcd k s t] denote the operation
|
||||||
|
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
|
||||||
|
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||||
|
#define SET(a, b, c, d, k, s, Ti)\
|
||||||
|
t = a + H(b,c,d) + X[k] + Ti;\
|
||||||
|
a = ROTATE_LEFT(t, s) + b
|
||||||
|
/* Do the following 16 operations. */
|
||||||
|
SET(a, b, c, d, 5, 4, T33);
|
||||||
|
SET(d, a, b, c, 8, 11, T34);
|
||||||
|
SET(c, d, a, b, 11, 16, T35);
|
||||||
|
SET(b, c, d, a, 14, 23, T36);
|
||||||
|
SET(a, b, c, d, 1, 4, T37);
|
||||||
|
SET(d, a, b, c, 4, 11, T38);
|
||||||
|
SET(c, d, a, b, 7, 16, T39);
|
||||||
|
SET(b, c, d, a, 10, 23, T40);
|
||||||
|
SET(a, b, c, d, 13, 4, T41);
|
||||||
|
SET(d, a, b, c, 0, 11, T42);
|
||||||
|
SET(c, d, a, b, 3, 16, T43);
|
||||||
|
SET(b, c, d, a, 6, 23, T44);
|
||||||
|
SET(a, b, c, d, 9, 4, T45);
|
||||||
|
SET(d, a, b, c, 12, 11, T46);
|
||||||
|
SET(c, d, a, b, 15, 16, T47);
|
||||||
|
SET(b, c, d, a, 2, 23, T48);
|
||||||
|
#undef SET
|
||||||
|
|
||||||
|
/* Round 4. */
|
||||||
|
/* Let [abcd k s t] denote the operation
|
||||||
|
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
|
||||||
|
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
|
||||||
|
#define SET(a, b, c, d, k, s, Ti)\
|
||||||
|
t = a + I(b,c,d) + X[k] + Ti;\
|
||||||
|
a = ROTATE_LEFT(t, s) + b
|
||||||
|
/* Do the following 16 operations. */
|
||||||
|
SET(a, b, c, d, 0, 6, T49);
|
||||||
|
SET(d, a, b, c, 7, 10, T50);
|
||||||
|
SET(c, d, a, b, 14, 15, T51);
|
||||||
|
SET(b, c, d, a, 5, 21, T52);
|
||||||
|
SET(a, b, c, d, 12, 6, T53);
|
||||||
|
SET(d, a, b, c, 3, 10, T54);
|
||||||
|
SET(c, d, a, b, 10, 15, T55);
|
||||||
|
SET(b, c, d, a, 1, 21, T56);
|
||||||
|
SET(a, b, c, d, 8, 6, T57);
|
||||||
|
SET(d, a, b, c, 15, 10, T58);
|
||||||
|
SET(c, d, a, b, 6, 15, T59);
|
||||||
|
SET(b, c, d, a, 13, 21, T60);
|
||||||
|
SET(a, b, c, d, 4, 6, T61);
|
||||||
|
SET(d, a, b, c, 11, 10, T62);
|
||||||
|
SET(c, d, a, b, 2, 15, T63);
|
||||||
|
SET(b, c, d, a, 9, 21, T64);
|
||||||
|
#undef SET
|
||||||
|
|
||||||
|
/* Then perform the following additions. (That is increment each
|
||||||
|
of the four registers by the value it had before this block
|
||||||
|
was started.) */
|
||||||
|
pms->abcd[0] += a;
|
||||||
|
pms->abcd[1] += b;
|
||||||
|
pms->abcd[2] += c;
|
||||||
|
pms->abcd[3] += d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
md5_init(md5_state_t *pms)
|
||||||
|
{
|
||||||
|
pms->count[0] = pms->count[1] = 0;
|
||||||
|
pms->abcd[0] = 0x67452301;
|
||||||
|
pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
|
||||||
|
pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
|
||||||
|
pms->abcd[3] = 0x10325476;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
|
||||||
|
{
|
||||||
|
const md5_byte_t *p = data;
|
||||||
|
int left = nbytes;
|
||||||
|
int offset = (pms->count[0] >> 3) & 63;
|
||||||
|
md5_word_t nbits = (md5_word_t)(nbytes << 3);
|
||||||
|
|
||||||
|
if (nbytes <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Update the message length. */
|
||||||
|
pms->count[1] += nbytes >> 29;
|
||||||
|
pms->count[0] += nbits;
|
||||||
|
if (pms->count[0] < nbits)
|
||||||
|
pms->count[1]++;
|
||||||
|
|
||||||
|
/* Process an initial partial block. */
|
||||||
|
if (offset) {
|
||||||
|
int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
|
||||||
|
|
||||||
|
memcpy(pms->buf + offset, p, copy);
|
||||||
|
if (offset + copy < 64)
|
||||||
|
return;
|
||||||
|
p += copy;
|
||||||
|
left -= copy;
|
||||||
|
md5_process(pms, pms->buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process full blocks. */
|
||||||
|
for (; left >= 64; p += 64, left -= 64)
|
||||||
|
md5_process(pms, p);
|
||||||
|
|
||||||
|
/* Process a final partial block. */
|
||||||
|
if (left)
|
||||||
|
memcpy(pms->buf, p, left);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
md5_finish(md5_state_t *pms, md5_byte_t digest[16])
|
||||||
|
{
|
||||||
|
static const md5_byte_t pad[64] = {
|
||||||
|
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
|
};
|
||||||
|
md5_byte_t data[8];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Save the length before padding. */
|
||||||
|
for (i = 0; i < 8; ++i)
|
||||||
|
data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
|
||||||
|
/* Pad to 56 bytes mod 64. */
|
||||||
|
md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
|
||||||
|
/* Append the length. */
|
||||||
|
md5_append(pms, data, 8);
|
||||||
|
for (i = 0; i < 16; ++i)
|
||||||
|
digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
|
||||||
|
}
|
91
Contrib/VPatch/Source/Plugin/md5.h
Normal file
91
Contrib/VPatch/Source/Plugin/md5.h
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source 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 source distribution.
|
||||||
|
|
||||||
|
L. Peter Deutsch
|
||||||
|
ghost@aladdin.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
|
||||||
|
/*
|
||||||
|
Independent implementation of MD5 (RFC 1321).
|
||||||
|
|
||||||
|
This code implements the MD5 Algorithm defined in RFC 1321, whose
|
||||||
|
text is available at
|
||||||
|
http://www.ietf.org/rfc/rfc1321.txt
|
||||||
|
The code is derived from the text of the RFC, including the test suite
|
||||||
|
(section A.5) but excluding the rest of Appendix A. It does not include
|
||||||
|
any code or documentation that is identified in the RFC as being
|
||||||
|
copyrighted.
|
||||||
|
|
||||||
|
The original and principal author of md5.h is L. Peter Deutsch
|
||||||
|
<ghost@aladdin.com>. Other authors are noted in the change history
|
||||||
|
that follows (in reverse chronological order):
|
||||||
|
|
||||||
|
2002-04-13 lpd Removed support for non-ANSI compilers; removed
|
||||||
|
references to Ghostscript; clarified derivation from RFC 1321;
|
||||||
|
now handles byte order either statically or dynamically.
|
||||||
|
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
|
||||||
|
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
|
||||||
|
added conditionalization for C++ compilation from Martin
|
||||||
|
Purschke <purschke@bnl.gov>.
|
||||||
|
1999-05-03 lpd Original version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef md5_INCLUDED
|
||||||
|
# define md5_INCLUDED
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This package supports both compile-time and run-time determination of CPU
|
||||||
|
* byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
|
||||||
|
* compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
|
||||||
|
* defined as non-zero, the code will be compiled to run only on big-endian
|
||||||
|
* CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
|
||||||
|
* run on either big- or little-endian CPUs, but will run slightly less
|
||||||
|
* efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef unsigned char md5_byte_t; /* 8-bit byte */
|
||||||
|
typedef unsigned int md5_word_t; /* 32-bit word */
|
||||||
|
|
||||||
|
/* Define the state of the MD5 Algorithm. */
|
||||||
|
typedef struct md5_state_s {
|
||||||
|
md5_word_t count[2]; /* message length in bits, lsw first */
|
||||||
|
md5_word_t abcd[4]; /* digest buffer */
|
||||||
|
md5_byte_t buf[64]; /* accumulate block */
|
||||||
|
} md5_state_t;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Initialize the algorithm. */
|
||||||
|
void md5_init(md5_state_t *pms);
|
||||||
|
|
||||||
|
/* Append a string to the message. */
|
||||||
|
void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
|
||||||
|
|
||||||
|
/* Finish the message and return the digest. */
|
||||||
|
void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* end extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* md5_INCLUDED */
|
|
@ -1,44 +1,50 @@
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// vpatchdll.c: NSIS plug-in version of the VPatch runtime
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// -=* VPatch *=-
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2001-2005 Koen van de Sande / Van de Sande Productions
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Website: http://www.tibed.net/vpatch
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source 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 source distribution.
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include "../../../ExDLL/exdll.h"
|
#include "apply_patch.h"
|
||||||
|
#include "checksum.h"
|
||||||
|
#include "..\..\..\ExDLL\exdll.h"
|
||||||
|
|
||||||
int DoPatch(HANDLE hPatch, HANDLE hSource, HANDLE hDest);
|
/* ------------------------ Plug-in code ------------------------- */
|
||||||
void strcopy(char *tgt, const char *src);
|
|
||||||
char* chop_arg(char **args);
|
|
||||||
|
|
||||||
#define PATCH_SUCCESS 0
|
|
||||||
#define PATCH_ERROR 1
|
|
||||||
#define PATCH_CORRUPT 2
|
|
||||||
#define PATCH_NOMATCH 3
|
|
||||||
#define PATCH_UPTODATE 4
|
|
||||||
#define FILE_ERR_PATCH 5
|
|
||||||
#define FILE_ERR_SOURCE 6
|
|
||||||
#define FILE_ERR_DEST 7
|
|
||||||
|
|
||||||
HINSTANCE g_hInstance;
|
HINSTANCE g_hInstance;
|
||||||
|
|
||||||
HWND g_hwndParent;
|
HWND g_hwndParent;
|
||||||
|
|
||||||
void __declspec(dllexport) vpatchfile(HWND hwndParent, int string_size,
|
void __declspec(dllexport) vpatchfile(HWND hwndParent, int string_size,
|
||||||
char *variables, stack_t **stacktop)
|
char *variables, stack_t **stacktop) {
|
||||||
{
|
|
||||||
g_hwndParent=hwndParent;
|
g_hwndParent=hwndParent;
|
||||||
|
|
||||||
EXDLL_INIT();
|
EXDLL_INIT();
|
||||||
|
|
||||||
|
|
||||||
// note if you want parameters from the stack, pop them off in order.
|
|
||||||
// i.e. if you are called via exdll::myFunction file.dat poop.dat
|
|
||||||
// calling popstring() the first time would give you file.dat,
|
|
||||||
// and the second time would give you poop.dat.
|
|
||||||
// you should empty the stack of your parameters, and ONLY your
|
|
||||||
// parameters.
|
|
||||||
|
|
||||||
// do your stuff here
|
|
||||||
{
|
{
|
||||||
static char source[1024];
|
char source[MAX_PATH];
|
||||||
static char dest[1024];
|
char dest[MAX_PATH];
|
||||||
static char exename[1024];
|
char exename[MAX_PATH];
|
||||||
HANDLE hPatch, hSource, hDest;
|
HANDLE hPatch, hSource, hDest;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
@ -78,7 +84,7 @@ void __declspec(dllexport) vpatchfile(HWND hwndParent, int string_size,
|
||||||
|
|
||||||
if ((result != PATCH_SUCCESS)) {
|
if ((result != PATCH_SUCCESS)) {
|
||||||
if (result == PATCH_ERROR)
|
if (result == PATCH_ERROR)
|
||||||
pushstring("An error occurred while patching");
|
pushstring("An error occured while patching");
|
||||||
else if (result == PATCH_CORRUPT)
|
else if (result == PATCH_CORRUPT)
|
||||||
pushstring("Patch data is invalid or corrupt");
|
pushstring("Patch data is invalid or corrupt");
|
||||||
else if (result == PATCH_NOMATCH)
|
else if (result == PATCH_NOMATCH)
|
||||||
|
@ -94,183 +100,79 @@ void __declspec(dllexport) vpatchfile(HWND hwndParent, int string_size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DLL_CHECKSUMS
|
||||||
|
void __declspec(dllexport) GetFileCRC32(HWND hwndParent, int string_size,
|
||||||
|
char *variables, stack_t **stacktop) {
|
||||||
|
g_hwndParent=hwndParent;
|
||||||
|
|
||||||
|
EXDLL_INIT();
|
||||||
|
|
||||||
BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
|
{
|
||||||
{
|
char filename[MAX_PATH];
|
||||||
|
char crc_string[9];
|
||||||
|
HANDLE hFile;
|
||||||
|
unsigned long crc;
|
||||||
|
|
||||||
|
popstring(filename);
|
||||||
|
|
||||||
|
hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
|
||||||
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
|
if (hFile == INVALID_HANDLE_VALUE) {
|
||||||
|
//pushstring("ERROR: Unable to open file for CRC32 calculation");
|
||||||
|
pushstring("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!FileCRC(hFile, &crc)) {
|
||||||
|
//pushstring("ERROR: Unable to calculate CRC32");
|
||||||
|
pushstring("");
|
||||||
|
} else {
|
||||||
|
crc_string[8] = '\0';
|
||||||
|
CRC32ToString(crc_string,crc);
|
||||||
|
pushstring(crc_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(hFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __declspec(dllexport) GetFileMD5(HWND hwndParent, int string_size,
|
||||||
|
char *variables, stack_t **stacktop) {
|
||||||
|
g_hwndParent=hwndParent;
|
||||||
|
|
||||||
|
EXDLL_INIT();
|
||||||
|
|
||||||
|
{
|
||||||
|
char filename[MAX_PATH];
|
||||||
|
char md5_string[33];
|
||||||
|
HANDLE hFile;
|
||||||
|
md5_byte_t digest[16];
|
||||||
|
|
||||||
|
popstring(filename);
|
||||||
|
|
||||||
|
hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
|
||||||
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
|
if (hFile == INVALID_HANDLE_VALUE) {
|
||||||
|
//pushstring("ERROR: Unable to open file for MD5 calculation");
|
||||||
|
pushstring("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!FileMD5(hFile, digest)) {
|
||||||
|
//pushstring("ERROR: Unable to calculate MD5");
|
||||||
|
pushstring("");
|
||||||
|
} else {
|
||||||
|
md5_string[32] = '\0';
|
||||||
|
MD5ToString(md5_string,digest);
|
||||||
|
pushstring(md5_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(hFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) {
|
||||||
g_hInstance=hInst;
|
g_hInstance=hInst;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
UINT CRCTable[256];
|
|
||||||
BOOL bInitCRC = FALSE;
|
|
||||||
|
|
||||||
void InitCRC() {
|
|
||||||
int i, j; unsigned long c;
|
|
||||||
for (c = i = 0; i < 256; c = ++i) {
|
|
||||||
for (j = 0; j < 8; j++) {
|
|
||||||
if (c & 1) c = (c>>1) ^ 0xEDB88320;
|
|
||||||
else c >>= 1;
|
|
||||||
}
|
|
||||||
CRCTable[i] = c;
|
|
||||||
}
|
|
||||||
bInitCRC = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define CRCBLOCKSIZE 4096
|
|
||||||
|
|
||||||
BOOL FileCRC(HANDLE hFile, DWORD *crc) {
|
|
||||||
static BYTE crcblock[CRCBLOCKSIZE];
|
|
||||||
DWORD read;
|
|
||||||
BYTE *p;
|
|
||||||
|
|
||||||
UINT c = 0xFFFFFFFF;
|
|
||||||
if (bInitCRC == FALSE)
|
|
||||||
InitCRC();
|
|
||||||
|
|
||||||
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
|
|
||||||
do {
|
|
||||||
if (ReadFile(hFile, crcblock, CRCBLOCKSIZE, &read, NULL) == FALSE)
|
|
||||||
return FALSE;
|
|
||||||
for (p = crcblock; p < crcblock + read; p++)
|
|
||||||
c = CRCTable[(c & 0xFF) ^ *p] ^ (c >> 8);
|
|
||||||
} while (read);
|
|
||||||
|
|
||||||
*crc = (c ^ 0xFFFFFFFF);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define BLOCKSIZE 16384
|
|
||||||
|
|
||||||
int DoPatch(HANDLE hPatch, HANDLE hSource, HANDLE hDest) {
|
|
||||||
|
|
||||||
static char block[BLOCKSIZE];
|
|
||||||
|
|
||||||
unsigned long temp = 0;
|
|
||||||
unsigned long read;
|
|
||||||
unsigned long source_crc = 0;
|
|
||||||
unsigned long patch_dest_crc = 0;
|
|
||||||
long patches = 0;
|
|
||||||
int already_uptodate = 0;
|
|
||||||
// special 'addition' for the dll: since the patch file is now
|
|
||||||
// in a seperate file, the VPAT header might be right at the start
|
|
||||||
// of the file, and a pointer at the end of the file is probably missing
|
|
||||||
// (because all patch generator versions don't append it, the linker/gui
|
|
||||||
// does this).
|
|
||||||
SetFilePointer(hPatch, 0, NULL, FILE_BEGIN);
|
|
||||||
ReadFile(hPatch, &temp, 4, &read, NULL);
|
|
||||||
// it's not at the start of file -> there must be a pointer at the end of
|
|
||||||
// file then
|
|
||||||
if (temp != 0x54415056) {
|
|
||||||
SetFilePointer(hPatch, -4, NULL, FILE_END);
|
|
||||||
ReadFile(hPatch, &temp, 4, &read, NULL);
|
|
||||||
|
|
||||||
SetFilePointer(hPatch, temp, NULL, FILE_BEGIN);
|
|
||||||
ReadFile(hPatch, &temp, 4, &read, NULL);
|
|
||||||
if (temp != 0x54415056)
|
|
||||||
return PATCH_CORRUPT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!FileCRC(hSource, &source_crc))
|
|
||||||
return PATCH_ERROR;
|
|
||||||
|
|
||||||
|
|
||||||
ReadFile(hPatch, &patches, 4, &read, NULL);
|
|
||||||
|
|
||||||
while (patches--) {
|
|
||||||
long patch_blocks = 0, patch_size = 0;
|
|
||||||
unsigned long patch_source_crc = 0;
|
|
||||||
|
|
||||||
ReadFile(hPatch, &patch_blocks, 4, &read, NULL);
|
|
||||||
ReadFile(hPatch, &patch_source_crc, 4, &read, NULL);
|
|
||||||
ReadFile(hPatch, &patch_dest_crc, 4, &read, NULL);
|
|
||||||
ReadFile(hPatch, &patch_size, 4, &read, NULL);
|
|
||||||
|
|
||||||
//added by Koen - check to see if it's already up-to-date for some patch (so
|
|
||||||
//we can tell NSIS this isn't an error, but we already have the latest version)
|
|
||||||
if (source_crc == patch_dest_crc) {
|
|
||||||
already_uptodate = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (source_crc == patch_source_crc) {
|
|
||||||
while (patch_blocks--) {
|
|
||||||
unsigned char blocktype = 0;
|
|
||||||
unsigned long blocksize = 0;
|
|
||||||
ReadFile(hPatch, &blocktype, 1, &read, NULL);
|
|
||||||
|
|
||||||
switch (blocktype) {
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
if (blocktype == 1)
|
|
||||||
{ unsigned char x; blocksize = ReadFile(hPatch,&x,1,&read,NULL)? x:0; }
|
|
||||||
else if (blocktype == 2)
|
|
||||||
{ unsigned short x; blocksize = ReadFile(hPatch,&x,2,&read,NULL)? x:0; }
|
|
||||||
else
|
|
||||||
{ unsigned long x; blocksize = ReadFile(hPatch,&x,4,&read,NULL)? x:0; }
|
|
||||||
|
|
||||||
if (!blocksize || !ReadFile(hPatch, &temp, 4, &read, NULL) || read != 4)
|
|
||||||
return PATCH_CORRUPT;
|
|
||||||
|
|
||||||
SetFilePointer(hSource, temp, 0, FILE_BEGIN);
|
|
||||||
|
|
||||||
do {
|
|
||||||
ReadFile(hSource, block, min(BLOCKSIZE, blocksize), &read, NULL);
|
|
||||||
WriteFile(hDest, block, read, &temp, NULL);
|
|
||||||
if (temp != min(BLOCKSIZE, blocksize))
|
|
||||||
return PATCH_ERROR;
|
|
||||||
blocksize -= temp;
|
|
||||||
} while (temp);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 5:
|
|
||||||
case 6:
|
|
||||||
case 7:
|
|
||||||
if (blocktype == 5)
|
|
||||||
{ unsigned char x; blocksize = ReadFile(hPatch,&x,1,&read,NULL)? x:0; }
|
|
||||||
else if (blocktype == 6)
|
|
||||||
{ unsigned short x; blocksize = ReadFile(hPatch,&x,2,&read,NULL)? x:0; }
|
|
||||||
else
|
|
||||||
{ unsigned long x; blocksize = ReadFile(hPatch,&x,4,&read,NULL)? x:0; }
|
|
||||||
|
|
||||||
if (!blocksize)
|
|
||||||
return PATCH_CORRUPT;
|
|
||||||
|
|
||||||
do {
|
|
||||||
ReadFile(hPatch, block, min(BLOCKSIZE, blocksize), &read, NULL);
|
|
||||||
WriteFile(hDest, block, read, &temp, NULL);
|
|
||||||
if (temp != min(BLOCKSIZE, blocksize))
|
|
||||||
return PATCH_ERROR;
|
|
||||||
blocksize -= temp;
|
|
||||||
} while (temp);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return PATCH_CORRUPT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
unsigned long dest_crc = 0;
|
|
||||||
FileCRC(hDest, &dest_crc);
|
|
||||||
if (dest_crc != patch_dest_crc)
|
|
||||||
return PATCH_ERROR;
|
|
||||||
|
|
||||||
return PATCH_SUCCESS;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SetFilePointer(hPatch, patch_size, NULL, FILE_CURRENT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//added by Koen - if already up to date, it doesn't matter that we didn't match
|
|
||||||
if(already_uptodate) {
|
|
||||||
return PATCH_UPTODATE;
|
|
||||||
} else {
|
|
||||||
return PATCH_NOMATCH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
#------------------------------------------------------------------------------
|
|
||||||
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: GenPat\GenPat2.dpr
|
|
||||||
$(DCC)
|
|
||||||
|
|
||||||
VAppend.exe: GenPat\VAppend.dpr
|
|
||||||
$(DCC)
|
|
||||||
|
|
||||||
VPatchGUI.exe: gui\VPatchGUI.dpr
|
|
||||||
$(DCC)
|
|
||||||
|
|
||||||
|
|
22
Contrib/VPatch/VPatchLib.nsh
Normal file
22
Contrib/VPatch/VPatchLib.nsh
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
; PatchLib v3.0
|
||||||
|
; =============
|
||||||
|
;
|
||||||
|
; Library with macro for use with VPatch (DLL version) in NSIS 2.0.5+
|
||||||
|
; Created by Koen van de Sande
|
||||||
|
|
||||||
|
!macro VPatchFile PATCHDATA SOURCEFILE TEMPFILE
|
||||||
|
InitPluginsDir
|
||||||
|
File /oname=$PLUGINSDIR\${PATCHDATA} ${PATCHDATA}
|
||||||
|
vpatch::vpatchfile "$PLUGINSDIR\${PATCHDATA}" "${SOURCEFILE}" "${TEMPFILE}"
|
||||||
|
Pop $1
|
||||||
|
DetailPrint $1
|
||||||
|
StrCpy $1 $1 2
|
||||||
|
StrCmp $1 "OK" ok_${SOURCEFILE}
|
||||||
|
SetErrors
|
||||||
|
ok_${SOURCEFILE}:
|
||||||
|
IfFileExists "${TEMPFILE}" +1 end_${SOURCEFILE}
|
||||||
|
Delete "${SOURCEFILE}"
|
||||||
|
Rename /REBOOTOK "${TEMPFILE}" "${SOURCEFILE}"
|
||||||
|
end_${SOURCEFILE}:
|
||||||
|
Delete "$PLUGINSDIR\${PATCHDATA}"
|
||||||
|
!macroend
|
|
@ -19,8 +19,27 @@ DirText "Choose a folder in which to install the VPatch Test!"
|
||||||
ShowInstDetails show
|
ShowInstDetails show
|
||||||
|
|
||||||
;--------------------------------
|
;--------------------------------
|
||||||
|
; The normal way to use VPatch
|
||||||
|
;--------------------------------
|
||||||
|
!include "VPatchLib.nsh"
|
||||||
|
|
||||||
Section ""
|
Section "Update file"
|
||||||
|
; Set output path to the installation directory
|
||||||
|
SetOutPath $INSTDIR
|
||||||
|
|
||||||
|
; Extract the old file under name 'updatefile.txt'
|
||||||
|
File /oname=updatefile.txt oldfile.txt
|
||||||
|
|
||||||
|
; Update the file - it will be replaced with the new version
|
||||||
|
DetailPrint "Updating updatefile.txt using patch..."
|
||||||
|
!insertmacro VPatchFile "patch.pat" "$INSTDIR\updatefile.txt" "$INSTDIR\temporaryfile.txt"
|
||||||
|
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
;-------------------------------
|
||||||
|
; The hard way to use VPatch
|
||||||
|
;-------------------------------
|
||||||
|
Section "New version in separate file"
|
||||||
|
|
||||||
; Set output path to the installation directory
|
; Set output path to the installation directory
|
||||||
SetOutPath $INSTDIR
|
SetOutPath $INSTDIR
|
||||||
|
@ -33,7 +52,7 @@ Section ""
|
||||||
File /oname=$PLUGINSDIR\patch.pat patch.pat
|
File /oname=$PLUGINSDIR\patch.pat patch.pat
|
||||||
|
|
||||||
; Update the old file to the new file using the patch
|
; Update the old file to the new file using the patch
|
||||||
DetailPrint "Updating oldfile.txt using patch..."
|
DetailPrint "Updating oldfile.txt using patch to newfile.txt..."
|
||||||
vpatch::vpatchfile "$PLUGINSDIR\patch.pat" "$INSTDIR\oldfile.txt" "$INSTDIR\newfile.txt"
|
vpatch::vpatchfile "$PLUGINSDIR\patch.pat" "$INSTDIR\oldfile.txt" "$INSTDIR\newfile.txt"
|
||||||
|
|
||||||
; Show result
|
; Show result
|
||||||
|
|
Binary file not shown.
|
@ -633,6 +633,8 @@ Section "VPatch" SecPluginsVPatch
|
||||||
File ..\Docs\VPatch\Readme.html
|
File ..\Docs\VPatch\Readme.html
|
||||||
SetOutPath $INSTDIR\Bin
|
SetOutPath $INSTDIR\Bin
|
||||||
File ..\Bin\GenPat.exe
|
File ..\Bin\GenPat.exe
|
||||||
|
SetOutPath $INSTDIR\Include
|
||||||
|
File ..\Include\VPatchLib.nsh
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
SectionGroupEnd
|
SectionGroupEnd
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
## TODO
|
## TODO
|
||||||
#
|
#
|
||||||
# * VPatch GenPat & distribution
|
|
||||||
# * Write SConscript for NSIS Menu
|
# * Write SConscript for NSIS Menu
|
||||||
# - Use inheritance instead of current wxWidgets patches
|
# - Use inheritance instead of current wxWidgets patches
|
||||||
# - Compile for POSIX too? wxWidgets is cross platform after all...
|
# - Compile for POSIX too? wxWidgets is cross platform after all...
|
||||||
|
@ -41,13 +40,15 @@ utils = [
|
||||||
'Makensisw',
|
'Makensisw',
|
||||||
'NSIS Menu',
|
'NSIS Menu',
|
||||||
'UIs',
|
'UIs',
|
||||||
|
'VPatch/Source/GenPat',
|
||||||
'zip2exe'
|
'zip2exe'
|
||||||
]
|
]
|
||||||
|
|
||||||
misc = [
|
misc = [
|
||||||
'Graphics',
|
'Graphics',
|
||||||
'Language files',
|
'Language files',
|
||||||
'Modern UI'
|
'Modern UI',
|
||||||
|
'VPatch'
|
||||||
]
|
]
|
||||||
|
|
||||||
defenv = Environment()
|
defenv = Environment()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue