├── src
└── main
│ └── java
│ └── org
│ └── jbsdiff
│ ├── ui
│ ├── package-info.java
│ ├── CLI.java
│ └── FileUI.java
│ ├── sort
│ ├── package-info.java
│ ├── SearchResult.java
│ └── SuffixSort.java
│ ├── package-info.java
│ ├── DiffSettings.java
│ ├── InvalidHeaderException.java
│ ├── CountingOutputStream.java
│ ├── DefaultDiffSettings.java
│ ├── ControlBlock.java
│ ├── Offset.java
│ ├── Header.java
│ ├── Patch.java
│ └── Diff.java
├── .gitignore
├── NOTICE.txt
├── README.md
├── LICENSE.txt
├── pom.xml
└── docs
└── APACHE-2.0.txt
/src/main/java/org/jbsdiff/ui/package-info.java:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Provides UI functionality for the org.jbsdiff library.
4 | */
5 | package org.jbsdiff.ui;
6 |
--------------------------------------------------------------------------------
/src/main/java/org/jbsdiff/sort/package-info.java:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Provides a Java port of the qsufsort Suffix Sorting implementation found in
4 | * bsdiff.
5 | */
6 | package org.jbsdiff.sort;
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Java template
3 | *.class
4 |
5 | # Mobile Tools for Java (J2ME)
6 | .mtj.tmp/
7 |
8 | # Package Files #
9 | *.jar
10 | *.war
11 | *.ear
12 | .idea/
13 | *.iml
14 | target/
15 |
16 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
17 | hs_err_pid*
18 |
19 |
20 |
--------------------------------------------------------------------------------
/NOTICE.txt:
--------------------------------------------------------------------------------
1 | This work is licensed under the 2-clause BSD license:
2 |
3 | http://opensource.org/licenses/BSD-2-Clause
4 |
5 | It also includes components from the Apache Commons Compress library, licensed
6 | under the Apache License 2.0. A text copy is available in /docs, or can be
7 | viewed online at:
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0.html
10 |
11 | The XZ for Java library, included with this distribution, has been released to
12 | the public domain.
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | jbsdiff
2 | =======
3 | A Java implementation of bsdiff (http://www.daemonology.net/bsdiff/)
4 |
5 |
6 | Usage
7 | =====
8 | jbsdiff can be used from its command line interface:
9 |
10 | java -jar jbsdiff.jar command oldfile newfile patchfile
11 |
12 | Where *command* is either 'diff' or 'patch.' You can also specify the
13 | compression algorithm used during a diff operation by setting a system property:
14 |
15 | java -Djbsdiff.compressor=gz -jar jbsdiff.jar diff a.bin b.bin patch.gz
16 |
17 | Supported compression algorithms (from the Apache Commons Compress library) are
18 | bzip2 (the default), gz, pack200, and xz.
19 |
20 | ...but jbsdiff is mostly intended to be used as a library. See the _ui_ package
21 | for usage examples.
22 |
23 | To compile the jar do a
24 | ```
25 | mvn clean compile assembly:single
26 | ```
27 |
28 | Also available at
29 |
30 | [](http://clojars.org/org.jbsdiff/jbsdiff)
31 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2015, Colorado State University
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without modification,
6 | are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | This software is provided by the copyright holders and contributors "as is" and
15 | any express or implied warranties, including, but not limited to, the implied
16 | warranties of merchantability and fitness for a particular purpose are
17 | disclaimed. In no event shall the copyright holder or contributors be liable for
18 | any direct, indirect, incidental, special, exemplary, or consequential damages
19 | (including, but not limited to, procurement of substitute goods or services;
20 | loss of use, data, or profits; or business interruption) however caused and on
21 | any theory of liability, whether in contract, strict liability, or tort
22 | (including negligence or otherwise) arising in any way out of the use of this
23 | software, even if advised of the possibility of such damage.
24 | */
25 |
--------------------------------------------------------------------------------
/src/main/java/org/jbsdiff/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013, Colorado State University
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without modification,
6 | are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | This software is provided by the copyright holders and contributors "as is" and
15 | any express or implied warranties, including, but not limited to, the implied
16 | warranties of merchantability and fitness for a particular purpose are
17 | disclaimed. In no event shall the copyright holder or contributors be liable for
18 | any direct, indirect, incidental, special, exemplary, or consequential damages
19 | (including, but not limited to, procurement of substitute goods or services;
20 | loss of use, data, or profits; or business interruption) however caused and on
21 | any theory of liability, whether in contract, strict liability, or tort
22 | (including negligence or otherwise) arising in any way out of the use of this
23 | software, even if advised of the possibility of such damage.
24 | */
25 |
26 |
27 | /**
28 | * This library is a native Java implementation of bsdiff
29 | * (http://www.daemonology.net/bsdiff/). The library provides diff and patch
30 | * functionality that is compatible with the reference implementation.
31 | *
32 | * Additional compression algorithms are also supported through the Apache
33 | * Commons Compress library.
34 | */
35 | package org.jbsdiff;
36 |
--------------------------------------------------------------------------------
/src/main/java/org/jbsdiff/DiffSettings.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013, Colorado State University
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without modification,
6 | are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | This software is provided by the copyright holders and contributors "as is" and
15 | any express or implied warranties, including, but not limited to, the implied
16 | warranties of merchantability and fitness for a particular purpose are
17 | disclaimed. In no event shall the copyright holder or contributors be liable for
18 | any direct, indirect, incidental, special, exemplary, or consequential damages
19 | (including, but not limited to, procurement of substitute goods or services;
20 | loss of use, data, or profits; or business interruption) however caused and on
21 | any theory of liability, whether in contract, strict liability, or tort
22 | (including negligence or otherwise) arising in any way out of the use of this
23 | software, even if advised of the possibility of such damage.
24 | */
25 |
26 | package org.jbsdiff;
27 |
28 | /**
29 | * Defines directives that control how the Diff process is carried out.
30 | *
31 | * @author malensek
32 | */
33 | public interface DiffSettings {
34 |
35 | /**
36 | * Provides the name of the compression algorithm to use during diffing.
37 | *
38 | * @return String containing a compression algorithm name to be used by the
39 | * Commons Compress CompressorStreamFactory.
40 | */
41 | public String getCompression();
42 |
43 | /**
44 | * Defines the suffix sorting algorithm to be used during Diff creation.
45 | *
46 | * @param input input array
47 | * @return Sorted array of indices
48 | */
49 | public int[] sort(byte[] input);
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/org/jbsdiff/InvalidHeaderException.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013, Colorado State University
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without modification,
6 | are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | This software is provided by the copyright holders and contributors "as is" and
15 | any express or implied warranties, including, but not limited to, the implied
16 | warranties of merchantability and fitness for a particular purpose are
17 | disclaimed. In no event shall the copyright holder or contributors be liable for
18 | any direct, indirect, incidental, special, exemplary, or consequential damages
19 | (including, but not limited to, procurement of substitute goods or services;
20 | loss of use, data, or profits; or business interruption) however caused and on
21 | any theory of liability, whether in contract, strict liability, or tort
22 | (including negligence or otherwise) arising in any way out of the use of this
23 | software, even if advised of the possibility of such damage.
24 | */
25 |
26 | package org.jbsdiff;
27 |
28 | /**
29 | * An exception that indicates a malformed bsdiff header.
30 | *
31 | * @author malensek
32 | */
33 |
34 | public class InvalidHeaderException extends Exception {
35 |
36 | private static final long serialVersionUID = -3712364093810940826L;
37 |
38 | public InvalidHeaderException() {
39 | super();
40 | }
41 |
42 | public InvalidHeaderException(String detail) {
43 | super(detail);
44 | }
45 |
46 | /**
47 | * Creates an InvalidHeaderException with details about the invalid field
48 | * that was set, and its value.
49 | */
50 | public InvalidHeaderException(String fieldName, int value) {
51 | super("Invalid header field; " + fieldName + " = " + value);
52 | }
53 | }
54 |
55 |
--------------------------------------------------------------------------------
/src/main/java/org/jbsdiff/CountingOutputStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013, Colorado State University
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without modification,
6 | are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | This software is provided by the copyright holders and contributors "as is" and
15 | any express or implied warranties, including, but not limited to, the implied
16 | warranties of merchantability and fitness for a particular purpose are
17 | disclaimed. In no event shall the copyright holder or contributors be liable for
18 | any direct, indirect, incidental, special, exemplary, or consequential damages
19 | (including, but not limited to, procurement of substitute goods or services;
20 | loss of use, data, or profits; or business interruption) however caused and on
21 | any theory of liability, whether in contract, strict liability, or tort
22 | (including negligence or otherwise) arising in any way out of the use of this
23 | software, even if advised of the possibility of such damage.
24 | */
25 |
26 | package org.jbsdiff;
27 |
28 | import java.io.IOException;
29 | import java.io.OutputStream;
30 |
31 | /**
32 | * A passthrough OutputStream implementation that counts (and can report) the
33 | * number of bytes that have been written to the stream.
34 | *
35 | * @author malensek
36 | */
37 | public class CountingOutputStream extends OutputStream {
38 |
39 | private OutputStream out;
40 | private int counter;
41 |
42 | public CountingOutputStream(OutputStream out) {
43 | this.out = out;
44 | }
45 |
46 | @Override
47 | public void write(int b) throws IOException {
48 | counter++;
49 | out.write(b);
50 | }
51 |
52 | /**
53 | * Retrieves the number of bytes that have been written to this stream so
54 | * far.
55 | */
56 | public int getCount() {
57 | return counter;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/org/jbsdiff/sort/SearchResult.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013, Colorado State University
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without modification,
6 | are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | This software is provided by the copyright holders and contributors "as is" and
15 | any express or implied warranties, including, but not limited to, the implied
16 | warranties of merchantability and fitness for a particular purpose are
17 | disclaimed. In no event shall the copyright holder or contributors be liable for
18 | any direct, indirect, incidental, special, exemplary, or consequential damages
19 | (including, but not limited to, procurement of substitute goods or services;
20 | loss of use, data, or profits; or business interruption) however caused and on
21 | any theory of liability, whether in contract, strict liability, or tort
22 | (including negligence or otherwise) arising in any way out of the use of this
23 | software, even if advised of the possibility of such damage.
24 | */
25 |
26 | package org.jbsdiff.sort;
27 |
28 | /**
29 | * Represents a binary search result for a string of bytes, containing the
30 | * longest match found and the position in the sorted suffix array.
31 | *
32 | * @author malensek
33 | */
34 | public class SearchResult {
35 |
36 | /** Number of matched bytes */
37 | private int length;
38 |
39 | /** Position of the result in the suffix array */
40 | private int position;
41 |
42 | public SearchResult(int length, int position) {
43 | this.length = length;
44 | this.position = position;
45 | }
46 |
47 | @Override
48 | public String toString() {
49 | return new String("length = " + length + ", position = " + position);
50 | }
51 |
52 | public int getLength() {
53 | return length;
54 | }
55 |
56 | public int getPosition() {
57 | return position;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/org/jbsdiff/DefaultDiffSettings.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013, Colorado State University
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without modification,
6 | are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | This software is provided by the copyright holders and contributors "as is" and
15 | any express or implied warranties, including, but not limited to, the implied
16 | warranties of merchantability and fitness for a particular purpose are
17 | disclaimed. In no event shall the copyright holder or contributors be liable for
18 | any direct, indirect, incidental, special, exemplary, or consequential damages
19 | (including, but not limited to, procurement of substitute goods or services;
20 | loss of use, data, or profits; or business interruption) however caused and on
21 | any theory of liability, whether in contract, strict liability, or tort
22 | (including negligence or otherwise) arising in any way out of the use of this
23 | software, even if advised of the possibility of such damage.
24 | */
25 |
26 | package org.jbsdiff;
27 |
28 | import org.apache.commons.compress.compressors.CompressorStreamFactory;
29 | import org.jbsdiff.sort.SuffixSort;
30 |
31 | /**
32 | * Provides a default set of DiffSettings that produces patches that are
33 | * compatible with the bsdiff reference implementation.
34 | *
35 | * @author malensek
36 | */
37 | public class DefaultDiffSettings implements DiffSettings {
38 |
39 | private String compression;
40 |
41 | public DefaultDiffSettings() {
42 | compression = CompressorStreamFactory.BZIP2;
43 | }
44 |
45 | public DefaultDiffSettings(String compression) {
46 | this.compression = compression;
47 | }
48 |
49 | @Override
50 | public String getCompression() {
51 | return compression;
52 | }
53 |
54 | @Override
55 | public int[] sort(byte[] input) {
56 |
57 | int[] I = new int[input.length + 1];
58 | int[] V = new int[input.length + 1];
59 | SuffixSort.qsufsort(I, V, input);
60 |
61 | return I;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.jbsdiff
8 | jbsdiff
9 | jar
10 | 1.0-SNAPSHOT
11 |
12 |
13 |
14 | jbsdiff
15 |
16 |
17 | src/main/resources
18 |
19 |
20 |
21 |
22 |
23 | org.apache.maven.plugins
24 | maven-compiler-plugin
25 | 3.1
26 |
27 | 1.6
28 | 1.6
29 |
30 |
31 |
32 | maven-assembly-plugin
33 |
34 |
35 |
36 | org.jbsdiff.ui.CLI
37 |
38 |
39 |
40 | jar-with-dependencies
41 |
42 | false
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | org.apache.commons
52 | commons-compress
53 | 1.5
54 |
55 |
56 |
57 |
58 |
59 | central
60 | http://repo1.maven.org/maven2
61 | Repository for dependencies
62 |
63 | true
64 | interval:10080
65 |
66 |
67 |
68 |
69 |
70 |
71 | clojars.org
72 | Clojars repository
73 | https://clojars.org/repo
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/src/main/java/org/jbsdiff/ui/CLI.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013, Colorado State University
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without modification,
6 | are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | This software is provided by the copyright holders and contributors "as is" and
15 | any express or implied warranties, including, but not limited to, the implied
16 | warranties of merchantability and fitness for a particular purpose are
17 | disclaimed. In no event shall the copyright holder or contributors be liable for
18 | any direct, indirect, incidental, special, exemplary, or consequential damages
19 | (including, but not limited to, procurement of substitute goods or services;
20 | loss of use, data, or profits; or business interruption) however caused and on
21 | any theory of liability, whether in contract, strict liability, or tort
22 | (including negligence or otherwise) arising in any way out of the use of this
23 | software, even if advised of the possibility of such damage.
24 | */
25 |
26 | package org.jbsdiff.ui;
27 |
28 | import java.io.File;
29 |
30 | /**
31 | * Provides a simple command line interface for the org.jbsdiff tools.
32 | *
33 | * @author malensek
34 | */
35 | public class CLI {
36 |
37 | public static void main(String[] args) throws Exception {
38 | if (args.length < 4) {
39 | System.out.println("Not enough parameters!");
40 | System.out.println();
41 | printUsage();
42 | }
43 |
44 | String compression = System.getProperty("jbsdiff.compressor", "bzip2");
45 | compression = compression.toLowerCase();
46 |
47 | try {
48 | String command = args[0].toLowerCase();
49 | File oldFile = new File(args[1]);
50 | File newFile = new File(args[2]);
51 | File patchFile = new File(args[3]);
52 |
53 | if (command.equals("diff")) {
54 | FileUI.diff(oldFile, newFile, patchFile, compression);
55 | } else if (command.equals("patch")) {
56 | FileUI.patch(oldFile, newFile, patchFile);
57 | } else {
58 | printUsage();
59 | }
60 |
61 | } catch (Exception e) {
62 | e.printStackTrace();
63 | System.exit(1);
64 | }
65 | }
66 |
67 | public static void printUsage() {
68 | String usage = String.format("" +
69 | "Usage: COMMAND oldfile newfile patchfile%n%n" +
70 |
71 | "Where COMMAND is either 'diff' or 'patch.'%n%n" +
72 |
73 | "The jbsdiff.compressor property can be used to select a different %n" +
74 | "compression scheme at runtime:%n%n" +
75 |
76 | " java -Djbsdiff.compressor=gz -jar jbsdiff-?.?.jar diff " +
77 | "a.bin b.bin patch.gz%n%n" +
78 | "Supported compression schemes: bzip2 (default), gz, pack200, xz.%n%n" +
79 | "The compression algorithm used will be detected automatically during %n" +
80 | "patch operations. NOTE: algorithms other than bzip2 are incompatible %n" +
81 | "with the reference implementation of bsdiff!");
82 |
83 | System.out.println(usage);
84 | System.exit(1);
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/main/java/org/jbsdiff/ui/FileUI.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013, Colorado State University
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without modification,
6 | are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | This software is provided by the copyright holders and contributors "as is" and
15 | any express or implied warranties, including, but not limited to, the implied
16 | warranties of merchantability and fitness for a particular purpose are
17 | disclaimed. In no event shall the copyright holder or contributors be liable for
18 | any direct, indirect, incidental, special, exemplary, or consequential damages
19 | (including, but not limited to, procurement of substitute goods or services;
20 | loss of use, data, or profits; or business interruption) however caused and on
21 | any theory of liability, whether in contract, strict liability, or tort
22 | (including negligence or otherwise) arising in any way out of the use of this
23 | software, even if advised of the possibility of such damage.
24 | */
25 |
26 | package org.jbsdiff.ui;
27 |
28 | import org.apache.commons.compress.compressors.CompressorException;
29 | import org.apache.commons.compress.compressors.CompressorStreamFactory;
30 | import org.jbsdiff.*;
31 |
32 | import java.io.*;
33 |
34 | /**
35 | * Provides an interface for working with bsdiff files on disk.
36 | *
37 | * @author malensek
38 | */
39 | public class FileUI {
40 |
41 | public static void diff(File oldFile, File newFile, File patchFile)
42 | throws CompressorException, FileNotFoundException, InvalidHeaderException,
43 | IOException {
44 | diff(oldFile, newFile, patchFile, CompressorStreamFactory.BZIP2);
45 | }
46 |
47 | public static void diff(File oldFile, File newFile, File patchFile,
48 | String compression)
49 | throws CompressorException, FileNotFoundException, InvalidHeaderException,
50 | IOException {
51 | FileInputStream oldIn = new FileInputStream(oldFile);
52 | byte[] oldBytes = new byte[(int) oldFile.length()];
53 | oldIn.read(oldBytes);
54 | oldIn.close();
55 |
56 | FileInputStream newIn = new FileInputStream(newFile);
57 | byte[] newBytes = new byte[(int) newFile.length()];
58 | newIn.read(newBytes);
59 | newIn.close();
60 |
61 | FileOutputStream out = new FileOutputStream(patchFile);
62 | DiffSettings settings = new DefaultDiffSettings(compression);
63 | Diff.diff(oldBytes, newBytes, out, settings);
64 | out.close();
65 | }
66 |
67 | public static void patch(File oldFile, File newFile, File patchFile)
68 | throws CompressorException, FileNotFoundException, InvalidHeaderException,
69 | IOException {
70 | FileInputStream oldIn = new FileInputStream(oldFile);
71 | byte[] oldBytes = new byte[(int) oldFile.length()];
72 | oldIn.read(oldBytes);
73 | oldIn.close();
74 |
75 | FileInputStream patchIn = new FileInputStream(patchFile);
76 | byte[] patchBytes = new byte[(int) patchFile.length()];
77 | patchIn.read(patchBytes);
78 | patchIn.close();
79 |
80 | FileOutputStream out = new FileOutputStream(newFile);
81 | Patch.patch(oldBytes, patchBytes, out);
82 | out.close();
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/main/java/org/jbsdiff/ControlBlock.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013, Colorado State University
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without modification,
6 | are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | This software is provided by the copyright holders and contributors "as is" and
15 | any express or implied warranties, including, but not limited to, the implied
16 | warranties of merchantability and fitness for a particular purpose are
17 | disclaimed. In no event shall the copyright holder or contributors be liable for
18 | any direct, indirect, incidental, special, exemplary, or consequential damages
19 | (including, but not limited to, procurement of substitute goods or services;
20 | loss of use, data, or profits; or business interruption) however caused and on
21 | any theory of liability, whether in contract, strict liability, or tort
22 | (including negligence or otherwise) arising in any way out of the use of this
23 | software, even if advised of the possibility of such damage.
24 | */
25 |
26 | package org.jbsdiff;
27 |
28 | import java.io.IOException;
29 | import java.io.InputStream;
30 | import java.io.OutputStream;
31 |
32 | /**
33 | * Represents a bsdiff Control Block. Control blocks consist of a set of
34 | * triples (x, y, z) meaning:
35 | *
36 | *
Add x bytes from the old file to x bytes from the diff block
37 | *
Copy y bytes from the extra block
38 | *
Seek forwards in the old file by z bytes
39 | *
40 | *
41 | * @author malensek
42 | */
43 | class ControlBlock {
44 |
45 | /**
46 | * Length of the patch diff block
47 | */
48 | private int diffLength;
49 |
50 | /**
51 | * Length of the patch extra block
52 | */
53 | private int extraLength;
54 |
55 | /**
56 | * Bytes to seek forward after completing the control block directives.
57 | */
58 | private int seekLength;
59 |
60 | public ControlBlock() {
61 | }
62 |
63 | /**
64 | * Read a bsdiff control block from an input stream.
65 | */
66 | public ControlBlock(InputStream in) throws IOException {
67 | diffLength = Offset.readOffset(in);
68 | extraLength = Offset.readOffset(in);
69 | seekLength = Offset.readOffset(in);
70 | }
71 |
72 | public ControlBlock(int diffLength, int extraLength, int seekLength) {
73 | this.diffLength = diffLength;
74 | this.extraLength = extraLength;
75 | this.seekLength = seekLength;
76 | }
77 |
78 | /**
79 | * Writes a ControlBlock to an OutputStream.
80 | */
81 | public void write(OutputStream out) throws IOException {
82 | Offset.writeOffset(diffLength, out);
83 | Offset.writeOffset(extraLength, out);
84 | Offset.writeOffset(seekLength, out);
85 | }
86 |
87 | @Override
88 | public String toString() {
89 | return diffLength + ", " + extraLength + ", " + seekLength;
90 | }
91 |
92 | public int getDiffLength() {
93 | return diffLength;
94 | }
95 |
96 | public void setDiffLength(int length) {
97 | diffLength = length;
98 | }
99 |
100 | public int getExtraLength() {
101 | return extraLength;
102 | }
103 |
104 | public void setExtraLength(int length) {
105 | extraLength = length;
106 | }
107 |
108 | public int getSeekLength() {
109 | return seekLength;
110 | }
111 |
112 | public void setSeekLength(int length) {
113 | seekLength = length;
114 | }
115 |
116 | }
117 |
--------------------------------------------------------------------------------
/src/main/java/org/jbsdiff/Offset.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013, Colorado State University
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without modification,
6 | are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | This software is provided by the copyright holders and contributors "as is" and
15 | any express or implied warranties, including, but not limited to, the implied
16 | warranties of merchantability and fitness for a particular purpose are
17 | disclaimed. In no event shall the copyright holder or contributors be liable for
18 | any direct, indirect, incidental, special, exemplary, or consequential damages
19 | (including, but not limited to, procurement of substitute goods or services;
20 | loss of use, data, or profits; or business interruption) however caused and on
21 | any theory of liability, whether in contract, strict liability, or tort
22 | (including negligence or otherwise) arising in any way out of the use of this
23 | software, even if advised of the possibility of such damage.
24 | */
25 |
26 | package org.jbsdiff;
27 |
28 | import java.io.IOException;
29 | import java.io.InputStream;
30 | import java.io.OutputStream;
31 |
32 | /**
33 | * bsdiff encodes offsets (represented by the C off_t type) as 64-bit chunks.
34 | * In this implementation only 32-bit signed integers are supported, but the
35 | * additional encoding steps are left to illustrate the process (which, in Java,
36 | * would encode/decode a long primitive data type).
37 | *
38 | * @author malensek
39 | */
40 | class Offset {
41 |
42 | /**
43 | * Size of a bsdiff-encoded offset, in bytes.
44 | */
45 | public static final int OFFSET_SIZE = 8;
46 |
47 | /**
48 | * Reads a bsdiff-encoded offset (based on the C off_t type) from an
49 | * {@link InputStream}.
50 | */
51 | public static int readOffset(InputStream in) throws IOException {
52 | byte[] buf = new byte[OFFSET_SIZE];
53 | int bytesRead = in.read(buf);
54 | if (bytesRead < OFFSET_SIZE) {
55 | throw new IOException("Could not read offset.");
56 | }
57 |
58 | int y = 0;
59 | y = buf[7] & 0x7F;
60 | y *= 256;
61 | y += buf[6] & 0xFF;
62 | y *= 256;
63 | y += buf[5] & 0xFF;
64 | y *= 256;
65 | y += buf[4] & 0xFF;
66 | y *= 256;
67 | y += buf[3] & 0xFF;
68 | y *= 256;
69 | y += buf[2] & 0xFF;
70 | y *= 256;
71 | y += buf[1] & 0xFF;
72 | y *= 256;
73 | y += buf[0] & 0xFF;
74 |
75 | /* An integer overflow occurred */
76 | if (y < 0) {
77 | throw new IOException(
78 | "Integer overflow: 64-bit offsets not supported.");
79 | }
80 |
81 | if ((buf[7] & 0x80) != 0) {
82 | y = -y;
83 | }
84 |
85 | return y;
86 | }
87 |
88 | /**
89 | * Writes a bsdiff-encoded offset to an {@link OutputStream}.
90 | *
91 | * @param value Integer value to encode and write
92 | */
93 | public static void writeOffset(int value, OutputStream out)
94 | throws IOException {
95 | byte[] buf = new byte[OFFSET_SIZE];
96 | int y = 0;
97 |
98 | if (value < 0) {
99 | y = -value;
100 | /* Set the sign bit */
101 | buf[7] |= 0x80;
102 | } else {
103 | y = value;
104 | }
105 |
106 | buf[0] |= y % 256;
107 | y -= buf[0] & 0xFF;
108 | y /= 256;
109 | buf[1] |= y % 256;
110 | y -= buf[1] & 0xFF;
111 | y /= 256;
112 | buf[2] |= y % 256;
113 | y -= buf[2] & 0xFF;
114 | y /= 256;
115 | buf[3] |= y % 256;
116 | y -= buf[3] & 0xFF;
117 | y /= 256;
118 | buf[4] |= y % 256;
119 | y -= buf[4] & 0xFF;
120 | y /= 256;
121 | buf[5] |= y % 256;
122 | y -= buf[5] & 0xFF;
123 | y /= 256;
124 | buf[6] |= y % 256;
125 | y -= buf[6] & 0xFF;
126 | y /= 256;
127 | buf[7] |= y % 256;
128 |
129 | out.write(buf);
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/src/main/java/org/jbsdiff/Header.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013, Colorado State University
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without modification,
6 | are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | This software is provided by the copyright holders and contributors "as is" and
15 | any express or implied warranties, including, but not limited to, the implied
16 | warranties of merchantability and fitness for a particular purpose are
17 | disclaimed. In no event shall the copyright holder or contributors be liable for
18 | any direct, indirect, incidental, special, exemplary, or consequential damages
19 | (including, but not limited to, procurement of substitute goods or services;
20 | loss of use, data, or profits; or business interruption) however caused and on
21 | any theory of liability, whether in contract, strict liability, or tort
22 | (including negligence or otherwise) arising in any way out of the use of this
23 | software, even if advised of the possibility of such damage.
24 | */
25 |
26 | package org.jbsdiff;
27 |
28 | import java.io.DataInputStream;
29 | import java.io.IOException;
30 | import java.io.InputStream;
31 | import java.io.OutputStream;
32 |
33 | /**
34 | * Data structure that encapsulates a bsdiff header. The header is composed of
35 | * 8-byte fields, starting with the magic number "BSDIFF40."
36 | *
37 | * 0: BSDIFF40
38 | * 8: length of control block
39 | * 16: length of the diff block
40 | * 24: size of the output file
41 | *
42 | * @author malensek
43 | */
44 |
45 | class Header {
46 |
47 | /**
48 | * Size of the Header, in bytes. 4 fields * 8 bytes = 32 bytes
49 | */
50 | public static final int HEADER_SIZE = 32;
51 |
52 | /**
53 | * Magic number to mark the start of a bsdiff header.
54 | */
55 | public static final String HEADER_MAGIC = "BSDIFF40";
56 |
57 | private String magic;
58 | private int controlLength;
59 | private int diffLength;
60 | private int outLength;
61 |
62 | public Header() {
63 | }
64 |
65 | /**
66 | * Read a bsdiff header from an InputStream.
67 | */
68 | public Header(InputStream in) throws IOException, InvalidHeaderException {
69 | InputStream headerIn = new DataInputStream(in);
70 | byte[] buf = new byte[8];
71 |
72 | headerIn.read(buf);
73 | magic = new String(buf);
74 | if (!magic.equals("BSDIFF40")) {
75 | throw new InvalidHeaderException("Header missing magic number");
76 | }
77 |
78 | controlLength = Offset.readOffset(headerIn);
79 | diffLength = Offset.readOffset(headerIn);
80 | outLength = Offset.readOffset(headerIn);
81 |
82 | verify();
83 | }
84 |
85 | public Header(int controlLength, int diffLength, int outLength)
86 | throws InvalidHeaderException {
87 | this.controlLength = controlLength;
88 | this.diffLength = diffLength;
89 | this.outLength = outLength;
90 |
91 | verify();
92 | }
93 |
94 | /**
95 | * Writes the Header to an OutputStream.
96 | */
97 | public void write(OutputStream out) throws IOException {
98 | out.write(HEADER_MAGIC.getBytes());
99 | Offset.writeOffset(controlLength, out);
100 | Offset.writeOffset(diffLength, out);
101 | Offset.writeOffset(outLength, out);
102 | }
103 |
104 | /**
105 | * Verifies the values of the header fields.
106 | */
107 | private void verify() throws InvalidHeaderException {
108 | if (controlLength < 0) {
109 | throw new InvalidHeaderException("control block length",
110 | controlLength);
111 | }
112 |
113 | if (diffLength < 0) {
114 | throw new InvalidHeaderException("diff block length", diffLength);
115 | }
116 |
117 | if (outLength < 0) {
118 | throw new InvalidHeaderException("output file length", outLength);
119 | }
120 | }
121 |
122 | @Override
123 | public String toString() {
124 | String s = "";
125 |
126 | s += magic + "\n";
127 | s += "control bytes = " + controlLength + "\n";
128 | s += "diff bytes = " + diffLength + "\n";
129 | s += "output size = " + outLength;
130 |
131 | return s;
132 | }
133 |
134 | public int getControlLength() {
135 | return controlLength;
136 | }
137 |
138 | public void setControlLength(int length) throws InvalidHeaderException {
139 | controlLength = length;
140 | verify();
141 | }
142 |
143 | public int getDiffLength() {
144 | return diffLength;
145 | }
146 |
147 | public void setDiffLength(int length) throws InvalidHeaderException {
148 | diffLength = length;
149 | verify();
150 | }
151 |
152 | public int getOutputLength() {
153 | return outLength;
154 | }
155 |
156 | public void setOutputLength(int length) throws InvalidHeaderException {
157 | outLength = length;
158 | verify();
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/src/main/java/org/jbsdiff/Patch.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013, Colorado State University
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without modification,
6 | are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | This software is provided by the copyright holders and contributors "as is" and
15 | any express or implied warranties, including, but not limited to, the implied
16 | warranties of merchantability and fitness for a particular purpose are
17 | disclaimed. In no event shall the copyright holder or contributors be liable for
18 | any direct, indirect, incidental, special, exemplary, or consequential damages
19 | (including, but not limited to, procurement of substitute goods or services;
20 | loss of use, data, or profits; or business interruption) however caused and on
21 | any theory of liability, whether in contract, strict liability, or tort
22 | (including negligence or otherwise) arising in any way out of the use of this
23 | software, even if advised of the possibility of such damage.
24 | */
25 |
26 | package org.jbsdiff;
27 |
28 | import org.apache.commons.compress.compressors.CompressorException;
29 | import org.apache.commons.compress.compressors.CompressorStreamFactory;
30 |
31 | import java.io.ByteArrayInputStream;
32 | import java.io.IOException;
33 | import java.io.InputStream;
34 | import java.io.OutputStream;
35 |
36 | /**
37 | * This class provides functionality for using an old file and a patch to
38 | * generate a new file using the bsdiff patching algorithm.
39 | *
40 | * @author malensek
41 | */
42 | public class Patch {
43 |
44 | /**
45 | * Using an old file and its accompanying patch, this method generates a new
46 | * (updated) file and writes it to an {@link OutputStream}.
47 | */
48 | public static void patch(byte[] old, byte[] patch, OutputStream out)
49 | throws CompressorException, InvalidHeaderException, IOException {
50 | /* Read bsdiff header */
51 | InputStream headerIn = new ByteArrayInputStream(patch);
52 | Header header = new Header(headerIn);
53 | headerIn.close();
54 |
55 | /* Set up InputStreams for reading different regions of the patch */
56 | InputStream controlIn, dataIn, extraIn;
57 | controlIn = new ByteArrayInputStream(patch);
58 | dataIn = new ByteArrayInputStream(patch);
59 | extraIn = new ByteArrayInputStream(patch);
60 |
61 | try {
62 | /* Seek to the correct offsets in each stream */
63 | controlIn.skip(Header.HEADER_SIZE);
64 | dataIn.skip(Header.HEADER_SIZE + header.getControlLength());
65 | extraIn.skip(Header.HEADER_SIZE + header.getControlLength() +
66 | header.getDiffLength());
67 |
68 | /* Set up compressed streams */
69 | CompressorStreamFactory compressor = new CompressorStreamFactory();
70 | controlIn = compressor.createCompressorInputStream(controlIn);
71 | dataIn = compressor.createCompressorInputStream(dataIn);
72 | extraIn = compressor.createCompressorInputStream(extraIn);
73 |
74 | /* Start patching */
75 | int newPointer = 0, oldPointer = 0;
76 | byte[] output = new byte[header.getOutputLength()];
77 | while (newPointer < output.length) {
78 |
79 | ControlBlock control = new ControlBlock(controlIn);
80 |
81 | /* Read diff string */
82 | read(dataIn, output, newPointer, control.getDiffLength());
83 |
84 | /* Add old data to diff string */
85 | for (int i = 0; i < control.getDiffLength(); ++i) {
86 | if ((oldPointer + i >= 0) && oldPointer + i < old.length) {
87 | output[newPointer + i] += old[oldPointer + i];
88 | }
89 | }
90 |
91 | newPointer += control.getDiffLength();
92 | oldPointer += control.getDiffLength();
93 |
94 | /* Copy the extra string to the output */
95 | read(extraIn, output, newPointer, control.getExtraLength());
96 |
97 | newPointer += control.getExtraLength();
98 | oldPointer += control.getSeekLength();
99 | }
100 |
101 | out.write(output);
102 |
103 | } finally {
104 | controlIn.close();
105 | dataIn.close();
106 | extraIn.close();
107 | }
108 | }
109 |
110 | /**
111 | * Reads data from an InputStream, and throws an {@link IOException} if
112 | * fewer bytes were read than requested. Since the lengths of data in a
113 | * bsdiff patch are explicitly encoded in the control blocks, reading less
114 | * than expected is an unrecoverable error.
115 | *
116 | * @param in InputStream to read from
117 | * @param dest byte array to read data into
118 | * @param off offset in dest to write data at
119 | * @param len length of the read
120 | */
121 | private static void read(InputStream in, byte[] dest, int off, int len)
122 | throws IOException {
123 | if (len == 0) {
124 | /* We don't need to do anything */
125 | return;
126 | }
127 |
128 | int read = in.read(dest, off, len);
129 | if (read < len) {
130 | throw new IOException("Corrupt patch; bytes expected = " + len +
131 | " bytes read = " + read);
132 | }
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/src/main/java/org/jbsdiff/Diff.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013, Colorado State University
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without modification,
6 | are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | This software is provided by the copyright holders and contributors "as is" and
15 | any express or implied warranties, including, but not limited to, the implied
16 | warranties of merchantability and fitness for a particular purpose are
17 | disclaimed. In no event shall the copyright holder or contributors be liable for
18 | any direct, indirect, incidental, special, exemplary, or consequential damages
19 | (including, but not limited to, procurement of substitute goods or services;
20 | loss of use, data, or profits; or business interruption) however caused and on
21 | any theory of liability, whether in contract, strict liability, or tort
22 | (including negligence or otherwise) arising in any way out of the use of this
23 | software, even if advised of the possibility of such damage.
24 | */
25 |
26 | package org.jbsdiff;
27 |
28 | import org.apache.commons.compress.compressors.CompressorException;
29 | import org.apache.commons.compress.compressors.CompressorStreamFactory;
30 | import org.jbsdiff.sort.SearchResult;
31 | import org.jbsdiff.sort.SuffixSort;
32 |
33 | import java.io.ByteArrayOutputStream;
34 | import java.io.IOException;
35 | import java.io.OutputStream;
36 |
37 | /**
38 | * This class provides functionality for generating bsdiff patches from two
39 | * source files (an old and new file). Using the differences between the old
40 | * and new files, a bsdiff patch can be applied to an old file to generate a
41 | * copy of the new file.
42 | *
43 | * @author malensek
44 | */
45 | public class Diff {
46 |
47 | /**
48 | * Using two different versions of a file, generate a bsdiff patch that can
49 | * be applied to the old file to create the new file. Uses the default
50 | * bzip2 compression algorithm.
51 | */
52 | public static void diff(byte[] oldBytes, byte[] newBytes, OutputStream out)
53 | throws CompressorException, InvalidHeaderException, IOException {
54 | diff(oldBytes, newBytes, out, new DefaultDiffSettings());
55 | }
56 |
57 | /**
58 | * Using two different versions of a file, generate a bsdiff patch that can
59 | * be applied to the old file to create the new file.
60 | */
61 | public static void diff(byte[] oldBytes, byte[] newBytes, OutputStream out,
62 | DiffSettings settings)
63 | throws CompressorException, InvalidHeaderException, IOException {
64 | CompressorStreamFactory compressor = new CompressorStreamFactory();
65 | String compression = settings.getCompression();
66 |
67 | int[] I = settings.sort(oldBytes);
68 |
69 | ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
70 | OutputStream patchOut =
71 | compressor.createCompressorOutputStream(compression, byteOut);
72 |
73 | SearchResult result = null;
74 | int scan = 0, len = 0, position = 0;
75 | int lastScan = 0, lastPos = 0, lastOffset = 0;
76 | int oldScore = 0, scsc = 0;
77 | int s, Sf, lenf, Sb, lenb;
78 | int overlap, Ss, lens;
79 |
80 | byte[] db = new byte[newBytes.length + 1];
81 | byte[] eb = new byte[newBytes.length + 1];
82 | int dblen = 0, eblen = 0;
83 |
84 | while (scan < newBytes.length) {
85 | oldScore = 0;
86 |
87 | for (scsc = scan += len; scan < newBytes.length; scan++) {
88 | result = SuffixSort.search(I,
89 | oldBytes, 0,
90 | newBytes, scan,
91 | 0, oldBytes.length);
92 | len = result.getLength();
93 | position = result.getPosition();
94 |
95 | for (; scsc < scan + len; scsc++) {
96 | if ((scsc + lastOffset < oldBytes.length) &&
97 | (oldBytes[scsc + lastOffset] == newBytes[scsc]))
98 | oldScore++;
99 | }
100 |
101 | if (((len == oldScore) && (len != 0)) || (len > oldScore + 8)) {
102 | break;
103 | }
104 |
105 | if ((scan + lastOffset < oldBytes.length) &&
106 | (oldBytes[scan + lastOffset] == newBytes[scan]))
107 | oldScore--;
108 | }
109 |
110 | if ((len != oldScore) || (scan == newBytes.length)) {
111 | s = 0;
112 | Sf = 0;
113 | lenf = 0;
114 | for (int i = 0; (lastScan + i < scan) &&
115 | (lastPos + i < oldBytes.length); ) {
116 | if (oldBytes[lastPos + i] == newBytes[lastScan + i]) {
117 | s++;
118 | }
119 |
120 | i++;
121 | if (s * 2 - i > Sf * 2 - lenf) {
122 | Sf = s;
123 | lenf = i;
124 | }
125 | }
126 |
127 | lenb = 0;
128 | if (scan < newBytes.length) {
129 | s = 0;
130 | Sb = 0;
131 | for (int i = 1; (scan >= lastScan + i) &&
132 | (position >= i); i++) {
133 | if (oldBytes[position - i] ==
134 | newBytes[scan - i]) {
135 | s++;
136 | }
137 | if (s * 2 - i > Sb * 2 - lenb) {
138 | Sb = s;
139 | lenb = i;
140 | }
141 | }
142 | }
143 |
144 | if (lastScan + lenf > scan - lenb) {
145 | overlap = (lastScan + lenf) - (scan - lenb);
146 | s = 0;
147 | Ss = 0;
148 | lens = 0;
149 | for (int i = 0; i < overlap; i++) {
150 | if (newBytes[lastScan + lenf - overlap + i] ==
151 | oldBytes[lastPos + lenf - overlap + i]) {
152 | s++;
153 | }
154 | if (newBytes[scan - lenb + i] ==
155 | oldBytes[position - lenb + i]) {
156 | s--;
157 | }
158 | if (s > Ss) {
159 | Ss = s;
160 | lens = i + 1;
161 | }
162 | }
163 | lenf += lens - overlap;
164 | lenb -= lens;
165 | }
166 |
167 | for (int i = 0; i < lenf; i++) {
168 | db[dblen + i] |= (newBytes[lastScan + i] -
169 | oldBytes[lastPos + i]);
170 | }
171 |
172 | for (int i = 0; i < (scan - lenb) - (lastScan + lenf); i++) {
173 | eb[eblen + i] = newBytes[lastScan + lenf + i];
174 | }
175 |
176 | dblen += lenf;
177 | eblen += (scan - lenb) - (lastScan + lenf);
178 |
179 | ControlBlock control = new ControlBlock();
180 | control.setDiffLength(lenf);
181 | control.setExtraLength((scan - lenb) - (lastScan + lenf));
182 | control.setSeekLength((position - lenb) -
183 | (lastPos + lenf));
184 | control.write(patchOut);
185 |
186 | lastScan = scan - lenb;
187 | lastPos = position - lenb;
188 | lastOffset = position - scan;
189 | }
190 | }
191 | /* Done writing control blocks */
192 | patchOut.close();
193 |
194 | Header header = new Header();
195 | header.setControlLength(byteOut.size());
196 |
197 | patchOut =
198 | compressor.createCompressorOutputStream(compression, byteOut);
199 | patchOut.write(db);
200 | patchOut.close();
201 | header.setDiffLength(byteOut.size() - header.getControlLength());
202 |
203 | patchOut =
204 | compressor.createCompressorOutputStream(compression, byteOut);
205 | patchOut.write(eb);
206 | patchOut.close();
207 |
208 | header.setOutputLength(newBytes.length);
209 |
210 | header.write(out);
211 | out.write(byteOut.toByteArray());
212 | }
213 | }
214 |
--------------------------------------------------------------------------------
/src/main/java/org/jbsdiff/sort/SuffixSort.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013, Colorado State University
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without modification,
6 | are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | This software is provided by the copyright holders and contributors "as is" and
15 | any express or implied warranties, including, but not limited to, the implied
16 | warranties of merchantability and fitness for a particular purpose are
17 | disclaimed. In no event shall the copyright holder or contributors be liable for
18 | any direct, indirect, incidental, special, exemplary, or consequential damages
19 | (including, but not limited to, procurement of substitute goods or services;
20 | loss of use, data, or profits; or business interruption) however caused and on
21 | any theory of liability, whether in contract, strict liability, or tort
22 | (including negligence or otherwise) arising in any way out of the use of this
23 | software, even if advised of the possibility of such damage.
24 | */
25 |
26 | package org.jbsdiff.sort;
27 |
28 | /**
29 | * Implements the suffix sorting and binary search algorithms found in bsdiff.
30 | *
31 | * @author malensek
32 | */
33 | public class SuffixSort {
34 | public static void qsufsort(int[] I, int[] V, byte[] data) {
35 | int[] buckets = new int[256];
36 | int i, h, len;
37 |
38 | for (i=0; i < data.length; i++) {
39 | buckets[data[i] & 0xFF]++;
40 | }
41 |
42 | for(i = 1; i < 256; i++) {
43 | buckets[i] += buckets[i - 1];
44 | }
45 |
46 | for (i = 255; i > 0; i--) {
47 | buckets[i] = buckets[i - 1];
48 | }
49 |
50 | buckets[0] = 0;
51 |
52 | for (i = 0; i < data.length; i++) {
53 | I[++buckets[data[i] & 0xFF]] = i;
54 | }
55 |
56 | I[0] = data.length;
57 |
58 | for (i = 0; i < data.length; i++) {
59 | V[i] = buckets[data[i] & 0xFF];
60 | }
61 |
62 | V[data.length] = 0;
63 |
64 | for (i = 1; i < 256; i++) {
65 | if (buckets[i] == buckets[i - 1] + 1) {
66 | I[buckets[i]] = -1;
67 | }
68 | }
69 |
70 | I[0] = -1;
71 |
72 | for (h = 1; I[0] != -(data.length + 1); h += h) {
73 | len = 0;
74 | for (i = 0; i < data.length + 1; ) {
75 | if (I[i] < 0) {
76 | len -= I[i];
77 | i -= I[i];
78 | } else {
79 | if (len != 0) {
80 | I[i - len] =- len;
81 | }
82 |
83 | len = V[I[i]] + 1 - i;
84 | split(I, V, i, len, h);
85 | i += len;
86 | len = 0;
87 | }
88 | }
89 | if(len != 0) {
90 | I[i - len] =- len;
91 | }
92 | }
93 |
94 | for(i = 0; i < data.length + 1; i++) {
95 | I[V[i]] = i;
96 | }
97 | }
98 |
99 | public static void split(int[] I, int[] V, int start, int len, int h) {
100 | int i, j, k, x, tmp, jj, kk;
101 |
102 | if (len < 16) {
103 | for (k = start; k < start + len; k += j) {
104 | j = 1;
105 | x = V[I[k] + h];
106 |
107 | for (i = 1; k + i < start + len; i++) {
108 | if (V[I[k + i] + h] < x) {
109 | x=V[I[k + i] + h];
110 | j=0;
111 | }
112 | if (V[I[k + i] + h] == x) {
113 | tmp = I[k + j];
114 | I[k + j] = I[k + i];
115 | I[k + i] = tmp;
116 | j++;
117 | }
118 | }
119 | for (i = 0; i < j; i++) {
120 | V[I[k + i]] = k + j -1;
121 | }
122 | if (j == 1) {
123 | I[k]= -1;
124 | }
125 | }
126 | return;
127 | }
128 |
129 | x = V[I[start + len / 2] + h];
130 | jj = 0;
131 | kk = 0;
132 | for (i = start; i < start + len; i++) {
133 | if (V[I[i] + h] < x) {
134 | jj++;
135 | }
136 |
137 | if(V[I[i] + h] == x) {
138 | kk++;
139 | }
140 | }
141 | jj += start;
142 | kk += jj;
143 |
144 | i = start;
145 | j = 0;
146 | k = 0;
147 | while (i < jj) {
148 | if (V[I[i] + h] < x) {
149 | i++;
150 | } else if (V[I[i] + h] == x) {
151 | tmp = I[i];
152 | I[i] = I[jj + j];
153 | I[jj + j] = tmp;
154 | j++;
155 | } else {
156 | tmp = I[i];
157 | I[i] = I[kk + k];
158 | I[kk + k] = tmp;
159 | k++;
160 | }
161 | }
162 |
163 | while (jj + j < kk) {
164 | if (V[I[jj + j] + h] == x) {
165 | j++;
166 | } else {
167 | tmp=I[jj + j];
168 | I[jj + j] = I[kk + k];
169 | I[kk + k] = tmp;
170 | k++;
171 | }
172 | }
173 |
174 | if (jj > start) {
175 | split(I, V, start, jj - start, h);
176 | }
177 |
178 | for (i = 0; i < kk - jj; i++) {
179 | V[I[jj + i]] = kk - 1;
180 | }
181 |
182 | if (jj == kk - 1) {
183 | I[jj]= -1;
184 | }
185 |
186 | if (start + len > kk) {
187 | split(I, V, kk, start + len - kk, h);
188 | }
189 | }
190 |
191 | /**
192 | * Starting from the beginning of two arrays, determines the amount of bytes
193 | * that are equal up until the first inequality.
194 | *
195 | * @param bytesA the first array to compare
196 | * @param offsetA index in the first array to start comparing at
197 | * @param bytesB the second array to compare
198 | * @param offsetB index in the second array to start comparing at
199 | *
200 | * @return the number of matching array entries
201 | */
202 | private static int matchLength(byte[] bytesA, int offsetA,
203 | byte[] bytesB, int offsetB) {
204 |
205 | int oldLimit = bytesA.length - offsetA;
206 | int newLimit = bytesB.length - offsetB;
207 |
208 | int i;
209 | for (i = 0; i < oldLimit && i < newLimit; ++i) {
210 | if (bytesA[i + offsetA] != bytesB[i + offsetB]) {
211 | break;
212 | }
213 | }
214 |
215 | return i;
216 | }
217 |
218 | public static SearchResult search(int[] I,
219 | byte[] oldBytes, int oldOffset,
220 | byte[] newBytes, int newOffset,
221 | int start, int end) {
222 |
223 | /* Are we done dividing the search space? */
224 | if (end - start < 2) {
225 | int x, y;
226 | x = matchLength(oldBytes, I[start], newBytes, newOffset);
227 | y = matchLength(oldBytes, I[end], newBytes, newOffset);
228 |
229 | if(x > y) {
230 | return new SearchResult(x, I[start]);
231 | } else {
232 | return new SearchResult(y, I[end]);
233 | }
234 | }
235 |
236 | /* Otherwise, find center pivot and compare */
237 | int center = start + (end - start) / 2;
238 | if (compareBytes(oldBytes, I[center], newBytes, newOffset) < 0) {
239 | return search(I, oldBytes, 0, newBytes, newOffset, center, end);
240 | } else {
241 | return search(I, oldBytes, 0, newBytes, newOffset, start, center);
242 | }
243 | }
244 |
245 | /**
246 | * Compare two byte arrays, similar to the C memcmp() function. A value
247 | * greater than 0 indicates the first byte that does not match is greater in
248 | * the first array, whereas a value less than zero indicates the byte is
249 | * greater in the second array.
250 | *
251 | * Note that the output of this implementation probably does not exactly
252 | * match the output of memcmp() on all platforms, but satisfies the memcmp()
253 | * contract.
254 | *
255 | * @param bytesA first array
256 | * @param offsetA index in the first array to start comparing at
257 | * @param bytesB second array
258 | * @param offsetB index in the second array to start comparing at
259 | *
260 | * @return int indicating the relationship between the two arrays.
261 | */
262 | private static int compareBytes(byte[] bytesA, int offsetA,
263 | byte[] bytesB, int offsetB) {
264 |
265 | /* Only compare up until the end of the smallest array */
266 | int length = Math.min(bytesA.length - offsetA, bytesB.length - offsetB);
267 |
268 | int valA = 0, valB = 0;
269 | for (int i = 0; i < length; ++i) {
270 | valA = bytesA[i + offsetA] & 0xFF;
271 | valB = bytesB[i + offsetB] & 0xFF;
272 |
273 | if (valA != valB) {
274 | break;
275 | }
276 | }
277 |
278 | return valA - valB;
279 | }
280 | }
281 |
--------------------------------------------------------------------------------
/docs/APACHE-2.0.txt:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------