aboutsummaryrefslogtreecommitdiff
path: root/generator/src/main/java/com/google/archivepatcher/generator/bsdiff/BsUtil.java
diff options
context:
space:
mode:
Diffstat (limited to 'generator/src/main/java/com/google/archivepatcher/generator/bsdiff/BsUtil.java')
-rw-r--r--generator/src/main/java/com/google/archivepatcher/generator/bsdiff/BsUtil.java106
1 files changed, 106 insertions, 0 deletions
diff --git a/generator/src/main/java/com/google/archivepatcher/generator/bsdiff/BsUtil.java b/generator/src/main/java/com/google/archivepatcher/generator/bsdiff/BsUtil.java
new file mode 100644
index 0000000..3631dcc
--- /dev/null
+++ b/generator/src/main/java/com/google/archivepatcher/generator/bsdiff/BsUtil.java
@@ -0,0 +1,106 @@
+// Copyright 2016 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.archivepatcher.generator.bsdiff;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Utility functions to be shared between BsDiff and BsPatch.
+ */
+class BsUtil {
+ /**
+ * Mask to determine whether a long written by {@link #writeFormattedLong(long, OutputStream)}
+ * is negative.
+ */
+ private static final long NEGATIVE_MASK = 1L << 63;
+
+ /**
+ * Writes a 64-bit signed integer to the specified {@link OutputStream}. The least significant
+ * byte is written first and the most significant byte is written last.
+ * @param value the value to write
+ * @param outputStream the stream to write to
+ */
+ static void writeFormattedLong(final long value, OutputStream outputStream)
+ throws IOException {
+ long y = value;
+ if (y < 0) {
+ y = (-y) | NEGATIVE_MASK;
+ }
+
+ for (int i = 0; i < 8; ++i) {
+ outputStream.write((byte) (y & 0xff));
+ y >>>= 8;
+ }
+ }
+
+ /**
+ * Reads a 64-bit signed integer written by {@link #writeFormattedLong(long, OutputStream)} from
+ * the specified {@link InputStream}.
+ * @param inputStream the stream to read from
+ */
+ static long readFormattedLong(InputStream inputStream) throws IOException {
+ long result = 0;
+ for (int bitshift = 0; bitshift < 64; bitshift += 8) {
+ result |= ((long) inputStream.read()) << bitshift;
+ }
+
+ if ((result - NEGATIVE_MASK) > 0) {
+ result = (result & ~NEGATIVE_MASK) * -1;
+ }
+ return result;
+ }
+
+ /**
+ * Provides functional equivalent to C/C++ lexicographical_compare. Warning: this calls {@link
+ * RandomAccessObject#seek(long)}, so the internal state of the data objects will be modified.
+ *
+ * @param data1 first byte array
+ * @param start1 index in the first array at which to start comparing
+ * @param length1 length of first byte array
+ * @param data2 second byte array
+ * @param start2 index in the second array at which to start comparing
+ * @param length2 length of second byte array
+ * @return result of lexicographical compare: negative if the first difference has a lower value
+ * in the first array, positive if the first difference has a lower value in the second array.
+ * If both arrays compare equal until one of them ends, the shorter sequence is
+ * lexicographically less than the longer one (i.e., it returns len(first array) -
+ * len(second array)).
+ */
+ static int lexicographicalCompare(
+ final RandomAccessObject data1,
+ final int start1,
+ final int length1,
+ final RandomAccessObject data2,
+ final int start2,
+ final int length2)
+ throws IOException {
+ int bytesLeft = Math.min(length1, length2);
+
+ data1.seek(start1);
+ data2.seek(start2);
+ while (bytesLeft-- > 0) {
+ final int i1 = data1.readUnsignedByte();
+ final int i2 = data2.readUnsignedByte();
+
+ if (i1 != i2) {
+ return i1 - i2;
+ }
+ }
+
+ return length1 - length2;
+ }
+}