/*
Bible Plus A Bible Reader for Blackberry
Copyright (C) 2010 Yohanes Nugroho
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 <http://www.gnu.org/licenses/>.
Yohanes Nugroho (yohanes@gmail.com)
*/
package com.compactbyte.bibleplus.reader;
import java.io.*;
/**
* Class to access any Palm PDB file.
*
*/
class PDBAccess {
private PDBHeader header;
private PDBRecord[] records;
private byte[] header_data;
private PDBDataStream is;
private int record_offsets[];
private int record_attrs[];
private boolean is_corrupted;
public PDBAccess(PDBDataStream is) {
this.is = is;
}
void close() throws IOException {
is.close();
// make sure it is garbage collected
header = null;
if (records != null) for (int i = 0; i < records.length; i++) {
records[i] = null;
}
records = null;
header_data = null;
is = null;
record_offsets = null;
record_attrs = null;
}
/**
* Read and parse PDB header
*
* @return PDBHeader object
*/
public PDBHeader getHeader() throws IOException {
if (header == null) {
header_data = new byte[78];
is.read(header_data);
header = new PDBHeader(header_data);
header.load();
// System.out.println(header);
records = new PDBRecord[header.getRecordCount()];
readOffsets();
if (record_offsets[record_offsets.length - 1] > is.getSize()) {
is_corrupted = true;
return null;
}
if (!is.canSeek()) {
readAll();
}
}
return header;
}
/**
* Check if the file is corrupted (invalid offset table)
*/
public boolean isCorrupted() {
return is_corrupted;
}
private void loadRecord(int recno) throws IOException {
int length;
if (recno < records.length - 1) {
length = record_offsets[recno + 1] - record_offsets[recno];
} else {
length = (int) is.getSize() - record_offsets[recno];
}
is.seek(record_offsets[recno]);
byte[] data = new byte[length];
is.read(data);
PDBRecord pr = new PDBRecord(data);
records[recno] = pr;
}
/**
* read all record to memory if we can not seek
*/
private void readAll() throws IOException {
// System.out.println("reading all");
for (int i = 0; i < header.getRecordCount(); i++) {
loadRecord(i);
}
}
private void readOffsets() throws IOException {
int n = header.getRecordCount();
byte[] temp_read = new byte[8 * n];
is.read(temp_read);
int offs = 0;
record_offsets = new int[n];
record_attrs = new int[n];
for (int i = 0; i < n; i++) {
int val = (((temp_read[offs] & 0xff) << 24)
| ((temp_read[offs + 1] & 0xff) << 16)
| ((temp_read[offs + 2] & 0xff) << 8)
| (temp_read[offs + 3] & 0xff));
record_offsets[i] = val;
// System.out.println("offsets: " + record_offsets[i]);
record_attrs[i] = temp_read[offs + 4];
offs += 8;
}
}
/**
* Read a record
*
* @param recno
* record number
* @return PDBRecord object
*/
public PDBRecord readRecord(int recno) throws IOException {
PDBRecord pr = records[recno];
if (pr == null) {
if (is.canSeek()) {
loadRecord(recno);
}
}
return records[recno];
}
/**
* remove record from cache
*/
public void removeFromCache(int recno) {
records[recno] = null;
}
}