]> source.dussan.org Git - jackcess.git/commitdiff
apply changes from patch: 2964626 - support for Jet3 and Jet5 formats.
authorDan Rollo <bhamail@users.sf.net>
Thu, 11 Mar 2010 22:57:26 +0000 (22:57 +0000)
committerDan Rollo <bhamail@users.sf.net>
Thu, 11 Mar 2010 22:57:26 +0000 (22:57 +0000)
still need to update tests/data to test against new formats.

git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/branches/newformats@439 f203690c-595d-4dc9-a70b-905162fa7fd2

src/java/com/healthmarketscience/jackcess/Database.java
src/java/com/healthmarketscience/jackcess/JetFormat.java
src/java/com/healthmarketscience/jackcess/UsageMap.java
test/data/accdb/test.accdb [new file with mode: 0644]
test/data/mdb2003/test2003.mdb [new file with mode: 0644]
test/data/mdb97/test97.mdb [new file with mode: 0644]
test/src/java/com/healthmarketscience/jackcess/JetFormatTest.java [new file with mode: 0644]
test/src/java/com/healthmarketscience/jackcess/UsageMapTest.java [new file with mode: 0644]

index 8609b65cc422a103252f0d3d425fff4c5d19b4ac..e31cc7def471db3df83891d3f601f41f87b320c7 100644 (file)
@@ -370,11 +370,24 @@ public class Database
             EMPTY_MDB)), 0, Integer.MAX_VALUE);
     return new Database(channel, autoSync);
   }
-  
-  private static FileChannel openChannel(File mdbFile, boolean readOnly)
+
+  /**
+   * Package visible only to support unit tests via DatabaseTest.openChannel().
+   * @param mdbFile file to open
+   * @param readOnly true if read-only
+   * @return a FileChannel on the given file.
+   * @exception FileNotFoundException
+   *            if the mode is <tt>"r"</tt> but the given file object does
+   *            not denote an existing regular file, or if the mode begins
+   *            with <tt>"rw"</tt> but the given file object does not denote
+   *            an existing, writable regular file and a new regular file of
+   *            that name cannot be created, or if some other error occurs
+   *            while opening or creating the file
+   */
+  static FileChannel openChannel(final File mdbFile, final boolean readOnly)
     throws FileNotFoundException
   {
-    String mode = (readOnly ? "r" : "rw");
+    final String mode = (readOnly ? "r" : "rw");
     return new RandomAccessFile(mdbFile, mode).getChannel();
   }
   
index 38b4bc52a86af7e2d677b1a5d7b6ff206ea65985..afb180484df197cd1859c71a5e5a6139a590947d 100644 (file)
@@ -52,6 +52,8 @@ public abstract class JetFormat {
   private static final byte CODE_VERSION_3 = 0x0;
   /** Version code for Jet version 4 */
   private static final byte CODE_VERSION_4 = 0x1;
+  /** Version code for Jet version 5 */
+  private static final byte CODE_VERSION_5 = 0x2;
 
   //These constants are populated by this class's constructor.  They can't be
   //populated by the subclass's constructor because they are final, and Java
@@ -131,10 +133,14 @@ public abstract class JetFormat {
   
   public final Charset CHARSET;
   
+  public static final JetFormat VERSION_3 = new Jet3Format();
   public static final JetFormat VERSION_4 = new Jet4Format();
+  public static final JetFormat VERSION_5 = new Jet5Format();
 
   /**
+   * @param channel the database file.
    * @return The Jet Format represented in the passed-in file
+   * @throws IOException if the database file format is unsupported.
    */
   public static JetFormat getFormat(FileChannel channel) throws IOException {
     ByteBuffer buffer = ByteBuffer.allocate(1);
@@ -144,8 +150,12 @@ public abstract class JetFormat {
     }
     buffer.flip();
     byte version = buffer.get();
-    if (version == CODE_VERSION_4) {
+    if (version == CODE_VERSION_3) {
+      return VERSION_3;
+    } else if (version == CODE_VERSION_4) {
       return VERSION_4;
+    } else if (version == CODE_VERSION_5) {
+      return VERSION_5;
     }
     throw new IOException("Unsupported version: " + version);
   }
@@ -300,10 +310,14 @@ public abstract class JetFormat {
     return _name;
   }
   
-  private static final class Jet4Format extends JetFormat {
+  private static class Jet4Format extends JetFormat {
 
     private Jet4Format() {
-      super("VERSION_4");
+      this("VERSION_4");
+    }
+
+    private Jet4Format(final String name) {
+      super(name);
     }
 
     @Override
@@ -438,4 +452,15 @@ public abstract class JetFormat {
     protected Charset defineCharset() { return Charset.forName("UTF-16LE"); }
   }
   
+  private static final class Jet3Format extends Jet4Format {
+      private Jet3Format() {
+        super("VERSION_3");
+      }
+  }
+
+  private static final class Jet5Format extends Jet4Format {
+      private Jet5Format() {
+        super("VERSION_5");
+      }
+  }
 }
index 6495f0ca979f856e1d5053b181d832e8e8bb8e3d..5e6ec1ed8f665f51bb333eefd622c8bbe38f63a4 100644 (file)
@@ -72,8 +72,11 @@ public class UsageMap
   /** the current handler implementation for reading/writing the specific
       usage map type.  note, this may change over time. */
   private Handler _handler;
-  
-  /**
+
+  /** Error message prefix used when map type is unrecognized. */
+  static final String MSG_PREFIX_UNRECOGNIZED_MAP = "Unrecognized map type: ";
+
+    /**
    * @param database database that contains this usage map
    * @param tableBuffer Buffer that contains this map's declaration
    * @param pageNum Page number that this usage map is contained in
@@ -139,7 +142,7 @@ public class UsageMap
     } else if (mapType == MAP_TYPE_REFERENCE) {
       _handler = new ReferenceHandler();
     } else {
-      throw new IOException("Unrecognized map type: " + mapType);
+      throw new IOException(MSG_PREFIX_UNRECOGNIZED_MAP + mapType);
     }
   }
   
diff --git a/test/data/accdb/test.accdb b/test/data/accdb/test.accdb
new file mode 100644 (file)
index 0000000..67bea0c
Binary files /dev/null and b/test/data/accdb/test.accdb differ
diff --git a/test/data/mdb2003/test2003.mdb b/test/data/mdb2003/test2003.mdb
new file mode 100644 (file)
index 0000000..a1a7fd8
Binary files /dev/null and b/test/data/mdb2003/test2003.mdb differ
diff --git a/test/data/mdb97/test97.mdb b/test/data/mdb97/test97.mdb
new file mode 100644 (file)
index 0000000..2aa1060
Binary files /dev/null and b/test/data/mdb97/test97.mdb differ
diff --git a/test/src/java/com/healthmarketscience/jackcess/JetFormatTest.java b/test/src/java/com/healthmarketscience/jackcess/JetFormatTest.java
new file mode 100644 (file)
index 0000000..ca46cdb
--- /dev/null
@@ -0,0 +1,49 @@
+package com.healthmarketscience.jackcess;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+
+/**
+ * @author Dan Rollo
+ *         Date: Mar 5, 2010
+ *         Time: 12:44:21 PM
+ */
+public final class JetFormatTest  extends TestCase {
+
+    static final File DB_1997 = new File("test/data/mdb97/test97.mdb");
+    static final File DB_2000 = new File("test/data/test.mdb");
+    static final File DB_2003 = new File("test/data/mdb2003/test2003.mdb");
+    static final File DB_2007 = new File("test/data/accdb/test.accdb");
+
+    public void testGetFormat() throws Exception {
+        try {
+            JetFormat.getFormat(null);
+            fail("npe");
+        } catch (NullPointerException e) {
+            assertNull(e.getMessage());
+        }
+
+        checkJetFormat(DB_1997, JetFormat.VERSION_3);
+        checkJetFormat(DB_2000, JetFormat.VERSION_4);
+        checkJetFormat(DB_2003, JetFormat.VERSION_4);
+        checkJetFormat(DB_2007, JetFormat.VERSION_5);
+    }
+
+    private static void checkJetFormat(final File dbFile, final JetFormat fmtExpected)
+            throws IOException {
+
+        final FileChannel channel = Database.openChannel(dbFile, false);
+        try {
+
+            final JetFormat fmtActual = JetFormat.getFormat(channel);
+            assertEquals("Unexpected JetFormat for dbFile: " + dbFile.getAbsolutePath(),
+                    fmtExpected, fmtActual);
+
+        } finally {
+            channel.close();
+        }
+    }
+}
diff --git a/test/src/java/com/healthmarketscience/jackcess/UsageMapTest.java b/test/src/java/com/healthmarketscience/jackcess/UsageMapTest.java
new file mode 100644 (file)
index 0000000..47937b5
--- /dev/null
@@ -0,0 +1,39 @@
+package com.healthmarketscience.jackcess;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * @author Dan Rollo
+ *         Date: Mar 5, 2010
+ *         Time: 2:21:22 PM
+ */
+public final class UsageMapTest extends TestCase {
+
+    public void testRead() throws Exception {
+        try {
+            Database.open(JetFormatTest.DB_1997);
+            fail("mdb v97 usage map unsupported");
+        } catch (IOException e) {
+            assertEquals(UsageMap.MSG_PREFIX_UNRECOGNIZED_MAP + 2, e.getMessage());
+        }
+
+        checkUsageMapRead(JetFormatTest.DB_2000, 743, 767);
+        checkUsageMapRead(JetFormatTest.DB_2007, 42, 511);
+    }
+
+    private static void checkUsageMapRead(final File dbFile,
+                                          final int expectedFirstPage, final int expectedLastPage)
+            throws IOException {
+
+        final Database db = Database.open(dbFile);
+        final UsageMap usageMap = UsageMap.read(db,
+                1, //PageChannel.PAGE_GLOBAL_USAGE_MAP,
+                0, //PageChannel.ROW_GLOBAL_USAGE_MAP,
+                true);
+        assertEquals("Unexpected FirstPageNumber.", expectedFirstPage, usageMap.getFirstPageNumber());
+        assertEquals("Unexpected LastPageNumber.", expectedLastPage, usageMap.getLastPageNumber());
+    }
+}