All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.googlecode.paradox.data.IndexData Maven / Gradle / Ivy

There is a newer version: 1.6.3
Show newest version
/*
 * IndexData.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.metadata.ParadoxDataFile;
import com.googlecode.paradox.metadata.ParadoxField;
import com.googlecode.paradox.metadata.ParadoxIndex;
import com.googlecode.paradox.utils.Utils;
import com.googlecode.paradox.utils.filefilters.SecondaryIndexFilter;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import static com.googlecode.paradox.utils.Utils.flip;
import static com.googlecode.paradox.utils.Utils.position;

/**
 * Reads index data files.
 *
 * @author Leonardo Alves da Costa
 * @version 1.1
 * @since 1.0
 */
public final class IndexData extends AbstractParadoxData {

    /**
     * Utility class.
     */
    private IndexData() {
        super();
    }

    /**
     * List the indexes in a database file.
     *
     * @param currentSchema the current schema file.
     * @param tableName     the table name.
     * @param connection    the database connection.
     * @return a list of {@link ParadoxIndex}.
     * @throws SQLException in case of reading failures.
     */
    public static List listIndexes(final File currentSchema, final String tableName,
            final ParadoxConnection connection) throws SQLException {
        final ArrayList indexes = new ArrayList<>();
        final String indexNamePattern = Utils.removeDb(tableName) + ".X??";
        final File[] fileList = currentSchema.listFiles(new SecondaryIndexFilter(indexNamePattern));
        if (fileList != null) {
            for (final File file : fileList) {
                try {
                    final ParadoxIndex index = IndexData.loadIndexHeader(file, connection);
                    indexes.add(index);
                } catch (final IOException ex) {
                    throw new SQLException("Error loading Paradox index.", ex);
                }
            }
        }
        return indexes;
    }

    /**
     * Loads the database file header.
     *
     * @param file       the database {@link File}.
     * @param connection the database connection.
     * @return the {@link ParadoxIndex} reference.
     * @throws IOException  if case of I/O exceptions.
     * @throws SQLException in case of database errors.
     */
    private static ParadoxIndex loadIndexHeader(final File file, final ParadoxConnection connection) throws IOException,
            SQLException {
        final ByteBuffer buffer = ByteBuffer.allocate(2048);

        buffer.order(ByteOrder.LITTLE_ENDIAN);

        final ParadoxIndex index = new ParadoxIndex(file, file.getName(), connection);

        try (final FileInputStream fs = new FileInputStream(file); FileChannel channel = fs.getChannel()) {
            channel.read(buffer);
            flip(buffer);

            index.setRecordSize(buffer.getShort());
            index.setHeaderSize(buffer.getShort());
            index.setType(buffer.get());
            index.setBlockSize(buffer.get());
            index.setRowCount(buffer.getInt());
            index.setUsedBlocks(buffer.getShort());
            index.setTotalBlocks(buffer.getShort());
            index.setFirstBlock(buffer.getShort());
            index.setLastBlock(buffer.getShort());

            position(buffer, 0x21);
            index.setFieldCount(buffer.getShort());
            index.setPrimaryFieldCount(buffer.getShort());

            position(buffer, 0x38);
            index.setWriteProtected(buffer.get());
            index.setVersionId(buffer.get());

            position(buffer, 0x49);
            index.setAutoIncrementValue(buffer.getInt());
            index.setFirstFreeBlock(buffer.getShort());

            position(buffer, 0x55);
            index.setReferentialIntegrity(buffer.get());

            parseVersionID(buffer, index);

            parseFields(buffer, index);

            IndexData.parseSortID(buffer, index);
            IndexData.parseIndexName(buffer, index);
        }
        return index;
    }

    /**
     * Parse the index names.
     *
     * @param buffer the buffer to parse.
     * @param index  the paradox index.
     */
    private static void parseIndexName(final ByteBuffer buffer, final ParadoxIndex index) {
        final ByteBuffer name = ByteBuffer.allocate(26);
        while (true) {
            final byte c = buffer.get();
            if (c == 0) {
                break;
            }
            name.put(c);
        }
        flip(name);
        final String tempName = index.getCharset().decode(name).toString();
        if (tempName.length() != 0) {
            index.setName(tempName);
        }
    }

    /**
     * Parse fields in index header.
     *
     * @param buffer the buffer to parse.
     * @param index  the paradox index.
     * @throws SQLException in case of parse errors.
     */
    protected static void parseFields(final ByteBuffer buffer, final ParadoxDataFile index) throws SQLException {
        final ArrayList fields = new ArrayList<>();
        for (int loop = 0; loop < index.getFieldCount(); loop++) {
            final ParadoxField field = new ParadoxField(loop + 1);
            field.setType(buffer.get());
            field.setSize((int) buffer.get());
            fields.add(field);
        }

        if (index.getVersionId() > 4) {
            if (index.getVersionId() == 0xC) {
                position(buffer, 0x78 + 261 + 4 + (6 * fields.size()));
            } else {
                position(buffer, 0x78 + 83 + (6 * fields.size()));
            }
        } else {
            position(buffer, 0x58 + 83 + (6 * fields.size()));
        }

        for (int loop = 0; loop < index.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(index.getCharset().decode(name).toString());
        }
        index.setFields(fields);

        final ArrayList fieldsOrder = new ArrayList<>();
        for (int loop = 0; loop < index.getFieldCount(); loop++) {
            fieldsOrder.add(buffer.getShort());
        }
        index.setFieldsOrder(fieldsOrder);
    }

    /**
     * Parse the sort order ID.
     *
     * @param buffer the buffer to parse.
     * @param index  the paradox index.
     */
    private static void parseSortID(final ByteBuffer buffer, final ParadoxIndex index) {
        final ByteBuffer sortOrderID = ByteBuffer.allocate(26);
        while (true) {
            final byte c = buffer.get();
            if (c == 0) {
                break;
            }
            sortOrderID.put(c);
        }
        flip(sortOrderID);
        index.setSortOrderID(index.getCharset().decode(sortOrderID).toString());
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy