001: /*
002: Copyright (c) 2005 Health Market Science, Inc.
003:
004: This library is free software; you can redistribute it and/or
005: modify it under the terms of the GNU Lesser General Public
006: License as published by the Free Software Foundation; either
007: version 2.1 of the License, or (at your option) any later version.
008:
009: This library is distributed in the hope that it will be useful,
010: but WITHOUT ANY WARRANTY; without even the implied warranty of
011: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: Lesser General Public License for more details.
013:
014: You should have received a copy of the GNU Lesser General Public
015: License along with this library; if not, write to the Free Software
016: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
017: USA
018:
019: You can contact Health Market Science at info@healthmarketscience.com
020: or at the following address:
021:
022: Health Market Science
023: 2700 Horizon Drive
024: Suite 200
025: King of Prussia, PA 19406
026: */
027:
028: package com.healthmarketscience.jackcess;
029:
030: import java.io.IOException;
031: import java.nio.ByteBuffer;
032: import java.nio.channels.FileChannel;
033: import java.nio.charset.Charset;
034:
035: /**
036: * Encapsulates constants describing a specific version of the Access Jet format
037: * @author Tim McCune
038: */
039: public abstract class JetFormat {
040:
041: /** Maximum size of a record minus OLE objects and Memo fields */
042: public static final int MAX_RECORD_SIZE = 1900; //2kb minus some overhead
043:
044: /** the "unit" size for text fields */
045: public static final short TEXT_FIELD_UNIT_SIZE = 2;
046: /** Maximum size of a text field */
047: public static final short TEXT_FIELD_MAX_LENGTH = 255 * TEXT_FIELD_UNIT_SIZE;
048:
049: /** Offset in the file that holds the byte describing the Jet format version */
050: private static final long OFFSET_VERSION = 20L;
051: /** Version code for Jet version 3 */
052: private static final byte CODE_VERSION_3 = 0x0;
053: /** Version code for Jet version 4 */
054: private static final byte CODE_VERSION_4 = 0x1;
055:
056: //These constants are populated by this class's constructor. They can't be
057: //populated by the subclass's constructor because they are final, and Java
058: //doesn't allow this; hence all the abstract defineXXX() methods.
059:
060: /** the name of this format */
061: private final String _name;
062:
063: /** Database page size in bytes */
064: public final int PAGE_SIZE;
065: public final long MAX_DATABASE_SIZE;
066:
067: public final int MAX_ROW_SIZE;
068:
069: public final int OFFSET_NEXT_TABLE_DEF_PAGE;
070: public final int OFFSET_NUM_ROWS;
071: public final int OFFSET_NEXT_AUTO_NUMBER;
072: public final int OFFSET_TABLE_TYPE;
073: public final int OFFSET_MAX_COLS;
074: public final int OFFSET_NUM_VAR_COLS;
075: public final int OFFSET_NUM_COLS;
076: public final int OFFSET_NUM_INDEX_SLOTS;
077: public final int OFFSET_NUM_INDEXES;
078: public final int OFFSET_OWNED_PAGES;
079: public final int OFFSET_FREE_SPACE_PAGES;
080: public final int OFFSET_INDEX_DEF_BLOCK;
081:
082: public final int OFFSET_INDEX_NUMBER_BLOCK;
083:
084: public final int OFFSET_COLUMN_TYPE;
085: public final int OFFSET_COLUMN_NUMBER;
086: public final int OFFSET_COLUMN_PRECISION;
087: public final int OFFSET_COLUMN_SCALE;
088: public final int OFFSET_COLUMN_FLAGS;
089: public final int OFFSET_COLUMN_COMPRESSED_UNICODE;
090: public final int OFFSET_COLUMN_LENGTH;
091: public final int OFFSET_COLUMN_VARIABLE_TABLE_INDEX;
092: public final int OFFSET_COLUMN_FIXED_DATA_OFFSET;
093:
094: public final int OFFSET_TABLE_DEF_LOCATION;
095: public final int OFFSET_NUM_ROWS_ON_PAGE;
096: public final int OFFSET_ROW_LOCATION_BLOCK;
097:
098: public final int OFFSET_ROW_START;
099: public final int OFFSET_USAGE_MAP_START;
100:
101: public final int OFFSET_USAGE_MAP_PAGE_DATA;
102:
103: public final int OFFSET_REFERENCE_MAP_PAGE_NUMBERS;
104:
105: public final int OFFSET_FREE_SPACE;
106: public final int OFFSET_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_NEXT_INDEX_LEAF_PAGE;
111:
112: public final int SIZE_INDEX_DEFINITION;
113: public final int SIZE_COLUMN_HEADER;
114: public final int SIZE_ROW_LOCATION;
115: public final int SIZE_LONG_VALUE_DEF;
116: public final int MAX_INLINE_LONG_VALUE_SIZE;
117: public final int SIZE_TDEF_HEADER;
118: public final int SIZE_TDEF_TRAILER;
119: public final int SIZE_COLUMN_DEF_BLOCK;
120: public final int SIZE_INDEX_ENTRY_MASK;
121:
122: public final int USAGE_MAP_TABLE_BYTE_LENGTH;
123:
124: public final Charset CHARSET;
125:
126: public static final JetFormat VERSION_4 = new Jet4Format();
127:
128: /**
129: * @return The Jet Format represented in the passed-in file
130: */
131: public static JetFormat getFormat(FileChannel channel)
132: throws IOException {
133: ByteBuffer buffer = ByteBuffer.allocate(1);
134: int bytesRead = channel.read(buffer, OFFSET_VERSION);
135: if (bytesRead < 1) {
136: throw new IOException("Empty database file");
137: }
138: buffer.flip();
139: byte version = buffer.get();
140: if (version == CODE_VERSION_4) {
141: return VERSION_4;
142: }
143: throw new IOException("Unsupported version: " + version);
144: }
145:
146: private JetFormat(String name) {
147: _name = name;
148:
149: PAGE_SIZE = definePageSize();
150: MAX_DATABASE_SIZE = defineMaxDatabaseSize();
151:
152: MAX_ROW_SIZE = defineMaxRowSize();
153:
154: OFFSET_NEXT_TABLE_DEF_PAGE = defineOffsetNextTableDefPage();
155: OFFSET_NUM_ROWS = defineOffsetNumRows();
156: OFFSET_NEXT_AUTO_NUMBER = defineOffsetNextAutoNumber();
157: OFFSET_TABLE_TYPE = defineOffsetTableType();
158: OFFSET_MAX_COLS = defineOffsetMaxCols();
159: OFFSET_NUM_VAR_COLS = defineOffsetNumVarCols();
160: OFFSET_NUM_COLS = defineOffsetNumCols();
161: OFFSET_NUM_INDEX_SLOTS = defineOffsetNumIndexSlots();
162: OFFSET_NUM_INDEXES = defineOffsetNumIndexes();
163: OFFSET_OWNED_PAGES = defineOffsetOwnedPages();
164: OFFSET_FREE_SPACE_PAGES = defineOffsetFreeSpacePages();
165: OFFSET_INDEX_DEF_BLOCK = defineOffsetIndexDefBlock();
166:
167: OFFSET_INDEX_NUMBER_BLOCK = defineOffsetIndexNumberBlock();
168:
169: OFFSET_COLUMN_TYPE = defineOffsetColumnType();
170: OFFSET_COLUMN_NUMBER = defineOffsetColumnNumber();
171: OFFSET_COLUMN_PRECISION = defineOffsetColumnPrecision();
172: OFFSET_COLUMN_SCALE = defineOffsetColumnScale();
173: OFFSET_COLUMN_FLAGS = defineOffsetColumnFlags();
174: OFFSET_COLUMN_COMPRESSED_UNICODE = defineOffsetColumnCompressedUnicode();
175: OFFSET_COLUMN_LENGTH = defineOffsetColumnLength();
176: OFFSET_COLUMN_VARIABLE_TABLE_INDEX = defineOffsetColumnVariableTableIndex();
177: OFFSET_COLUMN_FIXED_DATA_OFFSET = defineOffsetColumnFixedDataOffset();
178:
179: OFFSET_TABLE_DEF_LOCATION = defineOffsetTableDefLocation();
180: OFFSET_NUM_ROWS_ON_PAGE = defineOffsetNumRowsOnPage();
181: OFFSET_ROW_LOCATION_BLOCK = defineOffsetRowLocationBlock();
182:
183: OFFSET_ROW_START = defineOffsetRowStart();
184: OFFSET_USAGE_MAP_START = defineOffsetUsageMapStart();
185:
186: OFFSET_USAGE_MAP_PAGE_DATA = defineOffsetUsageMapPageData();
187:
188: OFFSET_REFERENCE_MAP_PAGE_NUMBERS = defineOffsetReferenceMapPageNumbers();
189:
190: OFFSET_FREE_SPACE = defineOffsetFreeSpace();
191: OFFSET_NUM_ROWS_ON_DATA_PAGE = defineOffsetNumRowsOnDataPage();
192:
193: OFFSET_INDEX_COMPRESSED_BYTE_COUNT = defineOffsetIndexCompressedByteCount();
194: OFFSET_INDEX_ENTRY_MASK = defineOffsetIndexEntryMask();
195: OFFSET_NEXT_INDEX_LEAF_PAGE = defineOffsetNextIndexLeafPage();
196:
197: SIZE_INDEX_DEFINITION = defineSizeIndexDefinition();
198: SIZE_COLUMN_HEADER = defineSizeColumnHeader();
199: SIZE_ROW_LOCATION = defineSizeRowLocation();
200: SIZE_LONG_VALUE_DEF = defineSizeLongValueDef();
201: MAX_INLINE_LONG_VALUE_SIZE = defineMaxInlineLongValueSize();
202: SIZE_TDEF_HEADER = defineSizeTdefHeader();
203: SIZE_TDEF_TRAILER = defineSizeTdefTrailer();
204: SIZE_COLUMN_DEF_BLOCK = defineSizeColumnDefBlock();
205: SIZE_INDEX_ENTRY_MASK = defineSizeIndexEntryMask();
206:
207: USAGE_MAP_TABLE_BYTE_LENGTH = defineUsageMapTableByteLength();
208:
209: CHARSET = defineCharset();
210: }
211:
212: protected abstract int definePageSize();
213:
214: protected abstract long defineMaxDatabaseSize();
215:
216: protected abstract int defineMaxRowSize();
217:
218: protected abstract int defineOffsetNextTableDefPage();
219:
220: protected abstract int defineOffsetNumRows();
221:
222: protected abstract int defineOffsetNextAutoNumber();
223:
224: protected abstract int defineOffsetTableType();
225:
226: protected abstract int defineOffsetMaxCols();
227:
228: protected abstract int defineOffsetNumVarCols();
229:
230: protected abstract int defineOffsetNumCols();
231:
232: protected abstract int defineOffsetNumIndexSlots();
233:
234: protected abstract int defineOffsetNumIndexes();
235:
236: protected abstract int defineOffsetOwnedPages();
237:
238: protected abstract int defineOffsetFreeSpacePages();
239:
240: protected abstract int defineOffsetIndexDefBlock();
241:
242: protected abstract int defineOffsetIndexNumberBlock();
243:
244: protected abstract int defineOffsetColumnType();
245:
246: protected abstract int defineOffsetColumnNumber();
247:
248: protected abstract int defineOffsetColumnPrecision();
249:
250: protected abstract int defineOffsetColumnScale();
251:
252: protected abstract int defineOffsetColumnFlags();
253:
254: protected abstract int defineOffsetColumnCompressedUnicode();
255:
256: protected abstract int defineOffsetColumnLength();
257:
258: protected abstract int defineOffsetColumnVariableTableIndex();
259:
260: protected abstract int defineOffsetColumnFixedDataOffset();
261:
262: protected abstract int defineOffsetTableDefLocation();
263:
264: protected abstract int defineOffsetNumRowsOnPage();
265:
266: protected abstract int defineOffsetRowLocationBlock();
267:
268: protected abstract int defineOffsetRowStart();
269:
270: protected abstract int defineOffsetUsageMapStart();
271:
272: protected abstract int defineOffsetUsageMapPageData();
273:
274: protected abstract int defineOffsetReferenceMapPageNumbers();
275:
276: protected abstract int defineOffsetFreeSpace();
277:
278: protected abstract int defineOffsetNumRowsOnDataPage();
279:
280: protected abstract int defineOffsetIndexCompressedByteCount();
281:
282: protected abstract int defineOffsetIndexEntryMask();
283:
284: protected abstract int defineOffsetNextIndexLeafPage();
285:
286: protected abstract int defineSizeIndexDefinition();
287:
288: protected abstract int defineSizeColumnHeader();
289:
290: protected abstract int defineSizeRowLocation();
291:
292: protected abstract int defineSizeLongValueDef();
293:
294: protected abstract int defineMaxInlineLongValueSize();
295:
296: protected abstract int defineSizeTdefHeader();
297:
298: protected abstract int defineSizeTdefTrailer();
299:
300: protected abstract int defineSizeColumnDefBlock();
301:
302: protected abstract int defineSizeIndexEntryMask();
303:
304: protected abstract int defineUsageMapTableByteLength();
305:
306: protected abstract Charset defineCharset();
307:
308: @Override
309: public String toString() {
310: return _name;
311: }
312:
313: private static final class Jet4Format extends JetFormat {
314:
315: private Jet4Format() {
316: super ("VERSION_4");
317: }
318:
319: @Override
320: protected int definePageSize() {
321: return 4096;
322: }
323:
324: @Override
325: protected long defineMaxDatabaseSize() {
326: return (2L * 1024L * 1024L * 1024L);
327: }
328:
329: @Override
330: protected int defineMaxRowSize() {
331: return PAGE_SIZE - 16;
332: }
333:
334: @Override
335: protected int defineOffsetNextTableDefPage() {
336: return 4;
337: }
338:
339: @Override
340: protected int defineOffsetNumRows() {
341: return 16;
342: }
343:
344: @Override
345: protected int defineOffsetNextAutoNumber() {
346: return 20;
347: }
348:
349: @Override
350: protected int defineOffsetTableType() {
351: return 40;
352: }
353:
354: @Override
355: protected int defineOffsetMaxCols() {
356: return 41;
357: }
358:
359: @Override
360: protected int defineOffsetNumVarCols() {
361: return 43;
362: }
363:
364: @Override
365: protected int defineOffsetNumCols() {
366: return 45;
367: }
368:
369: @Override
370: protected int defineOffsetNumIndexSlots() {
371: return 47;
372: }
373:
374: @Override
375: protected int defineOffsetNumIndexes() {
376: return 51;
377: }
378:
379: @Override
380: protected int defineOffsetOwnedPages() {
381: return 55;
382: }
383:
384: @Override
385: protected int defineOffsetFreeSpacePages() {
386: return 59;
387: }
388:
389: @Override
390: protected int defineOffsetIndexDefBlock() {
391: return 63;
392: }
393:
394: @Override
395: protected int defineOffsetIndexNumberBlock() {
396: return 52;
397: }
398:
399: @Override
400: protected int defineOffsetColumnType() {
401: return 0;
402: }
403:
404: @Override
405: protected int defineOffsetColumnNumber() {
406: return 5;
407: }
408:
409: @Override
410: protected int defineOffsetColumnPrecision() {
411: return 11;
412: }
413:
414: @Override
415: protected int defineOffsetColumnScale() {
416: return 12;
417: }
418:
419: @Override
420: protected int defineOffsetColumnFlags() {
421: return 15;
422: }
423:
424: @Override
425: protected int defineOffsetColumnCompressedUnicode() {
426: return 16;
427: }
428:
429: @Override
430: protected int defineOffsetColumnLength() {
431: return 23;
432: }
433:
434: @Override
435: protected int defineOffsetColumnVariableTableIndex() {
436: return 7;
437: }
438:
439: @Override
440: protected int defineOffsetColumnFixedDataOffset() {
441: return 21;
442: }
443:
444: @Override
445: protected int defineOffsetTableDefLocation() {
446: return 4;
447: }
448:
449: @Override
450: protected int defineOffsetNumRowsOnPage() {
451: return 12;
452: }
453:
454: @Override
455: protected int defineOffsetRowLocationBlock() {
456: return 16;
457: }
458:
459: @Override
460: protected int defineOffsetRowStart() {
461: return 14;
462: }
463:
464: @Override
465: protected int defineOffsetUsageMapStart() {
466: return 5;
467: }
468:
469: @Override
470: protected int defineOffsetUsageMapPageData() {
471: return 4;
472: }
473:
474: @Override
475: protected int defineOffsetReferenceMapPageNumbers() {
476: return 1;
477: }
478:
479: @Override
480: protected int defineOffsetFreeSpace() {
481: return 2;
482: }
483:
484: @Override
485: protected int defineOffsetNumRowsOnDataPage() {
486: return 12;
487: }
488:
489: @Override
490: protected int defineOffsetIndexCompressedByteCount() {
491: return 24;
492: }
493:
494: @Override
495: protected int defineOffsetIndexEntryMask() {
496: return 27;
497: }
498:
499: @Override
500: protected int defineOffsetNextIndexLeafPage() {
501: return 16;
502: }
503:
504: @Override
505: protected int defineSizeIndexDefinition() {
506: return 12;
507: }
508:
509: @Override
510: protected int defineSizeColumnHeader() {
511: return 25;
512: }
513:
514: @Override
515: protected int defineSizeRowLocation() {
516: return 2;
517: }
518:
519: @Override
520: protected int defineSizeLongValueDef() {
521: return 12;
522: }
523:
524: @Override
525: protected int defineMaxInlineLongValueSize() {
526: return 64;
527: }
528:
529: @Override
530: protected int defineSizeTdefHeader() {
531: return 63;
532: }
533:
534: @Override
535: protected int defineSizeTdefTrailer() {
536: return 2;
537: }
538:
539: @Override
540: protected int defineSizeColumnDefBlock() {
541: return 25;
542: }
543:
544: @Override
545: protected int defineSizeIndexEntryMask() {
546: return 453;
547: }
548:
549: @Override
550: protected int defineUsageMapTableByteLength() {
551: return 64;
552: }
553:
554: @Override
555: protected Charset defineCharset() {
556: return Charset.forName("UTF-16LE");
557: }
558: }
559:
560: }
|