View Javadoc
1   /*
2   Copyright (c) 2005 Health Market Science, Inc.
3   
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7   
8       http://www.apache.org/licenses/LICENSE-2.0
9   
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15  */
16  
17  package com.healthmarketscience.jackcess.impl;
18  
19  import java.io.IOException;
20  import java.nio.ByteBuffer;
21  import java.nio.channels.FileChannel;
22  import java.nio.charset.Charset;
23  import java.util.Collections;
24  import java.util.EnumSet;
25  import java.util.HashMap;
26  import java.util.Map;
27  import java.util.Set;
28  
29  import com.healthmarketscience.jackcess.DataType;
30  import com.healthmarketscience.jackcess.Database;
31  
32  /**
33   * Encapsulates constants describing a specific version of the Access Jet format
34   * @author Tim McCune
35   */
36  public abstract class JetFormat {
37    
38    /** Maximum size of a record minus OLE objects and Memo fields */
39    public static final int MAX_RECORD_SIZE = 1900;  //2kb minus some overhead
40  
41    /** the "unit" size for text fields */
42    public static final short TEXT_FIELD_UNIT_SIZE = 2;
43    /** Maximum size of a text field */
44    public static final short TEXT_FIELD_MAX_LENGTH = 255 * TEXT_FIELD_UNIT_SIZE;
45  
46    public enum CodecType {
47      NONE, JET, MSISAM, OFFICE;
48    }
49    
50    /** Offset in the file that holds the byte describing the Jet format
51        version */
52    private static final int OFFSET_VERSION = 20;
53    /** Version code for Jet version 3 */
54    private static final byte CODE_VERSION_3 = 0x0;
55    /** Version code for Jet version 4 */
56    private static final byte CODE_VERSION_4 = 0x1;
57    /** Version code for Jet version 12.0 */
58    private static final byte CODE_VERSION_12 = 0x2;
59    /** Version code for Jet version 14.0 */
60    private static final byte CODE_VERSION_14 = 0x3;
61    /** Version code for Jet version 16.7 */
62    private static final byte CODE_VERSION_16 = 0x5;
63  
64    /** location of the engine name in the header */
65    static final int OFFSET_ENGINE_NAME = 0x4;
66    /** length of the engine name in the header */
67    static final int LENGTH_ENGINE_NAME = 0xF;
68    /** amount of initial data to be read to determine database type */
69    private static final int HEADER_LENGTH = 21;
70    
71    private final static byte[] MSISAM_ENGINE = new byte[] {
72      'M', 'S', 'I', 'S', 'A', 'M', ' ', 'D', 'a', 't', 'a', 'b', 'a', 's', 'e'
73    };
74  
75    /** mask used to obfuscate the db header */
76    private static final byte[] BASE_HEADER_MASK = new byte[]{
77      (byte)0xB5, (byte)0x6F, (byte)0x03, (byte)0x62, (byte)0x61, (byte)0x08,
78      (byte)0xC2, (byte)0x55, (byte)0xEB, (byte)0xA9, (byte)0x67, (byte)0x72,
79      (byte)0x43, (byte)0x3F, (byte)0x00, (byte)0x9C, (byte)0x7A, (byte)0x9F,
80      (byte)0x90, (byte)0xFF, (byte)0x80, (byte)0x9A, (byte)0x31, (byte)0xC5,
81      (byte)0x79, (byte)0xBA, (byte)0xED, (byte)0x30, (byte)0xBC, (byte)0xDF, 
82      (byte)0xCC, (byte)0x9D, (byte)0x63, (byte)0xD9, (byte)0xE4, (byte)0xC3,
83      (byte)0x7B, (byte)0x42, (byte)0xFB, (byte)0x8A, (byte)0xBC, (byte)0x4E,
84      (byte)0x86, (byte)0xFB, (byte)0xEC, (byte)0x37, (byte)0x5D, (byte)0x44,
85      (byte)0x9C, (byte)0xFA, (byte)0xC6, (byte)0x5E, (byte)0x28, (byte)0xE6, 
86      (byte)0x13, (byte)0xB6, (byte)0x8A, (byte)0x60, (byte)0x54, (byte)0x94,
87      (byte)0x7B, (byte)0x36, (byte)0xF5, (byte)0x72, (byte)0xDF, (byte)0xB1,
88      (byte)0x77, (byte)0xF4, (byte)0x13, (byte)0x43, (byte)0xCF, (byte)0xAF,
89      (byte)0xB1, (byte)0x33, (byte)0x34, (byte)0x61, (byte)0x79, (byte)0x5B,
90      (byte)0x92, (byte)0xB5, (byte)0x7C, (byte)0x2A, (byte)0x05, (byte)0xF1,
91      (byte)0x7C, (byte)0x99, (byte)0x01, (byte)0x1B, (byte)0x98, (byte)0xFD,
92      (byte)0x12, (byte)0x4F, (byte)0x4A, (byte)0x94, (byte)0x6C, (byte)0x3E,
93      (byte)0x60, (byte)0x26, (byte)0x5F, (byte)0x95, (byte)0xF8, (byte)0xD0,
94      (byte)0x89, (byte)0x24, (byte)0x85, (byte)0x67, (byte)0xC6, (byte)0x1F,
95      (byte)0x27, (byte)0x44, (byte)0xD2, (byte)0xEE, (byte)0xCF, (byte)0x65,
96      (byte)0xED, (byte)0xFF, (byte)0x07, (byte)0xC7, (byte)0x46, (byte)0xA1,
97      (byte)0x78, (byte)0x16, (byte)0x0C, (byte)0xED, (byte)0xE9, (byte)0x2D,
98      (byte)0x62, (byte)0xD4};    
99  
100   /** value of the "AccessVersion" property for access 2000 dbs:
101       {@code "08.50"} */
102   private static final String ACCESS_VERSION_2000 = "08.50";
103   /** value of the "AccessVersion" property for access 2002/2003 dbs
104       {@code "09.50"}  */
105   private static final String ACCESS_VERSION_2003 = "09.50";
106 
107   /** known intro bytes for property maps */
108   static final byte[][] PROPERTY_MAP_TYPES = {
109     new byte[]{'M', 'R', '2', '\0'}, // access 2000+
110     new byte[]{'K', 'K', 'D', '\0'}};  // access 97
111 
112   // use nested inner class to avoid problematic static init loops
113   private static final class PossibleFileFormats {
114     private static final Map<String,Database.FileFormat> POSSIBLE_VERSION_3 = 
115       Collections.singletonMap((String)null, Database.FileFormat.V1997);
116 
117     private static final Map<String,Database.FileFormat> POSSIBLE_VERSION_4 = 
118       new HashMap<String,Database.FileFormat>();
119 
120     private static final Map<String,Database.FileFormat> POSSIBLE_VERSION_12 = 
121       Collections.singletonMap((String)null, Database.FileFormat.V2007);
122 
123     private static final Map<String,Database.FileFormat> POSSIBLE_VERSION_14 = 
124       Collections.singletonMap((String)null, Database.FileFormat.V2010);
125 
126     private static final Map<String,Database.FileFormat> POSSIBLE_VERSION_16 = 
127       Collections.singletonMap((String)null, Database.FileFormat.V2016);
128 
129     private static final Map<String,Database.FileFormat> POSSIBLE_VERSION_MSISAM = 
130       Collections.singletonMap((String)null, Database.FileFormat.MSISAM);
131 
132     static {
133       POSSIBLE_VERSION_4.put(ACCESS_VERSION_2000, Database.FileFormat.V2000);
134       POSSIBLE_VERSION_4.put(ACCESS_VERSION_2003, Database.FileFormat.V2003);
135       POSSIBLE_VERSION_4.put(null, Database.FileFormat.GENERIC_JET4);
136     }
137   }
138 
139   /** calculated types supported in version 14 */
140   private static final Set<DataType> V14_CALC_TYPES = 
141     EnumSet.of(DataType.BOOLEAN, DataType.BYTE, DataType.INT, DataType.LONG,
142                DataType.FLOAT, DataType.DOUBLE, DataType.GUID, 
143                DataType.SHORT_DATE_TIME, DataType.MONEY, DataType.NUMERIC, 
144                DataType.TEXT, DataType.MEMO);
145 
146   /** calculated types supported in version 16 */
147   private static final Set<DataType> V16_CALC_TYPES = EnumSet.of(DataType.BIG_INT);
148   static {
149     V16_CALC_TYPES.addAll(V14_CALC_TYPES);
150   }
151 
152   /** the JetFormat constants for the Jet database version "3" */
153   public static final JetFormat VERSION_3 = new Jet3Format();
154   /** the JetFormat constants for the Jet database version "4" */
155   public static final JetFormat VERSION_4 = new Jet4Format();
156   /** the JetFormat constants for the MSISAM database */
157   public static final JetFormat VERSION_MSISAM = new MSISAMFormat();
158   /** the JetFormat constants for the Jet database version "12.0" */
159   public static final JetFormat VERSION_12 = new Jet12Format();
160   /** the JetFormat constants for the Jet database version "14.0" */
161   public static final JetFormat VERSION_14 = new Jet14Format();
162   /** the JetFormat constants for the Jet database version "16.7" */
163   public static final JetFormat VERSION_16 = new Jet16Format();
164 
165   //These constants are populated by this class's constructor.  They can't be
166   //populated by the subclass's constructor because they are final, and Java
167   //doesn't allow this; hence all the abstract defineXXX() methods.
168 
169   /** the name of this format */
170   private final String _name;
171   
172   /** the read/write mode of this format */
173   public final boolean READ_ONLY;
174   
175   /** whether or not we can use indexes in this format */
176   public final boolean INDEXES_SUPPORTED;
177 
178   /** type of page encoding supported */
179   public final CodecType CODEC_TYPE;
180   
181   /** Database page size in bytes */
182   public final int PAGE_SIZE;
183   public final long MAX_DATABASE_SIZE;
184   
185   public final int MAX_ROW_SIZE;
186   public final int DATA_PAGE_INITIAL_FREE_SPACE;
187 
188   public final int OFFSET_MASKED_HEADER;
189   public final byte[] HEADER_MASK;
190   public final int OFFSET_HEADER_DATE;
191   public final int OFFSET_PASSWORD;
192   public final int SIZE_PASSWORD;
193   public final int OFFSET_SORT_ORDER;
194   public final int SIZE_SORT_ORDER;
195   public final int OFFSET_CODE_PAGE;
196   public final int OFFSET_ENCODING_KEY;
197   public final int OFFSET_NEXT_TABLE_DEF_PAGE;
198   public final int OFFSET_NUM_ROWS;
199   public final int OFFSET_NEXT_AUTO_NUMBER;
200   public final int OFFSET_NEXT_COMPLEX_AUTO_NUMBER;
201   public final int OFFSET_TABLE_TYPE;
202   public final int OFFSET_MAX_COLS;
203   public final int OFFSET_NUM_VAR_COLS;
204   public final int OFFSET_NUM_COLS;
205   public final int OFFSET_NUM_INDEX_SLOTS;
206   public final int OFFSET_NUM_INDEXES;
207   public final int OFFSET_OWNED_PAGES;
208   public final int OFFSET_FREE_SPACE_PAGES;
209   public final int OFFSET_INDEX_DEF_BLOCK;
210   
211   public final int SIZE_INDEX_COLUMN_BLOCK;
212   public final int SIZE_INDEX_INFO_BLOCK;
213   
214   public final int OFFSET_COLUMN_TYPE;
215   public final int OFFSET_COLUMN_NUMBER;
216   public final int OFFSET_COLUMN_PRECISION;
217   public final int OFFSET_COLUMN_SCALE;
218   public final int OFFSET_COLUMN_SORT_ORDER;
219   public final int OFFSET_COLUMN_CODE_PAGE;
220   public final int OFFSET_COLUMN_COMPLEX_ID;
221   public final int OFFSET_COLUMN_FLAGS;
222   public final int OFFSET_COLUMN_EXT_FLAGS;
223   public final int OFFSET_COLUMN_LENGTH;
224   public final int OFFSET_COLUMN_VARIABLE_TABLE_INDEX;
225   public final int OFFSET_COLUMN_FIXED_DATA_OFFSET;
226   public final int OFFSET_COLUMN_FIXED_DATA_ROW_OFFSET;
227   
228   public final int OFFSET_TABLE_DEF_LOCATION;
229   
230   public final int OFFSET_ROW_START;
231   public final int OFFSET_USAGE_MAP_START;
232   
233   public final int OFFSET_USAGE_MAP_PAGE_DATA;
234   
235   public final int OFFSET_REFERENCE_MAP_PAGE_NUMBERS;
236   
237   public final int OFFSET_FREE_SPACE;
238   public final int OFFSET_NUM_ROWS_ON_DATA_PAGE;
239   public final int MAX_NUM_ROWS_ON_DATA_PAGE;
240   
241   public final int OFFSET_INDEX_COMPRESSED_BYTE_COUNT;
242   public final int OFFSET_INDEX_ENTRY_MASK;
243   public final int OFFSET_PREV_INDEX_PAGE;
244   public final int OFFSET_NEXT_INDEX_PAGE;
245   public final int OFFSET_CHILD_TAIL_INDEX_PAGE;
246   
247   public final int SIZE_INDEX_DEFINITION;
248   public final int SIZE_COLUMN_HEADER;
249   public final int SIZE_ROW_LOCATION;
250   public final int SIZE_LONG_VALUE_DEF;
251   public final int MAX_INLINE_LONG_VALUE_SIZE;
252   public final int MAX_LONG_VALUE_ROW_SIZE;
253   public final int MAX_COMPRESSED_UNICODE_SIZE;
254   public final int SIZE_TDEF_HEADER;
255   public final int SIZE_TDEF_TRAILER;
256   public final int SIZE_COLUMN_DEF_BLOCK;
257   public final int SIZE_INDEX_ENTRY_MASK;
258   public final int SKIP_BEFORE_INDEX_FLAGS;
259   public final int SKIP_AFTER_INDEX_FLAGS;
260   public final int SKIP_BEFORE_INDEX_SLOT;
261   public final int SKIP_AFTER_INDEX_SLOT;
262   public final int SKIP_BEFORE_INDEX;
263   public final int SIZE_NAME_LENGTH;
264   public final int SIZE_ROW_COLUMN_COUNT;
265   public final int SIZE_ROW_VAR_COL_OFFSET;
266   
267   public final int USAGE_MAP_TABLE_BYTE_LENGTH;
268 
269   public final int MAX_COLUMNS_PER_TABLE;
270   public final int MAX_INDEXES_PER_TABLE;
271   public final int MAX_TABLE_NAME_LENGTH;
272   public final int MAX_COLUMN_NAME_LENGTH;
273   public final int MAX_INDEX_NAME_LENGTH;
274 
275   public final boolean LEGACY_NUMERIC_INDEXES;
276   
277   public final Charset CHARSET;
278   public final ColumnImpl.SortOrder DEFAULT_SORT_ORDER;
279   public final byte[] PROPERTY_MAP_TYPE;
280   
281   /**
282    * @param channel the database file.
283    * @return The Jet Format represented in the passed-in file
284    * @throws IOException if the database file format is unsupported.
285    */
286   public static JetFormat getFormat(FileChannel channel) throws IOException {
287     ByteBuffer buffer = ByteBuffer.allocate(HEADER_LENGTH);
288     int bytesRead = channel.read(buffer, 0L);
289     if(bytesRead < HEADER_LENGTH) {
290       throw new IOException("Empty database file");
291     }
292     buffer.flip();
293     byte version = buffer.get(OFFSET_VERSION);
294     if (version == CODE_VERSION_3) {
295       return VERSION_3;
296     } else if (version == CODE_VERSION_4) {
297       if(ByteUtil.matchesRange(buffer, OFFSET_ENGINE_NAME, MSISAM_ENGINE)) {
298         return VERSION_MSISAM;
299       }
300       return VERSION_4;
301     } else if (version == CODE_VERSION_12) {
302       return VERSION_12;
303     } else if (version == CODE_VERSION_14) {
304       return VERSION_14;
305     } else if (version == CODE_VERSION_16) {
306       return VERSION_16;
307     }
308     throw new IOException("Unsupported " +
309                           ((version < CODE_VERSION_3) ? "older" : "newer") +
310                           " version: " + version);
311   }
312   
313   private JetFormat(String name) {
314     _name = name;
315     
316     READ_ONLY = defineReadOnly();
317     INDEXES_SUPPORTED = defineIndexesSupported();
318     CODEC_TYPE = defineCodecType();
319     
320     PAGE_SIZE = definePageSize();
321     MAX_DATABASE_SIZE = defineMaxDatabaseSize();
322     
323     MAX_ROW_SIZE = defineMaxRowSize();
324     DATA_PAGE_INITIAL_FREE_SPACE = defineDataPageInitialFreeSpace();
325     
326     OFFSET_MASKED_HEADER = defineOffsetMaskedHeader();
327     HEADER_MASK = defineHeaderMask();
328     OFFSET_HEADER_DATE = defineOffsetHeaderDate();
329     OFFSET_PASSWORD = defineOffsetPassword();
330     SIZE_PASSWORD = defineSizePassword();
331     OFFSET_SORT_ORDER = defineOffsetSortOrder();
332     SIZE_SORT_ORDER = defineSizeSortOrder();
333     OFFSET_CODE_PAGE = defineOffsetCodePage();
334     OFFSET_ENCODING_KEY = defineOffsetEncodingKey();
335     OFFSET_NEXT_TABLE_DEF_PAGE = defineOffsetNextTableDefPage();
336     OFFSET_NUM_ROWS = defineOffsetNumRows();
337     OFFSET_NEXT_AUTO_NUMBER = defineOffsetNextAutoNumber();
338     OFFSET_NEXT_COMPLEX_AUTO_NUMBER = defineOffsetNextComplexAutoNumber();
339     OFFSET_TABLE_TYPE = defineOffsetTableType();
340     OFFSET_MAX_COLS = defineOffsetMaxCols();
341     OFFSET_NUM_VAR_COLS = defineOffsetNumVarCols();
342     OFFSET_NUM_COLS = defineOffsetNumCols();
343     OFFSET_NUM_INDEX_SLOTS = defineOffsetNumIndexSlots();
344     OFFSET_NUM_INDEXES = defineOffsetNumIndexes();
345     OFFSET_OWNED_PAGES = defineOffsetOwnedPages();
346     OFFSET_FREE_SPACE_PAGES = defineOffsetFreeSpacePages();
347     OFFSET_INDEX_DEF_BLOCK = defineOffsetIndexDefBlock();
348     
349     SIZE_INDEX_COLUMN_BLOCK = defineSizeIndexColumnBlock();
350     SIZE_INDEX_INFO_BLOCK = defineSizeIndexInfoBlock();
351     
352     OFFSET_COLUMN_TYPE = defineOffsetColumnType();
353     OFFSET_COLUMN_NUMBER = defineOffsetColumnNumber();
354     OFFSET_COLUMN_PRECISION = defineOffsetColumnPrecision();
355     OFFSET_COLUMN_SCALE = defineOffsetColumnScale();
356     OFFSET_COLUMN_SORT_ORDER = defineOffsetColumnSortOrder();
357     OFFSET_COLUMN_CODE_PAGE = defineOffsetColumnCodePage();
358     OFFSET_COLUMN_COMPLEX_ID = defineOffsetColumnComplexId();
359     OFFSET_COLUMN_FLAGS = defineOffsetColumnFlags();
360     OFFSET_COLUMN_EXT_FLAGS = defineOffsetColumnExtFlags();
361     OFFSET_COLUMN_LENGTH = defineOffsetColumnLength();
362     OFFSET_COLUMN_VARIABLE_TABLE_INDEX = defineOffsetColumnVariableTableIndex();
363     OFFSET_COLUMN_FIXED_DATA_OFFSET = defineOffsetColumnFixedDataOffset();
364     OFFSET_COLUMN_FIXED_DATA_ROW_OFFSET = defineOffsetColumnFixedDataRowOffset();
365     
366     OFFSET_TABLE_DEF_LOCATION = defineOffsetTableDefLocation();
367     
368     OFFSET_ROW_START = defineOffsetRowStart();
369     OFFSET_USAGE_MAP_START = defineOffsetUsageMapStart();
370     
371     OFFSET_USAGE_MAP_PAGE_DATA = defineOffsetUsageMapPageData();
372     
373     OFFSET_REFERENCE_MAP_PAGE_NUMBERS = defineOffsetReferenceMapPageNumbers();
374     
375     OFFSET_FREE_SPACE = defineOffsetFreeSpace();
376     OFFSET_NUM_ROWS_ON_DATA_PAGE = defineOffsetNumRowsOnDataPage();
377     MAX_NUM_ROWS_ON_DATA_PAGE = defineMaxNumRowsOnDataPage();
378     
379     OFFSET_INDEX_COMPRESSED_BYTE_COUNT = defineOffsetIndexCompressedByteCount();
380     OFFSET_INDEX_ENTRY_MASK = defineOffsetIndexEntryMask();
381     OFFSET_PREV_INDEX_PAGE = defineOffsetPrevIndexPage();
382     OFFSET_NEXT_INDEX_PAGE = defineOffsetNextIndexPage();
383     OFFSET_CHILD_TAIL_INDEX_PAGE = defineOffsetChildTailIndexPage();
384     
385     SIZE_INDEX_DEFINITION = defineSizeIndexDefinition();
386     SIZE_COLUMN_HEADER = defineSizeColumnHeader();
387     SIZE_ROW_LOCATION = defineSizeRowLocation();
388     SIZE_LONG_VALUE_DEF = defineSizeLongValueDef();
389     MAX_INLINE_LONG_VALUE_SIZE = defineMaxInlineLongValueSize();
390     MAX_LONG_VALUE_ROW_SIZE = defineMaxLongValueRowSize();
391     MAX_COMPRESSED_UNICODE_SIZE = defineMaxCompressedUnicodeSize();
392     SIZE_TDEF_HEADER = defineSizeTdefHeader();
393     SIZE_TDEF_TRAILER = defineSizeTdefTrailer();
394     SIZE_COLUMN_DEF_BLOCK = defineSizeColumnDefBlock();
395     SIZE_INDEX_ENTRY_MASK = defineSizeIndexEntryMask();
396     SKIP_BEFORE_INDEX_FLAGS = defineSkipBeforeIndexFlags();
397     SKIP_AFTER_INDEX_FLAGS = defineSkipAfterIndexFlags();
398     SKIP_BEFORE_INDEX_SLOT = defineSkipBeforeIndexSlot();
399     SKIP_AFTER_INDEX_SLOT = defineSkipAfterIndexSlot();
400     SKIP_BEFORE_INDEX = defineSkipBeforeIndex();
401     SIZE_NAME_LENGTH = defineSizeNameLength();
402     SIZE_ROW_COLUMN_COUNT = defineSizeRowColumnCount();
403     SIZE_ROW_VAR_COL_OFFSET = defineSizeRowVarColOffset();
404 
405     USAGE_MAP_TABLE_BYTE_LENGTH = defineUsageMapTableByteLength();
406 
407     MAX_COLUMNS_PER_TABLE = defineMaxColumnsPerTable();
408     MAX_INDEXES_PER_TABLE = defineMaxIndexesPerTable();
409     MAX_TABLE_NAME_LENGTH = defineMaxTableNameLength();
410     MAX_COLUMN_NAME_LENGTH = defineMaxColumnNameLength();
411     MAX_INDEX_NAME_LENGTH = defineMaxIndexNameLength();
412     
413     LEGACY_NUMERIC_INDEXES = defineLegacyNumericIndexes();
414     
415     CHARSET = defineCharset();
416     DEFAULT_SORT_ORDER = defineDefaultSortOrder();
417     PROPERTY_MAP_TYPE = definePropMapType();
418   }
419   
420   protected abstract boolean defineReadOnly();
421   protected abstract boolean defineIndexesSupported();
422   protected abstract CodecType defineCodecType();
423   
424   protected abstract int definePageSize();
425   protected abstract long defineMaxDatabaseSize();
426   
427   protected abstract int defineMaxRowSize();
428   protected abstract int defineDataPageInitialFreeSpace();
429   
430   protected abstract int defineOffsetMaskedHeader();
431   protected abstract byte[] defineHeaderMask();
432   protected abstract int defineOffsetHeaderDate();
433   protected abstract int defineOffsetPassword();
434   protected abstract int defineSizePassword();
435   protected abstract int defineOffsetSortOrder();
436   protected abstract int defineSizeSortOrder();
437   protected abstract int defineOffsetCodePage();
438   protected abstract int defineOffsetEncodingKey();
439   protected abstract int defineOffsetNextTableDefPage();
440   protected abstract int defineOffsetNumRows();
441   protected abstract int defineOffsetNextAutoNumber();
442   protected abstract int defineOffsetNextComplexAutoNumber();
443   protected abstract int defineOffsetTableType();
444   protected abstract int defineOffsetMaxCols();
445   protected abstract int defineOffsetNumVarCols();
446   protected abstract int defineOffsetNumCols();
447   protected abstract int defineOffsetNumIndexSlots();
448   protected abstract int defineOffsetNumIndexes();
449   protected abstract int defineOffsetOwnedPages();
450   protected abstract int defineOffsetFreeSpacePages();
451   protected abstract int defineOffsetIndexDefBlock();
452   
453   protected abstract int defineSizeIndexColumnBlock();
454   protected abstract int defineSizeIndexInfoBlock();
455   
456   protected abstract int defineOffsetColumnType();
457   protected abstract int defineOffsetColumnNumber();
458   protected abstract int defineOffsetColumnPrecision();
459   protected abstract int defineOffsetColumnScale();
460   protected abstract int defineOffsetColumnSortOrder();
461   protected abstract int defineOffsetColumnCodePage();
462   protected abstract int defineOffsetColumnComplexId();
463   protected abstract int defineOffsetColumnFlags();
464   protected abstract int defineOffsetColumnExtFlags();
465   protected abstract int defineOffsetColumnLength();
466   protected abstract int defineOffsetColumnVariableTableIndex();
467   protected abstract int defineOffsetColumnFixedDataOffset();
468   protected abstract int defineOffsetColumnFixedDataRowOffset();
469   
470   protected abstract int defineOffsetTableDefLocation();
471   
472   protected abstract int defineOffsetRowStart();
473   protected abstract int defineOffsetUsageMapStart();
474   
475   protected abstract int defineOffsetUsageMapPageData();
476   
477   protected abstract int defineOffsetReferenceMapPageNumbers();
478   
479   protected abstract int defineOffsetFreeSpace();
480   protected abstract int defineOffsetNumRowsOnDataPage();
481   protected abstract int defineMaxNumRowsOnDataPage();
482   
483   protected abstract int defineOffsetIndexCompressedByteCount();
484   protected abstract int defineOffsetIndexEntryMask();
485   protected abstract int defineOffsetPrevIndexPage();
486   protected abstract int defineOffsetNextIndexPage();
487   protected abstract int defineOffsetChildTailIndexPage();
488   
489   protected abstract int defineSizeIndexDefinition();
490   protected abstract int defineSizeColumnHeader();
491   protected abstract int defineSizeRowLocation();
492   protected abstract int defineSizeLongValueDef();
493   protected abstract int defineMaxInlineLongValueSize();
494   protected abstract int defineMaxLongValueRowSize();
495   protected abstract int defineMaxCompressedUnicodeSize();
496   protected abstract int defineSizeTdefHeader();
497   protected abstract int defineSizeTdefTrailer();
498   protected abstract int defineSizeColumnDefBlock();
499   protected abstract int defineSizeIndexEntryMask();
500   protected abstract int defineSkipBeforeIndexFlags();
501   protected abstract int defineSkipAfterIndexFlags();
502   protected abstract int defineSkipBeforeIndexSlot();
503   protected abstract int defineSkipAfterIndexSlot();
504   protected abstract int defineSkipBeforeIndex();
505   protected abstract int defineSizeNameLength();
506   protected abstract int defineSizeRowColumnCount();
507   protected abstract int defineSizeRowVarColOffset();
508 
509   protected abstract int defineUsageMapTableByteLength();
510 
511   protected abstract int defineMaxColumnsPerTable();
512   protected abstract int defineMaxIndexesPerTable();
513   protected abstract int defineMaxTableNameLength();
514   protected abstract int defineMaxColumnNameLength();
515   protected abstract int defineMaxIndexNameLength();
516   
517   protected abstract Charset defineCharset();
518   protected abstract ColumnImpl.SortOrder defineDefaultSortOrder();
519   protected abstract byte[] definePropMapType();
520 
521   protected abstract boolean defineLegacyNumericIndexes();
522 
523   protected abstract Map<String,Database.FileFormat> getPossibleFileFormats();
524 
525   public abstract boolean isSupportedDataType(DataType type);
526 
527   public abstract boolean isSupportedCalculatedDataType(DataType type);
528 
529   @Override
530   public String toString() {
531     return _name;
532   }
533   
534   private static class Jet3Format extends JetFormat {
535 
536     private Jet3Format() {
537       super("VERSION_3");
538     }
539 
540     @Override
541     protected boolean defineReadOnly() { return true; }
542 	    
543     @Override
544     protected boolean defineIndexesSupported() { return false; }
545 
546     @Override
547     protected CodecType defineCodecType() { 
548       return CodecType.JET; 
549     }
550 	    
551     @Override
552     protected int definePageSize() { return 2048; }
553 	    
554     @Override
555     protected long defineMaxDatabaseSize() {
556       return (1L * 1024L * 1024L * 1024L);
557     }
558 	    
559     @Override
560     protected int defineMaxRowSize() { return 2012; }
561     @Override
562     protected int defineDataPageInitialFreeSpace() { return PAGE_SIZE - 14; }
563 	    
564     @Override
565     protected int defineOffsetMaskedHeader() { return 24; }
566     @Override
567     protected byte[] defineHeaderMask() { 
568       return ByteUtil.copyOf(BASE_HEADER_MASK, BASE_HEADER_MASK.length - 2); 
569     }
570     @Override
571     protected int defineOffsetHeaderDate() { return -1; }
572     @Override
573     protected int defineOffsetPassword() { return 66; }
574     @Override
575     protected int defineSizePassword() { return 20; }
576     @Override
577     protected int defineOffsetSortOrder() { return 58; }
578     @Override
579     protected int defineSizeSortOrder() { return 2; }
580     @Override
581     protected int defineOffsetCodePage() { return 60; }
582     @Override
583     protected int defineOffsetEncodingKey() { return 62; }
584     @Override
585     protected int defineOffsetNextTableDefPage() { return 4; }
586     @Override
587     protected int defineOffsetNumRows() { return 12; }
588     @Override
589     protected int defineOffsetNextAutoNumber() { return 20; }
590     @Override
591     protected int defineOffsetNextComplexAutoNumber() { return -1; }
592     @Override
593     protected int defineOffsetTableType() { return 20; }
594     @Override
595     protected int defineOffsetMaxCols() { return 21; }
596     @Override
597     protected int defineOffsetNumVarCols() { return 23; }
598     @Override
599     protected int defineOffsetNumCols() { return 25; }
600     @Override
601     protected int defineOffsetNumIndexSlots() { return 27; }
602     @Override
603     protected int defineOffsetNumIndexes() { return 31; }
604     @Override
605     protected int defineOffsetOwnedPages() { return 35; }
606     @Override
607     protected int defineOffsetFreeSpacePages() { return 39; }
608     @Override
609     protected int defineOffsetIndexDefBlock() { return 43; }
610 
611     @Override
612     protected int defineSizeIndexColumnBlock() { return 39; }
613     @Override
614     protected int defineSizeIndexInfoBlock() { return 20; }
615 	    
616     @Override
617     protected int defineOffsetColumnType() { return 0; }
618     @Override
619     protected int defineOffsetColumnNumber() { return 1; }
620     @Override
621     protected int defineOffsetColumnPrecision() { return 11; }
622     @Override
623     protected int defineOffsetColumnScale() { return 12; }
624     @Override
625     protected int defineOffsetColumnSortOrder() { return 9; }
626     @Override
627     protected int defineOffsetColumnCodePage() { return 11; }
628     @Override
629     protected int defineOffsetColumnComplexId() { return -1; }
630     @Override
631     protected int defineOffsetColumnFlags() { return 13; }
632     @Override
633     protected int defineOffsetColumnExtFlags() { return -1; }
634     @Override
635     protected int defineOffsetColumnLength() { return 16; }
636     @Override
637     protected int defineOffsetColumnVariableTableIndex() { return 3; }
638     @Override
639     protected int defineOffsetColumnFixedDataOffset() { return 14; }
640     @Override
641     protected int defineOffsetColumnFixedDataRowOffset() { return 1; }
642 	  
643     @Override
644     protected int defineOffsetTableDefLocation() { return 4; }
645 	    
646     @Override
647     protected int defineOffsetRowStart() { return 10; }
648     @Override
649     protected int defineOffsetUsageMapStart() { return 5; }
650 	    
651     @Override
652     protected int defineOffsetUsageMapPageData() { return 4; }
653 	    
654     @Override
655     protected int defineOffsetReferenceMapPageNumbers() { return 1; }
656 	    
657     @Override
658     protected int defineOffsetFreeSpace() { return 2; }
659     @Override
660     protected int defineOffsetNumRowsOnDataPage() { return 8; }
661     @Override
662     protected int defineMaxNumRowsOnDataPage() { return 255; }
663 	    
664     @Override
665     protected int defineOffsetIndexCompressedByteCount() { return 20; }
666     @Override
667     protected int defineOffsetIndexEntryMask() { return 22; }
668     @Override
669     protected int defineOffsetPrevIndexPage() { return 8; }
670     @Override
671     protected int defineOffsetNextIndexPage() { return 12; }
672     @Override
673     protected int defineOffsetChildTailIndexPage() { return 16; }
674 	    
675     @Override
676     protected int defineSizeIndexDefinition() { return 8; }
677     @Override
678     protected int defineSizeColumnHeader() { return 18; }
679     @Override
680     protected int defineSizeRowLocation() { return 2; }
681     @Override
682     protected int defineSizeLongValueDef() { return 12; }
683     @Override
684     protected int defineMaxInlineLongValueSize() { return 64; }
685     @Override
686     protected int defineMaxLongValueRowSize() { return 2032; }
687     @Override
688     protected int defineMaxCompressedUnicodeSize() { return 1024; }
689     @Override
690     protected int defineSizeTdefHeader() { return 43; }
691     @Override
692     protected int defineSizeTdefTrailer() { return 2; }
693     @Override
694     protected int defineSizeColumnDefBlock() { return 25; }
695     @Override
696     protected int defineSizeIndexEntryMask() { return 226; }
697     @Override
698     protected int defineSkipBeforeIndexFlags() { return 0; }
699     @Override
700     protected int defineSkipAfterIndexFlags() { return 0; }
701     @Override
702     protected int defineSkipBeforeIndexSlot() { return 0; }
703     @Override
704     protected int defineSkipAfterIndexSlot() { return 0; }
705     @Override
706     protected int defineSkipBeforeIndex() { return 0; }
707     @Override
708     protected int defineSizeNameLength() { return 1; }
709     @Override
710     protected int defineSizeRowColumnCount() { return 1; }
711     @Override
712     protected int defineSizeRowVarColOffset() { return 1; }
713 	    
714     @Override
715     protected int defineUsageMapTableByteLength() { return 128; }
716 	      
717     @Override
718     protected int defineMaxColumnsPerTable() { return 255; }
719 	      
720     @Override
721     protected int defineMaxIndexesPerTable() { return 32; }
722 	      
723     @Override
724     protected int defineMaxTableNameLength() { return 64; }
725 	      
726     @Override
727     protected int defineMaxColumnNameLength() { return 64; }
728 	      
729     @Override
730     protected int defineMaxIndexNameLength() { return 64; }
731 	      
732     @Override
733     protected boolean defineLegacyNumericIndexes() { return true; }
734 
735     @Override
736     protected Charset defineCharset() { return Charset.defaultCharset(); }
737 
738     @Override
739     protected ColumnImpl.SortOrder defineDefaultSortOrder() {
740       return ColumnImpl.GENERAL_LEGACY_SORT_ORDER;
741     }
742 
743     @Override
744     protected byte[] definePropMapType() {
745       return PROPERTY_MAP_TYPES[1];
746     }
747     
748     @Override
749     protected Map<String,Database.FileFormat> getPossibleFileFormats()
750     {
751       return PossibleFileFormats.POSSIBLE_VERSION_3;
752     }
753 
754     @Override
755     public boolean isSupportedDataType(DataType type) {
756       return ((type != DataType.COMPLEX_TYPE) &&
757               (type != DataType.BIG_INT));
758     }
759 
760     @Override
761     public boolean isSupportedCalculatedDataType(DataType type) {
762       return false;
763     }
764   }
765   
766   private static class Jet4Format extends JetFormat {
767 
768     private Jet4Format() {
769       this("VERSION_4");
770     }
771 
772     private Jet4Format(String name) {
773       super(name);
774     }
775 
776     @Override
777     protected boolean defineReadOnly() { return false; }
778     
779     @Override
780     protected boolean defineIndexesSupported() { return true; }
781 	    
782     @Override
783     protected CodecType defineCodecType() { 
784       return CodecType.JET; 
785     }
786 
787     @Override
788     protected int definePageSize() { return 4096; }
789     
790     @Override
791     protected long defineMaxDatabaseSize() {
792       return (2L * 1024L * 1024L * 1024L);
793     }
794     
795     @Override
796     protected int defineMaxRowSize() { return 4060; }
797     @Override
798     protected int defineDataPageInitialFreeSpace() { return PAGE_SIZE - 14; }
799     
800     @Override
801     protected int defineOffsetMaskedHeader() { return 24; }
802     @Override
803     protected byte[] defineHeaderMask() { return BASE_HEADER_MASK; }
804     @Override
805     protected int defineOffsetHeaderDate() { return 114; }
806     @Override
807     protected int defineOffsetPassword() { return 66; }
808     @Override
809     protected int defineSizePassword() { return 40; }
810     @Override
811     protected int defineOffsetSortOrder() { return 110; }
812     @Override
813     protected int defineSizeSortOrder() { return 4; }
814     @Override
815     protected int defineOffsetCodePage() { return 60; }
816     @Override
817     protected int defineOffsetEncodingKey() { return 62; }
818     @Override
819     protected int defineOffsetNextTableDefPage() { return 4; }
820     @Override
821     protected int defineOffsetNumRows() { return 16; }
822     @Override
823     protected int defineOffsetNextAutoNumber() { return 20; }
824     @Override
825     protected int defineOffsetNextComplexAutoNumber() { return -1; }
826     @Override
827     protected int defineOffsetTableType() { return 40; }
828     @Override
829     protected int defineOffsetMaxCols() { return 41; }
830     @Override
831     protected int defineOffsetNumVarCols() { return 43; }
832     @Override
833     protected int defineOffsetNumCols() { return 45; }
834     @Override
835     protected int defineOffsetNumIndexSlots() { return 47; }
836     @Override
837     protected int defineOffsetNumIndexes() { return 51; }
838     @Override
839     protected int defineOffsetOwnedPages() { return 55; }
840     @Override
841     protected int defineOffsetFreeSpacePages() { return 59; }
842     @Override
843     protected int defineOffsetIndexDefBlock() { return 63; }
844 
845     @Override
846     protected int defineSizeIndexColumnBlock() { return 52; }
847     @Override
848     protected int defineSizeIndexInfoBlock() { return 28; }
849     
850     @Override
851     protected int defineOffsetColumnType() { return 0; }
852     @Override
853     protected int defineOffsetColumnNumber() { return 5; }
854     @Override
855     protected int defineOffsetColumnPrecision() { return 11; }
856     @Override
857     protected int defineOffsetColumnScale() { return 12; }
858     @Override
859     protected int defineOffsetColumnSortOrder() { return 11; }
860     @Override
861     protected int defineOffsetColumnCodePage() { return -1; }
862     @Override
863     protected int defineOffsetColumnComplexId() { return -1; }
864     @Override
865     protected int defineOffsetColumnFlags() { return 15; }
866     @Override
867     protected int defineOffsetColumnExtFlags() { return 16; }
868     @Override
869     protected int defineOffsetColumnLength() { return 23; }
870     @Override
871     protected int defineOffsetColumnVariableTableIndex() { return 7; }
872     @Override
873     protected int defineOffsetColumnFixedDataOffset() { return 21; }
874     @Override
875     protected int defineOffsetColumnFixedDataRowOffset() { return 2; }
876   
877     @Override
878     protected int defineOffsetTableDefLocation() { return 4; }
879     
880     @Override
881     protected int defineOffsetRowStart() { return 14; }
882     @Override
883     protected int defineOffsetUsageMapStart() { return 5; }
884     
885     @Override
886     protected int defineOffsetUsageMapPageData() { return 4; }
887     
888     @Override
889     protected int defineOffsetReferenceMapPageNumbers() { return 1; }
890     
891     @Override
892     protected int defineOffsetFreeSpace() { return 2; }
893     @Override
894     protected int defineOffsetNumRowsOnDataPage() { return 12; }
895     @Override
896     protected int defineMaxNumRowsOnDataPage() { return 255; }
897     
898     @Override
899     protected int defineOffsetIndexCompressedByteCount() { return 24; }
900     @Override
901     protected int defineOffsetIndexEntryMask() { return 27; }
902     @Override
903     protected int defineOffsetPrevIndexPage() { return 12; }
904     @Override
905     protected int defineOffsetNextIndexPage() { return 16; }
906     @Override
907     protected int defineOffsetChildTailIndexPage() { return 20; }
908     
909     @Override
910     protected int defineSizeIndexDefinition() { return 12; }
911     @Override
912     protected int defineSizeColumnHeader() { return 25; }
913     @Override
914     protected int defineSizeRowLocation() { return 2; }
915     @Override
916     protected int defineSizeLongValueDef() { return 12; }
917     @Override
918     protected int defineMaxInlineLongValueSize() { return 64; }
919     @Override
920     protected int defineMaxLongValueRowSize() { return 4076; }
921     @Override
922     protected int defineMaxCompressedUnicodeSize() { return 1024; }
923     @Override
924     protected int defineSizeTdefHeader() { return 63; }
925     @Override
926     protected int defineSizeTdefTrailer() { return 2; }
927     @Override
928     protected int defineSizeColumnDefBlock() { return 25; }
929     @Override
930     protected int defineSizeIndexEntryMask() { return 453; }
931     @Override
932     protected int defineSkipBeforeIndexFlags() { return 4; }
933     @Override
934     protected int defineSkipAfterIndexFlags() { return 5; }
935     @Override
936     protected int defineSkipBeforeIndexSlot() { return 4; }
937     @Override
938     protected int defineSkipAfterIndexSlot() { return 4; }
939     @Override
940     protected int defineSkipBeforeIndex() { return 4; }
941     @Override
942     protected int defineSizeNameLength() { return 2; }
943     @Override
944     protected int defineSizeRowColumnCount() { return 2; }
945     @Override
946     protected int defineSizeRowVarColOffset() { return 2; }
947     
948     @Override
949     protected int defineUsageMapTableByteLength() { return 64; }
950       
951     @Override
952     protected int defineMaxColumnsPerTable() { return 255; }
953 	      
954     @Override
955     protected int defineMaxIndexesPerTable() { return 32; }
956       
957     @Override
958     protected int defineMaxTableNameLength() { return 64; }
959       
960     @Override
961     protected int defineMaxColumnNameLength() { return 64; }
962       
963     @Override
964     protected int defineMaxIndexNameLength() { return 64; }
965       
966     @Override
967     protected boolean defineLegacyNumericIndexes() { return true; }
968 
969     @Override
970     protected Charset defineCharset() { return Charset.forName("UTF-16LE"); }
971 
972     @Override
973     protected ColumnImpl.SortOrder defineDefaultSortOrder() {
974       return ColumnImpl.GENERAL_LEGACY_SORT_ORDER;
975     }
976 
977     @Override
978     protected byte[] definePropMapType() {
979       return PROPERTY_MAP_TYPES[0];
980     }
981 
982     @Override
983     protected Map<String,Database.FileFormat> getPossibleFileFormats()
984     {
985       return PossibleFileFormats.POSSIBLE_VERSION_4;
986     }
987 
988     @Override
989     public boolean isSupportedDataType(DataType type) {
990       return ((type != DataType.COMPLEX_TYPE) &&
991               (type != DataType.BIG_INT));
992     }
993 
994     @Override
995     public boolean isSupportedCalculatedDataType(DataType type) {
996       return false;
997     }
998   }
999   
1000   private static final class MSISAMFormat extends Jet4Format {
1001     private MSISAMFormat() {
1002       super("MSISAM");
1003     }
1004 
1005     @Override
1006     protected CodecType defineCodecType() { 
1007       return CodecType.MSISAM; 
1008     }
1009 
1010     @Override
1011     protected Map<String,Database.FileFormat> getPossibleFileFormats()
1012     {
1013       return PossibleFileFormats.POSSIBLE_VERSION_MSISAM;
1014     }
1015   }
1016 
1017   private static class Jet12Format extends Jet4Format {
1018     private Jet12Format() {
1019       super("VERSION_12");
1020     }
1021 
1022     private Jet12Format(String name) {
1023       super(name);
1024     }
1025 
1026     @Override
1027     protected CodecType defineCodecType() { 
1028       return CodecType.OFFICE; 
1029     }
1030 
1031     @Override
1032     protected boolean defineLegacyNumericIndexes() { return false; }
1033 
1034     @Override
1035     protected Map<String,Database.FileFormat> getPossibleFileFormats() {
1036       return PossibleFileFormats.POSSIBLE_VERSION_12;
1037     }
1038 
1039     @Override
1040     protected int defineOffsetNextComplexAutoNumber() { return 28; }
1041 
1042     @Override
1043     protected int defineOffsetColumnComplexId() { return 11; }
1044     
1045     @Override
1046     public boolean isSupportedDataType(DataType type) {
1047       return (type != DataType.BIG_INT);
1048     }
1049 
1050     @Override
1051     public boolean isSupportedCalculatedDataType(DataType type) {
1052       return false;
1053     }
1054   }
1055 
1056   private static class Jet14Format extends Jet12Format {
1057     private Jet14Format() {
1058       super("VERSION_14");
1059     }
1060 
1061     private Jet14Format(String name) {
1062       super(name);
1063     }
1064 
1065     @Override
1066     protected ColumnImpl.SortOrder defineDefaultSortOrder() {
1067       return ColumnImpl.GENERAL_SORT_ORDER;
1068     }
1069 
1070     @Override
1071     protected byte[] definePropMapType() {
1072       return PROPERTY_MAP_TYPES[0];
1073     }
1074 
1075     @Override
1076     protected Map<String,Database.FileFormat> getPossibleFileFormats() {
1077       return PossibleFileFormats.POSSIBLE_VERSION_14;
1078     }
1079 
1080     @Override
1081     public boolean isSupportedCalculatedDataType(DataType type) {
1082       return V14_CALC_TYPES.contains(type);
1083     }
1084   }
1085 
1086   private static final class Jet16Format extends Jet14Format {
1087 
1088     private Jet16Format() {
1089       super("VERSION_16");
1090     }
1091     
1092     @Override
1093     public boolean isSupportedDataType(DataType type) {
1094       return true;
1095     }
1096 
1097     @Override
1098     protected Map<String,Database.FileFormat> getPossibleFileFormats() {
1099       return PossibleFileFormats.POSSIBLE_VERSION_16;
1100     }
1101 
1102     @Override
1103     public boolean isSupportedCalculatedDataType(DataType type) {
1104       return V16_CALC_TYPES.contains(type);
1105     }
1106   }
1107 
1108 }