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