source upload

This commit is contained in:
Razor12911
2022-01-17 22:16:47 +02:00
parent 12936d065b
commit 098e8c48de
1778 changed files with 1206749 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
unit BDiffDecoder;
interface
uses
UPatcher;
procedure MakePatch(Data1, Data2, Data3: Pointer; const Size1, Size2: Integer;
var Size3: Integer);
implementation
procedure MakePatch(Data1, Data2, Data3: Pointer; const Size1, Size2: Integer;
var Size3: Integer);
var
Patcher: TPatcher;
begin
Patcher := TPatcher.Create;
try
Patcher.Apply(Data1, Data2, Data3, Size1, Size2, Size3);
finally
Patcher.Free;
end;
end;
end.

View File

@@ -0,0 +1,33 @@
unit BDiffEncoder;
interface
uses
UDiffer, ULogger, UBDiffTypes;
procedure MakeDiff(Data1, Data2, Data3: Pointer; const Size1, Size2: Integer;
var Size3: Integer);
implementation
procedure MakeDiff(Data1, Data2, Data3: Pointer; const Size1, Size2: Integer;
var Size3: Integer);
var
Differ: TDiffer;
Logger: TLogger;
begin
Logger := TLoggerFactory.Instance(False);
try
Differ := TDiffer.Create;
try
Differ.Format := TFormat.FMT_BINARY;
Differ.MakeDiff(Data1, Data2, Data3, Size1, Size2, Size3, Logger);
finally
Differ.Free;
end;
finally
Logger.Free;
end;
end;
end.

225
contrib/bdiff/Build.txt Normal file
View File

@@ -0,0 +1,225 @@
================================================================================
BDiff / BPatch Build Instructions
================================================================================
Introduction
--------------------------------------------------------------------------------
BDiff / BPatch is written in Object Pascal and is targeted at Delphi XE. The
Delphi IDE can be used to modify the source and to perform test builds. Final
builds should be built using the provided makefile, but you can get away with
using the IDE if you don't change any resources.
These instructions only apply to building the current release of BDiff / BPatch.
Earlier releases back to v0.2.6a will have their own versions of this file.
Requirements
--------------------------------------------------------------------------------
You need the following tools to perform a full build and release of BDiff /
BPatch:
Delphi Command Line compiler (DCC32)
------------------------------------
The preferred version is Delphi XE. If you have this compiler please use it. The
DELPHIROOT environment variable must be set to the install path of the version
Delphi you are using. DCC32.exe must be present in the Bin sub-directory of the
path specified by DELPHIROOT. If DELPHIROOT is not set then Make will fail.
Alternatives:
+ Unicode versions of Delphi other than XE may work, but haven't been tested.
Non Unicode compilers will fail to compile the code.
+ Only versions of Delphi that ship with the DCC32 command line compiler can
be used with the make files.
+ As noted above you can compile Pascal code from the Delphi IDE instead of
running DCC32.
BRCC32 resource compiler (BRCC32)
---------------------------------
BRCC32 is distributed with Delphi. It is needed to compile resource files. The
Makefile expects to find BRCC32 in the same directory as DCC32.
Borland MAKE
------------
This is the make tool that ships with Delphi. You can use any version that
works. I've tested only the version that ships with Delphi XE. The makefile
calls Make recursively: it uses the same command line that you used to call it,
so there are no requirements as to the location of Make.
DelphiDabbler Version Information Editor (VIEd)
-----------------------------------------------
This program is required to convert the .vi files that specify version
information into an intermediate .rc file that is compiled by BRCC32. VIEd is
expected to be on the system path unless the VIEDROOT environment variable is
set to indicate VIEd's installation directory. You can get VIEd here:
http://delphidabbler.com/software/vied
Zip.exe
-------
This program is required to create the release exe file. Again it is assumed to
be on the path unless the ZIPROOT environment variable is set to its install
directory. You can get a Windows version at:
http://stahlforce.com/dev/index.php?tool=zipunzip
Dependencies
--------------------------------------------------------------------------------
The source depends only on the Delphi VCL, so provided you have Delphi
installed, the source should compile without building any other libraries.
Preparations
--------------------------------------------------------------------------------
Get the source code
-------------------
The source code of BDiff / BPatch is maintained in the delphidabbler/bdiff Git
repository on GitHub at https://github.com/delphidabbler/bdiff
Each release from v0.2.5 onwards is available from GitHub. You can download an
archive containing the required release. Note that releases prior to v0.2.7 were
originally maintained in a Subversion repository and therefore their
documentation will refer to Subversion rather than Git.
Once the source is cloned or forked you should end up with a folder structure
like this:
+--+ { root: .gitignore, this file, and some documentation}
|
+-- Docs { documentation files }
|
+-- Src { project group and master make files }
| |
| +-- BDiff { source and makefile for BDiff }
| |
| +-- BPatch { source and makefile for BPatch }
| |
| +-- Common { code common to both programs }
|
+-- Test { test scripts }
If, by chance you also have a Build directory and sub-directories don't worry.
Git users will also see the usual .git hidden directory.
Configure the source tree
-------------------------
Before you can get hacking, you need to prepare the code. Open a command
console, navigate into the Src sub-folder and do:
> Make config
You may need to replace "Make" above with the full path to Make if it isn't on
the path, or if the Make that runs isn't the Borland / CodeGear version.
Once "Make config" has completed your folder structure should have changed to:
+--+
|
+-- Build { contains files created in build process }
| |
| +-- Bin { parent of binary folders }
| | |
| | +-- BDiff { receives binary files for BDiff (.dcu and .res) }
| | |
| | +-- BPatch { receives binary files for BPatch (.dcu and .res) }
| |
| +-- Exe { receives executable files }
| |
| +-- Release { receives release zip file }
|
+-- Docs
|
+-- Src
| |
| +-- BDiff
| |
| +-- BPatch
|
+-- Test
Git has been configured to ignore the Build folder and its contents. In addition
Make will have created .cfg files from templates. These files are needed for
DCC32 to run correctly. The .cfg files will be ignored by Git.
If you are intending to use the Delphi IDE to compile code, you should also do:
> Make res
This compiles the resource files that the IDE needs to link into compiled
executables.
Modify the source
-----------------
If you plan to modify the source, you can do it now.
If you are using the Delphi IDE you should load the BDiff.groupproj project
group file from the Src folder into the IDE - this contains both the BDiff and
BPatch targets.
Compile
-------
Compile the code by doing
> Make exe
This builds the resources then builds the whole of the Pascal source using the
DCC32 command line compiler.
Even if you have built the code in the IDE you advised to run "Make exe".
At any time you can rebuild the resources using "Make res" or rebuild the pascal
code without also building resources by using "Make pascal".
Testing
-------
Some simple tests can be run to check that BDiff and BPatch are working
correctly. For details see ReadMe.txt in the Test folder.
Prepare the executable release file
-----------------------------------
If you want to create a zip file containing the executable programs and required
documentation do:
> Make release
This deletes any temporary files then creates the required zip file. You can
change the default name of the zip file by defining the RELEASEFILENAME
environment variable with the required name (excluding extension). For example,
to generate a release file named my-file.zip define RELEASEFILENAME as 'my-file'
or do:
> Make -DRELEASEFILENAME=myfile release
If you issue a Make with no target it will re-run config, build the executable
code and create the release.
Tidy up
-------
At any time you can tidy up temporary files by doing:
> Make clean
If you also want to remove the .cfg files generated from .cfg.tplt files along
with the entire Build directory you can do:
> Make deepclean

View File

@@ -0,0 +1,84 @@
v0.2.8 - released 19 Sep 2016
BDiff.exe v0.2.8 (build 9)
BPatch.exe v0.2.8 (build 9)
+ Converted to support Unicode file names and use of Unicode strings internally.
+ Switched to Delphi XE compiler from Delphi 7.
+ Added new test to test script.
+ Significant overhaul and updates to documentation.
v0.2.7 - released 19 Jul 2014
BDiff.exe v0.2.7 (build 8)
BPatch.exe v0.2.7 (build 8)
+ Bug fixes in BDiff:
- "New" and "old" file names for a diff cannot now be the same.
- Patch file name specified in --output or -o switches must now have a different name from other file names specified on command line.
+ Major refactoring:
- Big change from procedural to modularised, mainly OOP code split into several units.
- Pascalified code in terms of variable names, camel casing etc.
- Revised logic of some methods.
- Reduced usage of some pointers, including replacing use characters pointers with Pascal strings.
+ Revised and reformatted documentation: license and read-me files converted to markdown format.
+ Minor changes to the license.
v0.2.6a - released 06 Aug 2009
BDiff.exe v0.2.6 (build 7)
BPatch.exe v0.2.6 (build 7)
+ Removed source code from distribution.
+ Documentation updated re changes.
+ No changes to executable code other than to update build numbers.
v0.2.6 - released 02 Aug 2009
BDiff.exe v0.2.6 (build 6)
BPatch.exe v0.2.6 (build 6)
+ Changed to use sytem temporary folder for temporary files instead of current directory.
+ Typo in BDiff help screen fixed.
+ Some refactoring:
- Code rationalised to have only one exit point in each application rather than multiple halt points.
- Fatal errors now handled by exceptions rather than by calling Halt().
- Some duplicated code pulled into units shared between BDiff and BPatch.
- Ensured code that depends on single byte characters uses fixed size types instead of Char, which changes size in later compilers.
+ Replaced build scripts with make files.
+ Tests rewritten and extended:
- Three different tests are now provided in place of one: all three patch formats are now tested.
- Option added to display program version information.
- Option added to clear temporary files generated by running the tests.
- Location of BDiff and BPatch programs being tested can now be specified.
+ Documentation overhauled.
v0.2.5 - released 14 Aug 2008
BDiff.exe v0.2.5 (build 5) [v0.2.4 skipped]
BPatch.exe v0.2.5 (build 5)
+ Renamed BPtch back to BPatch.
+ Added manifests to resources of both BPatch and BDiff to inform Windows Vista to run them as invoked. This prevents Vista from elevating BPatch because of the word "patch" in its name.
v0.2.4 - released 07 Apr 2008
BDiff.exe v0.2.3 (build 4)
BPtch.exe v0.2.4 (build 4)
+ Renamed BPatch as BPtch to prevent Windows Vista from flagging the program as requiring elevation.
+ Also altered BPtch's version information to remove the word "patch" for same reason!
+ BDiff was not changed except for incrementing build number.
v0.2.3 - released 18 Sep 2007
BDiff.exe v0.2.3 (build 3)
BPatch.exe v0.2.3 (build 3) [v0.2.2 skipped]
+ Fixed bug where BPatch could not overwrite existing files.
+ Fixed small bug in -h and -v switches in both programs.
+ Fixed memory leaks in BDiff.
+ Switched to Delphi 7 compiler from Delphi 4.
+ Prevented compiler warnings in both programs.
+ Added batch files to build projects.
+ Updated help screens.
+ Made some minor refactorings.
+ Removed conditional compilation for non-Windows targets.
+ Added test batch file a sample files.
+ Changed to new binary and source license.
v0.2.2(pas) - released 21 Dec 2003
BDiff.exe v0.2.2 (build 2)
BPatch.exe v0.2.1 (build 2)
+ Fixed bug in BDiff by translating revised C code provided by Stefan Reuther. BDiff.exe is affected by the change while BPatch.exe remains unchanged.
v0.2.1(pas) - released 29 Nov 2003
BDiff.exe v0.2.1 (build 1)
BPatch.exe v0.2.1 (build 1)
+ First Pascal version. This is a direct translation of v0.2 of Stefan Reuther's C code published in 1999.

View File

@@ -0,0 +1,124 @@
NAME
bdiff - difference of binary files
SYNOPSIS
bdiff [options] old-file new-file [>patch-file]
DESCRIPTION
bdiff computes differences between two binary files. Output can be either a
somewhat human-readable protocol, or a binary file readable by bpatch. Output is
sent to standard output unless the --output option is used to specify an output
file.
bdiff handles insertion and deletion of data as well as changed bytes.
OPTIONS
-q - Use QUOTED format (default);
-f - Use FILTERED format;
-b - Use BINARY format;
--format=FMT - Select format by name: (binary, filtered, quoted)
-m N, - Two chunks of data are recognized as being identical if
--min-equal=N they are at least N bytes long, the default is 24.
-o FILENAME, - Write diff to specified file instead of standard output.
--output=FILENAME Specifying --output=- does nothing. Use as an alternative
to shell redirection.
-V, - Print status messages while processing input;
--verbose
-h, - Show help screen and exit;
--help
-v, - Show version number and exit.
--version
ALGORITHM
bdiff tries to locate maximum-length substrings of the new file in the old data.
Substrings shorter than N (argument to the -m option) are not considered
acceptable matches. Everything covered by such a substring is transmitted as a
position, length pair, everything else as literal data.
bdiff uses the block-sort technique to allow O(lgN) searches in the file, giving
an estimated O(NlgN) algorithm on average.
The program requires about five times as much memory as the old file, plus
storage for the new file. This should be real memory, bdiff accesses all of it
very often.
OUTPUT FORMATS
The quoted format (default) is similar to diff output in unified format: '+'
means added data, and a space means data kept from the old file. Lines prefixed
with '@' inform you about the position of the next 'space' line in the source
file (byte offset).
Unlike in diff, there's no implicit line feed after each line of output.
Non-printable characters (see isprint(3)[1]) and the backslash character are
represented by a \ followed by the octal three-digit character code.
The filtered format is like the quoted format, but non-printable characters are
replaced by dots (.).
The binary format is machine-readable, and omits details for common blocks. All
words are in little-endian format (low byte first). The format is:
8 bytes - Signature "bdiff02\x1A", where 02 is kind-of a version number. An
earlier version (with an O(n^3) algorithm) used the number 01. \x1A
is ASCII 26 (Control-Z, an MS-DOS end-of-file marker).
4 bytes - Length of old file in bytes.
4 bytes - Length of new file in bytes.
n bytes - The patch itself, a sequence of the following records:
literally added data:
1 byte - ASCII 43 ('+');
4 bytes - number of bytes;
n bytes - data.
common block:
1 byte - ASCII 64 ('@');
4 bytes - file position in old file;
4 bytes - number of bytes;
4 bytes - checksum.
The checksum is computed using the following algorithm:
long checksum(char* data, size_t len)
{
long l = 0;
while(len--) {
l = ((l >> 30) & 3) | (l << 2);
l ^= *data++;
}
return l;
}
(rotate current checksum left by two and xor in the current byte)
ADMINISTRATIVIA
This manual page is for version 0.2.6 or later of bdiff.
See the file LICENSE.md for details of licensing and copyright.
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.
FOOTNOTES
[1] http://www.openbsd.org/cgi-bin/man.cgi?query=isprint&sektion=3

View File

@@ -0,0 +1,49 @@
NAME
bpatch - apply binary batch
SYNOPSIS
bpatch [options] old-file [ new-file ] [<patch-file]
DESCRIPTION
bpatch applies a binary patch generated by bdiff. Patches are read from standard
input unless the --input option is used to specify an input file.
old-file is the same file as used as the first argument to bdiff. bpatch will
create a copy of the file given as second argument to bdiff in new-file by using
the information from old-file and patch-file.
If new-file is omitted, the old file is replaced with the new file.
bpatch will detect if the patch does not match old-file, or if the patch has
been garbled. Remember to transmit binary patches as binary files!
In case of an error, new-file will not be touched.
OPTIONS
-i PATCH-FILE, - Read patch from specified file instead of standard input.
--input=PATCH-FILE Specifying --input=- does nothing. Use as an alternative
to shell redirection.
-h, - Show help screen.
--help
-v, - Show version number.
--version
ADMINISTRATIVIA
This manual page is for version 0.2.6 or later of bpatch.
See the file LICENSE.md for details of licensing and copyright.
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.

View File

@@ -0,0 +1,94 @@
--------------------------------------------------------------------------------
This file contains copies of emails exchanged between Peter Johnson and Stefan
Reuther that relate to licensing of Peter's Pascal translation of Stefan's
original source code.
**NOTE:** Email addresses have been partially obscured.
--------------------------------------------------------------------------------
From: xxxxx@delphidabbler.com
To: Streu@xxxxx.de
Date: 04/12/2003 01:59
Hi Stefan
I found v0.2 of your BDiff/BPatch files on the net and the programs meet my
needs quite well. However I would like to modify the code to strip out the
core functions and place that in a DLL to be accessed by one of my Windows
programs. Since I program in mainly in Object Pascal, I've created a literal
translation of your code in Pascal (to run on Windows platforms) as a first
step.
I've published the Pascal version on my website (see
http://www.delphidabbler.com/software.php?id=bdiff) and have tried to comply
with the terms published with v0.2 of your code. The new version is made
available under the same terms as your original code and the C code is
included in the download. You've been given full credit for the additional
code and your copyright is acknowledged.
I hope you are happy for your code to be used in this way and for me to
develop it to meet my needs and to publish the result. Please let me know if
you have any problems with this.
Thanks for making your code available. Please do get in touch if you have
any comments.
Regards
Peter Johnson
xxxxx@openlink.org
http://www.delphidabbler.com/
--------------------------------------------------------------------------------
From: Streu@xxxxx.de
To: xxxxx@delphidabbler.com
Date: 04/12/2003 12:06
Hello,
On Thu, Dec 04, 2003 at 01:59:05AM -0000, Peter David Johnson wrote:
> > I found v0.2 of your BDiff/BPatch files on the net and the programs meet my
> > needs quite well. However I would like to modify the code to strip out the
> > core functions and place that in a DLL to be accessed by one of my Windows
> > programs.
Go ahead and do what you want with it.
> > I've published the Pascal version on my website (see
> > http://www.delphidabbler.com/software.php?id=bdiff) and have tried to comply
> > with the terms published with v0.2 of your code. The new version is made
> > available under the same terms as your original code and the C code is
> > included in the download. You've been given full credit for the additional
> > code and your copyright is acknowledged.
Nice. (Don't worry about those "copyright terms" too much.
Everything's fine with me unless you claim 'I invented it and
now I patent it').
I mainly wrote that program to give out binary patches of my
other programs; I also have a nice Turbo Pascal version of a
'patch' utility; if you want it, no problem, but I doubt it
helps you too much under Windows. For fairness I should say the
'bdiff' is not the best binary-diff program there is (at least I
already had one which found smaller diffs, but I can't find it
right now), but it is simple and easy to handle.
> > I hope you are happy for your code to be used in this way and for me to
> > develop it to meet my needs and to publish the result. Please let me know if
> > you have any problems with this.
To be honest, I had almost forgotten that that file was on my
web site :)
Oh well, this reminds me that the version on the website has a
bug. And since I forgot that it's there, I forgot to update it.
I attach the fixed version of 'blksort.c'. The bug causes it to
crash on certain data. The problem is in 'find_string'.
Stefan
--------------------------------------------------------------------------------

View File

@@ -0,0 +1,49 @@
================================================================================
License for original BDiff / BPatch releases 0.1 and 0.2 (C source code)
================================================================================
(c) copyright 1999 by Stefan Reuther <Streu@gmx.de>. Copying this program is
allowed, as long as you include source code and document changes you made in a
user-visible way so people know they're using your version, not mine.
This program is distributed in the hope that it will be useful, but without
warranties of any kind, be they explicit or implicit.
================================================================================
License used for BDiff / BPatch v0.2.1 and v0.2.2
================================================================================
The copyright statement and terms of use and distribution granted by the
original author are:
<20> copyright 1999 by Stefan Reuther*. Copying this program is allowed, as long
as you include source code and document changes you made in a user-visible way
so people know they're using your version, not mine.
This program is distributed in the hope that it will be useful, but without
warranties of any kind, be they explicit or implicit.
Additional copyright and terms of using the Pascal translation are as follows:
The Pascal translation is <20> copyright 2003 by Peter Johnson. Copying the
Pascal translation and any modifications of the original code is allowed
providing changes are made clear.
No warranties of any kind are provided.
Many thanks to Stefan for creating this software.
* Stefan's email address is included in the original document but has not been
included here for obvious reasons - please see the file bdiff.1 that is included
in the download for details.
================================================================================
License used for current version BDiff / BPatch
================================================================================
The current version of the license can be found in LICENSE.md in the root of the
Git repository.
================================================================================

View File

@@ -0,0 +1,54 @@
================================================================================
NOTES ON THE PASCAL TRANSLATION OF BDIFF / BPATCH
================================================================================
Release 0.2.1 (pas)
-------------------
This version is a fairly literal, line by line, translation of Stefan Reuther's
BDiff v0.2 and BPatch v0.2. The differences are:
+ The Pascal translation is only suitable for use on Windows targets - it
compiles to a Win32 console application and uses the Windows API.
+ The C version encounters problems reading and writing binary difference files
via shell redirection: MS-DOS / Windows could garble input or output because
of end-of-line character translations. Therefore Stefan provided the --output
(or -o) and --input (or -i) switches to overcome this problem. These switches
are used instead of shell redirection on MS-DOS / Windows.
The Pascal translation does not have this problem and shell redirection can be
used safely on Windows systems. Therefore the --input and --output switches
are not required, but have been retained.
+ The numeric parameter to BDiff's -m or --min-equal switches can be specified
in decimal, octal or hexadecimal notation on the C version. The Pascal
translation supports only decimal notation.
+ The Pascal versions of BDiff and BPatch contain embedded Windows version
information.
+ Both the C and Pascal versions share a BPatch bug: the program crashes if only
one file is supplied on the command line.
Release 0.2.2 (pas)
------------------
This version is again a fairly literal translation. The only change (except for
updated version information) is that BDiff contains a Pascal translation of a
bug fix in the block sort code for which Stefan provided updated C source code.
Release 0.2.3 and later
-----------------------
From this release BDiff and BPatch broke the link with the original C source and
began to develop separately, so further translation notes are not provided.
Note though that all 0.2.x releases remained functionally equivalent other than
for bug fixes.
--------------------------------------------------------------------------------

View File

@@ -0,0 +1,644 @@
================================================================================
BDIFF / BPATCH: Historical update information from v0.2.1 to v0.2.5
================================================================================
This file records known changes to files and releases of the BDiff / BPatch
utilities from the first Pascal release (v0.2.1) until release 0.2.5 when the
project was placed under version control with Subversion. Later the code was
ported from Subversion to Git.
There are three sections:
+ Files: Lists all source code and development tools and provides details of
changes to these files that preceded version control.
+ Releases: Lists all the releases of BDiff / BPatch and notes which file
revisions were included in each release.
+ Compilers: Lists the compilers required to build each release.
================================================================================
FILES
================================================================================
This section lists all files for which update history is known between the first
released version of the utilities and release 0.2.5.
--------------------------------------------------------------------------------
DevTools\BuildAll.bat
--------------------------------------------------------------------------------
v1.0 of 16 Sep 2007 - Original version
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
DevTools\BuildPascal.bat
--------------------------------------------------------------------------------
v1.0 of 16 Sep 2007 - First version.
v1.1 of 07 Apr 2008 - Modified to work with BPtch renamed from BPatch.
v1.2 of 14 Aug 2008 - Changed back to work "unrenamed" BPatch.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
DevTools\BuildResources.bat
--------------------------------------------------------------------------------
v1.0 of 16 Sep 2007 - First version.
v1.1 of 07 Apr 2008 - Modified to work with BPtch renamed from BPatch.
v1.2 of 14 Aug 2008 - Changed back to work "unrenamed" BPatch.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
DevTools\Release.bat
--------------------------------------------------------------------------------
v1.0 of 18 Sep 2007 - First version.
v1.1 of 07 Apr 2008 - Updated to work with renamed BPtch (from BPatch).
- Now copy .res files from Bin directories.
v1.2 of 14 Aug 2008 - Changed back to work "unrenamed" BPatch.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
DevTools\Tidy.bat
--------------------------------------------------------------------------------
v1.0 of 16 Sep 2007 - Original version.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Docs\BDiff.phf
--------------------------------------------------------------------------------
18 Sep 2007 - New project update file for BDiff.
07 Apr 2008 - Added details of BDiff v0.2.3 build 4.
14 Aug 2008 - Added details of BDiff v0.2.5 build 5.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Docs\BDiff.txt
--------------------------------------------------------------------------------
27 Nov 2003 - Original version - based on OrigC\bdiff.1.
07 Apr 2008 - Revised to refer to BDiff 0.2.4 instead of 0.2.
- Removed crosss references to other "man pages"
14 Aug 2008 - Reformatted document.
- Revised, clarified and corrected text.
- Provided new disclaimer paragraph.
- Provided new copyright paragraph.
- Revised to refer to BDiff 0.2.4 instead of 0.2.4.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Docs\BPatch.phf
--------------------------------------------------------------------------------
18 Sep 2007 - New project update file for BPatch.
07 Apr 2008 - Added details of BPtch v0.2.4.
- Noted BPatch renamed as BPtch.
- Renamed as BPtch.phf from BPatch.phf.
14 Aug 2008 - Added details of BPatch v0.2.5.
- Noted BPatch renamed back to original name.
- Renamed from BPtch.phf back to BPatch.phf.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Docs\BPatch.txt
--------------------------------------------------------------------------------
27 Nov 2003 - Original version - based on OrigC\bpatch.1.
07 Apr 2008 - Revised to refer to BPtch 0.2.4 instead of BPatch 0.2.
- Removed crosss references to other "man pages"
- Renamed as BPtch.txt from BPatch.txt
14 Aug 2008 - Reformatted document.
- Revised, clarified and corrected text.
- Provided new disclaimer paragraph.
- Provided new copyright paragraph.
- Revised to refer to BDiff 0.2.4 instead of 0.2.4.
- Renamed back to BPatch.txt from BPtch.txt
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Docs\ChangeLog.txt
--------------------------------------------------------------------------------
29 Nov 2003 - First version of project's changelog for release 0.2.1.
21 Dec 2003 - Added info about release 0.2.2.
18 Sep 2007 - Added info about release 0.2.3.
- Removed info about C versions.
07 Apr 2008 - Added info about release 0.2.4.
14 Aug 2008 - Added info about release 0.2.5.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Docs\EmailsReLicense.txt
--------------------------------------------------------------------------------
17 Sep 2007 - Record of emails between Peter Johnson and Stefan Reuther
re licensing terms.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Docs\LICENSE
--------------------------------------------------------------------------------
18 Sep 2007 - License file containing new license for project.
08 Apr 2008 - Revised re change of name of BPatch to BPtch.
14 Aug 2008 - Revised re change of name of BPtch back to BPacth.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Docs\OldLicenses.txt
--------------------------------------------------------------------------------
18 Sep 2007 - Record of old licenses for C code and Pascal
translations.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Docs\PasTrans.txt
--------------------------------------------------------------------------------
29 Nov 2003 - First version of Pascal Translation notes.
21 Dec 2003 - Modified re changes in release 0.2.2
18 Sep 2007 - Modified re changes in release 0.2.3 and later
08 Apr 2008 - Noted change of name of BPatch to BPtch.
- Added section for release 0.2.4 and later.
14 Aug 2008 - Noted change of name of BPtch back to BPatch.
- Added section for release 0.2.5 and later.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Docs\README
--------------------------------------------------------------------------------
29 Nov 2003 - First version of read me file covering program outline,
installation, source code and copyright.
- Original name was ReadMe.txt
18 Sep 2007 - Renamed from ReadMe.txt to README.
- Completely rewritten.
07 Apr 2008 - Noted change of name of BPatch to BPtch.
- Added note re provided binary files in source code
section.
14 Aug 2008 - Noted change of name of BPtch back to BPatch.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
OrigC\bdiff.1
--------------------------------------------------------------------------------
20 Jul 1999 - Original version supplied by Stefan Reuther
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
OrigC\bdiff.c
--------------------------------------------------------------------------------
20 Jul 1999 - Original version supplied by Stefan Reuther
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
OrigC\blksort.c
--------------------------------------------------------------------------------
20 Jul 1999 - Original version supplied by Stefan Reuther
16 Dec 2003 - Bug fix supplied by Stefan Reuther
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
OrigC\bpatch.1
--------------------------------------------------------------------------------
20 Jul 1999 - Original version supplied by Stefan Reuther
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
OrigC\bpatch.c
--------------------------------------------------------------------------------
20 Jul 1999 - Original version supplied by Stefan Reuther
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
OrigC\makefile
--------------------------------------------------------------------------------
20 Jul 1999 - Original version supplied by Stefan Reuther
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
OrigC\README
--------------------------------------------------------------------------------
20 Jul 1999 - Original version supplied by Stefan Reuther
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Src\BDiff.bpg
--------------------------------------------------------------------------------
28 Nov 2003 - Original project group file containing BDiff and BPatch.
07 Apr 2008 - Revised re renaming of BPatch to BPtch.
14 Aug 2008 - Revised re renaming of BPtch back to BPatch.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Src\BDiff\BDiff.cfg
--------------------------------------------------------------------------------
28 Nov 2003 - Original Delphi project config file.
21 Dec 2003 - Changed some absolute file paths.
18 Sep 2007 - Revised for Delphi 7.
- Made path to exe files relative.
07 Apr 2008 - Changed some absolute library file paths.
14 Aug 2008 - No changes: touched file.
--------------------------------------------------------------------------------
Src\BDiff\BDiff.dpr
--------------------------------------------------------------------------------
v1.0 of 28 Nov 2003 - Original version.
v1.1 of 18 Sep 2007 - Changed copyright and license notice.
v1.2 of 14 Aug 2008 - Included BDiff resource that contains a manifest that
tells Vista to run program as invoked.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Src\BDiff\BDiff.manifest
--------------------------------------------------------------------------------
v1.0 of 14 Aug 2008 - Original version that permits application to run without
elevation on Vista.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Src\BDiff\BDiff.rc
--------------------------------------------------------------------------------
v1.0 of 14 Aug 2008 - Original version
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Src\BDiff\Build.bat
--------------------------------------------------------------------------------
v1.0 of 16 Sep 2007 - First version.
v1.1 of 14 Aug 2008 - Added code to compile .rc file.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Src\BDiff\UBDiff.pas
--------------------------------------------------------------------------------
v1.0 of 28 Nov 2003 - Original Pascal translation of bdiff.c
v1.1 of 18 Sep 2007 - Fixed memory leaks by freeing various memory buffers.
- Removed "side-by-side" C code.
- Updated help screen copyright statement and added
information about -o / --output switch and various
format options.
- Changed date format displayed by --version switch.
- Fixed small bug in -h and -v options.
- Fixed a buffer size in print_binary_add routine.
- Updated version constant to 0.2.3.
- Changed copyright and license notice.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Src\BDiff\UBDiffTypes.pas
--------------------------------------------------------------------------------
v1.0 of 28 Nov 2003 - Original version.
v1.1 of 18 Sep 2007 - Changed copyright and license notice.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Src\BDiff\UBDiffUtils.pas
--------------------------------------------------------------------------------
v1.0 of 28 Nov 2003 - Original version.
v1.1 of 18 Sep 2007 - Added new RedirectStdOut() routine.
- Removed redundant malloc() routine.
- Explicitly cast handles of stdout and stderr to
correct types
- Changed copyright and license notice.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Src\BDiff\UBlkSort.pas
--------------------------------------------------------------------------------
v1.0 of 28 Nov 2003 - Original Pascal translation of blksort.c
v1.1 of 21 Dec 2003 - Bug fix based on updated blksort.c provided by Stefan
Reuther.
v1.2 of 18 Sep 2007 - Replaced call to C-style malloc() function with call to
GetMem. Made a few minor related modifications.
- Changed copyright and license notice.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Src\BDiff\VBDiff.vi
--------------------------------------------------------------------------------
28 Nov 2003 - First version: file version is 0.2.1 build 1 and product
version is 0.2.1.
21 Dec 2003 - Updated file version to 0.2.2 build 2 and product version
to 0.2.2.
18 Sep 2007 - Added header comments and license.
- Removed RC comments and output dir path.
- Modified LegalCopyright string table entry.
- Updated file version to 0.2.3 build 3 and product version
to 0.2.3.
- Updated file description.
- Changed comments to give overview of distribution and
refer to License.txt.
- Deleted identifier string to let default value be used.
- Removed SpecialBuild string item and macro references.
- Added build number to file version string.
07 Apr 2008 - Updated file version to 0.2.3 build 4 and product version
to 0.2.4.
14 Aug 2008 - Updated file version to 0.2.5 build 5 and product version
to 0.2.5.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Src\BPatch\BPatch.cfg
--------------------------------------------------------------------------------
28 Nov 2003 - Original Delphi project config file.
21 Dec 2003 - Changed some absolute file paths.
18 Sep 2007 - Revised for Delphi 7.
- Made path to exe files relative.
07 Apr 2008 - Changed some absolute library file paths.
- Change relative paths re renamed BPtch directory.
- Renamed file from BPatch.cfg to BPtch.cfg.
14 Aug 2008 - Change relative paths re renamed BPatch directory.
- Renamed file from BPtch.cfg back to BPatch.cfg.
--------------------------------------------------------------------------------
Src\BPatch\BPatch.dpr
--------------------------------------------------------------------------------
v1.0 of 28 Nov 2003 - Original version.
v1.1 of 18 Sep 2007 - Changed copyright and license notice.
v1.2 of 07 Apr 2008 - Renamed from BPatch.dpr to BPtch.dpr. "BPatch" caused
Windows Vista to flag the program for elevation!
v1.3 of 14 Aug 2008 - Renamed back to BPatch.dpr from BPtch.dpr.
- Included BPatch.res containing manifest that causes
program to be run as invoked, overriding Vista's desire
to elevate the program because "patch" is included in
name.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Src\BPatch\BPatch.manifest
--------------------------------------------------------------------------------
v1.0 of 14 Aug 2008 - Original version that permits application to run without
elevation on Vista (Vista would elevate without this
because "Patch" is in file name).
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Src\BPatch\BPatch.rc
--------------------------------------------------------------------------------
v1.0 of 14 Aug 2008 - Original version.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Src\BPatch\Build.bat
--------------------------------------------------------------------------------
v1.0 of 16 Sep 2007 - First version.
v1.1 of 07 Apr 2008 - Altered to work with BPtch renamed from BPatch.
v1.2 of 14 Aug 2008 - Altered back work with "unrenamed" BPatch.
- Added code to compile .rc file.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Src\BPatch\UBPatch.pas
--------------------------------------------------------------------------------
v1.0 of 28 Nov 2003 - Original Pascal translation of bpatch.c
v1.1 of 18 Sep 2007 - Fixed bug preventing overwriting of existing output
files.
- Removed "side-by-side" C code.
- Removed conditional Windows / DOS conditional code.
- Updated help screen copyright statement.
- Changed date format displayed by --version switch.
- Fixed small bug in -h and -v options.
- Moved code that redirects stdin to UBDiffUtils unit.
- Updated version constant to 0.2.3 (skipping 0.2.2).
- Changed copyright and license notice.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Src\BPatch\UBPatchTypes.pas
--------------------------------------------------------------------------------
v1.0 of 28 Nov 2003 - Original version.
v1.1 of 18 Sep 2007 - Changed copyright and license notice.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Src\BPatch\UBPatchUtils.pas
--------------------------------------------------------------------------------
v1.0 of 28 Nov 2003 - Original version.
v1.1 of 18 Sep 2007 - Added RedirectStdIn() routine.
- Explicitly cast handles of stdin, stdout and stderr to
correct types.
- Changed copyright and license notice.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Src\BPatch\VBPatch.vi
--------------------------------------------------------------------------------
28 Nov 2003 - First version: file version is 0.2.1 build 1 and product
version is 0.2.1.
21 Dec 2003 - Updated file version to 0.2.1 build 2 and product number
to 0.2.2
18 Sep 2007 - Added header comments license.
- Removed RC comments and output dir path.
- Modified LegalCopyright string table entry.
- Updated file version to 0.2.3 build 3 and product version
to 0.2.3.
- Updated file description.
- Changed comments to give overview of distribution and
refer to License.txt.
- Deleted identifier string to let default value be used.
- Removed SpecialBuild string item and macro references.
- Added build number to file version string.
07 Apr 2008 - Updated file version to 0.2.4 build 4 and product version
to 0.2.4.
- Rephrased text to avoid the use of the word "patch" due
to problems with Windows Vista.
- Changed OriginalFileName to BPtch.exe
14 Aug 2008 - Updated file version to 0.2.5 build 5 and product version
to 0.2.5.
- Changed OriginalFileName back to BPatch.exe.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Test\Test.bat
--------------------------------------------------------------------------------
v1.0 of 18 Sep 2007 - First version.
v1.0 of 07 Apr 2008 - Revised to work with BPtch renamed from BPatch.
v1.2 of 14 Aug 2008 - Revised to work with "unrenamed" BPatch.
- Forced to work with exe files from Exe folder, preventing
calling of any other versions on path.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Test\Test1
--------------------------------------------------------------------------------
21 Dec 2003 - Copy of UBlkSort.pas used as 1st generation document used
in test comparisons.
31 Jul 2009 - MOVED TO SUBVERSION
--------------------------------------------------------------------------------
Test\Test2
--------------------------------------------------------------------------------
15 Sep 2007 - Modified copy of UBlkSort.pas used as 2nd generation
document for use in test comparisons for checking against
Test1.
31 Jul 2009 - MOVED TO SUBVERSION
================================================================================
RELEASES
================================================================================
This section lists all releases of the utilities from the first Pascal version
to release 0.2.5. For each release the following is noted:
+ Version and build number of BDiff and BPatch.
+ Brief notes of changes to each utility.
+ List of new and added source files.
The Development tools, .bpg and .cfg files, test files and documentation are not
included in this information.
--------------------------------------------------------------------------------
v0.2.1 of 29 Nov 2003
--------------------------------------------------------------------------------
BDiff.exe v0.2.1 build 1
Notes:
+ First Pascal translation of BDiff v0.2 by Stefan Reuther.
File changes:
+ New: BDiff.dpr 1.0
+ New: UBDiff.pas 1.0
+ New: UBDiffTypes.pas 1.0
+ New: UBDiffUtils.pas 1.0
+ New: UBlkSort.pas 1.0
+ New: VBDiff.vi 28 Nov 2003
BPatch.exe v0.2.1 build 1
Notes:
+ First Pascal translation of BPatch v0.2 by Stefan Reuther.
File changes:
+ New: BPatch.dpr 1.0
+ New: UBPatch.pas 1.0
+ New: UBPatchTypes.pas 1.0
+ New: UBPatchUtils.pas 1.0
+ New: VBPatch.vi 28 Nov 2003
--------------------------------------------------------------------------------
v0.2.2 of 21 Dec 2003
--------------------------------------------------------------------------------
BDiff.exe v0.2.2 build 2
Notes:
+ Fixed bug in block sort, per fix in C program provided by Stefan Reuther.
File changes:
+ Updated: UBlkSort.pas 1.1
+ Updated: VBDiff.vi 21 Dec 2003
BPatch.exe v0.2.1 build 2
Notes:
+ Unchanged other than to update product abd build number in version
information.
File changes:
+ Updated: VBPatch.vi 21 Dec 2003
--------------------------------------------------------------------------------
v0.2.3 of 18 Sep 2007
--------------------------------------------------------------------------------
BDiff.exe v0.2.3 build 3
Notes:
+ Fixed some memory leaks.
+ Fixed small bug in -h and -v switches.
+ Updated copyright statements on help screen and description of missing
options.
+ Updated version to v0.2.3.
+ Added batch file that can build the project.
+ Some minor refactoring.
+ Switched off various warnings in .cfg file.
+ Changed to new binary and source license.
File changes:
+ Updated: BDiff.dpr 1.1
+ Updated: UBDiff.pas 1.1
+ Updated: UBDiffTypes.pas 1.1
+ Updated: UBDiffUtils.pas 1.1
+ Updated: UBlkSort.pas 1.2
+ Updated: VBDiff.vi 18 Sep 2007
+ New: Build.bat 1.0
BPatch.exe v0.2.3 build 3 (v0.2.2 skipped)
Notes:
+ Fixed bug where the program could not overwrite existing files.
+ Fixed small bug in -h and -v switches.
+ Removed conditional compilation for unsupported target OSs.
+ Updated copyright statements on help screen.
+ Updated version to v0.2.3, skipping v0.2.2 to synchronise with BDiff.
+ Added batch file that can build the project.
+ Some minor refactoring.
+ Switched off various warnings in .cfg file.
+ Changed to new binary and source license.
File changes:
+ Updated: BPatch.dpr 1.1
+ Updated: UBPatch.pas 1.1
+ Updated: UBPatchTypes.pas 1.1
+ Updated: UBPatchUtils.pas 1.1
+ Updated: VBPatch.vi 18 Sep 2007
+ New: Build.bat 1.0
--------------------------------------------------------------------------------
v0.2.4 of 07 Apr 2008
--------------------------------------------------------------------------------
BDiff.exe v0.2.3 build 4
Notes:
+ Unchanged except that build number incremented to 4.
File changes:
+ VBDiff.vi 07 Apr 2008
BPatch.exe v0.2.4 build 4
Notes:
+ Renamed program from BPatch to BPtch and removed the word "patch" from
version information. This was to prevent Windows Vista from requiring the
program to be run in elevated state.
File changes:
+ Updated: BPtch.dpr 1.2 (renamed from BPatch.dpr)
+ Updated: VBPatch.vi 07 Apr 2008
+ Updated: Build.bat 1.1
--------------------------------------------------------------------------------
v0.2.5 of 14 Aug 2008
--------------------------------------------------------------------------------
BDiff.exe v0.2.5 build 5 (v0.2.4 skipped)
Notes:
+ Added manifest to resources that tells Windows Vista to run program as
invoked.
+ Skipped a version number to v0.2.5 to keep in sync with BPatch.
File changes:
+ Updated: BDiff.dpr 1.2
+ New: BDiff.manifest 1.0
+ New: BDiff.rc 1.0
+ Updated: Build.bat 1.1
+ Updated: VBDiff.vi 14 Aug 2008
BPatch.exe v0.2.5 build 5
Notes:
+ Renamed program back to BPatch from BPtch.
+ Added a manifest to resources that informs Vista to run the program as
invoked. This overrides Vista's desire to run elevated because "patch" is
in file name.
File changes:
+ Updated: BPatch.dpr 1.3 (renamed from BPtch.dpr)
+ New: BPatch.manifest 1.0
+ New: BPatch.rc 1.0
+ Updated: Build.bat 1.2
+ Updated: VBPatch.vi 14 Aug 2008
================================================================================
COMPILERS
================================================================================
This section notes the various compilers and build tools used to create each
release of the utilities from the first Pascal version to v0.2.5.
--------------------------------------------------------------------------------
v0.2.1 of 29 Nov 2003
--------------------------------------------------------------------------------
+ Delphi 4
+ DelphiDabbler Version Information Editor v2.10
+ Borland BRCC32
--------------------------------------------------------------------------------
v0.2.2 of 21 Dec 2003
--------------------------------------------------------------------------------
+ Delphi 4
+ DelphiDabbler Version Information Editor v2.10.1
+ Borland BRCC32
--------------------------------------------------------------------------------
v0.2.3 of 18 Sep 2007
--------------------------------------------------------------------------------
+ Delphi 7
+ DelphiDabbler Version Information Editor v2.11
+ Borland BRCC32 v5.4
--------------------------------------------------------------------------------
v0.2.4 of 07 Apr 2008
--------------------------------------------------------------------------------
+ Delphi 7
+ DelphiDabbler Version Information Editor v2.11
+ Borland BRCC32 v5.4
--------------------------------------------------------------------------------
v0.2.5 of 14 Aug 2008
--------------------------------------------------------------------------------
+ Delphi 7
+ DelphiDabbler Version Information Editor v2.11.2
+ Borland BRCC32 v5.4

18
contrib/bdiff/LICENSE.md Normal file
View File

@@ -0,0 +1,18 @@
BDiff / BPatch License
======================
_BDiff_ and _BPatch_ have been developed from a Pascal translation of original C source code by Stefan Reuther. The Pascal translation was created by Peter D Johnson.
The original C source code was copyright (c) 1999 by Stefan Reuther (Streu@gmx.de). The Pascal translation and subsequent updates are copyright (c) 2003-2016 by Peter D Johnson (@delphidabbler).
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 and to alter it and redistribute it, 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 acknowledgement in the product documentation would be appreciated but is not required.
2. All redistributions of source code files must retain any author, copyright and license notices that are currently in place in the source code files. An unchanged copy of this license must be included with the redistribution.
3. All redistributions in binary form must contain all occurrences of the above copyright notices and any web site addresses that are currently in place (for example in help screens). A copy of this license must be included with the redistribution.
4. Modified versions in source or binary form must be plainly marked as such, and must not be misrepresented as being the original software. Details of modification must be included in source code files. All original author, license and copyright statements must be retained unchanged.

60
contrib/bdiff/README.md Normal file
View File

@@ -0,0 +1,60 @@
BDiff / BPatch
==============
Binary diff and patch programs for the Windows command line.
Introduction
------------
_BDiff_ computes differences between two binary files. Output can be either a somewhat human-readable protocol in plain text, or a binary file that is readable by _BPatch_.
_BPatch_ applies a binary patch generated by _BDiff_ to a file to recreate the original file.
See the files `BDiff.txt` and `BPatch.txt` in the `Docs` directory for details of how to use the programs.
_BDiff_ and _BPatch_ are derived from Stefan Reuther's _bdiff_ and _bpatch_ v0.2 and a later bug fix by Stefan.
The original C source was translated into Object Pascal by Peter D Johnson ([@delphdabbler](https://twitter.com/delphidabbler)). The programs are are based on updates of the Pascal code base.
The programs should run on any current version of Windows.
For more information see the see the [project web pages](http://delphidabbler.com/software/bdiff).
Installation
------------
Copy the provided executable files to the required location. No further installation is required.
You may want to modify the Windows PATH environment variable to include the location of the programs.
To uninstall simply delete the programs. They make no changes to the system. If you changed the PATH environment variable you may wish to adjust this.
Tests
-----
You can test the operation of _BDiff_ and _BPatch_ using the `Test.bat` script in the `Test` directory. See `ReadMe.txt` in that directory for details.
Source Code
-----------
### Pascal Source
The current source code is maintained in the [delphidabbler/bdiff](https://github.com/delphidabbler/bdiff) Git repository on GitHub. It contains releases going back to v0.2.5. Earlier versions were not under version control and are no longer available.
> **Note:** Until February 2014 the source code was maintained in a Subversion repository. A dump of the repo is available from [Google Drive](https://drive.google.com/file/d/0B8qEVqTUMgmJcF9zVnk0Zk1VMDQ/view?usp=sharing).
For information on how to build the Pascal source, see `Build.txt` in the root of the Git repo.
### C Source
The original C source code can be downloaded from http://phost.de/~stefan/Files/bdiff-02.zip.
Copyright and License
---------------------
See the file `LICENCE.md` for details of copyright and the license that applies to this software.
Change Log
----------
The change log is provided in the file `CHANGELOG.txt`.

105
contrib/bdiff/UAppInfo.pas Normal file
View File

@@ -0,0 +1,105 @@
{
* Provides information about program: file name, date and version info.
* Common code used by both BDiff and BPatch.
}
unit UAppInfo;
interface
type
TAppInfo = class(TObject)
private
{ Fully specified file name of program, with absolute path }
class function ProgramPath: string;
public
{ Name of program's executable file, without path }
class function ProgramFileName: string;
{ Name of program, without file extension }
class function ProgramBaseName: string;
{ Program's product version number }
class function ProgramVersion: string;
{ Last modification date of program's executable file }
class function ProgramExeDate: string;
end;
implementation
uses
// Delphi
SysUtils, Windows;
{ TAppInfo }
class function TAppInfo.ProgramBaseName: string;
begin
Result := ChangeFileExt(ProgramFileName, '');
end;
class function TAppInfo.ProgramExeDate: string;
var
FileDate: TDateTime; // date stamp of exe file
begin
if FileAge(ProgramPath, FileDate) then
Result := FormatDateTime('dd mmm yyyy', FileDate)
else
Result := '';
end;
class function TAppInfo.ProgramFileName: string;
begin
Result := ExtractFileName(ProgramPath);
end;
class function TAppInfo.ProgramPath: string;
begin
Result := ParamStr(0);
end;
class function TAppInfo.ProgramVersion: string;
var
Dummy: DWORD; // unused variable required in API calls
VerInfoSize: Integer; // size of version information data
VerInfoBuf: Pointer; // buffer holding version information
ValPtr: Pointer; // pointer to a version information value
FFI: TVSFixedFileInfo; // fixed file information from version info
begin
Result := '';
// Get fixed file info from program's version info
// get size of version info
VerInfoSize := GetFileVersionInfoSize(PChar(ProgramPath), Dummy);
if VerInfoSize > 0 then
begin
// create buffer and read version info into it
GetMem(VerInfoBuf, VerInfoSize);
try
if GetFileVersionInfo(
PChar(ProgramPath), Dummy, VerInfoSize, VerInfoBuf
) then
begin
// get fixed file info from version info (ValPtr points to it)
if VerQueryValue(VerInfoBuf, '\', ValPtr, Dummy) then
begin
FFI := PVSFixedFileInfo(ValPtr)^;
// Build version info string from product version field of FFI
Result := Format(
'%d.%d.%d',
[
HiWord(FFI.dwProductVersionMS),
LoWord(FFI.dwProductVersionMS),
HiWord(FFI.dwProductVersionLS)
]
);
end
end;
finally
FreeMem(VerInfoBuf);
end;
end;
end;
end.

View File

@@ -0,0 +1,54 @@
{
* Class that emits BDiff's version information and help screen on standard
* output.
}
unit UBDiffInfoWriter;
interface
uses
UInfoWriter;
type
TBDiffInfoWriter = class(TInfoWriter)
protected
class function HelpText: string; override;
end;
implementation
uses
SysUtils,
UAppInfo;
{ TBDiffInfoWriter }
class function TBDiffInfoWriter.HelpText: string;
begin
Result := Format(
'%0:s: binary ''diff'' - compare two binary files'#13#10#13#10
+ 'Usage: %0:s [options] old-file new-file [>patch-file]'#13#10#13#10
+ 'Difference between old-file and new-file written to standard output'
+ #13#10#13#10
+ 'Valid options:'#13#10
+ ' -q Use QUOTED format'#13#10
+ ' -f Use FILTERED format'#13#10
+ ' -b Use BINARY format'#13#10
+ ' --format=FMT Use format FMT (''quoted'', ''filter[ed]'' '
+ 'or ''binary'')'#13#10
+ ' -m N --min-equal=N Minimum equal bytes to recognize an equal chunk'
+ #13#10
+ ' -o FN --output=FN Set output file name (instead of stdout)'#13#10
+ ' -V --verbose Show status messages'#13#10
+ ' -h --help Show this help screen'#13#10
+ ' -v --version Show version information'#13#10
+ #13#10
+ '(c) copyright 1999 Stefan Reuther <Streu@gmx.de>'#13#10
+ '(c) copyright 2003-2016 Peter Johnson (@delphidabbler)'#13#10,
[TAppInfo.ProgramFileName]
);
end;
end.

View File

@@ -0,0 +1,107 @@
{
* Static class containing main program logic for BDiff program.
}
unit UBDiffMain;
interface
uses
UBDiffParams;
type
TMain = class(TObject)
private
class procedure DisplayHelp;
class procedure DisplayVersion;
class procedure CreateDiff(Params: TParams);
class procedure RedirectStdOut(const FileName: string);
public
class procedure Run;
end;
implementation
uses
SysUtils,
UAppInfo, UDiffer, UBDiffInfoWriter, UBDiffUtils, UErrors, ULogger;
{ TMain }
class procedure TMain.CreateDiff(Params: TParams);
var
Differ: TDiffer;
Logger: TLogger;
begin
// create the diff
Logger := TLoggerFactory.Instance(Params.Verbose);
try
Differ := TDiffer.Create;
try
Differ.MinMatchLength := Params.MinEqual;
Differ.Format := Params.Format;
Differ.MakeDiff(Params.OldFileName, Params.NewFileName, Logger);
finally
Differ.Free;
end;
finally
Logger.Free;
end;
end;
class procedure TMain.DisplayHelp;
begin
TBDiffInfoWriter.HelpScreen;
end;
class procedure TMain.DisplayVersion;
begin
TBDiffInfoWriter.VersionInfo;
end;
class procedure TMain.RedirectStdOut(const FileName: string);
var
PatchFileHandle: Integer;
begin
// redirect standard output to patch file
PatchFileHandle := FileCreate(FileName);
if PatchFileHandle <= 0 then
OSError;
TIO.RedirectStdOut(PatchFileHandle);
end;
class procedure TMain.Run;
var
Params: TParams;
begin
ExitCode := 0;
try
Params := TParams.Create;
try
Params.Parse;
if Params.Help then
DisplayHelp
else if Params.Version then
DisplayVersion
else
begin
if (Params.PatchFileName <> '') and (Params.PatchFileName <> '-') then
RedirectStdOut(Params.PatchFileName);
CreateDiff(Params);
end;
finally
Params.Free;
end;
except
on E: Exception do
begin
ExitCode := 1;
TIO.WriteStrFmt(
TIO.StdErr, '%0:s: %1:s'#13#10, [TAppInfo.ProgramFileName, E.Message]
);
end;
end;
end;
end.

View File

@@ -0,0 +1,185 @@
{
* Implements a class that parses command lines and records parameters.
}
unit UBDiffParams;
interface
uses
// Project
UBaseParams, UBDiffTypes;
type
TParams = class(TBaseParams)
private
fVerbose: Boolean;
fMinEqual: Integer;
fOldFileName: string;
fPatchFileName: string;
fNewFileName: string;
fFormat: TFormat;
procedure SetFormat(const Value: string);
procedure SetMinEqual(const Value: string);
protected
function ParseLongOption(const Option: string; var ParamIdx: Integer;
var Terminated: Boolean): Boolean; override;
function ParseShortOption(const Options: string; const OptionIdx: Integer;
var ParamIdx: Integer; var Terminated: Boolean): Boolean; override;
procedure ParseFileName(const FileName: string); override;
procedure Finalize; override;
public
constructor Create;
property OldFileName: string read fOldFileName;
property NewFileName: string read fNewFileName;
property PatchFileName: string read fPatchFileName;
property MinEqual: Integer read fMinEqual default 24;
property Verbose: Boolean read fVerbose default False;
property Help;
property Version;
property Format: TFormat read fFormat default FMT_QUOTED;
end;
implementation
uses
// Delphi
SysUtils, StrUtils;
{ TParams }
constructor TParams.Create;
begin
inherited;
fOldFileName := '';
fNewFileName := '';
fPatchFileName := '';
fMinEqual := 24;
fVerbose := False;
fFormat := FMT_QUOTED;
end;
procedure TParams.Finalize;
begin
if fNewFileName = '' then
Error('need two filenames');
if SameFileName(fOldFileName, fNewFileName) then
Error('file names must not be the same');
if SameFileName(fOldFileName, fPatchFileName)
or SameFileName(fNewFileName, fPatchFileName) then
Error('output file name must differ from other file names');
end;
procedure TParams.ParseFileName(const FileName: string);
begin
if fOldFileName = '' then
fOldFileName := FileName
else if fNewFileName = '' then
fNewFileName := FileName
else
Error('too many file names on command line');
end;
function TParams.ParseLongOption(const Option: string; var ParamIdx: Integer;
var Terminated: Boolean): Boolean;
begin
Result := inherited ParseLongOption(Option, ParamIdx, Terminated);
if Result then
Exit;
Result := True;
if Option = '--verbose' then
fVerbose := True
else if Option = '--output' then
begin
Inc(ParamIdx);
if ParamStr(ParamIdx) = '' then
Error('missing argument to ''--output''');
fPatchFileName := ParamStr(ParamIdx);
end
else if AnsiStartsStr('--output=', Option) then
fPatchFileName := StripLeadingChars(Option, Length('--output='))
else if Option = '--format' then
begin
Inc(ParamIdx);
SetFormat(ParamStr(ParamIdx));
end
else if AnsiStartsStr('--format=', Option) then
SetFormat(StripLeadingChars(Option, Length('--format=')))
else if Option = '--min-equal' then
begin
Inc(ParamIdx);
SetMinEqual(ParamStr(ParamIdx));
end
else if AnsiStartsStr('--min-equal=', Option) then
SetMinEqual(StripLeadingChars(Option, Length('--min-equal=')))
else
Result := False;
end;
function TParams.ParseShortOption(const Options: string;
const OptionIdx: Integer; var ParamIdx: Integer; var Terminated: Boolean):
Boolean;
begin
Result := inherited ParseShortOption(
Options, OptionIdx, ParamIdx, Terminated
);
if Result then
Exit;
Result := True;
case Options[OptionIdx] of
'V':
fVerbose := True;
'q':
fFormat := FMT_QUOTED;
'f':
fFormat := FMT_FILTERED;
'b':
fFormat := FMT_BINARY;
'm':
begin
Inc(ParamIdx);
SetMinEqual(ParamStr(ParamIdx));
end;
'o':
begin
Inc(ParamIdx);
if ParamStr(ParamIdx) = '' then
Error('missing argument to ''-o''');
fPatchFileName := ParamStr(ParamIdx);
end;
else
Result := False;
end;
end;
procedure TParams.SetFormat(const Value: string);
begin
if Value = '' then
Error('missing argument to ''--format''');
if Value = 'quoted' then
fFormat := FMT_QUOTED
else if (Value = 'filter') or (Value = 'filtered') then
fFormat := FMT_FILTERED
else if Value = 'binary' then
fFormat := FMT_BINARY
else
Error('invalid format specification');
end;
procedure TParams.SetMinEqual(const Value: string);
var
X: Int64; // number parsed from command line
begin
if Value = '' then
Error('missing argument to ''--min-equal'' / ''-m''');
if not TryStrToInt64(Value, X) or (X < 0) then
Error('malformed number on command line');
if (X = 0) or (X > $7FFF) then
Error('number out of range on command line');
fMinEqual := Integer(X);
end;
end.

View File

@@ -0,0 +1,40 @@
{
* Contains type declarations for BDiff.
}
unit UBDiffTypes;
interface
type
{ Some uses of *size_t in original C code actually reference an array of
size_t and are referenced using array[] notation. The following types are
declared to use in these circumstances to enable similar notation in
Pascal }
TBlock = array[0..0] of Cardinal;
PBlock = ^TBlock;
{ The original C code refers to the buffered file contents as an array of
Char. The fact that Char is signed in C (-127..128) and unsigned in Pascal
(0..255) means that the block sort algorithm and string lookup functions
operate differently in C and Pascal. We therefore define a signed *ansi*
char type - SignedAnsiChar - of the correct range and refer to the buffered
file contents as an array of this new type. Since ShortInt is defined as
(-127..128) we use this as the basis for SignedAnsiChar}
SignedAnsiChar = type ShortInt;
PSignedAnsiChar = ^SignedAnsiChar;
TSignedAnsiCharArray = array[0..(MaxInt div SizeOf(SignedAnsiChar) - 1)]
of SignedAnsiChar;
PSignedAnsiCharArray = ^TSignedAnsiCharArray;
{ Output format to use }
TFormat = (FMT_BINARY, FMT_FILTERED, FMT_QUOTED);
implementation
end.

View File

@@ -0,0 +1,36 @@
{
* Contains utility functions used for BDiff. Includes Pascal implementations
* of, or alternatives for, some standard C library code.
}
unit UBDiffUtils;
interface
uses
// Project
UUtils;
type
TIO = class(TCommonIO)
public
{ Redirects standard output to a given file handle }
class procedure RedirectStdOut(const Handle: Integer);
end;
implementation
uses
// Delphi
Windows;
{ TIO }
class procedure TIO.RedirectStdOut(const Handle: Integer);
begin
Windows.SetStdHandle(STD_OUTPUT_HANDLE, Cardinal(Handle));
end;
end.

View File

@@ -0,0 +1,49 @@
{
* Class that emits BPatch's version information and help screen on standard
* output.
}
unit UBPatchInfoWriter;
interface
uses
UInfoWriter;
type
TBPatchInfoWriter = class(TInfoWriter)
protected
class function HelpText: string; override;
end;
implementation
uses
SysUtils,
UAppInfo;
{ TBPatchInfoWriter }
class function TBPatchInfoWriter.HelpText: string;
begin
Result := Format(
'%0:s: binary ''patch'' - apply binary patch'#13#10
+ #13#10
+ 'Usage: %0:s [options] old-file [new-file] [<patch-file]'#13#10#13#10
+ 'Creates new-file from old-file and patch-file'#13#10
+ 'If new-file is not provided old-file is updated in place'#13#10
+ #13#10
+ 'Valid options:'#13#10
+ ' -i FN --input=FN Set input file name (instead of stdin)'
+ #13#10
+ ' -h --help Show this help screen'#13#10
+ ' -v --version Show version information'#13#10
+ #13#10
+ '(c) copyright 1999 Stefan Reuther <Streu@gmx.de>'#13#10
+ '(c) copyright 2003-2016 Peter Johnson (@delphidabbler)'#13#10,
[TAppInfo.ProgramFileName]
);
end;
end.

View File

@@ -0,0 +1,82 @@
{
* Static class containing main program logic for BPatch program.
}
unit UBPatchMain;
interface
type
TMain = class(TObject)
private
class procedure DisplayHelp;
class procedure DisplayVersion;
class procedure RedirectStdIn(const FileName: string);
public
class procedure Run;
end;
implementation
uses
SysUtils,
UAppInfo, UPatcher, UBPatchInfoWriter, UBPatchParams, UBPatchUtils, UErrors;
{ TMain }
class procedure TMain.DisplayHelp;
begin
TBPatchInfoWriter.HelpScreen;
end;
class procedure TMain.DisplayVersion;
begin
TBPatchInfoWriter.VersionInfo;
end;
class procedure TMain.RedirectStdIn(const FileName: string);
var
PatchFileHandle: Integer;
begin
PatchFileHandle := FileOpen(FileName, fmOpenRead or fmShareDenyNone);
if PatchFileHandle <= 0 then
OSError;
TIO.RedirectStdIn(PatchFileHandle);
end;
class procedure TMain.Run;
var
Params: TParams;
begin
ExitCode := 0;
Params := TParams.Create;
try
try
Params.Parse;
if Params.Help then
DisplayHelp
else if Params.Version then
DisplayVersion
else
begin
if (Params.PatchFileName <> '') and (Params.PatchFileName <> '-') then
RedirectStdIn(Params.PatchFileName);
TPatcher.Apply(Params.OldFileName, Params.NewFileName);
end;
finally
Params.Free;
end;
except
on E: Exception do
begin
ExitCode := 1;
TIO.WriteStrFmt(
TIO.StdErr, '%0:s: %1:s'#13#10, [TAppInfo.ProgramFileName, E.Message]
);
end;
end;
end;
end.

View File

@@ -0,0 +1,115 @@
{
* Implements a class that parses command lines and records parameters.
}
unit UBPatchParams;
interface
uses
// Project
UBaseParams;
type
TParams = class(TBaseParams)
private
fOldFileName: string;
fNewFileName: string;
fPatchFileName: string;
protected
function ParseLongOption(const Option: string; var ParamIdx: Integer;
var Terminated: Boolean): Boolean; override;
function ParseShortOption(const Options: string; const OptionIdx: Integer;
var ParamIdx: Integer; var Terminated: Boolean): Boolean; override;
procedure ParseFileName(const FileName: string); override;
procedure Finalize; override;
public
constructor Create;
property OldFileName: string read fOldFileName;
property NewFileName: string read fNewFileName;
property PatchFileName: string read fPatchFileName;
property Help;
property Version;
end;
implementation
uses
// Delphi
StrUtils;
{ TParams }
constructor TParams.Create;
begin
inherited;
fOldFileName := '';
fNewFileName := '';
fPatchFileName := '';
end;
procedure TParams.Finalize;
begin
if fOldFileName = '' then
Error('file name argument missing');
if fNewFileName = '' then
fNewFileName := fOldFileName;
end;
procedure TParams.ParseFileName(const FileName: string);
begin
if fOldFileName = '' then
fOldFileName := FileName
else if fNewFileName = '' then
fNewFileName := FileName
else
Error('too many file names on command line');
end;
function TParams.ParseLongOption(const Option: string; var ParamIdx: Integer;
var Terminated: Boolean): Boolean;
begin
Result := inherited ParseLongOption(Option, ParamIdx, Terminated);
if Result then
Exit;
Result := True;
if Option = '--input' then
begin
Inc(ParamIdx);
if ParamStr(ParamIdx) = '' then
Error('missing argument to ''--input''');
fPatchFileName := ParamStr(ParamIdx);
end
else if AnsiStartsStr('--input=', Option) then
fPatchFileName := StripLeadingChars(Option, Length('--input='))
else
Result := False;
end;
function TParams.ParseShortOption(const Options: string;
const OptionIdx: Integer; var ParamIdx: Integer; var Terminated: Boolean):
Boolean;
begin
Result := inherited ParseShortOption(
Options, OptionIdx, ParamIdx, Terminated
);
if Result then
Exit;
Result := True;
case Options[OptionIdx] of
'i':
begin
Inc(ParamIdx);
if ParamStr(ParamIdx) = '' then
Error('missing argument to ''-i''');
fPatchFileName := ParamStr(ParamIdx);
end
else
Result := False;
end;
end;
end.

View File

@@ -0,0 +1,81 @@
{
* Contains utility functions used for BPatch. Includes Pascal implementations
* of some standard C library code.
}
unit UBPatchUtils;
interface
uses
// Project
UUtils;
const
// Value representing end of file (as returned from TIO.GetCh).
EOF: Integer = -1;
// seek flag used by TIO.Seek (other possible values not used in program).
SEEK_SET = 0;
type
TIO = class(TCommonIO)
public
{ Redirects standard input from a given file handle }
class procedure RedirectStdIn(const Handle: Integer);
{ Seeks to given offset from given origin in file specified by Handle.
Returns True on success, false on failure. }
class function Seek(Handle: Integer; Offset: Longint; Origin: Integer):
Boolean;
{ Checks if given file handle is at end of file. }
class function AtEOF(Handle: Integer): Boolean;
{ Gets a single ANSI character from file specified by Handle and returns it,
or EOF. }
class function GetCh(Handle: Integer): Integer;
end;
implementation
uses
// Delphi
SysUtils, Windows;
{ TIO }
class function TIO.AtEOF(Handle: Integer): Boolean;
var
CurPos: Integer;
Size: Integer;
begin
CurPos := SysUtils.FileSeek(Handle, 0, 1);
Size := Windows.GetFileSize(Handle, nil);
Result := CurPos = Size;
end;
class function TIO.GetCh(Handle: Integer): Integer;
var
Ch: AnsiChar;
begin
if AtEOF(Handle) then
Result := EOF
else
begin
SysUtils.FileRead(Handle, Ch, SizeOf(Ch));
Result := Integer(Ch);
end;
end;
class procedure TIO.RedirectStdIn(const Handle: Integer);
begin
Windows.SetStdHandle(STD_INPUT_HANDLE, Cardinal(Handle));
end;
class function TIO.Seek(Handle, Offset, Origin: Integer): Boolean;
begin
Result := SysUtils.FileSeek(Handle, Offset, Origin) >= 0;
end;
end.

View File

@@ -0,0 +1,160 @@
{
* Implements an abstract base class for classes that parse command lines.
}
unit UBaseParams;
interface
uses
// Delphi
SysUtils;
type
TBaseParams = class(TObject)
private
fHelp: Boolean;
fVersion: Boolean;
protected
class function StripLeadingChars(const S: string; const Count: Integer):
string;
procedure Error(const Msg: string); overload;
procedure Error(const Fmt: string; const Args: array of const); overload;
function ParseLongOption(const Option: string; var ParamIdx: Integer;
var Terminated: Boolean): Boolean; virtual;
function ParseShortOption(const Options: string; const OptionIdx: Integer;
var ParamIdx: Integer; var Terminated: Boolean): Boolean; virtual;
procedure ParseFileName(const FileName: string); virtual; abstract;
procedure Finalize; virtual; abstract;
public
constructor Create;
procedure Parse;
property Help: Boolean read fHelp default False;
property Version: Boolean read fVersion default False;
end;
type
EParams = class(Exception);
implementation
uses
// Delphi
StrUtils,
// Project
UErrors;
{ TBaseParams }
procedure TBaseParams.Error(const Msg: string);
begin
raise EParams.Create(Msg);
end;
constructor TBaseParams.Create;
begin
inherited Create;
fVersion := False;
fHelp := False;
end;
procedure TBaseParams.Error(const Fmt: string; const Args: array of const);
begin
raise EParams.CreateFmt(Fmt, Args);
end;
procedure TBaseParams.Parse;
var
ParamIdx: Integer;
CharIdx: Integer;
Param: string;
Terminated: Boolean;
begin
// Parse command line
Terminated := False;
ParamIdx := 1;
while ParamIdx <= ParamCount do
begin
Param := ParamStr(ParamIdx);
if AnsiStartsStr('-', Param) then
begin
if AnsiStartsStr('--', Param) then
begin
// long option
if not ParseLongOption(Param, ParamIdx, Terminated) then
Error('unknown option ''%s''', [Param]);
if Terminated then
Exit;
end
else
begin
// short options
for CharIdx := 2 to Length(Param) do
begin
if not ParseShortOption(Param, CharIdx, ParamIdx, Terminated) then
Error('unknown option ''-%s''', [Param[CharIdx]]);
if Terminated then
Exit;
end;
end;
end
else
ParseFileName(Param);
Inc(ParamIdx);
end;
Finalize;
end;
function TBaseParams.ParseLongOption(const Option: string;
var ParamIdx: Integer; var Terminated: Boolean): Boolean;
begin
Result := True;
if Option = '--help' then
begin
fHelp := True;
Terminated := True;
end
else if Option = '--version' then
begin
fVersion := True;
Terminated := True;
end
else
Result := False;
end;
function TBaseParams.ParseShortOption(const Options: string;
const OptionIdx: Integer; var ParamIdx: Integer;
var Terminated: Boolean): Boolean;
begin
Result := True;
case Options[OptionIdx] of
'h':
if OptionIdx = Length(Options) then
begin
fHelp := True;
Terminated := True;
end;
'v':
if OptionIdx = Length(Options) then
begin
fVersion := True;
Terminated := True;
end;
else
Result := False;
end;
end;
class function TBaseParams.StripLeadingChars(const S: string;
const Count: Integer): string;
begin
if Count > 0 then
Result := AnsiRightStr(S, Length(S) - Count)
else
Result := S;
end;
end.

View File

@@ -0,0 +1,153 @@
{
* Implements block sort.
*
* Based on parts of blksort.c by Stefan Reuther, copyright (c) 1999 Stefan
* Reuther <Streu@gmx.de>.
}
unit UBlockSort;
interface
uses
// Project
UBDiffTypes;
type
TBlockSort = class(TObject)
private
class function Compare(A: Cardinal; B: Cardinal; Data: PSignedAnsiCharArray;
DataSize: Cardinal): Integer;
{ The 'sink element' part of heapsort }
class procedure Sink(Left: Cardinal; Right: Cardinal; Block: PBlock;
Data: PSignedAnsiCharArray; DataSize: Cardinal);
public
{ Returns array of offsets into data, sorted by position.
@param Data [in] Data to be sorted. Must not be nil.
@param DataSize [in] Size of data to be sorted, must be > 0.
@return Pointer to block of sorted indices into Data. Caller must free.
@except raises EOutOfMemory if can't allocate sorted data block.
}
class function Execute(Data: PSignedAnsiCharArray; DataSize: Cardinal):
PBlock;
end;
implementation
{
GENERAL IMPLEMENTATION NOTE (Stefan Reuther)
Block-sort part of bdiff:
Taking the data area of length N, we generate N substrings:
- first substring is data area, length N
- 2nd is data area sans first character, length N-1
- ith is data area sans first i-1 characters, length N-i+1
- Nth is last character of data area, length 1
These strings are sorted to allow fast (i.e., binary) searching in data
area. Of course, we don't really generate these N*N/2 bytes of strings: we
use an array of N size_t's indexing the data.
PASCAL IMPLEMENTATION NOTE (Peter Johnson)
The fact that C's (ansi) Char type is signed and Pascal's is unsigned is
relevant to the string sorting and accessing code described above. Thefore
we use a specially defined SignedAnsiChar to maintain the data buffer to
ensure that the the Pascal performs in the same way as the C code.
}
{ TBlockSort }
class function TBlockSort.Compare(A, B: Cardinal;
Data: PSignedAnsiCharArray; DataSize: Cardinal): Integer;
var
PA: PSignedAnsiChar;
PB: PSignedAnsiChar;
Len: Cardinal;
begin
PA := @Data[A];
PB := @Data[B];
Len := DataSize - A;
if DataSize - B < Len then
Len := DataSize - B;
while (Len <> 0) and (PA^ = PB^) do
begin
Inc(PA);
Inc(PB);
Dec(Len);
end;
if Len = 0 then
begin
Result := A - B;
Exit;
end;
Result := PA^ - PB^;
end;
class function TBlockSort.Execute(Data: PSignedAnsiCharArray;
DataSize: Cardinal): PBlock;
var
I, Temp, Left, Right: Cardinal;
begin
if DataSize = 0 then
begin
Result := nil;
Exit;
end;
GetMem(Result, SizeOf(Cardinal) * DataSize);
// initialize unsorted data
for I := 0 to Pred(DataSize) do
Result[I] := I;
// heapsort
Left := DataSize div 2;
Right := DataSize;
while Left > 0 do
begin
Dec(Left);
Sink(Left, Right, Result, Data, DataSize);
end;
while Right > 0 do
begin
Temp := Result[Left];
Result[Left] := Result[Right-1];
Result[Right-1] := Temp;
Dec(Right);
Sink(Left, Right, Result, Data, DataSize);
end;
end;
class procedure TBlockSort.Sink(Left, Right: Cardinal; Block: PBlock;
Data: PSignedAnsiCharArray; DataSize: Cardinal);
var
I, J, X: Cardinal;
begin
I := Left;
X := Block[I];
while True do
begin
J := 2 * I + 1;
if J >= Right then
Break;
if J < Right - 1 then
if Compare(Block[J], Block[J+1], Data, DataSize) < 0 then
Inc(J);
if Compare(X, Block[J], Data, DataSize) > 0 then
Break;
Block[I] := Block[J];
I := J;
end;
Block[I] := X;
end;
end.

304
contrib/bdiff/UDiffer.pas Normal file
View File

@@ -0,0 +1,304 @@
{
* Class that generates a diff for two files, logging progress as required.
*
* Based on bdiff.c and part of blksort.c by Stefan Reuther, copyright (c) 1999
* Stefan Reuther <Streu@gmx.de>.
}
unit UDiffer;
interface
uses
UBDiffTypes, UFileData, ULogger;
{ Structure for a matching block }
type
TMatch = record
OldOffset: Cardinal;
NewOffset: Cardinal;
BlockLength: Cardinal;
end;
PMatch = ^TMatch;
type
TDiffer = class(TObject)
private
fMinMatchLength: Cardinal;
fFormat: TFormat;
function FindMaxMatch(OldFile: TFileData; SortedOldData: PBlock;
SearchText: PSignedAnsiChar; SearchTextLength: Cardinal): TMatch;
/// <summary>Finds maximum length "sub-string" of CompareData that is in
/// Data.</summary>
/// <param name="Data">PSignedAnsiCharArray [in] Data to be searched for
/// "sub-string".</param>
/// <param name="Block">PBlock [in] Block of indexes into Data that sort
/// sub-strings of Data.</param>
/// <param name="DataSize">Cardinal [in] Size of Data.</param>
/// <param name="CompareData">PSignedAnsiChar [in] Pointer to data to be
/// compared to Data.</param>
/// <param name="CompareDataSize">Cardinal [in] Size of data pointed to by
/// CompareData.</param>
/// <param name="FoundPos">Cardinal [out] Position in Data where
/// "sub-string" was found.</param>
/// <returns>Cardinal. Length of found "sub-string".</returns>
function FindString(Data: PSignedAnsiCharArray; Block: PBlock;
DataSize: Cardinal; CompareData: PSignedAnsiChar;
CompareDataSize: Cardinal; out FoundPos: Cardinal): Cardinal;
public
constructor Create;
destructor Destroy; override;
procedure MakeDiff(const OldFileName, NewFileName: string;
const Logger: TLogger); overload;
procedure MakeDiff(OldData, NewData, DiffData: Pointer;
OldSize, NewSize: Integer; var DiffSize: Integer;
const Logger: TLogger); overload;
property MinMatchLength: Cardinal read fMinMatchLength write fMinMatchLength
default 24;
property Format: TFormat read fFormat write fFormat default FMT_QUOTED;
end;
implementation
{$IOCHECKS OFF}
uses
// Project
UBlockSort, UErrors, UPatchWriters;
{ TDiffer }
constructor TDiffer.Create;
begin
inherited Create;
fMinMatchLength := 24; // default minimum match length
fFormat := FMT_QUOTED; // default output format
end;
destructor TDiffer.Destroy;
begin
inherited;
end;
function TDiffer.FindMaxMatch(OldFile: TFileData; SortedOldData: PBlock;
SearchText: PSignedAnsiChar; SearchTextLength: Cardinal): TMatch;
var
FoundPos: Cardinal;
FoundLen: Cardinal;
begin
Result.BlockLength := 0; { no match }
Result.NewOffset := 0;
while (SearchTextLength <> 0) do
begin
FoundLen := FindString(OldFile.Data, SortedOldData, OldFile.Size,
SearchText, SearchTextLength, FoundPos);
if FoundLen >= fMinMatchLength then
begin
Result.OldOffset := FoundPos;
Result.BlockLength := FoundLen;
Exit;
end;
Inc(SearchText);
Inc(Result.NewOffset);
Dec(SearchTextLength);
end;
end;
function TDiffer.FindString(Data: PSignedAnsiCharArray; Block: PBlock;
DataSize: Cardinal; CompareData: PSignedAnsiChar; CompareDataSize: Cardinal;
out FoundPos: Cardinal): Cardinal;
var
First: Cardinal; // first position in Data to search
Last: Cardinal; // last position in Data to search
Mid: Cardinal; // mid point of Data to search
FoundSize: Cardinal; // size of matching "sub-string"
FoundMax: Cardinal; // maximum size of matching "sub-string"
PData: PSignedAnsiChar; // ptr to char in Data to be compared
PCompareData: PSignedAnsiChar; // ptr to char in CompareData to be compared
begin
First := 0;
Last := DataSize - 1;
Result := 0;
FoundPos := 0;
// Do binary search of Data
while First <= Last do
begin
// Get mid point of (sorted) Data to search
Mid := (First + Last) div 2;
// Set pointer to start of Data search string
PData := @Data[Block[Mid]];
// Set pointer to start of CompareData
PCompareData := CompareData;
// Calculate maximum possible size of matching substring
FoundMax := DataSize - Block[Mid];
if FoundMax > CompareDataSize then
FoundMax := CompareDataSize;
// Find and count match chars from Data and CompareData
FoundSize := 0;
while (FoundSize < FoundMax) and (PData^ = PCompareData^) do
begin
Inc(FoundSize);
Inc(PData);
Inc(PCompareData);
end;
// We found a "match" of length FoundSize, position Block[Mid]
if FoundSize > Result then
begin
Result := FoundSize;
FoundPos := Block[Mid];
end;
// Determine next search area
// Note: If FoundSize = FoundMatch then substrings match
if (FoundSize = FoundMax) or (PData^ < PCompareData^) then
// substring <= current data string: search above
First := Mid + 1
else
// substring < current data string: search below
begin
Last := Mid;
if Last <> 0 then
Dec(Last)
else
Break;
end;
end;
end;
procedure TDiffer.MakeDiff(const OldFileName, NewFileName: string;
const Logger: TLogger);
var
OldFile: TFileData;
NewFile: TFileData;
NewOffset: Cardinal;
ToDo: Cardinal;
SortedOldData: PBlock;
Match: TMatch;
PatchWriter: TPatchWriter;
begin
{ initialize }
OldFile := nil;
NewFile := nil;
SortedOldData := nil;
PatchWriter := TPatchWriterFactory.Instance(fFormat);
try
Logger.Log('loading old file');
OldFile := TFileData.Create(OldFileName);
Logger.Log('loading new file');
NewFile := TFileData.Create(NewFileName);
Logger.Log('block sorting old file');
SortedOldData := TBlockSort.Execute(OldFile.Data, OldFile.Size);
if not Assigned(SortedOldData) then
Error('virtual memory exhausted');
Logger.Log('generating patch');
PatchWriter.Header(OldFile.Name, NewFile.Name, OldFile.Size, NewFile.Size);
{ main loop }
ToDo := NewFile.Size;
NewOffset := 0;
while (ToDo <> 0) do
begin
Match := FindMaxMatch(OldFile, SortedOldData,
@NewFile.Data[NewOffset], ToDo);
if Match.BlockLength <> 0 then
begin
{ found a match }
if Match.NewOffset <> 0 then
{ preceded by a "copy" block }
PatchWriter.Add(@NewFile.Data[NewOffset], Match.NewOffset);
Inc(NewOffset, Match.NewOffset);
Dec(ToDo, Match.NewOffset);
PatchWriter.Copy(NewFile.Data, NewOffset, Match.OldOffset,
Match.BlockLength);
Inc(NewOffset, Match.BlockLength);
Dec(ToDo, Match.BlockLength);
end
else
begin
PatchWriter.Add(@NewFile.Data[NewOffset], ToDo);
Break;
end;
end;
Logger.Log('done');
finally
// finally section new to v1.1
if Assigned(SortedOldData) then
FreeMem(SortedOldData);
OldFile.Free;
NewFile.Free;
PatchWriter.Free;
end;
end;
procedure TDiffer.MakeDiff(OldData, NewData, DiffData: Pointer;
OldSize, NewSize: Integer; var DiffSize: Integer; const Logger: TLogger);
var
OldFile: TFileData;
NewFile: TFileData;
NewOffset: Cardinal;
ToDo: Cardinal;
SortedOldData: PBlock;
Match: TMatch;
PatchWriter: TPatchWriter;
begin
{ initialize }
DiffSize := 0;
OldFile := nil;
NewFile := nil;
SortedOldData := nil;
PatchWriter := TPatchWriterFactory.Instance(fFormat);
PatchWriter.Memory := DiffData;
PatchWriter.Size := 0;
PatchWriter.WriteToMemory := True;
try
Logger.Log('loading old file');
OldFile := TFileData.Create(OldData, OldSize);
Logger.Log('loading new file');
NewFile := TFileData.Create(NewData, NewSize);
Logger.Log('block sorting old file');
SortedOldData := TBlockSort.Execute(OldFile.Data, OldFile.Size);
if not Assigned(SortedOldData) then
Error('virtual memory exhausted');
Logger.Log('generating patch');
PatchWriter.Header(OldFile.Name, NewFile.Name, OldFile.Size, NewFile.Size);
{ main loop }
ToDo := NewFile.Size;
NewOffset := 0;
while (ToDo <> 0) do
begin
Match := FindMaxMatch(OldFile, SortedOldData,
@NewFile.Data[NewOffset], ToDo);
if Match.BlockLength <> 0 then
begin
{ found a match }
if Match.NewOffset <> 0 then
{ preceded by a "copy" block }
PatchWriter.Add(@NewFile.Data[NewOffset], Match.NewOffset);
Inc(NewOffset, Match.NewOffset);
Dec(ToDo, Match.NewOffset);
PatchWriter.Copy(NewFile.Data, NewOffset, Match.OldOffset,
Match.BlockLength);
Inc(NewOffset, Match.BlockLength);
Dec(ToDo, Match.BlockLength);
end
else
begin
PatchWriter.Add(@NewFile.Data[NewOffset], ToDo);
Break;
end;
end;
Logger.Log('done');
DiffSize := PatchWriter.Size;
finally
// finally section new to v1.1
if Assigned(SortedOldData) then
FreeMem(SortedOldData);
OldFile.Free;
NewFile.Free;
PatchWriter.Free;
end;
end;
end.

58
contrib/bdiff/UErrors.pas Normal file
View File

@@ -0,0 +1,58 @@
{
* Helper routines to generate exceptions.
* Common code used by both BDiff and BPatch.
}
unit UErrors;
interface
{ Raises an exception with given message }
procedure Error(const Msg: string); overload;
{ Raises an exception with message created from format string and values }
procedure Error(const Fmt: string; const Args: array of const); overload;
{ Raises exception determined by last operating system error }
procedure OSError;
implementation
uses
// Project
Sysutils;
{ Raises an exception with given message }
procedure Error(const Msg: string);
begin
raise Exception.Create(Msg);
end;
{ Raises an exception with message created from format string and values }
procedure Error(const Fmt: string; const Args: array of const);
begin
raise Exception.CreateFmt(Fmt, Args);
end;
{ Raises exception determined by last operating system error }
procedure OSError;
var
LastError: Integer;
Err: EOSError;
begin
LastError := GetLastError;
if LastError <> 0 then
Err := EOSError.Create(SysErrorMessage(LastError))
else
Err := EOSError.Create('Unknown operating system error');
Err.ErrorCode := LastError;
raise Err;
end;
end.

View File

@@ -0,0 +1,95 @@
{
* Implements class that reads a file and provides access to its data.
}
unit UFileData;
interface
uses
// Project
UBDiffTypes;
type
TFileData = class(TObject)
private
fData: PSignedAnsiCharArray;
fSize: Cardinal;
fName: string;
procedure LoadFile;
public
constructor Create(const FileName: string); overload;
constructor Create(Memory: Pointer; Size: Integer); overload;
destructor Destroy; override;
property Name: string read fName;
property Size: Cardinal read fSize;
property Data: PSignedAnsiCharArray read fData;
end;
implementation
uses
// Delphi
SysUtils, Windows,
// Project
UErrors;
{ TFileData }
constructor TFileData.Create(const FileName: string);
begin
inherited Create;
fName := FileName;
LoadFile;
end;
constructor TFileData.Create(Memory: Pointer; Size: Integer);
begin
inherited Create;
fName := '';
fData := Memory;
fSize := Size;
end;
destructor TFileData.Destroy;
begin
if fName <> '' then
if Assigned(fData) then
FreeMem(fData);
inherited;
end;
procedure TFileData.LoadFile;
var
FileHandle: Integer;
BytesRead: Integer;
begin
FileHandle := FileOpen(fName, fmOpenRead or fmShareDenyWrite);
try
if FileHandle = -1 then
Error('Cannot open file %s', [fName]);
fSize := GetFileSize(FileHandle, nil);
if fSize = Cardinal(-1) then
Error('Cannot find size of file %s - may be to large', [fName]);
if fSize = 0 then
Error('File %s is empty', [fName]);
try
GetMem(fData, fSize);
BytesRead := FileRead(FileHandle, fData^, fSize);
if BytesRead = -1 then
Error('Cannot read from file %s', [fName]);
if fSize <> Cardinal(BytesRead) then
Error('Error reading from file %s', [fName]);
except
if Assigned(fData) then
FreeMem(fData, fSize);
raise;
end;
finally
if FileHandle <> -1 then
FileClose(FileHandle);
end;
end;
end.

View File

@@ -0,0 +1,45 @@
{
* Abstract base class for classes that emit version information and help
* screens on standard output.
}
unit UInfoWriter;
interface
type
TInfoWriter = class(TObject)
protected
class function HelpText: string; virtual; abstract;
public
class procedure VersionInfo;
class procedure HelpScreen;
end;
implementation
uses
UAppInfo, UUtils;
{ TInfoWriter }
class procedure TInfoWriter.HelpScreen;
begin
TCommonIO.WriteStr(TCommonIO.StdOut, HelpText);
end;
class procedure TInfoWriter.VersionInfo;
begin
// NOTE: original code displayed compile date using C's __DATE__ macro. Since
// there is no Pascal equivalent of __DATE__ we display update date of program
// file instead
TCommonIO.WriteStrFmt(
TCommonIO.StdOut,
'%s-%s %s '#13#10,
[TAppInfo.ProgramBaseName, TAppInfo.ProgramVersion, TAppInfo.ProgramExeDate]
);
end;
end.

64
contrib/bdiff/ULogger.pas Normal file
View File

@@ -0,0 +1,64 @@
{
* Classes used to log messages plus a factory class. One logger class logs to
* standard error while the second does nothing.
}
unit ULogger;
interface
type
TLogger = class(TObject)
public
procedure Log(const Msg: string); virtual; abstract;
end;
type
TLoggerFactory = class(TObject)
public
class function Instance(Verbose: Boolean): TLogger;
end;
implementation
uses
UAppInfo, UBDiffUtils;
type
TVerboseLogger = class(TLogger)
public
procedure Log(const Msg: string); override;
end;
type
TSilentLogger = class(TLogger)
public
procedure Log(const Msg: string); override;
end;
{ TVerboseLogger }
procedure TVerboseLogger.Log(const Msg: string);
begin
TIO.WriteStrFmt(TIO.StdErr, '%s: %s'#13#10, [TAppInfo.ProgramFileName, Msg]);
end;
{ TSilentLogger }
procedure TSilentLogger.Log(const Msg: string);
begin
// Do nothing: no output required
end;
{ TLoggerFactory }
class function TLoggerFactory.Instance(Verbose: Boolean): TLogger;
begin
if Verbose then
Result := TVerboseLogger.Create
else
Result := TSilentLogger.Create;
end;
end.

View File

@@ -0,0 +1,299 @@
{
* Heirachy of classes used to write various types of patch, along with factory
* class.
*
* Patch generation code based on portions of bdiff.c by Stefan Reuther,
* copyright (c) 1999 Stefan Reuther <Streu@gmx.de>.
}
unit UPatchWriters;
interface
uses
// Project
UBDiffTypes;
type
TPatchWriter = class(TObject)
private
FWriteToMemory: Boolean;
public
Memory: Pointer;
Size: Integer;
procedure Header(const OldFileName, NewFileName: string;
const OldFileSize, NewFileSize: Cardinal); virtual; abstract;
procedure Add(Data: PSignedAnsiChar; Length: Cardinal); virtual; abstract;
procedure Copy(NewBuf: PSignedAnsiCharArray; NewPos: Cardinal;
OldPos: Cardinal; Length: Cardinal); virtual; abstract;
property WriteToMemory: Boolean read FWriteToMemory write FWriteToMemory
default false;
end;
TPatchWriterFactory = class(TObject)
public
class function Instance(const Format: TFormat): TPatchWriter;
end;
implementation
uses
// Delphi
SysUtils,
// Project
UBDiffUtils;
type
TBinaryPatchWriter = class(TPatchWriter)
private
procedure PackLong(P: PSignedAnsiChar; L: Longint);
function CheckSum(Data: PSignedAnsiChar; Length: Cardinal): Longint;
public
procedure Header(const OldFileName, NewFileName: string;
const OldFileSize, NewFileSize: Cardinal); override;
procedure Add(Data: PSignedAnsiChar; Length: Cardinal); override;
procedure Copy(NewBuf: PSignedAnsiCharArray; NewPos: Cardinal;
OldPos: Cardinal; Length: Cardinal); override;
end;
TTextPatchWriter = class(TPatchWriter)
protected
{ Checks if an ANSI character is a printable ASCII character. }
class function IsPrint(const Ch: AnsiChar): Boolean;
procedure CopyHeader(NewPos: Cardinal; OldPos: Cardinal; Length: Cardinal);
procedure Header(const OldFileName, NewFileName: string;
const OldFileSize, NewFileSize: Cardinal); override;
end;
TQuotedPatchWriter = class(TTextPatchWriter)
private
procedure QuotedData(Data: PSignedAnsiChar; Length: Cardinal);
{ Returns octal representation of given value as a 3 digit string. }
class function ByteToOct(const Value: Byte): string;
public
procedure Add(Data: PSignedAnsiChar; Length: Cardinal); override;
procedure Copy(NewBuf: PSignedAnsiCharArray; NewPos: Cardinal;
OldPos: Cardinal; Length: Cardinal); override;
end;
TFilteredPatchWriter = class(TTextPatchWriter)
private
procedure FilteredData(Data: PSignedAnsiChar; Length: Cardinal);
public
procedure Add(Data: PSignedAnsiChar; Length: Cardinal); override;
procedure Copy(NewBuf: PSignedAnsiCharArray; NewPos: Cardinal;
OldPos: Cardinal; Length: Cardinal); override;
end;
{ TPatchWriterFactory }
class function TPatchWriterFactory.Instance(const Format: TFormat)
: TPatchWriter;
begin
case Format of
FMT_BINARY:
Result := TBinaryPatchWriter.Create;
FMT_FILTERED:
Result := TFilteredPatchWriter.Create;
FMT_QUOTED:
Result := TQuotedPatchWriter.Create;
else
raise Exception.Create('Invalid format type');
end;
end;
{ TBinaryPatchWriter }
procedure TBinaryPatchWriter.Add(Data: PSignedAnsiChar; Length: Cardinal);
var
Rec: packed record DataLength: array [0 .. 3] of SignedAnsiChar;
// length of added adata
end;
const
cPlusSign: AnsiChar = '+'; // flags added data
begin
Inc(Size, TIO.WriteStr(TIO.StdOut, cPlusSign, FWriteToMemory, Memory, Size));
PackLong(@Rec.DataLength, Length);
Inc(Size, TIO.WriteRaw(TIO.StdOut, @Rec, SizeOf(Rec), FWriteToMemory,
Memory, Size));
Inc(Size, TIO.WriteRaw(TIO.StdOut, Data, Length, FWriteToMemory,
Memory, Size));
// data added
end;
{ Compute simple checksum }
function TBinaryPatchWriter.CheckSum(Data: PSignedAnsiChar;
Length: Cardinal): Longint;
begin
Result := 0;
while Length <> 0 do
begin
Dec(Length);
Result := ((Result shr 30) and 3) or (Result shl 2);
Result := Result xor Ord(Data^);
Inc(Data);
end;
end;
procedure TBinaryPatchWriter.Copy(NewBuf: PSignedAnsiCharArray;
NewPos, OldPos, Length: Cardinal);
var
Rec: packed record CopyStart: array [0 .. 3] of SignedAnsiChar;
// starting pos of copied data
CopyLength: array [0 .. 3] of SignedAnsiChar; // length copied data
CheckSum: array [0 .. 3] of SignedAnsiChar; // validates copied data
end;
const
cAtSign: AnsiChar = '@'; // flags command data in both file
begin
Inc(Size, TIO.WriteStr(TIO.StdOut, cAtSign, FWriteToMemory, Memory, Size));
PackLong(@Rec.CopyStart, OldPos);
PackLong(@Rec.CopyLength, Length);
PackLong(@Rec.CheckSum, CheckSum(@NewBuf[NewPos], Length));
Inc(Size, TIO.WriteRaw(TIO.StdOut, @Rec, SizeOf(Rec), FWriteToMemory,
Memory, Size));
end;
procedure TBinaryPatchWriter.Header(const OldFileName, NewFileName: string;
const OldFileSize, NewFileSize: Cardinal);
var
Head: packed record Signature: array [0 .. 7] of SignedAnsiChar;
// file signature
OldDataSize: array [0 .. 3] of SignedAnsiChar; // size of old data file
NewDataSize: array [0 .. 3] of SignedAnsiChar; // size of new data file
end;
const
// File signature. Must be 8 bytes. Format is 'bdiff' + file-version + #$1A
// where file-version is a two char string, here '02'.
// If file format is changed then increment the file version
cFileSignature: array [0 .. 7] of AnsiChar = 'bdiff02'#$1A;
begin
Assert(Length(cFileSignature) = 8);
Move(cFileSignature, Head.Signature[0], Length(cFileSignature));
PackLong(@Head.OldDataSize, OldFileSize);
PackLong(@Head.NewDataSize, NewFileSize);
Inc(Size, TIO.WriteRaw(TIO.StdOut, @Head, SizeOf(Head), FWriteToMemory,
Memory, Size));
end;
{ Pack long in little-endian format to P }
{ NOTE: P must point to a block of at least 4 bytes }
procedure TBinaryPatchWriter.PackLong(P: PSignedAnsiChar; L: Integer);
begin
P^ := L and $FF;
Inc(P);
P^ := (L shr 8) and $FF;
Inc(P);
P^ := (L shr 16) and $FF;
Inc(P);
P^ := (L shr 24) and $FF;
end;
{ TTextPatchWriter }
procedure TTextPatchWriter.CopyHeader(NewPos, OldPos, Length: Cardinal);
begin
Inc(Size, TIO.WriteStrFmt(TIO.StdOut, '@ -[%d] => +[%d] %d bytes'#13#10' ',
[OldPos, NewPos, Length], FWriteToMemory, Memory, Size));
end;
procedure TTextPatchWriter.Header(const OldFileName, NewFileName: string;
const OldFileSize, NewFileSize: Cardinal);
begin
Inc(Size, TIO.WriteStrFmt(TIO.StdOut,
'%% --- %s (%d bytes)'#13#10'%% +++ %s (%d bytes)'#13#10,
[OldFileName, OldFileSize, NewFileName, NewFileSize], FWriteToMemory,
Memory, Size));
end;
class function TTextPatchWriter.IsPrint(const Ch: AnsiChar): Boolean;
begin
Result := Ch in [#32 .. #126];
end;
{ TQuotedPatchWriter }
procedure TQuotedPatchWriter.Add(Data: PSignedAnsiChar; Length: Cardinal);
begin
Inc(Size, TIO.WriteStr(TIO.StdOut, '+', FWriteToMemory, Memory, Size));
QuotedData(Data, Length);
Inc(Size, TIO.WriteStr(TIO.StdOut, #13#10, FWriteToMemory, Memory, Size));
end;
class function TQuotedPatchWriter.ByteToOct(const Value: Byte): string;
var
Idx: Integer;
Digit: Byte;
Remainder: Byte;
begin
Result := '';
Remainder := Value;
for Idx := 1 to 3 do
begin
Digit := Remainder mod 8;
Remainder := Remainder div 8;
Result := Chr(Digit + Ord('0')) + Result;
end;
end;
procedure TQuotedPatchWriter.Copy(NewBuf: PSignedAnsiCharArray;
NewPos, OldPos, Length: Cardinal);
begin
CopyHeader(NewPos, OldPos, Length);
QuotedData(@NewBuf[NewPos], Length);
Inc(Size, TIO.WriteStr(TIO.StdOut, #13#10, FWriteToMemory, Memory, Size));
end;
procedure TQuotedPatchWriter.QuotedData(Data: PSignedAnsiChar;
Length: Cardinal);
begin
while (Length <> 0) do
begin
if IsPrint(AnsiChar(Data^)) and (AnsiChar(Data^) <> '\') then
Inc(Size, TIO.WriteStr(TIO.StdOut, AnsiChar(Data^), FWriteToMemory,
Memory, Size))
else
Inc(Size, TIO.WriteStr(TIO.StdOut, '\' + ByteToOct(Data^ and $FF),
FWriteToMemory, Memory, Size));
Inc(Data);
Dec(Length);
end;
end;
{ TFilteredPatchWriter }
procedure TFilteredPatchWriter.Add(Data: PSignedAnsiChar; Length: Cardinal);
begin
Inc(Size, TIO.WriteStr(TIO.StdOut, '+', FWriteToMemory, Memory, Size));
FilteredData(Data, Length);
Inc(Size, TIO.WriteStr(TIO.StdOut, #13#10, FWriteToMemory, Memory, Size));
end;
procedure TFilteredPatchWriter.Copy(NewBuf: PSignedAnsiCharArray;
NewPos, OldPos, Length: Cardinal);
begin
CopyHeader(NewPos, OldPos, Length);
FilteredData(@NewBuf[NewPos], Length);
Inc(Size, TIO.WriteStr(TIO.StdOut, #13#10, FWriteToMemory, Memory, Size));
end;
procedure TFilteredPatchWriter.FilteredData(Data: PSignedAnsiChar;
Length: Cardinal);
begin
while Length <> 0 do
begin
if IsPrint(AnsiChar(Data^)) then
Inc(Size, TIO.WriteStr(TIO.StdOut, AnsiChar(Data^), FWriteToMemory,
Memory, Size))
else
Inc(Size, TIO.WriteStr(TIO.StdOut, '.', FWriteToMemory, Memory, Size));
Inc(Data);
Dec(Length);
end;
end;
end.

375
contrib/bdiff/UPatcher.pas Normal file
View File

@@ -0,0 +1,375 @@
{
* Class that applies patch to source file to re-create destination file.
*
* Based on bpatch.c by Stefan Reuther, copyright (c) 1999 Stefan Reuther
* <Streu@gmx.de>.
}
unit UPatcher;
interface
type
TPatcher = class(TObject)
private
{ Compute simple checksum }
class function CheckSum(Data: PAnsiChar; DataSize: Cardinal;
const BFCheckSum: Longint): Longint;
{ Get 32-bit quantity from char array }
class function GetLong(PCh: PAnsiChar): Longint;
{ Copy data from one stream to another, computing checksums
@param SourceFileHandle [in] Handle to file containing data to be copied.
@param DestFileHandle [in] Handle to file to receive copied data.
@param Count [in] Number of bytes to copy.
@param SourceCheckSum [in] Checksum for data to be copied
@param SourceIsPatch [in] Flag True when SourceFileHandle is patch file and
False when SourceFileHandle is source file.
}
class procedure CopyData(const SourceFileHandle, DestFileHandle: Integer;
Count, SourceCheckSum: Longint; const SourceIsPatch: Boolean); overload;
class procedure CopyData(SourceMemory, DestMemory: Pointer;
Count, SourceCheckSum: Longint; const SourceIsPatch: Boolean;
var Position1, Position2, OutSize: Integer); overload;
{ Creates a temporary file in user's temp directory and returns its name }
class function GetTempFileName: string;
public
{ Apply patch from standard input to SourceFileName and regenerate
DestFileName. }
class procedure Apply(const SourceFileName, DestFileName: string); overload;
class procedure Apply(OldData, DiffData, NewData: Pointer;
OldSize, DiffSize: Integer; var NewSize: Integer); overload;
end;
implementation
{$IOCHECKS OFF}
uses
// Delphi
Windows, SysUtils,
// Project
UAppInfo, UBPatchInfoWriter, UBPatchParams, UBPatchUtils, UErrors;
procedure ShowMessage(Msg: string; Caption: string = '');
begin
MessageBox(0, PWideChar(Msg), PWideChar(Caption), MB_OK or MB_TASKMODAL);
end;
const
FORMAT_VERSION = '02'; // binary diff file format version
BUFFER_SIZE = 4096; // size of buffer used to read files
{ TPatcher }
class procedure TPatcher.Apply(const SourceFileName, DestFileName: string);
var
SourceFileHandle: Integer; // source file handle
DestFileHandle: Integer; // destination file handle
TempFileName: string; // temporary file name
Header: array [0 .. 15] of AnsiChar; // patch file header
SourceLen: Longint; // expected length of source file
DestLen: Longint; // expected length of destination file
DataSize: Longint; // size of data to be copied to destination
SourceFilePos: Longint; // position in source file
Ch: Integer; // next character from patch, or EOF
const
ErrorMsg = 'Patch garbled - invalid section ''%''';
begin
try
// read header from patch file on standard input
if FileRead(TIO.StdIn, Header, 16) <> 16 then
Error('Patch not in BINARY format');
if StrLComp(Header, PAnsiChar('bdiff' + FORMAT_VERSION + #$1A), 8) <> 0 then
Error('Patch not in BINARY format');
// get length of source and destination files from header
SourceLen := GetLong(@Header[8]);
DestLen := GetLong(@Header[12]);
DestFileHandle := 0;
// open source file
SourceFileHandle := FileOpen(SourceFileName, fmOpenRead + fmShareDenyNone);
try
if SourceFileHandle <= 0 then
OSError;
// check destination file name
if Length(DestFileName) = 0 then
Error('Empty destination file name');
// create temporary file
TempFileName := GetTempFileName;
DestFileHandle := FileCreate(TempFileName);
if DestFileHandle <= 0 then
Error('Can''t create temporary file');
{ apply patch }
while True do
begin
Ch := TIO.GetCh(TIO.StdIn);
if Ch = EOF then
Break;
case Ch of
Integer('@'):
begin
// common block: copy from source
if FileRead(TIO.StdIn, Header, 12) <> 12 then
Error('Patch garbled - unexpected end of data');
DataSize := GetLong(@Header[4]);
SourceFilePos := GetLong(@Header[0]);
if (SourceFilePos < 0) or (DataSize <= 0) or
(SourceFilePos > SourceLen) or (DataSize > SourceLen) or
(DataSize + SourceFilePos > SourceLen) then
Error('Patch garbled - invalid change request');
if not TIO.Seek(SourceFileHandle, SourceFilePos, SEEK_SET) then
Error('Seek on source file failed');
CopyData(SourceFileHandle, DestFileHandle, DataSize,
GetLong(@Header[8]), False);
Dec(DestLen, DataSize);
end;
Integer('+'):
begin
// add data from patch file
if FileRead(TIO.StdIn, Header, 4) <> 4 then
Error('Patch garbled - unexpected end of data');
DataSize := GetLong(@Header[0]);
CopyData(TIO.StdIn, DestFileHandle, DataSize, 0, True);
Dec(DestLen, DataSize);
end;
else
Error('Patch garbled - invalid section ''%s''', [Char(Ch)]);
end;
if DestLen < 0 then
Error('Patch garbled - patch file longer than announced in header');
end;
if DestLen <> 0 then
Error('Patch garbled - destination file shorter than announced in header');
finally
FileClose(SourceFileHandle);
FileClose(DestFileHandle);
end;
// create destination file: overwrites any existing dest file with same name
SysUtils.DeleteFile(DestFileName);
if not RenameFile(TempFileName, DestFileName) then
Error('Can''t rename temporary file');
except
on E: Exception do
begin
SysUtils.DeleteFile(TempFileName);
raise;
end;
end;
end;
class procedure TPatcher.Apply(OldData, DiffData, NewData: Pointer;
OldSize, DiffSize: Integer; var NewSize: Integer);
var
Position1, Position2, Position3, Size1, Size2, Size3: Integer;
Header: array [0 .. 15] of AnsiChar; // patch file header
SourceLen: Longint; // expected length of source file
DestLen: Longint; // expected length of destination file
DataSize: Longint; // size of data to be copied to destination
SourceFilePos: Longint; // position in source file
Ch: Integer; // next character from patch, or EOF
B: AnsiChar;
const
ErrorMsg = 'Patch garbled - invalid section ''%''';
begin
Position1 := 0;
Position2 := 0;
Position3 := 0;
Size1 := OldSize;
Size2 := DiffSize;
Size3 := 0;
try
// read header from patch file on standard input
Move((PByte(DiffData) + Position2)^, Header, 16);
Inc(Position2, 16);
if StrLComp(Header, PAnsiChar('bdiff' + FORMAT_VERSION + #$1A), 8) <> 0 then
Error('Patch not in BINARY format');
// get length of source and destination files from header
SourceLen := GetLong(@Header[8]);
DestLen := GetLong(@Header[12]);
try
{ apply patch }
while True do
begin
if Position2 >= Size2 then
Ch := EOF
else
begin
Move((PByte(DiffData) + Position2)^, B, SizeOf(B));
Ch := Integer(B);
Inc(Position2, SizeOf(AnsiChar));
end;
if Ch = EOF then
Break;
case Ch of
Integer('@'):
begin
// common block: copy from source
Move((PByte(DiffData) + Position2)^, Header, 12);
Inc(Position2, 12);
DataSize := GetLong(@Header[4]);
SourceFilePos := GetLong(@Header[0]);
if (SourceFilePos < 0) or (DataSize <= 0) or
(SourceFilePos > SourceLen) or (DataSize > SourceLen) or
(DataSize + SourceFilePos > SourceLen) then
Error('Patch garbled - invalid change request');
Position1 := SourceFilePos;
CopyData((PByte(OldData) + Position1),
(PByte(NewData) + Position3), DataSize, GetLong(@Header[8]),
False, Position1, Position3, Size3);
Dec(DestLen, DataSize);
end;
Integer('+'):
begin
// add data from patch file
Move((PByte(DiffData) + Position2)^, Header, 4);
Inc(Position2, 4);
DataSize := GetLong(@Header[0]);
CopyData((PByte(DiffData) + Position2),
(PByte(NewData) + Position3), DataSize, 0, True, Position2,
Position3, Size3);
Dec(DestLen, DataSize);
end;
else
Error('Patch garbled - invalid section ''%s''', [Char(Ch)]);
end;
if DestLen < 0 then
Error('Patch garbled - patch file longer than announced in header');
end;
if DestLen <> 0 then
Error('Patch garbled - destination file shorter than announced in header');
finally
end;
except
on E: Exception do
begin
raise;
end;
end;
NewSize := Size3;
end;
class function TPatcher.CheckSum(Data: PAnsiChar; DataSize: Cardinal;
const BFCheckSum: Integer): Longint;
begin
Result := BFCheckSum;
while DataSize <> 0 do
begin
Dec(DataSize);
Result := ((Result shr 30) and 3) or (Result shl 2);
Result := Result xor PShortInt(Data)^;
Inc(Data);
end;
end;
class procedure TPatcher.CopyData(const SourceFileHandle, DestFileHandle
: Integer; Count, SourceCheckSum: Integer; const SourceIsPatch: Boolean);
var
DestCheckSum: Longint;
Buffer: array [0 .. BUFFER_SIZE - 1] of AnsiChar;
BytesToCopy: Cardinal;
begin
DestCheckSum := 0;
while Count <> 0 do
begin
if Count > BUFFER_SIZE then
BytesToCopy := BUFFER_SIZE
else
BytesToCopy := Count;
if FileRead(SourceFileHandle, Buffer, BytesToCopy) <> Integer(BytesToCopy)
then
begin
if TIO.AtEOF(SourceFileHandle) then
begin
if SourceIsPatch then
Error('Patch garbled - unexpected end of data')
else
Error('Source file does not match patch');
end
else
begin
if SourceIsPatch then
Error('Error reading patch file')
else
Error('Error reading source file');
end;
end;
if DestFileHandle <> 0 then
if FileWrite(DestFileHandle, Buffer, BytesToCopy) <> Integer(BytesToCopy)
then
Error('Error writing temporary file');
DestCheckSum := CheckSum(Buffer, BytesToCopy, DestCheckSum);
Dec(Count, BytesToCopy);
end;
if not SourceIsPatch and (DestCheckSum <> SourceCheckSum) then
Error('Source file does not match patch');
end;
class procedure TPatcher.CopyData(SourceMemory, DestMemory: Pointer;
Count, SourceCheckSum: Integer; const SourceIsPatch: Boolean;
var Position1, Position2, OutSize: Integer);
var
DestCheckSum: Longint;
BytesToCopy: Cardinal;
Pos: Integer;
begin
DestCheckSum := 0;
Pos := 0;
Inc(Position1, Count);
Inc(Position2, Count);
Inc(OutSize, Count);
while Count <> 0 do
begin
if Count > BUFFER_SIZE then
BytesToCopy := BUFFER_SIZE
else
BytesToCopy := Count;
Move((PByte(SourceMemory) + Pos)^, (PByte(DestMemory) + Pos)^, BytesToCopy);
// Move((PByte(SourceMemory) + Pos)^, Buffer, BytesToCopy);
// Move(Buffer, (PByte(DestMemory) + Pos)^, BytesToCopy);
DestCheckSum := CheckSum(PAnsiChar((PByte(SourceMemory) + Pos)),
BytesToCopy, DestCheckSum);
// DestCheckSum := CheckSum(Buffer, BytesToCopy, DestCheckSum);
Inc(Pos, BytesToCopy);
Dec(Count, BytesToCopy);
end;
if not SourceIsPatch and (DestCheckSum <> SourceCheckSum) then
Error('Source file does not match patch');
end;
class function TPatcher.GetLong(PCh: PAnsiChar): Longint;
var
PB: PByte;
LW: LongWord;
begin
PB := PByte(PCh);
LW := PB^;
Inc(PB);
LW := LW + 256 * PB^;
Inc(PB);
LW := LW + 65536 * PB^;
Inc(PB);
LW := LW + 16777216 * PB^;
Result := LW;
end;
class function TPatcher.GetTempFileName: string;
begin
// Get temporary folder
SetLength(Result, Windows.MAX_PATH);
Windows.GetTempPath(Windows.MAX_PATH, PChar(Result));
// Get unique temporary file name (it is created as side effect of this call)
if Windows.GetTempFileName(PChar(Result), '', 0, PChar(Result)) = 0 then
Error('Can''t create temporary file');
Result := PChar(Result)
end;
end.

96
contrib/bdiff/UUtils.pas Normal file
View File

@@ -0,0 +1,96 @@
{
* Contains utility functions used by both BDiff and BPatch.
}
unit UUtils;
interface
type
TCommonIO = class(TObject)
public
{ Returns Windows standard input handle }
class function StdIn: Integer;
{ Returns Windows standard output handle }
class function StdOut: Integer;
{ Returns Windows standard error handle }
class function StdErr: Integer;
{ Writes binary data to a file }
class function WriteRaw(Handle: THandle; BufPtr: Pointer; Size: Integer;
Memory: Boolean = False; Mem: Pointer = nil;
Position: Integer = 0): Integer;
{ Writes a string to a file }
class function WriteStr(Handle: THandle; const S: UnicodeString;
Memory: Boolean = False; Mem: Pointer = nil; Position: Integer = 0)
: Integer; overload;
class function WriteStr(Handle: THandle; const S: AnsiString;
Memory: Boolean = False; Mem: Pointer = nil; Position: Integer = 0)
: Integer; overload;
{ Writes a string built from format string and arguments to file }
class function WriteStrFmt(Handle: THandle; const Fmt: string;
Args: array of const; Memory: Boolean = False; Mem: Pointer = nil;
Position: Integer = 0): Integer;
end;
implementation
uses
// Delphi
SysUtils, Windows;
{ TCommonIO }
class function TCommonIO.StdErr: Integer;
begin
Result := Integer(Windows.GetStdHandle(STD_ERROR_HANDLE));
end;
class function TCommonIO.StdIn: Integer;
begin
Result := Integer(Windows.GetStdHandle(STD_INPUT_HANDLE));
end;
class function TCommonIO.StdOut: Integer;
begin
Result := Integer(Windows.GetStdHandle(STD_OUTPUT_HANDLE));
end;
class function TCommonIO.WriteRaw(Handle: THandle; BufPtr: Pointer;
Size: Integer; Memory: Boolean = False; Mem: Pointer = nil;
Position: Integer = 0): Integer;
var
Dummy: DWORD;
begin
Result := 0;
if Size <= 0 then
Exit;
Result := Size;
if Memory then
Move(BufPtr^, (PByte(Mem) + Position)^, Size)
else
Windows.WriteFile(Handle, BufPtr^, Size, Dummy, nil);
end;
class function TCommonIO.WriteStr(Handle: THandle; const S: UnicodeString;
Memory: Boolean = False; Mem: Pointer = nil; Position: Integer = 0): Integer;
var
Bytes: TBytes;
begin
Bytes := TEncoding.Default.GetBytes(S);
Result := WriteRaw(Handle, Bytes, Length(S), Memory, Mem, Position);
end;
class function TCommonIO.WriteStr(Handle: THandle; const S: AnsiString;
Memory: Boolean = False; Mem: Pointer = nil; Position: Integer = 0): Integer;
begin
Result := WriteRaw(Handle, PAnsiChar(S), Length(S), Memory, Mem, Position);
end;
class function TCommonIO.WriteStrFmt(Handle: THandle; const Fmt: string;
Args: array of const; Memory: Boolean = False; Mem: Pointer = nil;
Position: Integer = 0): Integer;
begin
Result := WriteStr(Handle, Format(Fmt, Args), Memory, Mem, Position);
end;
end.