diff options
author | Dan Rollo <bhamail@users.sf.net> | 2010-03-11 22:57:26 +0000 |
---|---|---|
committer | Dan Rollo <bhamail@users.sf.net> | 2010-03-11 22:57:26 +0000 |
commit | 8e306bc27b795188c11be761f5371dc2478f4350 (patch) | |
tree | 90b4484cee0431d5ad7d139cf1edd10691985ba0 | |
parent | 5186af380ec14b27a4cafa62d95025363a5b9a2e (diff) | |
download | jackcess-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.java | 19 | ||||
-rw-r--r-- | src/java/com/healthmarketscience/jackcess/JetFormat.java | 31 | ||||
-rw-r--r-- | src/java/com/healthmarketscience/jackcess/UsageMap.java | 9 | ||||
-rw-r--r-- | test/data/accdb/test.accdb | bin | 0 -> 413696 bytes | |||
-rw-r--r-- | test/data/mdb2003/test2003.mdb | bin | 0 -> 3162112 bytes | |||
-rw-r--r-- | test/data/mdb97/test97.mdb | bin | 0 -> 118784 bytes | |||
-rw-r--r-- | test/src/java/com/healthmarketscience/jackcess/JetFormatTest.java | 49 | ||||
-rw-r--r-- | test/src/java/com/healthmarketscience/jackcess/UsageMapTest.java | 39 |
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 Binary files differnew file mode 100644 index 0000000..67bea0c --- /dev/null +++ b/test/data/accdb/test.accdb diff --git a/test/data/mdb2003/test2003.mdb b/test/data/mdb2003/test2003.mdb Binary files differnew file mode 100644 index 0000000..a1a7fd8 --- /dev/null +++ b/test/data/mdb2003/test2003.mdb diff --git a/test/data/mdb97/test97.mdb b/test/data/mdb97/test97.mdb Binary files differnew file mode 100644 index 0000000..2aa1060 --- /dev/null +++ b/test/data/mdb97/test97.mdb 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()); + } +} |