summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Rollo <bhamail@users.sf.net>2010-03-11 22:57:26 +0000
committerDan Rollo <bhamail@users.sf.net>2010-03-11 22:57:26 +0000
commit8e306bc27b795188c11be761f5371dc2478f4350 (patch)
tree90b4484cee0431d5ad7d139cf1edd10691985ba0
parent5186af380ec14b27a4cafa62d95025363a5b9a2e (diff)
downloadjackcess-8e306bc27b795188c11be761f5371dc2478f4350.tar.gz
jackcess-8e306bc27b795188c11be761f5371dc2478f4350.zip
apply changes from patch: 2964626 - support for Jet3 and Jet5 formats.
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
-rw-r--r--src/java/com/healthmarketscience/jackcess/Database.java19
-rw-r--r--src/java/com/healthmarketscience/jackcess/JetFormat.java31
-rw-r--r--src/java/com/healthmarketscience/jackcess/UsageMap.java9
-rw-r--r--test/data/accdb/test.accdbbin0 -> 413696 bytes
-rw-r--r--test/data/mdb2003/test2003.mdbbin0 -> 3162112 bytes
-rw-r--r--test/data/mdb97/test97.mdbbin0 -> 118784 bytes
-rw-r--r--test/src/java/com/healthmarketscience/jackcess/JetFormatTest.java49
-rw-r--r--test/src/java/com/healthmarketscience/jackcess/UsageMapTest.java39
8 files changed, 138 insertions, 9 deletions
diff --git a/src/java/com/healthmarketscience/jackcess/Database.java b/src/java/com/healthmarketscience/jackcess/Database.java
index 8609b65..e31cc7d 100644
--- a/src/java/com/healthmarketscience/jackcess/Database.java
+++ b/src/java/com/healthmarketscience/jackcess/Database.java
@@ -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();
}
diff --git a/src/java/com/healthmarketscience/jackcess/JetFormat.java b/src/java/com/healthmarketscience/jackcess/JetFormat.java
index 38b4bc5..afb1804 100644
--- a/src/java/com/healthmarketscience/jackcess/JetFormat.java
+++ b/src/java/com/healthmarketscience/jackcess/JetFormat.java
@@ -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");
+ }
+ }
}
diff --git a/src/java/com/healthmarketscience/jackcess/UsageMap.java b/src/java/com/healthmarketscience/jackcess/UsageMap.java
index 6495f0c..5e6ec1e 100644
--- a/src/java/com/healthmarketscience/jackcess/UsageMap.java
+++ b/src/java/com/healthmarketscience/jackcess/UsageMap.java
@@ -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
index 0000000..67bea0c
--- /dev/null
+++ b/test/data/accdb/test.accdb
Binary files differ
diff --git a/test/data/mdb2003/test2003.mdb b/test/data/mdb2003/test2003.mdb
new file mode 100644
index 0000000..a1a7fd8
--- /dev/null
+++ b/test/data/mdb2003/test2003.mdb
Binary files differ
diff --git a/test/data/mdb97/test97.mdb b/test/data/mdb97/test97.mdb
new file mode 100644
index 0000000..2aa1060
--- /dev/null
+++ b/test/data/mdb97/test97.mdb
Binary files 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
index 0000000..ca46cdb
--- /dev/null
+++ b/test/src/java/com/healthmarketscience/jackcess/JetFormatTest.java
@@ -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
index 0000000..47937b5
--- /dev/null
+++ b/test/src/java/com/healthmarketscience/jackcess/UsageMapTest.java
@@ -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());
+ }
+}