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:
kichik 2005-09-17 09:25:44 +00:00
parent 9929eb7120
commit 4bf6509225
53 changed files with 3918 additions and 1782 deletions

Binary file not shown.

View file

@ -2,7 +2,7 @@
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>VPatch 2</title>
<title>VPatch 3</title>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
<style type="text/css">
/*<![CDATA[*/
@ -97,12 +97,13 @@ a:hover
<table width="750" class="maintable" cellspacing="0" cellpadding="0" align="center">
<tr>
<td>
<h1>VPatch 2</h1>
<h1>VPatch 3.0</h1>
<div>
<h2>Introduction</h2>
<div>
<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
reduce the download size of your updates, because only the differences
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
the command line tool GenPat.exe:</p>
<pre>
GENPAT data.dta data_20.dta data.pat
GENPAT oldfile.txt newfile.txt patch.pat
</pre>
<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
after the filenames), you can use a different block size. A smaller
block size may result in a smaller patch, but the generation will
take more time (the default blocksize is 64).</p>
<p>Using the /B=(BlockSize) parameter of the GenPat utility (put it
after the filenames), you can use a different block size. A smaller
block size may result in a smaller patch, but the generation will
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>
<h3>Update the file during installation</h3>
<div>
<p>Use the VPatch plug-in to update a file using a patch file:</p>
<pre>
vpatch::vpatchfile "pathfile.pat" "source.file" "new.file"
vpatch::vpatchfile "patch.pat" "oldfile.txt" "temporary_newfile.txt"
</pre>
<p>The result of the patch operating will be added to the stack and
can be one of the following texts:</p>
<ul>
<li>OK</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>No suitable patches were found</li>
</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 &quot;OK&quot;
because then the patch has succeeded and you can rename &quot;temporary_newfile.txt&quot;
to &quot;oldfile.txt&quot; to replace the original, if you want.</p>
</div>
<h3>Multiple patches in one file</h3>
<div>
<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
1 and 2 to version 3, you can put a 1 &gt; 3 and 2 &gt; 3 patch in
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
patch (based on the file CRC).</p>
</div>
<h3>GenPat exit codes</h3>
<h3>Patch generator (GenPat) exit codes</h3>
<div>
<p>In version 2.1 support was added for exit codes (known as error levels
in the DOS period) to GenPat. GenPat will return an exit code based
on success of the patch generation. Here is a list of the possible
exit codes:</p>
<table width="547" border="0" cellspacing="0" cellpadding="0">
<tr>
<td><b>Exit code</b></td>
<td><b>Description</b></td>
</tr>
<tr>
<td>0</td>
<td>Success</td>
</tr>
<tr>
<td>1</td>
<td>Arguments missing</td>
</tr>
<tr>
<td>2</td>
<td>Source file not found</td>
</tr>
<tr>
<td>3</td>
<td>Target file not found</td>
</tr>
<tr>
<td>4</td>
<td>Unknown error while reading existing patch file</td>
</tr>
<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>
<p>In version 3 the following exit codes (known as error levels in
the DOS period) can be returned by GenPat. GenPat will return an
exit code based on succes of the patch generation. Here is a list
of the possible exit codes:</p>
<table width="547" border="0" cellspacing="0" cellpadding="0">
<tr>
<td><b>Exit code</b></td>
<td><b>Description</b></td>
</tr>
<tr>
<td>0</td>
<td>Success</td>
</tr>
<tr>
<td>1</td>
<td>Arguments missing</td>
</tr>
<tr>
<td>2</td>
<td>Other error</td>
</tr>
<tr>
<td>3</td>
<td>Source file already has a patch in specified patch file (ERROR),
use /R switch to override</td>
</tr>
</table>
<p>These exit codes can be useful when you generate patch files through
a NSIS script.</p>
</div>
</div>
</div>
<div>
<h2>Source code</h2>
<div>
<p>Source code is available in the original package and in the CVS repository of NSIS.</p>
<h3>NSIS plug-in (C++)</h3>
<div>
<p>The source of the NSIS plug-in that applies patches can be found
in the Source\Plugin folder.</p>
</div>
<h3>Patch Generator (Delphi)</h3>
<h3>Patch Generator (C++)</h3>
<div>
<p>The most interesting part of VPatch, the actual patch generation
algorithm, can be found in Source\GenPat\PatchGenerator.pas. The header
of that file contains a brief explanation of the algorithm as well.</p>
<p>The most interesting part of VPatch, the actual patch generation
algoritm, can be found in Source\GenPat\PatchGenerator.cpp. The
header of that file contains a brief explanation of the algorithm
as well.</p>
</div>
<h3>User interface (Delphi)</h3>
<div>
@ -233,10 +219,54 @@ vpatch::vpatchfile "pathfile.pat" "source.file" "new.file"
edition), you will also need to install the <a href=
"http://www.delphi-gems.com">VirtualTreeView</a> component by Mike Lischke.</p>
</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>
<h2>Version history</h2>
<div>
<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
<ul>
<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>
<div>
<p>Written by Koen van de Sande<br />
C plug-in by Edgewize<br />
New documentation and example by Joost Verburg</p>
C plug-in initially by Edgewize, updated by Koen van de Sande<br />
New documentation and example by Joost Verburg and Koen van de Sande</p>
</div>
<h2>License</h2>
<div>
<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
warranty. In no event will the authors be held liable for any damages

22
Contrib/VPatch/SConscript Normal file
View 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)

View file

@ -6,48 +6,46 @@ uses Classes, SysUtils;
function DoGenerate(const Source, Target: String; Stream: TStream; Config: String): Integer; forward;
var
WaitAfterGenerate: Boolean = False;
OptimalPatches: Boolean = False;
implementation
uses PatchGenerator;
uses
OSUtil, Forms;
function DoGenerate(const Source, Target: String; Stream: TStream; Config: String): Integer;
var
PG: TPatchGenerator;
a: Integer;
F: TextFile;
Temp, BatchFile: String;
fs: TFileStream;
begin
WriteLn('Generating '+ExtractFileName(Source)+' to '+ExtractFileName(Target)+'...');
PG:=TPatchGenerator.Create;
PG.StartBlockSize:=512;
PG.MinimumBlockSize:=512;
PG.BlockDivider:=2;
PG.StepSize:=256;
try
a:=Pos(',',Config);
if(a=0) then a:=Length(Config)+1;
PG.StartBlockSize:=StrToInt(Copy(Config,1,a-1));
Config:=Copy(Config,a+1,Length(Config));
a:=Pos(',',Config);
if(a=0) then a:=Length(Config)+1;
PG.MinimumBlockSize:=StrToInt(Copy(Config,1,a-1));
Config:=Copy(Config,a+1,Length(Config));
a:=Pos(',',Config);
if(a=0) then a:=Length(Config)+1;
PG.BlockDivider:=StrToInt(Copy(Config,1,a-1));
Config:=Copy(Config,a+1,Length(Config));
a:=Pos(',',Config);
if(a=0) then a:=Length(Config)+1;
PG.StepSize:=StrToInt(Copy(Config,1,a-1));
finally
BatchFile:=ExcludeTrailingPathDelimiter(ExtractFilePath(Application.ExeName)) + PathDelim +'~generate_patch.bat';
AssignFile(F,BatchFile);
Rewrite(F);
Temp:=GetTempFile;
WriteLn(F,'@cls');
WriteLn(F,'@echo Generating '+ExtractFileName(Source)+' to '+ExtractFileName(Target)+'...');
Write(F,'genpat.exe "', Source, '" "', Target, '" "', Temp, '" /b='+Config);
if OptimalPatches then begin
Write(F,' /o');
end;
WriteLn(F,'');
if WaitAfterGenerate then begin
WriteLn(F,'@echo.');
WriteLn(F,'@pause');
end;
CloseFile(F);
Result:=PG.CreatePatch(Source,Target);
PG.WriteToStream(Stream);
PG.Free;
WriteLn(ExtractFileName(Source)+' -> '+ExtractFileName(Target)+': '+IntToStr(Result)+' bytes');
ExecWaitBatchFile(ExtractFilePath(BatchFile),BatchFile);
fs:=TFileStream.Create(Temp,fmOpenRead);
Stream.CopyFrom(fs,fs.Size);
Result:=fs.Size;
fs.Free;
DeleteFile(Temp);
DeleteFile(BatchFile);
end;
end.

View file

@ -4,7 +4,7 @@ object frmMain: TfrmMain
BorderIcons = [biSystemMenu, biMinimize]
BorderStyle = bsSingle
Caption = 'VG - VPatch GUI'
ClientHeight = 361
ClientHeight = 385
ClientWidth = 689
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
@ -12,6 +12,121 @@ object frmMain: TfrmMain
Font.Height = -11
Font.Name = 'MS Sans Serif'
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
OldCreateOrder = False
Position = poScreenCenter
@ -36,17 +151,59 @@ object frmMain: TfrmMain
object butAdd: TSpeedButton
Left = 24
Top = 328
Width = 89
Width = 193
Height = 25
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
end
object grpConfig: TGroupBox
Left = 232
Top = 43
Top = 51
Width = 441
Height = 278
Height = 270
Enabled = False
TabOrder = 0
object Label2: TLabel
@ -123,14 +280,6 @@ object frmMain: TfrmMain
Hint = 'Smaller gives smaller patch files, but decreased speed'
Caption = 'Block size'
end
object Label6: TLabel
Left = 32
Top = 248
Width = 91
Height = 13
Caption = 'Minimum block size'
Visible = False
end
object Label7: TLabel
Left = 232
Top = 224
@ -139,14 +288,6 @@ object frmMain: TfrmMain
Caption = 'Block divider'
Visible = False
end
object Label8: TLabel
Left = 232
Top = 248
Width = 43
Height = 13
Caption = 'Step size'
Visible = False
end
object txtStartBlockSize: TLabel
Left = 136
Top = 224
@ -171,78 +312,6 @@ object frmMain: TfrmMain
ItemHeight = 13
TabOrder = 1
end
object txtMinimumBlockSize: TEdit
Left = 136
Top = 248
Width = 65
Height = 21
TabOrder = 2
Text = '16'
Visible = False
OnChange = txtMinimumBlockSizeChange
end
object UDMinimumBlockSize: TUpDown
Left = 201
Top = 248
Width = 15
Height = 21
Associate = txtMinimumBlockSize
Min = 16
Max = 4096
Increment = 16
Position = 16
TabOrder = 3
Visible = False
Wrap = False
end
object UDBlockDivider: TUpDown
Left = 401
Top = 224
Width = 15
Height = 21
Associate = txtBlockDivider
Min = 2
Max = 512
Increment = 2
Position = 16
TabOrder = 4
Visible = False
Wrap = False
end
object txtBlockDivider: TEdit
Left = 336
Top = 224
Width = 65
Height = 21
TabOrder = 5
Text = '16'
Visible = False
OnChange = txtBlockDividerChange
end
object UDStepSize: TUpDown
Left = 401
Top = 248
Width = 15
Height = 21
Associate = txtStepSize
Min = 16
Max = 4096
Increment = 16
Position = 16
TabOrder = 6
Visible = False
Wrap = False
end
object txtStepSize: TEdit
Left = 336
Top = 248
Width = 65
Height = 21
TabOrder = 7
Text = '16'
Visible = False
OnChange = txtStepSizeChange
end
object tbBlockSize: TTrackBar
Left = 200
Top = 224
@ -250,22 +319,16 @@ object frmMain: TfrmMain
Height = 25
Max = 12
Min = 4
Orientation = trHorizontal
Frequency = 1
Position = 6
SelEnd = 0
SelStart = 0
TabOrder = 8
TickMarks = tmBottomRight
TickStyle = tsAuto
TabOrder = 2
OnChange = tbBlockSizeChange
end
end
object lstNew: TVirtualStringTree
Left = 24
Top = 48
Top = 56
Width = 193
Height = 273
Height = 265
Header.AutoSizeIndex = 0
Header.Font.Charset = DEFAULT_CHARSET
Header.Font.Color = clWindowText
@ -371,14 +434,25 @@ object frmMain: TfrmMain
end
end
end
object chkDebug: TCheckBox
object chkOutputWait: TCheckBox
Left = 232
Top = 336
Width = 289
Width = 305
Height = 17
Caption = 'Show extended information during patch generation'
Caption = 'Leave console window open after generating patches'
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
object MainMenu: TMainMenu
Images = IL
@ -446,6 +520,21 @@ object frmMain: TfrmMain
end
object mnuHelp: TMenuItem
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
Caption = '&About'
OnClick = mnuAboutClick

View file

@ -5,7 +5,7 @@ interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Buttons, StdCtrls, Menus, PatchClasses, VirtualTrees, VDSP_CRC,
ToolWin, ComCtrls, ImgList, ExtCtrls, PatchGenerator, Math;
ToolWin, ComCtrls, ImgList, ExtCtrls, Math, OSUtil;
const
UntitledFile='Untitled.vpj';
@ -50,16 +50,7 @@ type
toolCreateEXE: TToolButton;
barCool: TCoolBar;
Label5: TLabel;
Label6: TLabel;
txtMinimumBlockSize: TEdit;
UDMinimumBlockSize: TUpDown;
UDBlockDivider: TUpDown;
txtBlockDivider: TEdit;
Label7: TLabel;
UDStepSize: TUpDown;
txtStepSize: TEdit;
Label8: TLabel;
chkDebug: TCheckBox;
tbBlockSize: TTrackBar;
txtStartBlockSize: TLabel;
mnuClearcachedpatches: TMenuItem;
@ -70,6 +61,12 @@ type
toolCreatePAT: TToolButton;
dlgSaveDLL: TSaveDialog;
dlgSavePAT: TSaveDialog;
chkOutputWait: TCheckBox;
mnuWebsite: TMenuItem;
Readme1: TMenuItem;
N2: TMenuItem;
ReadmeincludedwithNSIS1: TMenuItem;
chkOptimal: TCheckBox;
procedure butAddClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
@ -95,11 +92,15 @@ type
procedure txtMinimumBlockSizeChange(Sender: TObject);
procedure txtBlockDividerChange(Sender: TObject);
procedure txtStepSizeChange(Sender: TObject);
procedure chkDebugClick(Sender: TObject);
procedure tbBlockSizeChange(Sender: TObject);
procedure mnuClearcachedpatchesClick(Sender: TObject);
procedure mnuCreateDLLClick(Sender: TObject);
procedure mnuCreatePATClick(Sender: TObject);
procedure chkOutputWaitClick(Sender: TObject);
procedure mnuWebsiteClick(Sender: TObject);
procedure Readme1Click(Sender: TObject);
procedure ReadmeincludedwithNSIS1Click(Sender: TObject);
procedure chkOptimalClick(Sender: TObject);
private
{ Private declarations }
// MS: TModeSelector;
@ -108,7 +109,6 @@ type
procedure OpenAFile(FileName: String; AskSave: Boolean=True; PromptNew: Boolean=False);
function CollectConfig: String;
procedure SetConfigTextBoxes(Config: String);
procedure PrintDebug(S: String);
public
{ Public declarations }
end;
@ -119,7 +119,7 @@ var
implementation
uses AboutForm;
uses AboutForm, DLLWrapper;
{$R *.dfm}
@ -292,15 +292,15 @@ begin
PP:=TPatchProject.Create;
ReloadNewTree;
if FileName<>'' then begin
fs:=nil;
try
fs:=TFileStream.Create(FileName,fmOpenRead);
PP.LoadFromStream(fs);
finally
try
PP.LoadFromStream(fs);
except
on E: Exception do ShowMessage(E.Message);
end;
dskName:=FileName;
ReloadNewTree;
fs.Free;
end;
end else begin
dskName:=UntitledFile;
if PromptNew then butAddClick(Self);
@ -318,6 +318,8 @@ procedure TfrmMain.mnuOpenClick(Sender: TObject);
begin
if dlgOpen.Execute then begin
OpenAFile(dlgOpen.FileName,True);
if lstNew.GetFirst <> nil then
lstNew.Selected[lstNew.GetFirst]:=True;
end;
end;
@ -460,7 +462,7 @@ end;
function TfrmMain.CollectConfig: String;
begin
Result:=txtStartBlockSize.Caption+','+txtMinimumBlockSize.Text+','+txtBlockDivider.Text+','+txtStepSize.Text;
Result:=txtStartBlockSize.Caption;
end;
procedure TfrmMain.txtMinimumBlockSizeChange(Sender: TObject);
@ -494,33 +496,6 @@ begin
Inc(i);
end;
tbBlockSize.Position := i;
a:=Pos(',',Config);
if(a=0) then a:=Length(Config)+1;
txtMinimumBlockSize.Text:=Copy(Config,1,a-1);
Config:=Copy(Config,a+1,Length(Config));
a:=Pos(',',Config);
if(a=0) then a:=Length(Config)+1;
txtBlockDivider.Text:=Copy(Config,1,a-1);
Config:=Copy(Config,a+1,Length(Config));
a:=Pos(',',Config);
if(a=0) then a:=Length(Config)+1;
txtStepSize.Text:=Copy(Config,1,a-1);
end;
procedure TfrmMain.chkDebugClick(Sender: TObject);
begin
if chkDebug.State = cbUnchecked then
PatchGenerator.DebugEvent:=nil
else
PatchGenerator.DebugEvent:=PrintDebug;
end;
procedure TfrmMain.PrintDebug(S: String);
begin
WriteLn(S);
end;
procedure TfrmMain.tbBlockSizeChange(Sender: TObject);
@ -534,6 +509,31 @@ begin
PP.ResetCache;
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
PP:=TPatchProject.Create;
end.

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

View file

@ -5,7 +5,7 @@ interface
uses Classes, sysutils, VDSP_CRC, DLLWrapper, Dialogs;
const
DEFAULT_CONFIG = '64,64,2,32';
DEFAULT_CONFIG = '64';
type
TAbstractFile = record
@ -215,7 +215,7 @@ begin
Result:=FOld[Index].FileName;
if FOld[Index].Cached then
if FOld[Index].Cache.Size>0 then begin
Result:=Result + ' ('+IntToStr(FOld[Index].Cache.Size)+' bytes)';
Result:=Result + ' ('+IntToStr(FOld[Index].Cache.Size)+' bytes to patch)';
end;
end;
@ -445,6 +445,7 @@ end;
procedure TPatchProject.LoadFromStream(Stream: TStream);
var
MagicWord: Array[0..15] of Char;
i: LongInt;
j: Integer;
begin
@ -453,15 +454,13 @@ begin
FPat[j].Free;
FPat[j]:=nil;
end;
Stream.Read(i,SizeOf(i));
if(i=$1A4A5056) then begin //still read old files
Stream.Read(i,SizeOf(i)); //16 dummy bytes
Stream.Read(i,SizeOf(i));
Stream.Read(i,SizeOf(i));
Stream.Read(i,SizeOf(i));
Stream.Read(MagicWord,SizeOf(MagicWord));
if SameText('VPatchProject 3'#26,MagicWord) then begin
Stream.Read(i,SizeOf(i)); //4 dummy bytes
end else
raise Exception.Create('Error: file format incompatible (only version 3 and newer are supported).');
Stream.Read(i,SizeOf(i));
end;
Stream.Read(i,SizeOf(i)); // file count
SetLength(FPat,i);
for j:=0 to i - 1 do begin
FPat[j]:=TPatchFile.Create(j,Stream);
@ -503,18 +502,15 @@ end;
procedure TPatchProject.SaveToStream(Stream: TStream);
var
HeadID: Array[0..3] of Char;
HeadID: Array[0..15] of Char;
i: LongInt;
j: Integer;
begin
HeadID:='VPJ'+#26;
HeadID:='VPatchProject 3'+#26;
Stream.Write(HeadID,SizeOf(HeadID));
//16 dummy bytes
//4 dummy bytes left
i:=0;
Stream.Write(i,SizeOf(i));
Stream.Write(i,SizeOf(i));
Stream.Write(i,SizeOf(i));
Stream.Write(i,SizeOf(i));
i:=Length(FPat);
Stream.Write(i,SizeOf(i));
for j:=0 to i - 1 do begin
@ -525,6 +521,7 @@ end;
procedure TPatchProject.WritePatches(Stream: TStream);
var
i,j,k,o: LongInt;
q: LongWord;
begin
k:=$54415056;
o:=Stream.Position;
@ -539,7 +536,10 @@ begin
end;
end;
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.Write(o,SizeOf(o));
end;

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

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

View 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

View file

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

View file

@ -4,16 +4,16 @@ uses
Forms,
MainForm in 'MainForm.pas' {frmMain},
PatchClasses in 'PatchClasses.pas',
VDSP_CRC in '..\GenPat\VDSP_CRC.pas',
DLLWrapper in 'DLLWrapper.pas',
AboutForm in 'AboutForm.pas' {frmAbout},
PatchGenerator in '..\GenPat\PatchGenerator.pas',
TreeCode in '..\GenPat\TreeCode.pas';
VDSP_CRC in 'vdsp_crc.pas',
OSUtil in 'OSUtil.pas';
{$R *.res}
begin
Application.Initialize;
Application.Title := 'VPatch GUI';
Application.CreateForm(TfrmMain, frmMain);
Application.Run;
end.

View file

@ -0,0 +1,5 @@
@echo off
echo Cleaning up all non-source files
del /S *.~*
del /S *.dcu
echo done.

View 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);
}
}

View 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

View 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
}

View 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

View 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);
}
}

View 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

View file

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

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

View 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

View 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
}

View 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

View 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;
}
}
}

View 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

View file

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

View 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')

View file

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

View file

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

View 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;
}
}

View 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

View 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;
}

View 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));
}

View 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 */

View file

@ -1,6 +1,9 @@
target = 'VPatch'
files = Split("""
apply_patch.c
checksum.c
md5.c
vpatchdll.c
""")
@ -8,19 +11,6 @@ libs = Split("""
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')
BuildPlugin(target, files, libs, examples, docs)
env.Distribute('Bin', '#Contrib/VPatch/GenPat.exe')
BuildPlugin(target, files, libs)

View 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;
}
}

View 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

View 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);
}
}

View 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

View 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));
}

View 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 */

View file

@ -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
#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);
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
/* ------------------------ Plug-in code ------------------------- */
HINSTANCE g_hInstance;
HWND g_hwndParent;
void __declspec(dllexport) vpatchfile(HWND hwndParent, int string_size,
char *variables, stack_t **stacktop)
{
char *variables, stack_t **stacktop) {
g_hwndParent=hwndParent;
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];
static char dest[1024];
static char exename[1024];
char source[MAX_PATH];
char dest[MAX_PATH];
char exename[MAX_PATH];
HANDLE hPatch, hSource, hDest;
int result;
@ -78,7 +84,7 @@ void __declspec(dllexport) vpatchfile(HWND hwndParent, int string_size,
if ((result != PATCH_SUCCESS)) {
if (result == PATCH_ERROR)
pushstring("An error occurred while patching");
pushstring("An error occured while patching");
else if (result == PATCH_CORRUPT)
pushstring("Patch data is invalid or corrupt");
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;
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;
}
}

View file

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

View 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

View file

@ -19,8 +19,27 @@ DirText "Choose a folder in which to install the VPatch Test!"
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
SetOutPath $INSTDIR
@ -33,7 +52,7 @@ Section ""
File /oname=$PLUGINSDIR\patch.pat patch.pat
; 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"
; Show result

Binary file not shown.

View file

@ -633,6 +633,8 @@ Section "VPatch" SecPluginsVPatch
File ..\Docs\VPatch\Readme.html
SetOutPath $INSTDIR\Bin
File ..\Bin\GenPat.exe
SetOutPath $INSTDIR\Include
File ..\Include\VPatchLib.nsh
SectionEnd
SectionGroupEnd

View file

@ -1,6 +1,5 @@
## TODO
#
# * VPatch GenPat & distribution
# * Write SConscript for NSIS Menu
# - Use inheritance instead of current wxWidgets patches
# - Compile for POSIX too? wxWidgets is cross platform after all...
@ -41,13 +40,15 @@ utils = [
'Makensisw',
'NSIS Menu',
'UIs',
'VPatch/Source/GenPat',
'zip2exe'
]
misc = [
'Graphics',
'Language files',
'Modern UI'
'Modern UI',
'VPatch'
]
defenv = Environment()