]> source.dussan.org Git - jackcess.git/commitdiff
clean up reading/writing 3-byte ints; long value length is 3-bytes (fix bug 1449812)
authorJames Ahlborn <jtahlborn@yahoo.com>
Mon, 31 Jul 2006 14:01:13 +0000 (14:01 +0000)
committerJames Ahlborn <jtahlborn@yahoo.com>
Mon, 31 Jul 2006 14:01:13 +0000 (14:01 +0000)
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@79 f203690c-595d-4dc9-a70b-905162fa7fd2

src/java/com/healthmarketscience/jackcess/ByteUtil.java
src/java/com/healthmarketscience/jackcess/Column.java
src/java/com/healthmarketscience/jackcess/Database.java
src/java/com/healthmarketscience/jackcess/Table.java
test/src/java/com/healthmarketscience/jackcess/DatabaseTest.java

index d35a354d81a485a8b17229668358f54d2233fbbf..9a797d9e28ea6d2a855c7866fc8898b7763a3771 100644 (file)
@@ -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;
   }
   
index 16f2be478e7bee7f539ab1530f1f47568ed1295d..d12133616edb327790e807b677914432f6cb985a 100644 (file)
@@ -69,15 +69,15 @@ public class Column implements Comparable<Column> {
   /**
    * 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<Column> {
    *                <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) {
@@ -351,7 +351,7 @@ public class Column implements Comparable<Column> {
   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<Column> {
   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<Column> {
     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;    
index 5635ed6d02002a19f0e0c5d290adb95e6e5e3300..2506be33efdbee3697a3ba38d0aa5072dd889381 100644 (file)
@@ -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();
index 9637c4ead6725953af9ee97e9db762442079809d..8cbd796d3607865b745b88ee9ff85ee2e6f5f196 100644 (file)
@@ -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;
   }
 
   /**
index 084fa65abc85a831f050b6a79f78c3679ef0869e..365b4554e751aece8f630b44abf9901a8ecd85be 100644 (file)
@@ -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,