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_COMPRESSED_BYTE_COUNT;
310   public final int SIZE_INDEX_ENTRY_MASK;
311   public final int SKIP_BEFORE_INDEX_FLAGS;
312   public final int SKIP_AFTER_INDEX_FLAGS;
313   public final int SKIP_BEFORE_INDEX_SLOT;
314   public final int SKIP_AFTER_INDEX_SLOT;
315   public final int SKIP_BEFORE_INDEX;
316   public final int SIZE_NAME_LENGTH;
317   public final int SIZE_ROW_COLUMN_COUNT;
318   public final int SIZE_ROW_VAR_COL_OFFSET;
319 
320   public final int USAGE_MAP_TABLE_BYTE_LENGTH;
321 
322   public final int MAX_COLUMNS_PER_TABLE;
323   public final int MAX_INDEXES_PER_TABLE;
324   public final int MAX_TABLE_NAME_LENGTH;
325   public final int MAX_COLUMN_NAME_LENGTH;
326   public final int MAX_INDEX_NAME_LENGTH;
327 
328   public final boolean LEGACY_NUMERIC_INDEXES;
329 
330   public final Charset CHARSET;
331   /** whether the code page in the database header names the charset for
332       text.  A format which stores text as unicode ignores it. */
333   public final boolean CODE_PAGE_CHARSET;
334   public final ColumnImpl.SortOrder DEFAULT_SORT_ORDER;
335   public final byte[] PROPERTY_MAP_TYPE;
336   public final int SIZE_TEXT_FIELD_UNIT;
337 
338   /**
339    * @param channel the database file.
340    * @return The Jet Format represented in the passed-in file
341    * @throws IOException if the database file format is unsupported.
342    */
343   public static JetFormat getFormat(FileChannel channel) throws IOException {
344     ByteBuffer buffer = ByteBuffer.allocate(HEADER_LENGTH);
345     int bytesRead = channel.read(buffer, 0L);
346     if(bytesRead < HEADER_LENGTH) {
347       throw new IOException("Empty database file");
348     }
349     buffer.flip();
350     int version = ByteUtil.getUnsignedByte(buffer, OFFSET_VERSION);
351     if (version == CODE_VERSION_3) {
352       return VERSION_3;
353     } else if (version == CODE_VERSION_4) {
354       if(ByteUtil.matchesRange(buffer, OFFSET_ENGINE_NAME, MSISAM_ENGINE)) {
355         return VERSION_MSISAM;
356       }
357       return VERSION_4;
358     } else if (version == CODE_VERSION_2007) {
359       return VERSION_2007;
360     } else if (version == CODE_VERSION_2010) {
361       return VERSION_2010;
362     } else if (version == CODE_VERSION_2016) {
363       return VERSION_2016;
364     } else if (version == CODE_VERSION_2019) {
365       return VERSION_2019;
366     }
367     throw new IOException("Unsupported version: " + version);
368   }
369 
370   private JetFormat(String name) {
371     _name = name;
372 
373     READ_ONLY = defineReadOnly();
374     INDEXES_SUPPORTED = defineIndexesSupported();
375     CODEC_TYPE = defineCodecType();
376 
377     PAGE_SIZE = definePageSize();
378     MAX_DATABASE_SIZE = defineMaxDatabaseSize();
379 
380     MAX_ROW_SIZE = defineMaxRowSize();
381     DATA_PAGE_INITIAL_FREE_SPACE = defineDataPageInitialFreeSpace();
382 
383     OFFSET_MASKED_HEADER = defineOffsetMaskedHeader();
384     HEADER_MASK = defineHeaderMask();
385     OFFSET_HEADER_DATE = defineOffsetHeaderDate();
386     OFFSET_PASSWORD = defineOffsetPassword();
387     SIZE_PASSWORD = defineSizePassword();
388     OFFSET_SORT_ORDER = defineOffsetSortOrder();
389     SIZE_SORT_ORDER = defineSizeSortOrder();
390     OFFSET_CODE_PAGE = defineOffsetCodePage();
391     OFFSET_ENCODING_KEY = defineOffsetEncodingKey();
392     OFFSET_NEXT_TABLE_DEF_PAGE = defineOffsetNextTableDefPage();
393     OFFSET_NUM_ROWS = defineOffsetNumRows();
394     OFFSET_NEXT_AUTO_NUMBER = defineOffsetNextAutoNumber();
395     OFFSET_NEXT_COMPLEX_AUTO_NUMBER = defineOffsetNextComplexAutoNumber();
396     OFFSET_TABLE_TYPE = defineOffsetTableType();
397     OFFSET_MAX_COLS = defineOffsetMaxCols();
398     OFFSET_NUM_VAR_COLS = defineOffsetNumVarCols();
399     OFFSET_NUM_COLS = defineOffsetNumCols();
400     OFFSET_NUM_INDEX_SLOTS = defineOffsetNumIndexSlots();
401     OFFSET_NUM_INDEXES = defineOffsetNumIndexes();
402     OFFSET_OWNED_PAGES = defineOffsetOwnedPages();
403     OFFSET_FREE_SPACE_PAGES = defineOffsetFreeSpacePages();
404     OFFSET_INDEX_DEF_BLOCK = defineOffsetIndexDefBlock();
405 
406     SIZE_INDEX_COLUMN_BLOCK = defineSizeIndexColumnBlock();
407     SIZE_INDEX_INFO_BLOCK = defineSizeIndexInfoBlock();
408 
409     OFFSET_COLUMN_TYPE = defineOffsetColumnType();
410     OFFSET_COLUMN_NUMBER = defineOffsetColumnNumber();
411     OFFSET_COLUMN_ID = defineOffsetColumnId();
412     OFFSET_COLUMN_PRECISION = defineOffsetColumnPrecision();
413     OFFSET_COLUMN_SCALE = defineOffsetColumnScale();
414     OFFSET_COLUMN_SORT_ORDER = defineOffsetColumnSortOrder();
415     OFFSET_COLUMN_CODE_PAGE = defineOffsetColumnCodePage();
416     OFFSET_COLUMN_COMPLEX_ID = defineOffsetColumnComplexId();
417     OFFSET_COLUMN_FLAGS = defineOffsetColumnFlags();
418     OFFSET_COLUMN_EXT_FLAGS = defineOffsetColumnExtFlags();
419     OFFSET_COLUMN_LENGTH = defineOffsetColumnLength();
420     OFFSET_COLUMN_VARIABLE_TABLE_INDEX = defineOffsetColumnVariableTableIndex();
421     OFFSET_COLUMN_FIXED_DATA_OFFSET = defineOffsetColumnFixedDataOffset();
422     OFFSET_COLUMN_FIXED_DATA_ROW_OFFSET = defineOffsetColumnFixedDataRowOffset();
423 
424     OFFSET_TABLE_DEF_LOCATION = defineOffsetTableDefLocation();
425 
426     OFFSET_ROW_START = defineOffsetRowStart();
427     OFFSET_USAGE_MAP_START = defineOffsetUsageMapStart();
428 
429     OFFSET_USAGE_MAP_PAGE_DATA = defineOffsetUsageMapPageData();
430 
431     OFFSET_REFERENCE_MAP_PAGE_NUMBERS = defineOffsetReferenceMapPageNumbers();
432 
433     OFFSET_FREE_SPACE = defineOffsetFreeSpace();
434     OFFSET_NUM_ROWS_ON_DATA_PAGE = defineOffsetNumRowsOnDataPage();
435     MAX_NUM_ROWS_ON_DATA_PAGE = defineMaxNumRowsOnDataPage();
436 
437     OFFSET_INDEX_COMPRESSED_BYTE_COUNT = defineOffsetIndexCompressedByteCount();
438     OFFSET_INDEX_LEVEL = defineOffsetIndexLevel();
439     OFFSET_INDEX_ENTRY_MASK = defineOffsetIndexEntryMask();
440     OFFSET_PREV_INDEX_PAGE = defineOffsetPrevIndexPage();
441     OFFSET_NEXT_INDEX_PAGE = defineOffsetNextIndexPage();
442     OFFSET_CHILD_TAIL_INDEX_PAGE = defineOffsetChildTailIndexPage();
443 
444     SIZE_INDEX_DEFINITION = defineSizeIndexDefinition();
445     SIZE_COLUMN_HEADER = defineSizeColumnHeader();
446     SIZE_ROW_LOCATION = defineSizeRowLocation();
447     SIZE_LONG_VALUE_DEF = defineSizeLongValueDef();
448     MAX_INLINE_LONG_VALUE_SIZE = defineMaxInlineLongValueSize();
449     MAX_LONG_VALUE_ROW_SIZE = defineMaxLongValueRowSize();
450     MAX_COMPRESSED_UNICODE_SIZE = defineMaxCompressedUnicodeSize();
451     SIZE_TDEF_HEADER = defineSizeTdefHeader();
452     SIZE_TDEF_TRAILER = defineSizeTdefTrailer();
453     SIZE_COLUMN_DEF_BLOCK = defineSizeColumnDefBlock();
454     SIZE_INDEX_COMPRESSED_BYTE_COUNT = defineSizeIndexCompressedByteCount();
455     SIZE_INDEX_ENTRY_MASK = defineSizeIndexEntryMask();
456     SKIP_BEFORE_INDEX_FLAGS = defineSkipBeforeIndexFlags();
457     SKIP_AFTER_INDEX_FLAGS = defineSkipAfterIndexFlags();
458     SKIP_BEFORE_INDEX_SLOT = defineSkipBeforeIndexSlot();
459     SKIP_AFTER_INDEX_SLOT = defineSkipAfterIndexSlot();
460     SKIP_BEFORE_INDEX = defineSkipBeforeIndex();
461     SIZE_NAME_LENGTH = defineSizeNameLength();
462     SIZE_ROW_COLUMN_COUNT = defineSizeRowColumnCount();
463     SIZE_ROW_VAR_COL_OFFSET = defineSizeRowVarColOffset();
464 
465     USAGE_MAP_TABLE_BYTE_LENGTH = defineUsageMapTableByteLength();
466 
467     MAX_COLUMNS_PER_TABLE = defineMaxColumnsPerTable();
468     MAX_INDEXES_PER_TABLE = defineMaxIndexesPerTable();
469     MAX_TABLE_NAME_LENGTH = defineMaxTableNameLength();
470     MAX_COLUMN_NAME_LENGTH = defineMaxColumnNameLength();
471     MAX_INDEX_NAME_LENGTH = defineMaxIndexNameLength();
472 
473     LEGACY_NUMERIC_INDEXES = defineLegacyNumericIndexes();
474 
475     CHARSET = defineCharset();
476     CODE_PAGE_CHARSET = defineCodePageCharset();
477     DEFAULT_SORT_ORDER = defineDefaultSortOrder();
478     PROPERTY_MAP_TYPE = definePropMapType();
479     SIZE_TEXT_FIELD_UNIT = defineSizeTextFieldUnit();
480   }
481 
482   protected abstract boolean defineReadOnly();
483   protected abstract boolean defineIndexesSupported();
484   protected abstract CodecType defineCodecType();
485 
486   protected abstract int definePageSize();
487   protected abstract long defineMaxDatabaseSize();
488 
489   protected abstract int defineMaxRowSize();
490   protected abstract int defineDataPageInitialFreeSpace();
491 
492   protected abstract int defineOffsetMaskedHeader();
493   protected abstract byte[] defineHeaderMask();
494   protected abstract int defineOffsetHeaderDate();
495   protected abstract int defineOffsetPassword();
496   protected abstract int defineSizePassword();
497   protected abstract int defineOffsetSortOrder();
498   protected abstract int defineSizeSortOrder();
499   protected abstract int defineOffsetCodePage();
500   protected abstract int defineOffsetEncodingKey();
501   protected abstract int defineOffsetNextTableDefPage();
502   protected abstract int defineOffsetNumRows();
503   protected abstract int defineOffsetNextAutoNumber();
504   protected abstract int defineOffsetNextComplexAutoNumber();
505   protected abstract int defineOffsetTableType();
506   protected abstract int defineOffsetMaxCols();
507   protected abstract int defineOffsetNumVarCols();
508   protected abstract int defineOffsetNumCols();
509   protected abstract int defineOffsetNumIndexSlots();
510   protected abstract int defineOffsetNumIndexes();
511   protected abstract int defineOffsetOwnedPages();
512   protected abstract int defineOffsetFreeSpacePages();
513   protected abstract int defineOffsetIndexDefBlock();
514 
515   protected abstract int defineSizeIndexColumnBlock();
516   protected abstract int defineSizeIndexInfoBlock();
517 
518   protected abstract int defineOffsetColumnType();
519   protected abstract int defineOffsetColumnNumber();
520   protected abstract int defineOffsetColumnId();
521   protected abstract int defineOffsetColumnPrecision();
522   protected abstract int defineOffsetColumnScale();
523   protected abstract int defineOffsetColumnSortOrder();
524   protected abstract int defineOffsetColumnCodePage();
525   protected abstract int defineOffsetColumnComplexId();
526   protected abstract int defineOffsetColumnFlags();
527   protected abstract int defineOffsetColumnExtFlags();
528   protected abstract int defineOffsetColumnLength();
529   protected abstract int defineOffsetColumnVariableTableIndex();
530   protected abstract int defineOffsetColumnFixedDataOffset();
531   protected abstract int defineOffsetColumnFixedDataRowOffset();
532 
533   protected abstract int defineOffsetTableDefLocation();
534 
535   protected abstract int defineOffsetRowStart();
536   protected abstract int defineOffsetUsageMapStart();
537 
538   protected abstract int defineOffsetUsageMapPageData();
539 
540   protected abstract int defineOffsetReferenceMapPageNumbers();
541 
542   protected abstract int defineOffsetFreeSpace();
543   protected abstract int defineOffsetNumRowsOnDataPage();
544   protected abstract int defineMaxNumRowsOnDataPage();
545 
546   protected abstract int defineOffsetIndexCompressedByteCount();
547   /** -1 for a format which has no index level byte */
548   protected abstract int defineOffsetIndexLevel();
549   protected abstract int defineOffsetIndexEntryMask();
550   protected abstract int defineOffsetPrevIndexPage();
551   protected abstract int defineOffsetNextIndexPage();
552   protected abstract int defineOffsetChildTailIndexPage();
553 
554   protected abstract int defineSizeIndexDefinition();
555   protected abstract int defineSizeColumnHeader();
556   protected abstract int defineSizeRowLocation();
557   protected abstract int defineSizeLongValueDef();
558   protected abstract int defineMaxInlineLongValueSize();
559   protected abstract int defineMaxLongValueRowSize();
560   protected abstract int defineMaxCompressedUnicodeSize();
561   protected abstract int defineSizeTdefHeader();
562   protected abstract int defineSizeTdefTrailer();
563   protected abstract int defineSizeColumnDefBlock();
564   protected abstract int defineSizeIndexCompressedByteCount();
565   protected abstract int defineSizeIndexEntryMask();
566   protected abstract int defineSkipBeforeIndexFlags();
567   protected abstract int defineSkipAfterIndexFlags();
568   protected abstract int defineSkipBeforeIndexSlot();
569   protected abstract int defineSkipAfterIndexSlot();
570   protected abstract int defineSkipBeforeIndex();
571   protected abstract int defineSizeNameLength();
572   protected abstract int defineSizeRowColumnCount();
573   protected abstract int defineSizeRowVarColOffset();
574 
575   protected abstract int defineUsageMapTableByteLength();
576 
577   protected abstract int defineMaxColumnsPerTable();
578   protected abstract int defineMaxIndexesPerTable();
579   protected abstract int defineMaxTableNameLength();
580   protected abstract int defineMaxColumnNameLength();
581   protected abstract int defineMaxIndexNameLength();
582 
583   protected abstract Charset defineCharset();
584   protected abstract boolean defineCodePageCharset();
585   protected abstract ColumnImpl.SortOrder defineDefaultSortOrder();
586   protected abstract byte[] definePropMapType();
587   protected abstract int defineSizeTextFieldUnit();
588 
589   protected abstract boolean defineLegacyNumericIndexes();
590 
591   protected abstract Map<String,Database.FileFormat> getPossibleFileFormats();
592 
593   public abstract boolean isSupportedDataType(DataType type);
594 
595   public abstract boolean isSupportedCalculatedDataType(DataType type);
596 
597   @Override
598   public String toString() {
599     return _name;
600   }
601 
602   private static class Jet3Format extends JetFormat {
603 
604     private Jet3Format() {
605       super("VERSION_3");
606     }
607 
608     @Override
609     protected boolean defineReadOnly() { return true; }
610 
611     @Override
612     protected boolean defineIndexesSupported() { return true; }
613 
614     @Override
615     protected CodecType defineCodecType() {
616       return CodecType.JET;
617     }
618 
619     @Override
620     protected int definePageSize() { return 2048; }
621 
622     @Override
623     protected long defineMaxDatabaseSize() {
624       return (1L * 1024L * 1024L * 1024L);
625     }
626 
627     @Override
628     protected int defineMaxRowSize() { return 2012; }
629     @Override
630     protected int defineDataPageInitialFreeSpace() { return PAGE_SIZE - 14; }
631 
632     @Override
633     protected int defineOffsetMaskedHeader() { return 24; }
634     @Override
635     protected byte[] defineHeaderMask() {
636       return ByteUtil.copyOf(BASE_HEADER_MASK, BASE_HEADER_MASK.length - 2);
637     }
638     @Override
639     protected int defineOffsetHeaderDate() { return -1; }
640     @Override
641     protected int defineOffsetPassword() { return 66; }
642     @Override
643     protected int defineSizePassword() { return 20; }
644     @Override
645     protected int defineOffsetSortOrder() { return 58; }
646     @Override
647     protected int defineSizeSortOrder() { return 2; }
648     @Override
649     protected int defineOffsetCodePage() { return 60; }
650     @Override
651     protected int defineOffsetEncodingKey() { return 62; }
652     @Override
653     protected int defineOffsetNextTableDefPage() { return 4; }
654     @Override
655     protected int defineOffsetNumRows() { return 12; }
656     @Override
657     protected int defineOffsetNextAutoNumber() { return 16; }
658     @Override
659     protected int defineOffsetNextComplexAutoNumber() { return -1; }
660     @Override
661     protected int defineOffsetTableType() { return 20; }
662     @Override
663     protected int defineOffsetMaxCols() { return 21; }
664     @Override
665     protected int defineOffsetNumVarCols() { return 23; }
666     @Override
667     protected int defineOffsetNumCols() { return 25; }
668     @Override
669     protected int defineOffsetNumIndexSlots() { return 27; }
670     @Override
671     protected int defineOffsetNumIndexes() { return 31; }
672     @Override
673     protected int defineOffsetOwnedPages() { return 35; }
674     @Override
675     protected int defineOffsetFreeSpacePages() { return 39; }
676     @Override
677     protected int defineOffsetIndexDefBlock() { return 43; }
678 
679     @Override
680     protected int defineSizeIndexColumnBlock() { return 39; }
681     @Override
682     protected int defineSizeIndexInfoBlock() { return 20; }
683 
684     @Override
685     protected int defineOffsetColumnType() { return 0; }
686     @Override
687     protected int defineOffsetColumnNumber() { return 1; }
688     @Override
689     protected int defineOffsetColumnId() { return 5; }
690     @Override
691     protected int defineOffsetColumnPrecision() { return 11; }
692     @Override
693     protected int defineOffsetColumnScale() { return 12; }
694     @Override
695     protected int defineOffsetColumnSortOrder() { return 9; }
696     @Override
697     protected int defineOffsetColumnCodePage() { return 11; }
698     @Override
699     protected int defineOffsetColumnComplexId() { return -1; }
700     @Override
701     protected int defineOffsetColumnFlags() { return 13; }
702     @Override
703     protected int defineOffsetColumnExtFlags() { return -1; }
704     @Override
705     protected int defineOffsetColumnLength() { return 16; }
706     @Override
707     protected int defineOffsetColumnVariableTableIndex() { return 3; }
708     @Override
709     protected int defineOffsetColumnFixedDataOffset() { return 14; }
710     @Override
711     protected int defineOffsetColumnFixedDataRowOffset() { return 1; }
712 
713     @Override
714     protected int defineOffsetTableDefLocation() { return 4; }
715 
716     @Override
717     protected int defineOffsetRowStart() { return 10; }
718     @Override
719     protected int defineOffsetUsageMapStart() { return 5; }
720 
721     @Override
722     protected int defineOffsetUsageMapPageData() { return 4; }
723 
724     @Override
725     protected int defineOffsetReferenceMapPageNumbers() { return 1; }
726 
727     @Override
728     protected int defineOffsetFreeSpace() { return 2; }
729     @Override
730     protected int defineOffsetNumRowsOnDataPage() { return 8; }
731     @Override
732     protected int defineMaxNumRowsOnDataPage() { return 255; }
733 
734     @Override
735     protected int defineOffsetIndexCompressedByteCount() { return 20; }
736     @Override
737     protected int defineSizeIndexCompressedByteCount() { return 1; }
738     @Override
739     protected int defineOffsetIndexLevel() { return 21; }
740     @Override
741     protected int defineOffsetIndexEntryMask() { return 22; }
742     @Override
743     protected int defineOffsetPrevIndexPage() { return 8; }
744     @Override
745     protected int defineOffsetNextIndexPage() { return 12; }
746     @Override
747     protected int defineOffsetChildTailIndexPage() { return 16; }
748 
749     @Override
750     protected int defineSizeIndexDefinition() { return 8; }
751     @Override
752     protected int defineSizeColumnHeader() { return 18; }
753     @Override
754     protected int defineSizeRowLocation() { return 2; }
755     @Override
756     protected int defineSizeLongValueDef() { return 12; }
757     @Override
758     protected int defineMaxInlineLongValueSize() { return 64; }
759     @Override
760     protected int defineMaxLongValueRowSize() { return 2032; }
761     @Override
762     protected int defineMaxCompressedUnicodeSize() { return 1024; }
763     @Override
764     protected int defineSizeTdefHeader() { return 43; }
765     @Override
766     protected int defineSizeTdefTrailer() { return 2; }
767     @Override
768     protected int defineSizeColumnDefBlock() { return 25; }
769     @Override
770     protected int defineSizeIndexEntryMask() { return 226; }
771     @Override
772     protected int defineSkipBeforeIndexFlags() { return 0; }
773     @Override
774     protected int defineSkipAfterIndexFlags() { return 0; }
775     @Override
776     protected int defineSkipBeforeIndexSlot() { return 0; }
777     @Override
778     protected int defineSkipAfterIndexSlot() { return 0; }
779     @Override
780     protected int defineSkipBeforeIndex() { return 0; }
781     @Override
782     protected int defineSizeNameLength() { return 1; }
783     @Override
784     protected int defineSizeRowColumnCount() { return 1; }
785     @Override
786     protected int defineSizeRowVarColOffset() { return 1; }
787 
788     @Override
789     protected int defineUsageMapTableByteLength() { return 128; }
790 
791     @Override
792     protected int defineMaxColumnsPerTable() { return 255; }
793 
794     @Override
795     protected int defineMaxIndexesPerTable() { return 32; }
796 
797     @Override
798     protected int defineMaxTableNameLength() { return 64; }
799 
800     @Override
801     protected int defineMaxColumnNameLength() { return 64; }
802 
803     @Override
804     protected int defineMaxIndexNameLength() { return 64; }
805 
806     @Override
807     protected boolean defineLegacyNumericIndexes() { return true; }
808 
809     @Override
810     protected Charset defineCharset() {
811       // only the fallback, for a file whose code page names no charset this
812       // jvm has.  the platform default has been UTF-8 since java 18, so it
813       // decodes almost every jet 3 file wrongly
814       return Charset.defaultCharset();
815     }
816 
817     @Override
818     protected boolean defineCodePageCharset() { return true; }
819 
820     @Override
821     protected ColumnImpl.SortOrder defineDefaultSortOrder() {
822       return ColumnImpl.GENERAL_97_SORT_ORDER;
823     }
824 
825     @Override
826     protected byte[] definePropMapType() {
827       return PROPERTY_MAP_TYPES[1];
828     }
829 
830     @Override
831     protected int defineSizeTextFieldUnit() { return 1; }
832 
833     @Override
834     protected Map<String,Database.FileFormat> getPossibleFileFormats()
835     {
836       return PossibleFileFormats.POSSIBLE_VERSION_3;
837     }
838 
839     @Override
840     public boolean isSupportedDataType(DataType type) {
841       return !V3_UNSUPP_TYPES.contains(type);
842     }
843 
844     @Override
845     public boolean isSupportedCalculatedDataType(DataType type) {
846       return false;
847     }
848   }
849 
850   private static class Jet4Format extends JetFormat {
851 
852     private Jet4Format() {
853       this("VERSION_4");
854     }
855 
856     private Jet4Format(String name) {
857       super(name);
858     }
859 
860     @Override
861     protected boolean defineReadOnly() { return false; }
862 
863     @Override
864     protected boolean defineIndexesSupported() { return true; }
865 
866     @Override
867     protected CodecType defineCodecType() {
868       return CodecType.JET;
869     }
870 
871     @Override
872     protected int definePageSize() { return 4096; }
873 
874     @Override
875     protected long defineMaxDatabaseSize() {
876       return (2L * 1024L * 1024L * 1024L);
877     }
878 
879     @Override
880     protected int defineMaxRowSize() { return 4060; }
881     @Override
882     protected int defineDataPageInitialFreeSpace() { return PAGE_SIZE - 14; }
883 
884     @Override
885     protected int defineOffsetMaskedHeader() { return 24; }
886     @Override
887     protected byte[] defineHeaderMask() { return BASE_HEADER_MASK; }
888     @Override
889     protected int defineOffsetHeaderDate() { return 114; }
890     @Override
891     protected int defineOffsetPassword() { return 66; }
892     @Override
893     protected int defineSizePassword() { return 40; }
894     @Override
895     protected int defineOffsetSortOrder() { return 110; }
896     @Override
897     protected int defineSizeSortOrder() { return 4; }
898     @Override
899     protected int defineOffsetCodePage() { return 60; }
900     @Override
901     protected int defineOffsetEncodingKey() { return 62; }
902     @Override
903     protected int defineOffsetNextTableDefPage() { return 4; }
904     @Override
905     protected int defineOffsetNumRows() { return 16; }
906     @Override
907     protected int defineOffsetNextAutoNumber() { return 20; }
908     @Override
909     protected int defineOffsetNextComplexAutoNumber() { return -1; }
910     @Override
911     protected int defineOffsetTableType() { return 40; }
912     @Override
913     protected int defineOffsetMaxCols() { return 41; }
914     @Override
915     protected int defineOffsetNumVarCols() { return 43; }
916     @Override
917     protected int defineOffsetNumCols() { return 45; }
918     @Override
919     protected int defineOffsetNumIndexSlots() { return 47; }
920     @Override
921     protected int defineOffsetNumIndexes() { return 51; }
922     @Override
923     protected int defineOffsetOwnedPages() { return 55; }
924     @Override
925     protected int defineOffsetFreeSpacePages() { return 59; }
926     @Override
927     protected int defineOffsetIndexDefBlock() { return 63; }
928 
929     @Override
930     protected int defineSizeIndexColumnBlock() { return 52; }
931     @Override
932     protected int defineSizeIndexInfoBlock() { return 28; }
933 
934     @Override
935     protected int defineOffsetColumnType() { return 0; }
936     @Override
937     protected int defineOffsetColumnNumber() { return 5; }
938     @Override
939     protected int defineOffsetColumnId() { return 9; }
940     @Override
941     protected int defineOffsetColumnPrecision() { return 11; }
942     @Override
943     protected int defineOffsetColumnScale() { return 12; }
944     @Override
945     protected int defineOffsetColumnSortOrder() { return 11; }
946     @Override
947     protected int defineOffsetColumnCodePage() { return -1; }
948     @Override
949     protected int defineOffsetColumnComplexId() { return -1; }
950     @Override
951     protected int defineOffsetColumnFlags() { return 15; }
952     @Override
953     protected int defineOffsetColumnExtFlags() { return 16; }
954     @Override
955     protected int defineOffsetColumnLength() { return 23; }
956     @Override
957     protected int defineOffsetColumnVariableTableIndex() { return 7; }
958     @Override
959     protected int defineOffsetColumnFixedDataOffset() { return 21; }
960     @Override
961     protected int defineOffsetColumnFixedDataRowOffset() { return 2; }
962 
963     @Override
964     protected int defineOffsetTableDefLocation() { return 4; }
965 
966     @Override
967     protected int defineOffsetRowStart() { return 14; }
968     @Override
969     protected int defineOffsetUsageMapStart() { return 5; }
970 
971     @Override
972     protected int defineOffsetUsageMapPageData() { return 4; }
973 
974     @Override
975     protected int defineOffsetReferenceMapPageNumbers() { return 1; }
976 
977     @Override
978     protected int defineOffsetFreeSpace() { return 2; }
979     @Override
980     protected int defineOffsetNumRowsOnDataPage() { return 12; }
981     @Override
982     protected int defineMaxNumRowsOnDataPage() { return 255; }
983 
984     @Override
985     protected int defineOffsetIndexCompressedByteCount() { return 24; }
986     @Override
987     protected int defineSizeIndexCompressedByteCount() { return 2; }
988     @Override
989     protected int defineOffsetIndexLevel() { return 26; }
990     @Override
991     protected int defineOffsetIndexEntryMask() { return 27; }
992     @Override
993     protected int defineOffsetPrevIndexPage() { return 12; }
994     @Override
995     protected int defineOffsetNextIndexPage() { return 16; }
996     @Override
997     protected int defineOffsetChildTailIndexPage() { return 20; }
998 
999     @Override
1000     protected int defineSizeIndexDefinition() { return 12; }
1001     @Override
1002     protected int defineSizeColumnHeader() { return 25; }
1003     @Override
1004     protected int defineSizeRowLocation() { return 2; }
1005     @Override
1006     protected int defineSizeLongValueDef() { return 12; }
1007     @Override
1008     protected int defineMaxInlineLongValueSize() { return 64; }
1009     @Override
1010     protected int defineMaxLongValueRowSize() { return 4076; }
1011     @Override
1012     protected int defineMaxCompressedUnicodeSize() { return 1024; }
1013     @Override
1014     protected int defineSizeTdefHeader() { return 63; }
1015     @Override
1016     protected int defineSizeTdefTrailer() { return 2; }
1017     @Override
1018     protected int defineSizeColumnDefBlock() { return 25; }
1019     @Override
1020     protected int defineSizeIndexEntryMask() { return 453; }
1021     @Override
1022     protected int defineSkipBeforeIndexFlags() { return 4; }
1023     @Override
1024     protected int defineSkipAfterIndexFlags() { return 5; }
1025     @Override
1026     protected int defineSkipBeforeIndexSlot() { return 4; }
1027     @Override
1028     protected int defineSkipAfterIndexSlot() { return 4; }
1029     @Override
1030     protected int defineSkipBeforeIndex() { return 4; }
1031     @Override
1032     protected int defineSizeNameLength() { return 2; }
1033     @Override
1034     protected int defineSizeRowColumnCount() { return 2; }
1035     @Override
1036     protected int defineSizeRowVarColOffset() { return 2; }
1037 
1038     @Override
1039     protected int defineUsageMapTableByteLength() { return 64; }
1040 
1041     @Override
1042     protected int defineMaxColumnsPerTable() { return 255; }
1043 
1044     @Override
1045     protected int defineMaxIndexesPerTable() { return 32; }
1046 
1047     @Override
1048     protected int defineMaxTableNameLength() { return 64; }
1049 
1050     @Override
1051     protected int defineMaxColumnNameLength() { return 64; }
1052 
1053     @Override
1054     protected int defineMaxIndexNameLength() { return 64; }
1055 
1056     @Override
1057     protected boolean defineLegacyNumericIndexes() { return true; }
1058 
1059     @Override
1060     protected Charset defineCharset() { return StandardCharsets.UTF_16LE; }
1061 
1062     @Override
1063     protected boolean defineCodePageCharset() { return false; }
1064 
1065     @Override
1066     protected ColumnImpl.SortOrder defineDefaultSortOrder() {
1067       return ColumnImpl.GENERAL_LEGACY_SORT_ORDER;
1068     }
1069 
1070     @Override
1071     protected byte[] definePropMapType() {
1072       return PROPERTY_MAP_TYPES[0];
1073     }
1074 
1075     @Override
1076     protected int defineSizeTextFieldUnit() { return TEXT_FIELD_UNIT_SIZE; }
1077 
1078     @Override
1079     protected Map<String,Database.FileFormat> getPossibleFileFormats()
1080     {
1081       return PossibleFileFormats.POSSIBLE_VERSION_4;
1082     }
1083 
1084     @Override
1085     public boolean isSupportedDataType(DataType type) {
1086       return !V3_UNSUPP_TYPES.contains(type);
1087     }
1088 
1089     @Override
1090     public boolean isSupportedCalculatedDataType(DataType type) {
1091       return false;
1092     }
1093   }
1094 
1095   private static final class MSISAMFormat extends Jet4Format {
1096     private MSISAMFormat() {
1097       super("MSISAM");
1098     }
1099 
1100     @Override
1101     protected CodecType defineCodecType() {
1102       return CodecType.MSISAM;
1103     }
1104 
1105     @Override
1106     protected Map<String,Database.FileFormat> getPossibleFileFormats()
1107     {
1108       return PossibleFileFormats.POSSIBLE_VERSION_MSISAM;
1109     }
1110   }
1111 
1112   private static class Jet2007Format extends Jet4Format {
1113     private Jet2007Format() {
1114       super("VERSION_2007");
1115     }
1116 
1117     private Jet2007Format(String name) {
1118       super(name);
1119     }
1120 
1121     @Override
1122     protected CodecType defineCodecType() {
1123       return CodecType.OFFICE;
1124     }
1125 
1126     @Override
1127     protected boolean defineLegacyNumericIndexes() { return false; }
1128 
1129     @Override
1130     protected Map<String,Database.FileFormat> getPossibleFileFormats() {
1131       return PossibleFileFormats.POSSIBLE_VERSION_2007;
1132     }
1133 
1134     @Override
1135     protected int defineOffsetNextComplexAutoNumber() { return 28; }
1136 
1137     @Override
1138     protected int defineOffsetColumnComplexId() { return 11; }
1139 
1140     @Override
1141     public boolean isSupportedDataType(DataType type) {
1142       return !V12_UNSUPP_TYPES.contains(type);
1143     }
1144 
1145     @Override
1146     public boolean isSupportedCalculatedDataType(DataType type) {
1147       return false;
1148     }
1149   }
1150 
1151   private static class Jet2010Format extends Jet2007Format {
1152     private Jet2010Format() {
1153       super("VERSION_2010");
1154     }
1155 
1156     private Jet2010Format(String name) {
1157       super(name);
1158     }
1159 
1160     @Override
1161     protected ColumnImpl.SortOrder defineDefaultSortOrder() {
1162       return ColumnImpl.GENERAL_SORT_ORDER;
1163     }
1164 
1165     @Override
1166     protected byte[] definePropMapType() {
1167       return PROPERTY_MAP_TYPES[0];
1168     }
1169 
1170     @Override
1171     protected Map<String,Database.FileFormat> getPossibleFileFormats() {
1172       return PossibleFileFormats.POSSIBLE_VERSION_2010;
1173     }
1174 
1175     @Override
1176     public boolean isSupportedCalculatedDataType(DataType type) {
1177       return V14_CALC_TYPES.contains(type);
1178     }
1179   }
1180 
1181   private static class Jet2016Format extends Jet2010Format {
1182 
1183     private Jet2016Format() {
1184       super("VERSION_2016");
1185     }
1186 
1187     private Jet2016Format(String name) {
1188       super(name);
1189     }
1190 
1191     @Override
1192     public boolean isSupportedDataType(DataType type) {
1193       return !V16_UNSUPP_TYPES.contains(type);
1194     }
1195 
1196     @Override
1197     protected Map<String,Database.FileFormat> getPossibleFileFormats() {
1198       return PossibleFileFormats.POSSIBLE_VERSION_2016;
1199     }
1200 
1201     @Override
1202     public boolean isSupportedCalculatedDataType(DataType type) {
1203       return V16_CALC_TYPES.contains(type);
1204     }
1205   }
1206 
1207   private static final class Jet2019Format extends Jet2016Format {
1208 
1209     private Jet2019Format() {
1210       super("VERSION_2019");
1211     }
1212 
1213     @Override
1214     public boolean isSupportedDataType(DataType type) {
1215       return true;
1216     }
1217 
1218     @Override
1219     protected Map<String,Database.FileFormat> getPossibleFileFormats() {
1220       return PossibleFileFormats.POSSIBLE_VERSION_2019;
1221     }
1222   }
1223 
1224 }