Skip to content
Permalink
6800-specs-add
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
957 lines (887 sloc) 32.6 KB
/* ###
* IP: Public Domain
*/
package mobiledevices.dmg.ghidra;
import java.io.IOException;
/**
* A class for reading data from a
* generic byte provider in either big-endian or little-endian.
*
*
*/
public class GBinaryReader {
/**
* The size of a BYTE in Java.
*/
public final static int SIZEOF_BYTE = 1;
/**
* The size of a SHORT in Java.
*/
public final static int SIZEOF_SHORT = 2;
/**
* The size of an INTEGER in Java.
*/
public final static int SIZEOF_INT = 4;
/**
* The size of a LONG in Java.
*/
public final static int SIZEOF_LONG = 8;
private GByteProvider provider;
private GDataConverter converter;
private long currentIndex;
/**
* Constructs a reader using the given
* file and endian-order.
*
* If isLittleEndian is true, then all values read
* from the file will be done so assuming
* little-endian order.
*
* Otherwise, if isLittleEndian
* is false, then all values will be read
* assuming big-endian order.
*
* @param provider the byte provider
* @param isLittleEndian the endian-order
*/
public GBinaryReader(GByteProvider provider, boolean isLittleEndian) {
this.provider = provider;
setLittleEndian(isLittleEndian);
}
/**
* Returns a clone of this reader positioned at the new index.
* @param newIndex the new index
* @return a clone of this reader positioned at the new index
*/
public GBinaryReader clone(int newIndex) {
GBinaryReader clone = new GBinaryReader(provider, isLittleEndian());
clone.converter = converter;
clone.currentIndex = newIndex;
return clone;
}
/**
* Returns true if this reader will extract values in little endian,
* otherwise in big endian.
* @return true is little endian, false is big endian
*/
public boolean isLittleEndian() {
return converter instanceof GDataConverterLE;
}
/**
* Sets the endian of this binary reader.
* @param isLittleEndian true for little-endian and false for big-endian
*/
public void setLittleEndian(boolean isLittleEndian) {
if (isLittleEndian) {
converter = new GDataConverterLE();
}
else {
converter = new GDataConverterBE();
}
}
/**
* Returns the length of the underlying file.
* @return returns the length of the underlying file
* @exception IOException if an I/O error occurs
*/
public long length() throws IOException {
return provider.length();
}
/**
* Returns true if the specified index into
* the underlying byte provider is valid.
* @param index the index in the byte provider
* @return returns true if the specified index is valid
* @exception IOException if an I/O error occurs
*/
public boolean isValidIndex(int index) throws IOException {
return provider.isValidIndex(index & GConv.INT_MASK);
}
/**
* Returns true if the specified index into
* the underlying byte provider is valid.
* @param index the index in the byte provider
* @return returns true if the specified index is valid
* @exception IOException if an I/O error occurs
*/
public boolean isValidIndex(long index) throws IOException {
return provider.isValidIndex(index);
}
/**
* Aligns the current index on the specified alignment value.
* For example, if current index was 123 and align value was
* 16, then current index would become 128.
* @param alignValue
* @return the number of bytes required to align
*/
public int align(int alignValue) {
long align = currentIndex % alignValue;
if (align == 0) {
return 0;
}
currentIndex = currentIndex + (alignValue - align);
return (int)(alignValue - align);
}
////////////////////////////////////////////////////////////////////
/**
* A convenience method for setting the index using
* an integer.
*/
public void setPointerIndex(int index) {
this.currentIndex = index & GConv.INT_MASK;
}
/**
* Sets the current index to the specified value.
* The pointer index will allow the reader
* to operate as a psuedo-iterator.
*
* @param index the byte provider index value
*/
public void setPointerIndex(long index) {
this.currentIndex = index;
}
/**
* Returns the current index value.
* @return the current index value
*/
public long getPointerIndex() {
return currentIndex;
}
/**
* Peeks at the next byte without incrementing
* the current index.
* @return the next byte
* @exception IOException if an I/O error occurs
*/
public byte peekNextByte() throws IOException {
return readByte(currentIndex);
}
/**
* Peeks at the next short without incrementing
* the current index.
* @return the next short
* @exception IOException if an I/O error occurs
*/
public short peekNextShort() throws IOException {
return readShort(currentIndex);
}
/**
* Peeks at the next integer without incrementing
* the current index.
* @return the next int
* @exception IOException if an I/O error occurs
*/
public int peekNextInt() throws IOException {
return readInt(currentIndex);
}
/**
* Peeks at the next long without incrementing
* the current index.
* @return the next long
* @exception IOException if an I/O error occurs
*/
public long peekNextLong() throws IOException {
return readLong(currentIndex);
}
/**
* Reads the byte at the current index and then increments the current
* index by <code>SIZEOF_BYTE</code>.
* @return the byte at the current index
* @exception IOException if an I/O error occurs
*/
public byte readNextByte() throws IOException {
byte b = readByte(currentIndex);
currentIndex += SIZEOF_BYTE;
return b;
}
/**
* Reads the byte at the current index and then increments the current
* index by <code>SIZEOF_BYTE</code>.
* @return the byte at the current index
* @exception IOException if an I/O error occurs
*/
public byte readNextByte(byte minClamp, byte maxClamp, Byte... exceptions) throws IOException {
byte b = readByte(currentIndex, minClamp, maxClamp, exceptions);
currentIndex += SIZEOF_BYTE;
return b;
}
/**
* Reads the short at the current index and then increments the current
* index by <code>SIZEOF_SHORT</code>.
* @return the short at the current index
* @exception IOException if an I/O error occurs
*/
public short readNextShort() throws IOException {
short s = readShort(currentIndex);
currentIndex+=SIZEOF_SHORT;
return s;
}
/**
* Reads the short at the current index and then increments the current
* index by <code>SIZEOF_SHORT</code>.
* @return the short at the current index
* @exception IOException if an I/O error occurs
*/
public short readNextShort(short minClamp, short maxClamp, Short... exceptions) throws IOException {
short s = readShort(currentIndex, minClamp, maxClamp, exceptions);
currentIndex+=SIZEOF_SHORT;
return s;
}
/**
* Reads the integer at the current index and then increments the current
* index by <code>SIZEOF_INT</code>.
* @return the integer at the current index
* @exception IOException if an I/O error occurs
*/
public int readNextInt() throws IOException {
int i = readInt(currentIndex);
currentIndex+=SIZEOF_INT;
return i;
}
/**
* Reads the integer at the current index and then increments the current
* index by <code>SIZEOF_INT</code>.
* @return the integer at the current index
* @exception IOException if an I/O error occurs
*/
public int readNextInt(int minClamp, int maxClamp, Integer... exceptions) throws IOException {
int i = readInt(currentIndex, minClamp, maxClamp, exceptions);
currentIndex+=SIZEOF_INT;
return i;
}
/**
* Reads the long at the current index and then increments the current
* index by <code>SIZEOF_LONG</code>.
* @return the long at the current index
* @exception IOException if an I/O error occurs
*/
public long readNextLong() throws IOException {
long l = readLong(currentIndex);
currentIndex+=SIZEOF_LONG;
return l;
}
/**
* Reads the long at the current index and then increments the current
* index by <code>SIZEOF_LONG</code>.
* @return the long at the current index
* @exception IOException if an I/O error occurs
*/
public long readNextLong(long minClamp, long maxClamp, Long... exceptions) throws IOException {
long l = readLong(currentIndex, minClamp, maxClamp, exceptions);
currentIndex+=SIZEOF_LONG;
return l;
}
/**
* Reads the Ascii string at the current index and then increments the current
* index by the length of the Ascii string that was found. This method
* expects the string to be null-terminated.
* @return the null-terminated Ascii string at the current index
* @exception IOException if an I/O error occurs
*/
public String readNextAsciiString() throws IOException {
String s = readAsciiString(currentIndex);
currentIndex+=(s.length()+1);
return s;
}
/**
* Reads an Ascii string of <code>length</code>
* characters starting at the current index and then increments the current
* index by <code>length</code>.
*
* @return the Ascii string at the current index
*/
public String readNextAsciiString(int length) throws IOException {
String s = readAsciiString(currentIndex, length);
currentIndex+=length;
return s;
}
/**
* Reads the Unicode string at the current index and then increments the current
* index by the length of the Unicode string that was found. This method
* expects the string to be double null-terminated ('\0\0').
* @return the null-terminated Ascii string at the current index
* @exception IOException if an I/O error occurs
*/
public String readNextUnicodeString() throws IOException {
String s = readUnicodeString(currentIndex);
currentIndex += ((s.length()+1)*2);
return s;
}
/**
* Reads the unicode string at the current index and then increments the current
* index by <code>length</code>.
* @return the unicode string at the current index
* @exception IOException if an I/O error occurs
*/
public String readNextUnicodeString(int length) throws IOException {
String s = readUnicodeString(currentIndex, length);
currentIndex+=(length*2);
return s;
}
/**
* Reads a byte array of <code>nElements</code>
* starting at the current index and then increments the current
* index by <code>SIZEOF_BYTE * nElements</code>.
* @return the byte array starting at the current index
* @exception IOException if an I/O error occurs
*/
public byte [] readNextByteArray(int nElements) throws IOException {
byte [] b = readByteArray(currentIndex, nElements);
currentIndex+=(SIZEOF_BYTE*nElements);
return b;
}
/**
* Reads a byte array of <code>nElements</code>
* starting at the current index and then increments the current
* index by <code>SIZEOF_BYTE * nElements</code>.
* @return the byte array starting at the current index
* @exception IOException if an I/O error occurs
*/
public byte [] readNextByteArray(int nElements, byte minClamp, byte maxClamp, Byte... exceptions) throws IOException {
byte [] b = readByteArray(currentIndex, nElements, minClamp, maxClamp, exceptions);
currentIndex+=(SIZEOF_BYTE*nElements);
return b;
}
/**
* Reads a short array of <code>nElements</code>
* starting at the current index and then increments the current
* index by <code>SIZEOF_SHORT * nElements</code>.
* @return the short array starting at the current index
* @exception IOException if an I/O error occurs
*/
public short [] readNextShortArray(int nElements) throws IOException {
short [] s = readShortArray(currentIndex, nElements);
currentIndex+=(SIZEOF_SHORT*nElements);
return s;
}
/**
* Reads a short array of <code>nElements</code>
* starting at the current index and then increments the current
* index by <code>SIZEOF_SHORT * nElements</code>.
* @return the short array starting at the current index
* @exception IOException if an I/O error occurs
*/
public short [] readNextShortArray(int nElements, short minClamp, short maxClamp, Short... exceptions) throws IOException {
short [] s = readShortArray(currentIndex, nElements, minClamp, maxClamp, exceptions);
currentIndex+=(SIZEOF_SHORT*nElements);
return s;
}
/**
* Reads an integer array of <code>nElements</code>
* starting at the current index and then increments the current
* index by <code>SIZEOF_INT * nElements</code>.
* @return the integer array starting at the current index
* @exception IOException if an I/O error occurs
*/
public int [] readNextIntArray(int nElements) throws IOException {
int [] i = readIntArray(currentIndex, nElements);
currentIndex+=(SIZEOF_INT*nElements);
return i;
}
/**
* Reads an integer array of <code>nElements</code>
* starting at the current index and then increments the current
* index by <code>SIZEOF_INT * nElements</code>.
* @return the integer array starting at the current index
* @exception IOException if an I/O error occurs
*/
public int [] readNextIntArray(int nElements, int minClamp, int maxClamp, Integer... exceptions) throws IOException {
int [] i = readIntArray(currentIndex, nElements, minClamp, maxClamp, exceptions);
currentIndex+=(SIZEOF_INT*nElements);
return i;
}
/**
* Reads a long array of <code>nElements</code>
* starting at the current index and then increments the current
* index by <code>SIZEOF_LONG * nElements</code>.
* @return the long array starting at the current index
* @exception IOException if an I/O error occurs
*/
public long [] readNextLongArray(int nElements) throws IOException {
long [] l = readLongArray(currentIndex, nElements);
currentIndex+=(SIZEOF_LONG*nElements);
return l;
}
/**
* Reads a long array of <code>nElements</code>
* starting at the current index and then increments the current
* index by <code>SIZEOF_LONG * nElements</code>.
* @return the long array starting at the current index
* @exception IOException if an I/O error occurs
*/
public long [] readNextLongArray(int nElements, long minClamp, long maxClamp, Long... exceptions) throws IOException {
long [] l = readLongArray(currentIndex, nElements, minClamp, maxClamp, exceptions);
currentIndex+=(SIZEOF_LONG*nElements);
return l;
}
////////////////////////////////////////////////////////////////////
/**
* Returns a null-terminated Ascii string starting
* at <code>index</code>. The end of the string
* is denoted by a <code>null</code> character.
*
* @param index the index where the Ascii string begins
* @return the Ascii string
* @exception IOException if an I/O error occurs
*/
public String readAsciiString(long index) throws IOException {
StringBuffer buffer = new StringBuffer();
while (true) {
byte b = provider.readByte(index++);
if ((b >= 32) && (b <= 126)) {
buffer.append((char)b);
}
else {
break;
}
}
return buffer.toString().trim();
}
/**
* Returns an Ascii string of <code>length</code> bytes
* starting at <code>index</code>. This method does not
* care about null-terminators.
* @param index the index where the Ascii string begins
* @param length the length of the Ascii string
* @return the Ascii string
* @exception IOException if an I/O error occurs
*/
public String readAsciiString(long index, int length) throws IOException {
StringBuffer buffer = new StringBuffer();
for (int i = 0 ; i < length ; ++i) {
byte b = provider.readByte(index++);
buffer.append((char) (b & 0x00FF));
}
return buffer.toString().trim();
}
/**
* Returns a null-terminated Unicode string starting
* at <code>index</code>. The end of the string
* is denoted by two-byte Unicode <code>null</code> character.
* @param index the index where the Unicode string begins
* @return the Unicode string
* @exception IOException if an I/O error occurs
*/
public String readUnicodeString(long index) throws IOException {
StringBuffer buffer = new StringBuffer();
char c = 0;
int i = 0;
while (i < length()) {
c = (char)((provider.readByte(index++) & 0xff));
c += (char)((provider.readByte(index++) & 0xff) << 8);
if (c == 0x0000) {
break;
}
buffer.append(c);
i += 2;
}
return buffer.toString().trim();
}
/**
* Returns a Unicode string of <code>length</code> bytes
* starting at <code>index</code>. This method does not
* care about null-terminators.
* @param index the index where the Unicode string begins
* @param length the length of the Unicode string
* @return the Unicode string
* @exception IOException if an I/O error occurs
*/
public String readUnicodeString(long index, int length) throws IOException {
StringBuffer buffer = new StringBuffer();
char c = 0;
for (int i = 0 ; i < length*2 ; i+=2) {
c = (char)((provider.readByte(index++) & 0xff));
c += (char)((provider.readByte(index++) & 0xff) << 8);
buffer.append(c);
}
return buffer.toString().trim();
}
/**
* Returns the BYTE at <code>index<code>.
* @param index the index where the BYTE begins
* @return the BYTE
* @exception IOException if an I/O error occurs
*/
public byte readByte(long index) throws IOException {
return provider.readByte(index);
}
/**
* Returns the BYTE at <code>index</code>.
* @param index the index where the BYTE begins
* @return the BYTE
* @exception IOException if an I/O error occurs
*/
public byte readByte(long index, byte minClamp, byte maxClamp, Byte... exceptions) throws IOException {
byte b = readByte(index);
return clampByte(b, minClamp, maxClamp, exceptions);
}
/**
* Returns the SHORT at <code>index</code>.
* @param index the index where the SHORT begins
* @return the SHORT
* @exception IOException if an I/O error occurs
*/
public short readShort(long index) throws IOException {
byte [] bytes = provider.readBytes(index, SIZEOF_SHORT);
return converter.getShort(bytes);
}
/**
* Returns the SHORT at <code>index</code>.
* @param index the index where the SHORT begins
* @return the SHORT
* @exception IOException if an I/O error occurs
*/
public short readShort(long index, short minClamp, short maxClamp, Short... exceptions) throws IOException {
short s = readShort(index);
return clampShort(s, minClamp, maxClamp, exceptions);
}
/**
* Returns the INTEGER at <code>index</code>.
* @param index the index where the INTEGER begins
* @return the INTEGER
* @exception IOException if an I/O error occurs
*/
public int readInt(long index) throws IOException {
byte [] bytes = provider.readBytes(index, SIZEOF_INT);
return converter.getInt(bytes);
}
/**
* Returns the INTEGER at <code>index</code>.
* @param index the index where the INTEGER begins
* @return the INTEGER
* @exception IOException if an I/O error occurs
*/
public int readInt(long index, int minClamp, int maxClamp, Integer... exceptions) throws IOException {
int i = readInt(index);
return clampInt(i, minClamp, maxClamp, exceptions);
}
/**
* Returns the LONG at <code>index</code>.
* @param index the index where the LONG begins
* @return the LONG
* @exception IOException if an I/O error occurs
*/
public long readLong(long index) throws IOException {
byte [] bytes = provider.readBytes(index, SIZEOF_LONG);
return converter.getLong(bytes);
}
/**
* Returns the LONG at <code>index</code>.
* @param index the index where the LONG begins
* @return the LONG
* @exception IOException if an I/O error occurs
*/
public long readLong(long index, long minClamp, long maxClamp, Long... exceptions) throws IOException {
long l = readLong(index);
return clampLong(l, minClamp, maxClamp, exceptions);
}
/**
* Returns the BYTE array of <code>nElements</code>
* starting at <code>index</code>.
* @param index the index where the BYTE begins
* @param nElements the number of array elements
* @return the BYTE array
* @exception IOException if an I/O error occurs
*/
public byte [] readByteArray(long index, int nElements) throws IOException {
if (nElements < 0) {
throw new IOException("Invalid number of elements specified: "+nElements);
}
return provider.readBytes(index, nElements);
}
/**
* Returns the BYTE array of <code>nElements</code>
* starting at <code>index</code>.
* @param index the index where the BYTE begins
* @param nElements the number of array elements
* @return the BYTE array
* @exception IOException if an I/O error occurs
*/
public byte [] readByteArray(long index, int nElements, byte minClamp, byte maxClamp, Byte... exceptions) throws IOException {
byte[] array = readByteArray(index, nElements);
for (int ii = 0; ii < array.length; ++ii) {
array[ii] = clampByte(array[ii], minClamp, maxClamp, exceptions);
}
return array;
}
/**
* Returns the SHORT array of <code>nElements</code>
* starting at <code>index</code>.
* @param index the index where the SHORT begins
* @param nElements the number of array elements
* @return the SHORT array
* @exception IOException if an I/O error occurs
*/
public short [] readShortArray(long index, int nElements) throws IOException {
if (nElements < 0) {
throw new IOException("Invalid number of elements specified: "+nElements);
}
short [] arr = new short[nElements];
for (int i = 0 ; i < nElements ; ++i) {
arr[i] = readShort(index);
index += SIZEOF_SHORT;
}
return arr;
}
/**
* Returns the SHORT array of <code>nElements</code>
* starting at <code>index</code>.
* @param index the index where the SHORT begins
* @param nElements the number of array elements
* @return the SHORT array
* @exception IOException if an I/O error occurs
*/
public short [] readShortArray(long index, int nElements, short minClamp, short maxClamp, Short... exceptions) throws IOException {
short[] array = readShortArray(index, nElements);
for (int ii = 0; ii < array.length; ++ii) {
array[ii] = clampShort(array[ii], minClamp, maxClamp, exceptions);
}
return array;
}
/**
* Returns the INTEGER array of <code>nElements</code>
* starting at <code>index</code>.
* @param index the index where the INTEGER begins
* @param nElements the number of array elements
* @return the INTEGER array
* @exception IOException if an I/O error occurs
*/
public int [] readIntArray(long index, int nElements) throws IOException {
if (nElements < 0) {
throw new IOException("Invalid number of elements specified: "+nElements);
}
int [] arr = new int[nElements];
for (int i = 0 ; i < nElements ; ++i) {
arr[i] = readInt(index);
index += SIZEOF_INT;
}
return arr;
}
/**
* Returns the INTEGER array of <code>nElements</code>
* starting at <code>index</code>.
* @param index the index where the INTEGER begins
* @param nElements the number of array elements
* @return the INTEGER array
* @exception IOException if an I/O error occurs
*/
public int [] readIntArray(long index, int nElements, int minClamp, int maxClamp, Integer... exceptions) throws IOException {
int[] array = readIntArray(index, nElements);
for (int ii = 0; ii < array.length; ++ii) {
array[ii] = clampInt(array[ii], minClamp, maxClamp, exceptions);
}
return array;
}
/**
* Returns the LONG array of <code>nElements</code>
* starting at <code>index</code>.
* @param index the index where the LONG begins
* @param nElements the number of array elements
* @return the LONG array
* @exception IOException if an I/O error occurs
*/
public long [] readLongArray(long index, int nElements) throws IOException {
if (nElements < 0) {
throw new IOException("Invalid number of elements specified: "+nElements);
}
long [] arr = new long[nElements];
for (int i = 0 ; i < nElements ; ++i) {
arr[i] = readLong(index);
index += SIZEOF_LONG;
}
return arr;
}
/**
* Returns the LONG array of <code>nElements</code>
* starting at <code>index</code>.
* @param index the index where the LONG begins
* @param nElements the number of array elements
* @return the LONG array
* @exception IOException if an I/O error occurs
*/
public long [] readLongArray(long index, int nElements, long minClamp, long maxClamp, Long... exceptions) throws IOException {
long[] array = readLongArray(index, nElements);
for (int ii = 0; ii < array.length; ++ii) {
array[ii] = clampLong(array[ii], minClamp, maxClamp, exceptions);
}
return array;
}
/**
* Returns the Ascii string array of <code>nElements</code>
* starting at <code>index</code>
* @param index the index where the Ascii Strings begin
* @param nElements the number of array elements
* @return the Ascii String array
* @exception IOException if an I/O error occurs
*/
public String [] readAsciiStringArray(long index, int nElements) throws IOException {
if (nElements < 0) {
throw new IOException("Invalid number of elements specified: "+nElements);
}
String [] arr = new String[nElements];
for (int i = 0 ; i < nElements ; ++i) {
String tmp = readAsciiString(index);
arr[i] = tmp;
index += (tmp == null ? 1 : tmp.length());
}
return arr;
}
/**
* Writes the specified byte at the specified index.
* @param index the index where the byte should be written
* @param value the byte value to be written
* @exception IOException if an I/O error occurs
*/
public void writeByte(long index, byte value) throws IOException {
provider.writeByte(index, value);
}
/**
* Writes the specified short at the specified index.
* @param index the index where the short should be written
* @param value the short value to be written
* @exception IOException if an I/O error occurs
*/
public void writeShort(long index, short value) throws IOException {
byte [] bytes = converter.getBytes(value);
provider.writeBytes(index, bytes);
}
/**
* Writes the specified int at the specified index.
* @param index the index where the int should be written
* @param value the int value to be written
* @exception IOException if an I/O error occurs
*/
public void writeInt(long index, int value) throws IOException {
byte [] bytes = converter.getBytes(value);
provider.writeBytes(index, bytes);
}
/**
* Writes the specified long at the specified index.
* @param index the index where the long should be written
* @param value the long value to be written
* @exception IOException if an I/O error occurs
*/
public void writeLong(long index, long value) throws IOException {
byte [] bytes = converter.getBytes(value);
provider.writeBytes(index, bytes);
}
/**
* Returns the underlying byte provider.
* @return the underlying byte provider
*/
public GByteProvider getByteProvider() {
return provider;
}
protected byte clampByte(byte b, byte minClamp, byte maxClamp, Byte... exceptions) {
if (maxClamp < minClamp) {
throw new IllegalArgumentException("maxClamp < minClamp not allowed");
}
if (exceptions != null) {
if (exceptions.length % 2 != 0) {
throw new IllegalArgumentException("exceptions must be pairs of (flag, replacement) bytes");
}
}
boolean clamp = true;
if (exceptions != null) {
for (int ii = 0; ii < exceptions.length; ii += 2) {
if (b == exceptions[ii]) {
b = exceptions[ii+1];
clamp = false;
break;
}
}
}
if (clamp) {
if (b < minClamp) {
b = minClamp;
} else if (b > maxClamp) {
b = maxClamp;
}
}
return b;
}
protected short clampShort(short s, short minClamp, short maxClamp, Short... exceptions) {
if (maxClamp < minClamp) {
throw new IllegalArgumentException("maxClamp < minClamp not allowed");
}
if (exceptions != null) {
if (exceptions.length % 2 != 0) {
throw new IllegalArgumentException("exceptions must be pairs of (flag, replacement) shorts");
}
}
boolean clamp = true;
if (exceptions != null) {
for (int ii = 0; ii < exceptions.length; ii += 2) {
if (s == exceptions[ii]) {
s = exceptions[ii+1];
clamp = false;
break;
}
}
}
if (clamp) {
if (s < minClamp) {
s = minClamp;
} else if (s > maxClamp) {
s = maxClamp;
}
}
return s;
}
protected int clampInt(int i, int minClamp, int maxClamp, Integer... exceptions) {
if (maxClamp < minClamp) {
throw new IllegalArgumentException("maxClamp < minClamp not allowed");
}
if (exceptions != null) {
if (exceptions.length % 2 != 0) {
throw new IllegalArgumentException("exceptions must be pairs of (flag, replacement) ints");
}
}
boolean clamp = true;
if (exceptions != null) {
for (int ii = 0; ii < exceptions.length; ii += 2) {
if (i == exceptions[ii]) {
i = exceptions[ii+1];
clamp = false;
break;
}
}
}
if (clamp) {
if (i < minClamp) {
i = minClamp;
} else if (i > maxClamp) {
i = maxClamp;
}
}
return i;
}
protected long clampLong(long l, long minClamp, long maxClamp, Long... exceptions) {
if (maxClamp < minClamp) {
throw new IllegalArgumentException("maxClamp < minClamp not allowed");
}
if (exceptions != null) {
if (exceptions.length % 2 != 0) {
throw new IllegalArgumentException("exceptions must be pairs of (flag, replacement) longs");
}
}
boolean clamp = true;
if (exceptions != null) {
for (int ii = 0; ii < exceptions.length; ii += 2) {
if (l == exceptions[ii]) {
l = exceptions[ii+1];
clamp = false;
break;
}
}
}
if (clamp) {
if (l < minClamp) {
l = minClamp;
} else if (l > maxClamp) {
l = maxClamp;
}
}
return l;
}
}