├── 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 | [![Clojars Project](http://clojars.org/org.jbsdiff/jbsdiff/latest-version.svg)](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 | * 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 | --------------------------------------------------------------------------------