View Javadoc

1   /*
2   Copyright (c) 2005 Health Market Science, Inc.
3   
4   This library is free software; you can redistribute it and/or
5   modify it under the terms of the GNU Lesser General Public
6   License as published by the Free Software Foundation; either
7   version 2.1 of the License, or (at your option) any later version.
8   
9   This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  Lesser General Public License for more details.
13  
14  You should have received a copy of the GNU Lesser General Public
15  License along with this library; if not, write to the Free Software
16  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
17  USA
18  
19  You can contact Health Market Science at info@healthmarketscience.com
20  or at the following address:
21  
22  Health Market Science
23  2700 Horizon Drive
24  Suite 200
25  King of Prussia, PA 19406
26  */
27  
28  package com.healthmarketscience.jackcess;
29  
30  import java.io.IOException;
31  import java.nio.ByteBuffer;
32  import java.nio.channels.FileChannel;
33  import java.nio.charset.Charset;
34  
35  /**
36   * Encapsulates constants describing a specific version of the Access Jet format
37   * @author Tim McCune
38   */
39  public abstract class JetFormat {
40    
41    /** Maximum size of a record minus OLE objects and Memo fields */
42    public static final int MAX_RECORD_SIZE = 1900;  //2kb minus some overhead
43  
44    /** the "unit" size for text fields */
45    public static final short TEXT_FIELD_UNIT_SIZE = 2;
46    /** Maximum size of a text field */
47    public static final short TEXT_FIELD_MAX_LENGTH = 255 * TEXT_FIELD_UNIT_SIZE;
48    
49    /** Offset in the file that holds the byte describing the Jet format version */
50    private static final long OFFSET_VERSION = 20L;
51    /** Version code for Jet version 3 */
52    private static final byte CODE_VERSION_3 = 0x0;
53    /** Version code for Jet version 4 */
54    private static final byte CODE_VERSION_4 = 0x1;
55  
56    //These constants are populated by this class's constructor.  They can't be
57    //populated by the subclass's constructor because they are final, and Java
58    //doesn't allow this; hence all the abstract defineXXX() methods.
59  
60    /** the name of this format */
61    private final String _name;
62    
63    /** Database page size in bytes */
64    public final int PAGE_SIZE;
65    public final long MAX_DATABASE_SIZE;
66    
67    public final int MAX_ROW_SIZE;
68    public final int PAGE_INITIAL_FREE_SPACE;
69    
70    public final int OFFSET_NEXT_TABLE_DEF_PAGE;
71    public final int OFFSET_NUM_ROWS;
72    public final int OFFSET_NEXT_AUTO_NUMBER;
73    public final int OFFSET_TABLE_TYPE;
74    public final int OFFSET_MAX_COLS;
75    public final int OFFSET_NUM_VAR_COLS;
76    public final int OFFSET_NUM_COLS;
77    public final int OFFSET_NUM_INDEX_SLOTS;
78    public final int OFFSET_NUM_INDEXES;
79    public final int OFFSET_OWNED_PAGES;
80    public final int OFFSET_FREE_SPACE_PAGES;
81    public final int OFFSET_INDEX_DEF_BLOCK;
82    
83    public final int OFFSET_INDEX_NUMBER_BLOCK;
84    
85    public final int OFFSET_COLUMN_TYPE;
86    public final int OFFSET_COLUMN_NUMBER;
87    public final int OFFSET_COLUMN_PRECISION;
88    public final int OFFSET_COLUMN_SCALE;
89    public final int OFFSET_COLUMN_FLAGS;
90    public final int OFFSET_COLUMN_COMPRESSED_UNICODE;
91    public final int OFFSET_COLUMN_LENGTH;
92    public final int OFFSET_COLUMN_VARIABLE_TABLE_INDEX;
93    public final int OFFSET_COLUMN_FIXED_DATA_OFFSET;
94    
95    public final int OFFSET_TABLE_DEF_LOCATION;
96    
97    public final int OFFSET_ROW_START;
98    public final int OFFSET_USAGE_MAP_START;
99    
100   public final int OFFSET_USAGE_MAP_PAGE_DATA;
101   
102   public final int OFFSET_REFERENCE_MAP_PAGE_NUMBERS;
103   
104   public final int OFFSET_FREE_SPACE;
105   public final int OFFSET_NUM_ROWS_ON_DATA_PAGE;
106   public final int MAX_NUM_ROWS_ON_DATA_PAGE;
107   
108   public final int OFFSET_INDEX_COMPRESSED_BYTE_COUNT;
109   public final int OFFSET_INDEX_ENTRY_MASK;
110   public final int OFFSET_PREV_INDEX_PAGE;
111   public final int OFFSET_NEXT_INDEX_PAGE;
112   public final int OFFSET_CHILD_TAIL_INDEX_PAGE;
113   
114   public final int SIZE_INDEX_DEFINITION;
115   public final int SIZE_COLUMN_HEADER;
116   public final int SIZE_ROW_LOCATION;
117   public final int SIZE_LONG_VALUE_DEF;
118   public final int MAX_INLINE_LONG_VALUE_SIZE;
119   public final int MAX_LONG_VALUE_ROW_SIZE;
120   public final int SIZE_TDEF_HEADER;
121   public final int SIZE_TDEF_TRAILER;
122   public final int SIZE_COLUMN_DEF_BLOCK;
123   public final int SIZE_INDEX_ENTRY_MASK;
124   
125   public final int USAGE_MAP_TABLE_BYTE_LENGTH;
126   
127   public final Charset CHARSET;
128   
129   public static final JetFormat VERSION_4 = new Jet4Format();
130 
131   /**
132    * @return The Jet Format represented in the passed-in file
133    */
134   public static JetFormat getFormat(FileChannel channel) throws IOException {
135     ByteBuffer buffer = ByteBuffer.allocate(1);
136     int bytesRead = channel.read(buffer, OFFSET_VERSION);
137     if(bytesRead < 1) {
138       throw new IOException("Empty database file");
139     }
140     buffer.flip();
141     byte version = buffer.get();
142     if (version == CODE_VERSION_4) {
143       return VERSION_4;
144     }
145     throw new IOException("Unsupported version: " + version);
146   }
147   
148   private JetFormat(String name) {
149     _name = name;
150     
151     PAGE_SIZE = definePageSize();
152     MAX_DATABASE_SIZE = defineMaxDatabaseSize();
153     
154     MAX_ROW_SIZE = defineMaxRowSize();
155     PAGE_INITIAL_FREE_SPACE = definePageInitialFreeSpace();
156     
157     OFFSET_NEXT_TABLE_DEF_PAGE = defineOffsetNextTableDefPage();
158     OFFSET_NUM_ROWS = defineOffsetNumRows();
159     OFFSET_NEXT_AUTO_NUMBER = defineOffsetNextAutoNumber();
160     OFFSET_TABLE_TYPE = defineOffsetTableType();
161     OFFSET_MAX_COLS = defineOffsetMaxCols();
162     OFFSET_NUM_VAR_COLS = defineOffsetNumVarCols();
163     OFFSET_NUM_COLS = defineOffsetNumCols();
164     OFFSET_NUM_INDEX_SLOTS = defineOffsetNumIndexSlots();
165     OFFSET_NUM_INDEXES = defineOffsetNumIndexes();
166     OFFSET_OWNED_PAGES = defineOffsetOwnedPages();
167     OFFSET_FREE_SPACE_PAGES = defineOffsetFreeSpacePages();
168     OFFSET_INDEX_DEF_BLOCK = defineOffsetIndexDefBlock();
169     
170     OFFSET_INDEX_NUMBER_BLOCK = defineOffsetIndexNumberBlock();
171     
172     OFFSET_COLUMN_TYPE = defineOffsetColumnType();
173     OFFSET_COLUMN_NUMBER = defineOffsetColumnNumber();
174     OFFSET_COLUMN_PRECISION = defineOffsetColumnPrecision();
175     OFFSET_COLUMN_SCALE = defineOffsetColumnScale();
176     OFFSET_COLUMN_FLAGS = defineOffsetColumnFlags();
177     OFFSET_COLUMN_COMPRESSED_UNICODE = defineOffsetColumnCompressedUnicode();
178     OFFSET_COLUMN_LENGTH = defineOffsetColumnLength();
179     OFFSET_COLUMN_VARIABLE_TABLE_INDEX = defineOffsetColumnVariableTableIndex();
180     OFFSET_COLUMN_FIXED_DATA_OFFSET = defineOffsetColumnFixedDataOffset();
181     
182     OFFSET_TABLE_DEF_LOCATION = defineOffsetTableDefLocation();
183     
184     OFFSET_ROW_START = defineOffsetRowStart();
185     OFFSET_USAGE_MAP_START = defineOffsetUsageMapStart();
186     
187     OFFSET_USAGE_MAP_PAGE_DATA = defineOffsetUsageMapPageData();
188     
189     OFFSET_REFERENCE_MAP_PAGE_NUMBERS = defineOffsetReferenceMapPageNumbers();
190     
191     OFFSET_FREE_SPACE = defineOffsetFreeSpace();
192     OFFSET_NUM_ROWS_ON_DATA_PAGE = defineOffsetNumRowsOnDataPage();
193     MAX_NUM_ROWS_ON_DATA_PAGE = defineMaxNumRowsOnDataPage();
194     
195     OFFSET_INDEX_COMPRESSED_BYTE_COUNT = defineOffsetIndexCompressedByteCount();
196     OFFSET_INDEX_ENTRY_MASK = defineOffsetIndexEntryMask();
197     OFFSET_PREV_INDEX_PAGE = defineOffsetPrevIndexPage();
198     OFFSET_NEXT_INDEX_PAGE = defineOffsetNextIndexPage();
199     OFFSET_CHILD_TAIL_INDEX_PAGE = defineOffsetChildTailIndexPage();
200     
201     SIZE_INDEX_DEFINITION = defineSizeIndexDefinition();
202     SIZE_COLUMN_HEADER = defineSizeColumnHeader();
203     SIZE_ROW_LOCATION = defineSizeRowLocation();
204     SIZE_LONG_VALUE_DEF = defineSizeLongValueDef();
205     MAX_INLINE_LONG_VALUE_SIZE = defineMaxInlineLongValueSize();
206     MAX_LONG_VALUE_ROW_SIZE = defineMaxLongValueRowSize();
207     SIZE_TDEF_HEADER = defineSizeTdefHeader();
208     SIZE_TDEF_TRAILER = defineSizeTdefTrailer();
209     SIZE_COLUMN_DEF_BLOCK = defineSizeColumnDefBlock();
210     SIZE_INDEX_ENTRY_MASK = defineSizeIndexEntryMask();
211     
212     USAGE_MAP_TABLE_BYTE_LENGTH = defineUsageMapTableByteLength();
213     
214     CHARSET = defineCharset();
215   }
216   
217   protected abstract int definePageSize();
218   protected abstract long defineMaxDatabaseSize();
219   
220   protected abstract int defineMaxRowSize();
221   protected abstract int definePageInitialFreeSpace();
222   
223   protected abstract int defineOffsetNextTableDefPage();
224   protected abstract int defineOffsetNumRows();
225   protected abstract int defineOffsetNextAutoNumber();
226   protected abstract int defineOffsetTableType();
227   protected abstract int defineOffsetMaxCols();
228   protected abstract int defineOffsetNumVarCols();
229   protected abstract int defineOffsetNumCols();
230   protected abstract int defineOffsetNumIndexSlots();
231   protected abstract int defineOffsetNumIndexes();
232   protected abstract int defineOffsetOwnedPages();
233   protected abstract int defineOffsetFreeSpacePages();
234   protected abstract int defineOffsetIndexDefBlock();
235   
236   protected abstract int defineOffsetIndexNumberBlock();
237   
238   protected abstract int defineOffsetColumnType();
239   protected abstract int defineOffsetColumnNumber();
240   protected abstract int defineOffsetColumnPrecision();
241   protected abstract int defineOffsetColumnScale();
242   protected abstract int defineOffsetColumnFlags();
243   protected abstract int defineOffsetColumnCompressedUnicode();
244   protected abstract int defineOffsetColumnLength();
245   protected abstract int defineOffsetColumnVariableTableIndex();
246   protected abstract int defineOffsetColumnFixedDataOffset();
247   
248   protected abstract int defineOffsetTableDefLocation();
249   
250   protected abstract int defineOffsetRowStart();
251   protected abstract int defineOffsetUsageMapStart();
252   
253   protected abstract int defineOffsetUsageMapPageData();
254   
255   protected abstract int defineOffsetReferenceMapPageNumbers();
256   
257   protected abstract int defineOffsetFreeSpace();
258   protected abstract int defineOffsetNumRowsOnDataPage();
259   protected abstract int defineMaxNumRowsOnDataPage();
260   
261   protected abstract int defineOffsetIndexCompressedByteCount();
262   protected abstract int defineOffsetIndexEntryMask();
263   protected abstract int defineOffsetPrevIndexPage();
264   protected abstract int defineOffsetNextIndexPage();
265   protected abstract int defineOffsetChildTailIndexPage();
266   
267   protected abstract int defineSizeIndexDefinition();
268   protected abstract int defineSizeColumnHeader();
269   protected abstract int defineSizeRowLocation();
270   protected abstract int defineSizeLongValueDef();
271   protected abstract int defineMaxInlineLongValueSize();
272   protected abstract int defineMaxLongValueRowSize();
273   protected abstract int defineSizeTdefHeader();
274   protected abstract int defineSizeTdefTrailer();
275   protected abstract int defineSizeColumnDefBlock();
276   protected abstract int defineSizeIndexEntryMask();
277   
278   protected abstract int defineUsageMapTableByteLength();
279     
280   protected abstract Charset defineCharset();
281 
282   @Override
283   public String toString() {
284     return _name;
285   }
286   
287   private static final class Jet4Format extends JetFormat {
288 
289     private Jet4Format() {
290       super("VERSION_4");
291     }
292 
293     @Override
294     protected int definePageSize() { return 4096; }
295     
296     @Override
297     protected long defineMaxDatabaseSize() {
298       return (2L * 1024L * 1024L * 1024L);
299     }
300     
301     @Override
302     protected int defineMaxRowSize() { return 4060; }
303     @Override
304     protected int definePageInitialFreeSpace() { return PAGE_SIZE - 14; }
305     
306     @Override
307     protected int defineOffsetNextTableDefPage() { return 4; }
308     @Override
309     protected int defineOffsetNumRows() { return 16; }
310     @Override
311     protected int defineOffsetNextAutoNumber() { return 20; }
312     @Override
313     protected int defineOffsetTableType() { return 40; }
314     @Override
315     protected int defineOffsetMaxCols() { return 41; }
316     @Override
317     protected int defineOffsetNumVarCols() { return 43; }
318     @Override
319     protected int defineOffsetNumCols() { return 45; }
320     @Override
321     protected int defineOffsetNumIndexSlots() { return 47; }
322     @Override
323     protected int defineOffsetNumIndexes() { return 51; }
324     @Override
325     protected int defineOffsetOwnedPages() { return 55; }
326     @Override
327     protected int defineOffsetFreeSpacePages() { return 59; }
328     @Override
329     protected int defineOffsetIndexDefBlock() { return 63; }
330 
331     @Override
332     protected int defineOffsetIndexNumberBlock() { return 52; }
333     
334     @Override
335     protected int defineOffsetColumnType() { return 0; }
336     @Override
337     protected int defineOffsetColumnNumber() { return 5; }
338     @Override
339     protected int defineOffsetColumnPrecision() { return 11; }
340     @Override
341     protected int defineOffsetColumnScale() { return 12; }
342     @Override
343     protected int defineOffsetColumnFlags() { return 15; }
344     @Override
345     protected int defineOffsetColumnCompressedUnicode() { return 16; }
346     @Override
347     protected int defineOffsetColumnLength() { return 23; }
348     @Override
349     protected int defineOffsetColumnVariableTableIndex() { return 7; }
350     @Override
351     protected int defineOffsetColumnFixedDataOffset() { return 21; }
352   
353     @Override
354     protected int defineOffsetTableDefLocation() { return 4; }
355     
356     @Override
357     protected int defineOffsetRowStart() { return 14; }
358     @Override
359     protected int defineOffsetUsageMapStart() { return 5; }
360     
361     @Override
362     protected int defineOffsetUsageMapPageData() { return 4; }
363     
364     @Override
365     protected int defineOffsetReferenceMapPageNumbers() { return 1; }
366     
367     @Override
368     protected int defineOffsetFreeSpace() { return 2; }
369     @Override
370     protected int defineOffsetNumRowsOnDataPage() { return 12; }
371     @Override
372     protected int defineMaxNumRowsOnDataPage() { return 255; }
373     
374     @Override
375     protected int defineOffsetIndexCompressedByteCount() { return 24; }
376     @Override
377     protected int defineOffsetIndexEntryMask() { return 27; }
378     @Override
379     protected int defineOffsetPrevIndexPage() { return 12; }
380     @Override
381     protected int defineOffsetNextIndexPage() { return 16; }
382     @Override
383     protected int defineOffsetChildTailIndexPage() { return 20; }
384     
385     @Override
386     protected int defineSizeIndexDefinition() { return 12; }
387     @Override
388     protected int defineSizeColumnHeader() { return 25; }
389     @Override
390     protected int defineSizeRowLocation() { return 2; }
391     @Override
392     protected int defineSizeLongValueDef() { return 12; }
393     @Override
394     protected int defineMaxInlineLongValueSize() { return 64; }
395     @Override
396     protected int defineMaxLongValueRowSize() { return 4076; }
397     @Override
398     protected int defineSizeTdefHeader() { return 63; }
399     @Override
400     protected int defineSizeTdefTrailer() { return 2; }
401     @Override
402     protected int defineSizeColumnDefBlock() { return 25; }
403     @Override
404     protected int defineSizeIndexEntryMask() { return 453; }
405     
406     @Override
407     protected int defineUsageMapTableByteLength() { return 64; }
408       
409     @Override
410     protected Charset defineCharset() { return Charset.forName("UTF-16LE"); }
411   }
412   
413 }