| // 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; |
| } |
| } |