From: James Ahlborn Date: Mon, 31 Jul 2006 14:01:13 +0000 (+0000) Subject: clean up reading/writing 3-byte ints; long value length is 3-bytes (fix bug 1449812) X-Git-Tag: rel_1_1_6~17 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=c32f22b235a2cb0e6e317368a1b4323ea445c359;p=jackcess.git clean up reading/writing 3-byte ints; long value length is 3-bytes (fix bug 1449812) git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@79 f203690c-595d-4dc9-a70b-905162fa7fd2 --- diff --git a/src/java/com/healthmarketscience/jackcess/ByteUtil.java b/src/java/com/healthmarketscience/jackcess/ByteUtil.java index d35a354..9a797d9 100644 --- a/src/java/com/healthmarketscience/jackcess/ByteUtil.java +++ b/src/java/com/healthmarketscience/jackcess/ByteUtil.java @@ -29,6 +29,7 @@ package com.healthmarketscience.jackcess; import java.io.IOException; import java.nio.ByteBuffer; +import java.nio.ByteOrder; /** * Byte manipulation and display utilities @@ -41,31 +42,70 @@ public final class ByteUtil { "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; } diff --git a/src/java/com/healthmarketscience/jackcess/Column.java b/src/java/com/healthmarketscience/jackcess/Column.java index 16f2be4..d121336 100644 --- a/src/java/com/healthmarketscience/jackcess/Column.java +++ b/src/java/com/healthmarketscience/jackcess/Column.java @@ -69,15 +69,15 @@ public class Column implements Comparable { /** * 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*"); @@ -298,19 +298,19 @@ public class Column implements Comparable { * LONG_VALUE_TYPE_* * @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) { @@ -351,7 +351,7 @@ public class Column implements Comparable { 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; @@ -573,8 +573,8 @@ public class Column implements Comparable { 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); @@ -606,10 +606,10 @@ public class Column implements Comparable { 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; diff --git a/src/java/com/healthmarketscience/jackcess/Database.java b/src/java/com/healthmarketscience/jackcess/Database.java index 5635ed6..2506be3 100644 --- a/src/java/com/healthmarketscience/jackcess/Database.java +++ b/src/java/com/healthmarketscience/jackcess/Database.java @@ -373,9 +373,9 @@ public class Database { 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(); diff --git a/src/java/com/healthmarketscience/jackcess/Table.java b/src/java/com/healthmarketscience/jackcess/Table.java index 9637c4e..8cbd796 100644 --- a/src/java/com/healthmarketscience/jackcess/Table.java +++ b/src/java/com/healthmarketscience/jackcess/Table.java @@ -121,23 +121,23 @@ public class Table { _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; } /** diff --git a/test/src/java/com/healthmarketscience/jackcess/DatabaseTest.java b/test/src/java/com/healthmarketscience/jackcess/DatabaseTest.java index 084fa65..365b455 100644 --- a/test/src/java/com/healthmarketscience/jackcess/DatabaseTest.java +++ b/test/src/java/com/healthmarketscience/jackcess/DatabaseTest.java @@ -438,7 +438,7 @@ public class DatabaseTest extends TestCase { 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,