/*-
* Copyright (C) 2006-2007 Erik Larsson
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.catacombae.dmgextractor;
import java.io.*;
public class Util {
public static int sectorSize = 0x800;
/**
* Tests whether the current VM is a Java 6 or higher VM.
* @return
*/
public static boolean isJava6OrHigher() {
return System.getProperty("java.vm.version").compareTo("1.6") >= 0;
}
public static String byteArrayToHexString(byte[] array) {
return byteArrayToHexString(array, 0, array.length);
}
public static String byteArrayToHexString(byte[] array, int offset, int length) {
String result = "";
for(int i = offset; i < (offset+length); ++i) {
byte b = array[i];
String currentHexString = Integer.toHexString(b & 0xFF);
if(currentHexString.length() == 1)
currentHexString = "0" + currentHexString;
result += currentHexString;
}
return result;
}
public static String toHexStringBE(char[] array) {
return toHexStringBE(array, 0, array.length);
}
public static String toHexStringBE(char[] array, int offset, int length) {
StringBuilder result = new StringBuilder();
for(int i = offset; i < length; ++i)
result.append(toHexStringBE(array[i]));
return result.toString();
}
public static String toHexStringBE(short[] array) {
return toHexStringBE(array, 0, array.length);
}
public static String toHexStringBE(short[] array, int offset, int length) {
StringBuilder result = new StringBuilder();
for(int i = offset; i < length; ++i)
result.append(toHexStringBE(array[i]));
return result.toString();
}
public static String toHexStringBE(int[] array) {
return toHexStringBE(array, 0, array.length);
}
public static String toHexStringBE(int[] array, int offset, int length) {
StringBuilder result = new StringBuilder();
for(int i = offset; i < length; ++i)
result.append(toHexStringBE(array[i]));
return result.toString();
}
public static String toHexStringLE(byte n) { return byteArrayToHexString(toByteArrayLE(n)); }
public static String toHexStringLE(short n) { return byteArrayToHexString(toByteArrayLE(n)); }
public static String toHexStringLE(char n) { return byteArrayToHexString(toByteArrayLE(n)); }
public static String toHexStringLE(int n) { return byteArrayToHexString(toByteArrayLE(n)); }
public static String toHexStringLE(long n) { return byteArrayToHexString(toByteArrayLE(n)); }
public static String toHexStringBE(byte n) { return byteArrayToHexString(toByteArrayBE(n)); }
public static String toHexStringBE(short n) { return byteArrayToHexString(toByteArrayBE(n)); }
public static String toHexStringBE(char n) { return byteArrayToHexString(toByteArrayBE(n)); }
public static String toHexStringBE(int n) { return byteArrayToHexString(toByteArrayBE(n)); }
public static String toHexStringBE(long n) { return byteArrayToHexString(toByteArrayBE(n)); }
public static byte[] invert(byte[] array) {
byte[] newArray = new byte[array.length];
for(int i = 0; i < array.length; ++i)
newArray[newArray.length-i-1] = array[i];
return newArray;
}
public static long readLongLE(byte[] data) {
return readLongLE(data, 0);
}
public static long readLongLE(byte[] data, int offset) {
return (((long)data[offset+7] & 0xFF) << 56 |
((long)data[offset+6] & 0xFF) << 48 |
((long)data[offset+5] & 0xFF) << 40 |
((long)data[offset+4] & 0xFF) << 32 |
((long)data[offset+3] & 0xFF) << 24 |
((long)data[offset+2] & 0xFF) << 16 |
((long)data[offset+1] & 0xFF) << 8 |
((long)data[offset+0] & 0xFF) << 0);
}
public static int readIntLE(byte[] data) {
return readIntLE(data, 0);
}
public static int readIntLE(byte[] data, int offset) {
return ((data[offset+3] & 0xFF) << 24 |
(data[offset+2] & 0xFF) << 16 |
(data[offset+1] & 0xFF) << 8 |
(data[offset+0] & 0xFF) << 0);
}
public static short readShortLE(byte[] data) {
return readShortLE(data, 0);
}
public static short readShortLE(byte[] data, int offset) {
return (short) ((data[offset+1] & 0xFF) << 8 |
(data[offset+0] & 0xFF) << 0);
}
public static byte readByteLE(byte[] data) {
return readByteLE(data, 0);
}
public static byte readByteLE(byte[] data, int offset) {
return data[offset];
}
public static long readLongBE(byte[] data) {
return readLongBE(data, 0);
}
// public static void main(String[] args) {
// byte[] longTest1 = { 0, 0, 0, 0, 0, 0, 0, 13 };
// byte[] longTest2 = { 0, 31, 0, 0, 0, 0, 0, 0 };
// byte[] longTest3 = { 127, 0, 0, 0, 0, 0, 0, 0 };
// byte[] longTest4 = { 0, 0, 0, 1, 1, 1, 1, 1 };
// System.out.println("longTest1: " + readLongBE(longTest1));
// System.out.println("longTest2: " + readLongBE(longTest2));
// System.out.println("longTest3: " + readLongBE(longTest3));
// System.out.println("longTest4: " + readLongBE(longTest4));
// }
public static long readLongBE(byte[] data, int offset) {
// if(false) {
// long d1 = (data[offset+0] & 0xFFL) << 56;
// long d2 = (data[offset+1] & 0xFFL) << 48;
// long d3 = (data[offset+2] & 0xFFL) << 40;
// long d4 = (data[offset+3] & 0xFFL) << 32;
// long d5 = (data[offset+4] & 0xFFL) << 24;
// long d6 = (data[offset+5] & 0xFFL) << 16;
// long d7 = (data[offset+6] & 0xFFL) << 8;
// long d8 = (data[offset+7] & 0xFFL) << 0;
// System.out.println("1. 0x" + toHexStringBE(d1));
// System.out.println("2. 0x" + toHexStringBE(d2));
// System.out.println("3. 0x" + toHexStringBE(d3));
// System.out.println("4. 0x" + toHexStringBE(d4));
// System.out.println("5. 0x" + toHexStringBE(d5));
// System.out.println("6. 0x" + toHexStringBE(d6));
// System.out.println("7. 0x" + toHexStringBE(d7));
// System.out.println("8. 0x" + toHexStringBE(d8));
// return d1 | d2 | d3 | d4 | d5 | d6 | d7 | d8;
// }
// else {
return (((long)data[offset+0] & 0xFF) << 56 |
((long)data[offset+1] & 0xFF) << 48 |
((long)data[offset+2] & 0xFF) << 40 |
((long)data[offset+3] & 0xFF) << 32 |
((long)data[offset+4] & 0xFF) << 24 |
((long)data[offset+5] & 0xFF) << 16 |
((long)data[offset+6] & 0xFF) << 8 |
((long)data[offset+7] & 0xFF) << 0);
// }
}
public static int readIntBE(byte[] data) {
return readIntBE(data, 0);
}
public static int readIntBE(byte[] data, int offset) {
return ((data[offset+0] & 0xFF) << 24 |
(data[offset+1] & 0xFF) << 16 |
(data[offset+2] & 0xFF) << 8 |
(data[offset+3] & 0xFF) << 0);
}
public static short readShortBE(byte[] data) {
return readShortBE(data, 0);
}
public static short readShortBE(byte[] data, int offset) {
return (short) ((data[offset+0] & 0xFF) << 8 |
(data[offset+1] & 0xFF) << 0);
}
public static byte readByteBE(byte[] data) {
return readByteBE(data, 0);
}
public static byte readByteBE(byte[] data, int offset) {
return data[offset];
}
public static byte[] toByteArrayLE(byte b) {
byte[] result = new byte[1];
result[0] = b;
return result;
}
public static byte[] toByteArrayLE(short s) {
byte[] result = new byte[2];
result[0] = (byte) ((s >> 0) & 0xFF);
result[1] = (byte) ((s >> 8) & 0xFF);
return result;
}
public static byte[] toByteArrayLE(char c) {
byte[] result = new byte[2];
result[0] = (byte) ((c >> 0) & 0xFF);
result[1] = (byte) ((c >> 8) & 0xFF);
return result;
}
public static byte[] toByteArrayLE(int i) {
byte[] result = new byte[4];
result[0] = (byte) ((i >> 0) & 0xFF);
result[1] = (byte) ((i >> 8) & 0xFF);
result[2] = (byte) ((i >> 16) & 0xFF);
result[3] = (byte) ((i >> 24) & 0xFF);
return result;
}
public static byte[] toByteArrayLE(long l) {
byte[] result = new byte[8];
result[0] = (byte) ((l >> 0) & 0xFF);
result[1] = (byte) ((l >> 8) & 0xFF);
result[2] = (byte) ((l >> 16) & 0xFF);
result[3] = (byte) ((l >> 24) & 0xFF);
result[4] = (byte) ((l >> 32) & 0xFF);
result[5] = (byte) ((l >> 40) & 0xFF);
result[6] = (byte) ((l >> 48) & 0xFF);
result[7] = (byte) ((l >> 56) & 0xFF);
return result;
}
public static byte[] toByteArrayBE(byte b) {
byte[] result = new byte[1];
result[0] = b;
return result;
}
public static byte[] toByteArrayBE(short s) {
byte[] result = new byte[2];
result[0] = (byte) ((s >> 8) & 0xFF);
result[1] = (byte) ((s >> 0) & 0xFF);
return result;
}
public static byte[] toByteArrayBE(char c) {
byte[] result = new byte[2];
result[0] = (byte) ((c >> 8) & 0xFF);
result[1] = (byte) ((c >> 0) & 0xFF);
return result;
}
public static byte[] toByteArrayBE(int i) {
byte[] result = new byte[4];
result[0] = (byte) ((i >> 24) & 0xFF);
result[1] = (byte) ((i >> 16) & 0xFF);
result[2] = (byte) ((i >> 8) & 0xFF);
result[3] = (byte) ((i >> 0) & 0xFF);
return result;
}
public static byte[] toByteArrayBE(long l) {
byte[] result = new byte[8];
result[0] = (byte) ((l >> 56) & 0xFF);
result[1] = (byte) ((l >> 48) & 0xFF);
result[2] = (byte) ((l >> 40) & 0xFF);
result[3] = (byte) ((l >> 32) & 0xFF);
result[4] = (byte) ((l >> 24) & 0xFF);
result[5] = (byte) ((l >> 16) & 0xFF);
result[6] = (byte) ((l >> 8) & 0xFF);
result[7] = (byte) ((l >> 0) & 0xFF);
return result;
}
public static boolean zeroed(byte[] ba) {
for(byte b : ba)
if(b != 0)
return false;
return true;
}
public static void zero(byte[]... arrays) {
for(byte[] ba : arrays)
set(ba, 0, ba.length, (byte)0);
}
public static void zero(byte[] ba, int offset, int length) {
set(ba, offset, length, (byte)0);
}
public static void zero(short[]... arrays) {
for(short[] array : arrays)
set(array, 0, array.length, (short)0);
}
public static void zero(short[] ba, int offset, int length) {
set(ba, offset, length, (short)0);
}
public static void zero(int[]... arrays) {
for(int[] array : arrays)
set(array, 0, array.length, (int) 0);
}
public static void zero(int[] ba, int offset, int length) {
set(ba, offset, length, (int) 0);
}
public static void zero(long[]... arrays) {
for(long[] array : arrays)
set(array, 0, array.length, (long) 0);
}
public static void zero(long[] ba, int offset, int length) {
set(ba, offset, length, (long) 0);
}
public static void set(boolean[] array, boolean value) {
set(array, 0, array.length, value);
}
public static void set(byte[] array, byte value) {
set(array, 0, array.length, value);
}
public static void set(short[] array, short value) {
set(array, 0, array.length, value);
}
public static void set(char[] array, char value) {
set(array, 0, array.length, value);
}
public static void set(int[] array, int value) {
set(array, 0, array.length, value);
}
public static void set(long[] array, long value) {
set(array, 0, array.length, value);
}
public static <T> void set(T[] array, T value) {
set(array, 0, array.length, value);
}
public static void set(boolean[] ba, int offset, int length, boolean value) {
for(int i = offset; i < length; ++i)
ba[i] = value;
}
public static void set(byte[] ba, int offset, int length, byte value) {
for(int i = offset; i < length; ++i)
ba[i] = value;
}
public static void set(short[] ba, int offset, int length, short value) {
for(int i = offset; i < length; ++i)
ba[i] = value;
}
public static void set(char[] ba, int offset, int length, char value) {
for(int i = offset; i < length; ++i)
ba[i] = value;
}
public static void set(int[] ba, int offset, int length, int value) {
for(int i = offset; i < length; ++i)
ba[i] = value;
}
public static void set(long[] ba, int offset, int length, long value) {
for(int i = offset; i < length; ++i)
ba[i] = value;
}
public static <T> void set(T[] ba, int offset, int length, T value) {
for(int i = offset; i < length; ++i)
ba[i] = value;
}
public static byte[] createCopy(byte[] data) {
return createCopy(data, 0, data.length);
}
public static byte[] createCopy(byte[] data, int offset, int length) {
byte[] copy = new byte[length];
System.arraycopy(data, offset, copy, 0, length);
return copy;
}
/**
* Creates a copy of the input data reversed byte by byte. This is helpful for endian swapping.
*
* @param data
* @return
*/
public static byte[] createReverseCopy(byte[] data) {
return createReverseCopy(data, 0, data.length);
}
/**
* Creates a copy of the input data reversed byte by byte. This is helpful for endian swapping.
*
* @param data
* @param offset
* @param length
* @return
*/
public static byte[] createReverseCopy(byte[] data, int offset, int length) {
byte[] copy = new byte[length];
for(int i = 0; i < copy.length; ++i) {
copy[i] = data[offset+(length-i-1)];
}
return copy;
}
public static byte[] arrayCopy(byte[] source, byte[] dest) {
return arrayCopy(source, dest, 0);
}
public static byte[] arrayCopy(byte[] source, byte[] dest, int destPos) {
if(dest.length-destPos < source.length)
throw new RuntimeException("Destination array not large enough.");
System.arraycopy(source, 0, dest, 0, source.length);
return dest;
}
public static <T> T[] arrayCopy(T[] source, T[] dest) {
return arrayCopy(source, dest, 0);
}
public static <T> T[] arrayCopy(T[] source, T[] dest, int destPos) {
if(dest.length-destPos < source.length)
throw new RuntimeException("Destination array not large enough.");
System.arraycopy(source, 0, dest, 0, source.length);
return dest;
}
public static boolean arraysEqual(boolean[] a, boolean[] b) {
return arrayRegionsEqual(a, 0, a.length, b, 0, b.length);
}
public static boolean arrayRegionsEqual(boolean[] a, int aoff, int alen,
boolean[] b, int boff, int blen) {
if(alen != blen)
return false;
else {
for(int i = 0; i < alen; ++i)
if(a[aoff+i] != b[boff+i])
return false;
return true;
}
}
public static boolean arraysEqual(byte[] a, byte[] b) {
return arrayRegionsEqual(a, 0, a.length, b, 0, b.length);
}
public static boolean arrayRegionsEqual(byte[] a, int aoff, int alen,
byte[] b, int boff, int blen) {
if(a.length != blen)
return false;
else {
for(int i = 0; i < alen; ++i)
if(a[aoff+i] != b[boff+i])
return false;
return true;
}
}
public static boolean arraysEqual(char[] a, char[] b) {
return arrayRegionsEqual(a, 0, a.length, b, 0, b.length);
}
public static boolean arrayRegionsEqual(char[] a, int aoff, int alen,
char[] b, int boff, int blen) {
if(alen != blen)
return false;
else {
for(int i = 0; i < alen; ++i)
if(a[aoff+i] != b[boff+i])
return false;
return true;
}
}
public static boolean arraysEqual(short[] a, short[] b) {
return arrayRegionsEqual(a, 0, a.length, b, 0, b.length);
}
public static boolean arrayRegionsEqual(short[] a, int aoff, int alen,
short[] b, int boff, int blen) {
if(alen != blen)
return false;
else {
for(int i = 0; i < alen; ++i)
if(a[aoff+i] != b[boff+i])
return false;
return true;
}
}
public static boolean arraysEqual(int[] a, int[] b) {
return arrayRegionsEqual(a, 0, a.length, b, 0, b.length);
}
public static boolean arrayRegionsEqual(int[] a, int aoff, int alen,
int[] b, int boff, int blen) {
if(alen != blen)
return false;
else {
for(int i = 0; i < alen; ++i)
if(a[aoff+i] != b[boff+i])
return false;
return true;
}
}
public static boolean arraysEqual(long[] a, long[] b) {
return arrayRegionsEqual(a, 0, a.length, b, 0, b.length);
}
public static boolean arrayRegionsEqual(long[] a, int aoff, int alen,
long[] b, int boff, int blen) {
if(alen != blen)
return false;
else {
for(int i = 0; i < alen; ++i)
if(a[aoff+i] != b[boff+i])
return false;
return true;
}
}
public static boolean arraysEqual(Object[] a, Object[] b) {
return arrayRegionsEqual(a, 0, a.length, b, 0, b.length);
}
public static boolean arrayRegionsEqual(Object[] a, int aoff, int alen,
Object[] b, int boff, int blen) {
if(alen != blen)
return false;
else {
for(int i = 0; i < alen; ++i)
if(!a[aoff+i].equals(b[boff+i]))
return false;
return true;
}
}
public static long pow(long a, long b) {
if(b < 0) throw new IllegalArgumentException("b can not be negative");
long result = 1;
for(long i = 0; i < b; ++i)
result *= a;
return result;
}
public static int strlen(byte[] data) {
int length = 0;
for(byte b : data) {
if(b == 0)
break;
else
++length;
}
return length;
}
public static boolean getBit(long data, int bitNumber) {
return ((data >>> bitNumber) & 0x1) == 0x1;
}
public static int arrayCompareLex(byte[] a, byte[] b) {
return arrayCompareLex(a, 0, a.length, b, 0, b.length);
}
public static int arrayCompareLex(byte[] a, int aoff, int alen, byte[] b, int boff, int blen) {
int compareLen = alen < blen ? alen : blen; // equiv. Math.min
for(int i = 0; i < compareLen; ++i) {
byte curA = a[aoff+i];
byte curB = b[boff+i];
if(curA != curB)
return curA - curB;
}
return alen-blen; // The shortest array gets higher priority
}
public static int unsignedArrayCompareLex(char[] a, char[] b) {
return unsignedArrayCompareLex(a, 0, a.length, b, 0, b.length);
}
public static int unsignedArrayCompareLex(char[] a, int aoff, int alen, char[] b, int boff, int blen) {
int compareLen = alen < blen ? alen : blen; // equiv. Math.min
for(int i = 0; i < compareLen; ++i) {
int curA = a[aoff+i] & 0xFFFF; // Unsigned char values represented as int
int curB = b[boff+i] & 0xFFFF;
if(curA != curB)
return curA - curB;
}
return alen-blen; // The shortest array gets higher priority
}
// All below is from Util2 (got tired of having two Util classes...)
public static String toASCIIString(byte[] data) {
return toASCIIString(data, 0, data.length);
}
public static String toASCIIString(byte[] data, int offset, int length) {
return readString(data, offset, length, "US-ASCII");
}
public static String toASCIIString(short i) {
return toASCIIString(Util.toByteArrayBE(i));
}
public static String toASCIIString(int i) {
return toASCIIString(Util.toByteArrayBE(i));
}
public static String readString(byte[] data, String encoding) {
return readString(data, 0, data.length, encoding);
}
public static String readString(byte[] data, int offset, int length, String encoding) {
try {
return new String(data, offset, length, encoding);
} catch(Exception e) {
return null;
}
}
public static String readString(short i, String encoding) {
return readString(Util.toByteArrayBE(i), encoding);
}
public static String readString(int i, String encoding) {
return readString(Util.toByteArrayBE(i), encoding);
}
public static String readNullTerminatedASCIIString(byte[] data) {
return readNullTerminatedASCIIString(data, 0, data.length);
}
public static String readNullTerminatedASCIIString(byte[] data, int offset, int maxLength) {
int i;
for(i = offset; i < (offset+maxLength); ++i)
if(data[i] == 0) break;
return toASCIIString(data, offset, i-offset);
}
public static char readCharLE(byte[] data) {
return readCharLE(data, 0);
}
public static char readCharLE(byte[] data, int offset) {
return (char) ((data[offset+1] & 0xFF) << 8 |
(data[offset+0] & 0xFF) << 0);
}
public static char readCharBE(byte[] data) {
return readCharBE(data, 0);
}
public static char readCharBE(byte[] data, int offset) {
return (char) ((data[offset+0] & 0xFF) << 8 |
(data[offset+1] & 0xFF) << 0);
}
public static byte[] readByteArrayBE(byte[] b) {
return createCopy(b);
}
public static char[] readCharArrayBE(byte[] b) {
char[] result = new char[b.length/2];
for(int i = 0; i < result.length; ++i)
result[i] = Util.readCharBE(b, i*2);
return result;
}
public static short[] readShortArrayBE(byte[] b) {
short[] result = new short[b.length/2];
for(int i = 0; i < result.length; ++i)
result[i] = Util.readShortBE(b, i*2);
return result;
}
public static int[] readIntArrayBE(byte[] b) {
int[] result = new int[b.length/4];
for(int i = 0; i < result.length; ++i)
result[i] = Util.readIntBE(b, i*4);
return result;
}
public static long[] readLongArrayBE(byte[] b) {
long[] result = new long[b.length/8];
for(int i = 0; i < result.length; ++i)
result[i] = Util.readLongBE(b, i*8);
return result;
}
public static byte[] readByteArrayLE(char[] data) {
return readByteArrayLE(data, 0, data.length);
}
public static byte[] readByteArrayLE(char[] data, int offset, int size) {
byte[] result = new byte[data.length*2];
for(int i = 0; i < data.length; ++i) {
byte[] cur = toByteArrayLE(data[i]);
result[i*2] = cur[0];
result[i*2+1] = cur[1];
}
return result;
}
public static byte[] readByteArrayBE(char[] data) {
return readByteArrayBE(data, 0, data.length);
}
public static byte[] readByteArrayBE(char[] data, int offset, int size) {
byte[] result = new byte[data.length*2];
for(int i = 0; i < data.length; ++i) {
byte[] cur = toByteArrayBE(data[i]);
result[i*2] = cur[0];
result[i*2+1] = cur[1];
}
return result;
}
public static byte[] fillBuffer(InputStream is, byte[] buffer) throws IOException {
DataInputStream dis = new DataInputStream(is);
dis.readFully(buffer);
return buffer;
}
public static short unsign(byte b) {
return (short)(b & 0xFF);
}
public static int unsign(short s) {
return s & 0xFFFF;
}
public static long unsign(int i) {
return i & 0xFFFFFFFFL;
}
// Added 2007-06-24 for DMGExtractor
public static String readFully(Reader r) throws IOException {
StringBuilder sb = new StringBuilder();
char[] temp = new char[512];
long bytesRead = 0;
int curBytesRead = r.read(temp, 0, temp.length);
while(curBytesRead >= 0) {
sb.append(temp, 0, curBytesRead);
curBytesRead = r.read(temp, 0, temp.length);
}
return sb.toString();
}
// Added 2007-06-26 for DMGExtractor
public static String[] concatenate(String[] a, String... b) {
String[] c = new String[a.length+b.length];
System.arraycopy(a, 0, c, 0, a.length);
System.arraycopy(b, 0, c, a.length, b.length);
return c;
}
// From IRCForME
public static byte[] encodeString(String string, String encoding) {
try {
return string.getBytes(encoding);
} catch(Exception e) { return null; }
}
}