import java.io.IOException;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
/**
* Byte manipulation and display utilities
"8", "9", "A", "B", "C", "D", "E", "F"};
private ByteUtil() {}
+
+ /**
+ * Put an integer into the given buffer at the given offset as a 3-byte
+ * integer.
+ * @param buffer buffer into which to insert the int
+ * @param val Int to convert
+ */
+ public static void put3ByteInt(ByteBuffer buffer, int val)
+ {
+ int pos = buffer.position();
+ put3ByteInt(buffer, val, pos);
+ buffer.position(pos + 3);
+ }
/**
- * Convert an int from 4 bytes to 3
- * @param i Int to convert
- * @return Array of 3 bytes in little-endian order
+ * Put an integer into the given buffer at the given offset as a 3-byte
+ * integer.
+ * @param buffer buffer into which to insert the int
+ * @param val Int to convert
+ * @param offset offset at which to insert the int
*/
- public static byte[] to3ByteInt(int i) {
- byte[] rtn = new byte[3];
- rtn[0] = (byte) (i & 0xFF);
- rtn[1] = (byte) ((i >>> 8) & 0xFF);
- rtn[2] = (byte) ((i >>> 16) & 0xFF);
+ public static void put3ByteInt(ByteBuffer buffer, int val, int offset) {
+
+ int offInc = 1;
+ if(buffer.order() == ByteOrder.BIG_ENDIAN) {
+ offInc = -1;
+ offset += 2;
+ }
+
+ buffer.put(offset, (byte) (val & 0xFF));
+ buffer.put(offset + (1 * offInc), (byte) ((val >>> 8) & 0xFF));
+ buffer.put(offset + (2 * offInc), (byte) ((val >>> 16) & 0xFF));
+ }
+
+ /**
+ * Read a 3 byte int from a buffer
+ * @param buffer Buffer containing the bytes
+ * @return The int
+ */
+ public static int get3ByteInt(ByteBuffer buffer) {
+ int pos = buffer.position();
+ int rtn = get3ByteInt(buffer, pos);
+ buffer.position(pos + 3);
return rtn;
}
/**
- * Read a 3 byte int from a buffer in little-endian order
+ * Read a 3 byte int from a buffer
* @param buffer Buffer containing the bytes
* @param offset Offset at which to start reading the int
* @return The int
*/
public static int get3ByteInt(ByteBuffer buffer, int offset) {
- int rtn = buffer.get(offset) & 0xff;
- rtn += ((((int) buffer.get(offset + 1)) & 0xFF) << 8);
- rtn += ((((int) buffer.get(offset + 2)) & 0xFF) << 16);
- rtn &= 16777215; //2 ^ (8 * 3) - 1
+
+ int offInc = 1;
+ if(buffer.order() == ByteOrder.BIG_ENDIAN) {
+ offInc = -1;
+ offset += 2;
+ }
+
+ int rtn = buffer.get(offset) & 0xFF;
+ rtn += ((((int) buffer.get(offset + (1 * offInc))) & 0xFF) << 8);
+ rtn += ((((int) buffer.get(offset + (2 * offInc))) & 0xFF) << 16);
+ rtn &= 0xFFFFFF;
return rtn;
}
/**
* Long value (LVAL) type that indicates that the value is stored on the same page
*/
- private static final short LONG_VALUE_TYPE_THIS_PAGE = (short) 0x8000;
+ private static final byte LONG_VALUE_TYPE_THIS_PAGE = (byte) 0x80;
/**
* Long value (LVAL) type that indicates that the value is stored on another page
*/
- private static final short LONG_VALUE_TYPE_OTHER_PAGE = (short) 0x4000;
+ private static final byte LONG_VALUE_TYPE_OTHER_PAGE = (byte) 0x40;
/**
* Long value (LVAL) type that indicates that the value is stored on multiple other pages
*/
- private static final short LONG_VALUE_TYPE_OTHER_PAGES = (short) 0x0;
+ private static final byte LONG_VALUE_TYPE_OTHER_PAGES = (byte) 0x00;
private static final Pattern GUID_PATTERN = Pattern.compile("\\s*[{]([\\p{XDigit}]{8})-([\\p{XDigit}]{4})-([\\p{XDigit}]{4})-([\\p{XDigit}]{4})-([\\p{XDigit}]{12})[}]\\s*");
* <code>LONG_VALUE_TYPE_*</code>
* @return The LVAL data
*/
- private byte[] readLongBinaryValue(byte[] lvalDefinition, short[] outType)
+ private byte[] readLongBinaryValue(byte[] lvalDefinition, byte[] outType)
throws IOException
{
ByteBuffer def = ByteBuffer.wrap(lvalDefinition);
def.order(ByteOrder.LITTLE_ENDIAN);
- short length = def.getShort();
+ int length = ByteUtil.get3ByteInt(def);
// bail out gracefully here as we don't understand the format
if (length < 0)
{
return null;
}
byte[] rtn = new byte[length];
- short type = def.getShort();
+ byte type = def.get();
switch (type) {
case LONG_VALUE_TYPE_OTHER_PAGE:
if (lvalDefinition.length != _format.SIZE_LONG_VALUE_DEF) {
private String readLongStringValue(byte[] lvalDefinition)
throws IOException
{
- short[] type = new short[1];
+ byte[] type = new byte[1];
byte[] binData = readLongBinaryValue(lvalDefinition, type);
if(binData == null) {
return null;
public ByteBuffer writeLongValue(byte[] value) throws IOException {
ByteBuffer def = ByteBuffer.allocate(_format.SIZE_LONG_VALUE_DEF + value.length);
def.order(ByteOrder.LITTLE_ENDIAN);
- def.putShort((short) value.length);
- def.putShort(LONG_VALUE_TYPE_THIS_PAGE);
+ ByteUtil.put3ByteInt(def, value.length);
+ def.put(LONG_VALUE_TYPE_THIS_PAGE);
def.putInt(0);
def.putInt(0); //Unknown
def.put(value);
lvalPage.put(value);
ByteBuffer def = ByteBuffer.allocate(_format.SIZE_LONG_VALUE_DEF);
def.order(ByteOrder.LITTLE_ENDIAN);
- def.putShort((short) value.length);
- def.putShort(LONG_VALUE_TYPE_OTHER_PAGE);
+ ByteUtil.put3ByteInt(def, value.length);
+ def.put(LONG_VALUE_TYPE_OTHER_PAGE);
def.put((byte) 0); //Row number
- def.put(ByteUtil.to3ByteInt(_pageChannel.writeNewPage(lvalPage))); //Page #
+ ByteUtil.put3ByteInt(def, _pageChannel.writeNewPage(lvalPage)); //Page #
def.putInt(0); //Unknown
def.flip();
return def;
buffer.putInt(0); //Number of indexes in table
buffer.put((byte) 0); //Usage map row number
int usageMapPage = pageNumber + 1;
- buffer.put(ByteUtil.to3ByteInt(usageMapPage)); //Usage map page number
+ ByteUtil.put3ByteInt(buffer, usageMapPage); //Usage map page number
buffer.put((byte) 1); //Free map row number
- buffer.put(ByteUtil.to3ByteInt(usageMapPage)); //Free map page number
+ ByteUtil.put3ByteInt(buffer, usageMapPage); //Free map page number
if (LOG.isDebugEnabled()) {
int position = buffer.position();
buffer.rewind();
_format = format;
_tableDefPageNumber = pageNumber;
int nextPage;
- ByteBuffer nextPageBuffer = null;
- nextPage = _buffer.getInt(_format.OFFSET_NEXT_TABLE_DEF_PAGE);
- while (nextPage != 0) {
- if (nextPageBuffer == null) {
- nextPageBuffer = ByteBuffer.allocate(format.PAGE_SIZE);
- nextPageBuffer.order(ByteOrder.LITTLE_ENDIAN);
- }
- _pageChannel.readPage(nextPageBuffer, nextPage);
- nextPage = nextPageBuffer.getInt(_format.OFFSET_NEXT_TABLE_DEF_PAGE);
- ByteBuffer newBuffer = ByteBuffer.allocate(_buffer.capacity() + format.PAGE_SIZE - 8);
- newBuffer.order(ByteOrder.LITTLE_ENDIAN);
- newBuffer.put(_buffer);
- newBuffer.put(nextPageBuffer.array(), 8, format.PAGE_SIZE - 8);
- _buffer = newBuffer;
- }
- readPage();
- _name = name;
+ ByteBuffer nextPageBuffer = null;
+ nextPage = _buffer.getInt(_format.OFFSET_NEXT_TABLE_DEF_PAGE);
+ while (nextPage != 0) {
+ if (nextPageBuffer == null) {
+ nextPageBuffer = ByteBuffer.allocate(format.PAGE_SIZE);
+ nextPageBuffer.order(ByteOrder.LITTLE_ENDIAN);
+ }
+ _pageChannel.readPage(nextPageBuffer, nextPage);
+ nextPage = nextPageBuffer.getInt(_format.OFFSET_NEXT_TABLE_DEF_PAGE);
+ ByteBuffer newBuffer = ByteBuffer.allocate(_buffer.capacity() + format.PAGE_SIZE - 8);
+ newBuffer.order(ByteOrder.LITTLE_ENDIAN);
+ newBuffer.put(_buffer);
+ newBuffer.put(nextPageBuffer.array(), 8, format.PAGE_SIZE - 8);
+ _buffer = newBuffer;
+ }
+ readPage();
+ _name = name;
}
/**
table = mdb.getTable("Table3");
assertEquals(2, table.getIndexes().size());
assertEquals(3, table.getIndexSlotCount());
- }
+ }
private Object[] createTestRow() {
return new Object[] {"Tim", "R", "McCune", 1234, (byte) 0xad, 555.66d,