aboutsummaryrefslogtreecommitdiff
path: root/applier/src/main/java/com/google/archivepatcher/applier/bsdiff/BsPatch.java
diff options
context:
space:
mode:
Diffstat (limited to 'applier/src/main/java/com/google/archivepatcher/applier/bsdiff/BsPatch.java')
-rw-r--r--applier/src/main/java/com/google/archivepatcher/applier/bsdiff/BsPatch.java62
1 files changed, 53 insertions, 9 deletions
diff --git a/applier/src/main/java/com/google/archivepatcher/applier/bsdiff/BsPatch.java b/applier/src/main/java/com/google/archivepatcher/applier/bsdiff/BsPatch.java
index a7b2803..cfa8ded 100644
--- a/applier/src/main/java/com/google/archivepatcher/applier/bsdiff/BsPatch.java
+++ b/applier/src/main/java/com/google/archivepatcher/applier/bsdiff/BsPatch.java
@@ -15,13 +15,14 @@
package com.google.archivepatcher.applier.bsdiff;
import com.google.archivepatcher.applier.PatchFormatException;
-
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
+import java.util.logging.Level;
+import java.util.logging.Logger;
/**
* A Java implementation of the "bspatch" algorithm based on the BSD-2 licensed source code
@@ -29,9 +30,10 @@ import java.io.RandomAccessFile;
* size of 2GB for all binaries involved (old, new and patch binaries).
*/
public class BsPatch {
- /**
- * Standard header found at the start of every patch.
- */
+ /** If true, output verbose debugging information. */
+ private static final boolean VERBOSE = false;
+
+ /** Standard header found at the start of every patch. */
private static final String SIGNATURE = "ENDSLEY/BSDIFF43";
/**
@@ -56,6 +58,9 @@ public class BsPatch {
*/
private static final int OUTPUT_STREAM_BUFFER_SIZE = 16 * 1024;
+ /** An instance of Java logger for use with the {@code VERBOSE} mode. */
+ private static final Logger logger = Logger.getLogger(BsPatch.class.getName());
+
/**
* Applies a patch from |patchData| to the data in |oldData|, writing the result to |newData|.
*
@@ -68,22 +73,39 @@ public class BsPatch {
public static void applyPatch(
RandomAccessFile oldData, OutputStream newData, InputStream patchData)
throws PatchFormatException, IOException {
+ applyPatch(oldData, newData, patchData, null);
+ }
+
+ /**
+ * Applies a patch from |patchData| to the data in |oldData|, writing the result to |newData|
+ * while verifying that the expectedSize is obtained.
+ *
+ * @param oldData data to which the patch should be applied
+ * @param newData stream to write the new artifact to
+ * @param patchData stream to read patch instructions from
+ * @param expectedNewSize the expected number of bytes in |newData| when patching completes. Can
+ * be null in which case no expectedNewSize checks will be performed.
+ * @throws PatchFormatException if the patch stream is invalid
+ * @throws IOException if unable to read or write any of the data
+ */
+ public static void applyPatch(
+ RandomAccessFile oldData, OutputStream newData, InputStream patchData, Long expectedNewSize)
+ throws PatchFormatException, IOException {
patchData = new BufferedInputStream(patchData, PATCH_STREAM_BUFFER_SIZE);
newData = new BufferedOutputStream(newData, OUTPUT_STREAM_BUFFER_SIZE);
try {
- applyPatchInternal(oldData, newData, patchData);
+ applyPatchInternal(oldData, newData, patchData, expectedNewSize);
} finally {
newData.flush();
}
}
- /**
- * Does the work of the public applyPatch method.
- */
+ /** Does the work of the public applyPatch method. */
private static void applyPatchInternal(
final RandomAccessFile oldData,
final OutputStream newData,
- final InputStream patchData)
+ final InputStream patchData,
+ final Long expectedNewSize)
throws PatchFormatException, IOException {
final byte[] signatureBuffer = new byte[SIGNATURE.length()];
try {
@@ -106,6 +128,9 @@ public class BsPatch {
if (newSize < 0 || newSize > Integer.MAX_VALUE) {
throw new PatchFormatException("bad newSize");
}
+ if (expectedNewSize != null && expectedNewSize != newSize) {
+ throw new PatchFormatException("expectedNewSize != newSize");
+ }
// These buffers are used for performing transformations and copies. They are not stateful.
final byte[] buffer1 = new byte[PATCH_BUFFER_SIZE];
@@ -114,6 +139,7 @@ public class BsPatch {
// Offsets into |oldData| and |newData|.
long oldDataOffset = 0; // strobes |oldData| in order specified by the patch file
long newDataBytesWritten = 0; // monotonically increases from 0 .. |expectedNewSize|
+ int numDirectives = 0; // only used for debugging output
while (newDataBytesWritten < newSize) {
// Read "control data" for the operation. There are three values here:
@@ -133,6 +159,24 @@ public class BsPatch {
// be accumulated into |oldDataOffset| while |copySegmentLength| must NOT be.
final long offsetToNextInput = readBsdiffLong(patchData);
+ if (VERBOSE) {
+ numDirectives++;
+ logger.log(
+ Level.FINE,
+ "Patch directive "
+ + numDirectives
+ + ": oldDataOffset="
+ + oldDataOffset
+ + ", newDataBytesWritten="
+ + newDataBytesWritten
+ + ", diffSegmentLength="
+ + diffSegmentLength
+ + ", copySegmentLength="
+ + copySegmentLength
+ + ", offsetToNextInput="
+ + offsetToNextInput);
+ }
+
// Sanity-checks
if (diffSegmentLength < 0 || diffSegmentLength > Integer.MAX_VALUE) {
throw new PatchFormatException("bad diffSegmentLength");