blob: 3631dcc1c1d301716648d6068c5fa65e0b48605d [file] [log] [blame]
// 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;
}
}