com.googlecode.paradox.data.TableData Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of paradoxdriver Show documentation
Show all versions of paradoxdriver Show documentation
A Paradox Java Driver (using JDBC 4)
/*
* TableData.java 03/14/2009 Copyright (C) 2009 Leonardo Alves da Costa This program is free software: you can
* redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in
* the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a
* copy of the GNU General Public License along with this program. If not, see .
*/
package com.googlecode.paradox.data;
import com.googlecode.paradox.ParadoxConnection;
import com.googlecode.paradox.data.table.value.FieldValue;
import com.googlecode.paradox.metadata.ParadoxField;
import com.googlecode.paradox.metadata.ParadoxTable;
import com.googlecode.paradox.utils.SQLStates;
import com.googlecode.paradox.utils.Utils;
import com.googlecode.paradox.utils.filefilters.TableFilter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import static com.googlecode.paradox.utils.Utils.clear;
import static com.googlecode.paradox.utils.Utils.flip;
import static com.googlecode.paradox.utils.Utils.position;
/**
* Utility class for loading table files.
*
* @author Leonardo Alves da Costa
* @version 1.1
* @since 1.0
*/
public final class TableData extends AbstractParadoxData {
/**
* Utility class.
*/
private TableData() {
super();
}
/**
* List all database tables.
*
* @param currentSchema the current schema file.
* @param connection the database connection.
* @return all {@link ParadoxTable}.
* @throws SQLException in case of failures.
*/
public static List listTables(final File currentSchema, final ParadoxConnection connection) throws
SQLException {
final ArrayList tables = new ArrayList<>();
final File[] fileList = currentSchema.listFiles(new TableFilter());
if (fileList != null) {
for (final File file : fileList) {
final ParadoxTable table = TableData.loadTableHeader(file, connection);
tables.add(table);
}
}
return tables;
}
/**
* Gets all tables within a pattern.
*
* @param schema the schema directory.
* @param pattern the pattern.
* @param connection the database connection.
* @return the tables filtered.
* @throws SQLException in case of failures.
*/
public static List listTables(final File schema, final String pattern,
final ParadoxConnection connection) throws SQLException {
final List tables = new ArrayList<>();
final File[] fileList = schema.listFiles(new TableFilter(Utils.removeDb(pattern)));
if (fileList != null) {
Arrays.sort(fileList);
for (final File file : fileList) {
final ParadoxTable table = TableData.loadTableHeader(file, connection);
tables.add(table);
}
}
return tables;
}
/**
* Load the table data from file.
*
* @param table the table to read.
* @param fields the fields to read.
* @return the row values.
* @throws SQLException in case of failures.
*/
public static List> loadData(final ParadoxTable table,
final Collection fields) throws SQLException {
final List> ret = new ArrayList<>();
if (table.isEncrypted()) {
throw new SQLException("Unsupported encrypted table files.");
}
final int blockSize = table.getBlockSizeBytes();
final int recordSize = table.getRecordSize();
final int headerSize = table.getHeaderSize();
final ByteBuffer buffer = ByteBuffer.allocate(blockSize);
try (FileInputStream fs = new FileInputStream(table.getFile()); FileChannel channel = fs.getChannel()) {
if (table.getUsedBlocks() == 0) {
return ret;
}
long nextBlock = table.getFirstBlock();
do {
buffer.order(ByteOrder.LITTLE_ENDIAN);
channel.position(headerSize + ((nextBlock - 1) * blockSize));
clear(buffer);
channel.read(buffer);
flip(buffer);
nextBlock = buffer.getShort() & 0xFFFF;
// The block number.
buffer.getShort();
final int addDataSize = buffer.getShort();
final int rowsInBlock = (addDataSize / recordSize) + 1;
buffer.order(ByteOrder.BIG_ENDIAN);
for (int loop = 0; loop < rowsInBlock; loop++) {
ret.add(TableData.readRow(table, fields, buffer));
}
} while (nextBlock != 0);
} catch (final IOException e) {
throw new SQLException(e.getMessage(), SQLStates.INVALID_IO.getValue(), e);
}
return ret;
}
/**
* Fix the buffer position based on file version ID.
*
* @param table the Paradox table.
* @param buffer the buffer to fix.
* @param fieldsSize the field list.
*/
private static void fixTablePositionByVersion(final ParadoxTable table, final Buffer buffer,
final int fieldsSize) {
if (table.getVersionId() > 4) {
if (table.getVersionId() == 0xC) {
position(buffer, 0x78 + 261 + 4 + (6 * fieldsSize));
} else {
position(buffer, 0x78 + 83 + (6 * fieldsSize));
}
} else {
position(buffer, 0x58 + 83 + (6 * fieldsSize));
}
}
/**
* Gets the table header from a file.
*
* @param file the {@link File} to read.
* @param connection the database connection.
* @return the {@link ParadoxTable}.
* @throws SQLException in case of reading errors.
*/
private static ParadoxTable loadTableHeader(final File file, final ParadoxConnection connection) throws
SQLException {
final ParadoxTable table = new ParadoxTable(file, file.getName(), connection);
ByteBuffer buffer = ByteBuffer.allocate(2048);
buffer.order(ByteOrder.LITTLE_ENDIAN);
try (FileInputStream fs = new FileInputStream(file); FileChannel channel = fs.getChannel()) {
channel.read(buffer);
flip(buffer);
table.setRecordSize(buffer.getShort() & 0xFFFF);
table.setHeaderSize(buffer.getShort() & 0xFFFF);
table.setType(buffer.get());
table.setBlockSize(buffer.get());
table.setRowCount(buffer.getInt());
table.setUsedBlocks(buffer.getShort());
table.setTotalBlocks(buffer.getShort());
table.setFirstBlock(buffer.getShort());
table.setLastBlock(buffer.getShort());
position(buffer, 0x21);
table.setFieldCount(buffer.getShort());
table.setPrimaryFieldCount(buffer.getShort());
// Check for encrypted file.
position(buffer, 0x25);
int value = buffer.getInt();
position(buffer, 0x38);
table.setWriteProtected(buffer.get());
table.setVersionId(buffer.get());
// Paradox version 4.x and up.
if (value == 0xFF00FF00 && table.getVersionId() > 4) {
position(buffer, 0x5c);
value = buffer.getInt();
}
table.setEncryptedData(value);
position(buffer, 0x49);
table.setAutoIncrementValue(buffer.getInt());
table.setFirstFreeBlock(buffer.getShort());
position(buffer, 0x55);
table.setReferentialIntegrity(buffer.get());
parseVersionID(buffer, table);
final List fields = TableData.parseTableFields(table, buffer);
// Restart the buffer with all table header
channel.position(0);
buffer = ByteBuffer.allocate(table.getHeaderSize());
channel.read(buffer);
TableData.fixTablePositionByVersion(table, buffer, fields.size());
TableData.parseTableFieldsName(table, buffer, fields);
TableData.parseTableFieldsOrder(table, buffer);
} catch (final IOException e) {
throw new SQLException(e.getMessage(), SQLStates.INVALID_IO.getValue(), e);
}
return table;
}
/**
* Read fields attributes.
*
* @param table the Paradox table.
* @param buffer the buffer to read of.
* @return the Paradox field list.
* @throws SQLException in case of parse errors.
*/
private static List parseTableFields(final ParadoxTable table, final ByteBuffer buffer) throws
SQLException {
final List fields = new ArrayList<>();
for (int loop = 0; loop < table.getFieldCount(); loop++) {
final ParadoxField field = new ParadoxField(loop + 1);
field.setType(buffer.get());
field.setSize(buffer.get() & 0xff);
field.setTableName(table.getName());
field.setTable(table);
fields.add(field);
}
return fields;
}
/**
* Parse the Paradox fields name.
*
* @param table the Paradox table.
* @param buffer the buffer to read of.
* @param fields the field list.
*/
private static void parseTableFieldsName(final ParadoxTable table, final ByteBuffer buffer,
final List fields) {
for (int loop = 0; loop < table.getFieldCount(); loop++) {
final ByteBuffer name = ByteBuffer.allocate(261);
while (true) {
final byte c = buffer.get();
if (c == 0) {
break;
}
name.put(c);
}
flip(name);
fields.get(loop).setName(table.getCharset().decode(name).toString());
}
table.setFields(fields);
}
/**
* Parse the fields order.
*
* @param table the Paradox table.
* @param buffer the buffer to read of.
*/
private static void parseTableFieldsOrder(final ParadoxTable table, final ByteBuffer buffer) {
final List fieldsOrder = new ArrayList<>();
for (int loop = 0; loop < table.getFieldCount(); loop++) {
fieldsOrder.add(buffer.getShort());
}
table.setFieldsOrder(fieldsOrder);
}
/**
* Read a entire row.
*
* @param table the table to read of.
* @param fields the fields to read.
* @param buffer the buffer to read of.
* @return the row.
* @throws SQLException in case of parse errors.
*/
private static List readRow(final ParadoxTable table, final Collection fields,
final ByteBuffer buffer) throws SQLException {
final List row = new ArrayList<>();
for (final ParadoxField field : table.getFields()) {
final FieldValue fieldValue = FieldFactory.parse(table, buffer, field);
// Field filter
if (fields.contains(field) && (fieldValue != null)) {
fieldValue.setField(field);
row.add(fieldValue);
}
}
return row;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy