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