[jsword-svn] r1361 - trunk/jsword/src/main/java/org/crosswire/jsword/book/sword
dmsmith at www.crosswire.org
dmsmith at www.crosswire.org
Wed May 30 13:29:32 MST 2007
Author: dmsmith
Date: 2007-05-30 13:29:31 -0700 (Wed, 30 May 2007)
New Revision: 1361
Added:
trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/ZVerseBackend.java
Removed:
trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/CompressionType.java
trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/GZIPBackend.java
trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/LZSSBackend.java
Modified:
trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/BookType.java
trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/Msg.java
Log:
Changed JSword to fully use LZSS code.
Modified: trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/BookType.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/BookType.java 2007-05-30 20:27:18 UTC (rev 1360)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/BookType.java 2007-05-30 20:29:31 UTC (rev 1361)
@@ -70,14 +70,10 @@
protected AbstractBackend getBackend(SwordBookMetaData sbmd) throws BookException
{
- return getCompressedBackend(sbmd);
+ BlockType blockType = BlockType.fromString(sbmd.getProperty(ConfigEntryType.BLOCK_TYPE));
+ return new ZVerseBackend(sbmd, blockType);
}
- protected boolean isBackendSupported(SwordBookMetaData sbmd)
- {
- return isCompressedBackendSupported(sbmd);
- }
-
/**
* Serialization ID
*/
@@ -117,14 +113,10 @@
protected AbstractBackend getBackend(SwordBookMetaData sbmd) throws BookException
{
- return getCompressedBackend(sbmd);
+ BlockType blockType = BlockType.fromString(sbmd.getProperty(ConfigEntryType.BLOCK_TYPE));
+ return new ZVerseBackend(sbmd, blockType);
}
- protected boolean isBackendSupported(SwordBookMetaData sbmd)
- {
- return isCompressedBackendSupported(sbmd);
- }
-
/**
* Serialization ID
*/
@@ -263,11 +255,6 @@
return new GenBookBackend(sbmd);
}
- protected boolean isBackendSupported(SwordBookMetaData sbmd)
- {
- return true;
- }
-
/**
* Serialization ID
*/
@@ -318,19 +305,10 @@
*/
public boolean isSupported(SwordBookMetaData sbmd)
{
- return type != null && isBackendSupported(sbmd);
+ return type != null && sbmd != null;
}
/**
- * By default the backend is supported if the BookMetaData is not null.
- * @return true if this is a useable BackEnd
- */
- protected boolean isBackendSupported(SwordBookMetaData sbmd)
- {
- return sbmd != null;
- }
-
- /**
* Create a Book appropriate for the BookMetaData
* @throws BookException
*/
@@ -350,33 +328,6 @@
protected abstract AbstractBackend getBackend(SwordBookMetaData sbmd) throws BookException;
/**
- *
- */
- protected static AbstractBackend getCompressedBackend(SwordBookMetaData sbmd) throws BookException
- {
- String cStr = sbmd.getProperty(ConfigEntryType.COMPRESS_TYPE);
- if (cStr != null)
- {
- return CompressionType.fromString(cStr).getBackend(sbmd);
- }
- assert false;
- throw new BookException(Msg.COMPRESSION_UNSUPPORTED, new Object[] { "no compression given" }); //$NON-NLS-1$
- }
-
- /**
- *
- */
- protected static boolean isCompressedBackendSupported(SwordBookMetaData sbmd)
- {
- String cStr = sbmd.getProperty(ConfigEntryType.COMPRESS_TYPE);
- if (cStr != null)
- {
- return CompressionType.fromString(cStr).isSupported();
- }
- return false;
- }
-
- /**
* The name of the BookType
*/
private String name;
Deleted: trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/CompressionType.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/CompressionType.java 2007-05-30 20:27:18 UTC (rev 1360)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/CompressionType.java 2007-05-30 20:29:31 UTC (rev 1361)
@@ -1,166 +0,0 @@
-/**
- * Distribution License:
- * JSword is free software; you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License, version 2.1 as published by
- * the Free Software Foundation. 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 Lesser General Public License for more details.
- *
- * The License is available on the internet at:
- * http://www.gnu.org/copyleft/lgpl.html
- * or by writing to:
- * Free Software Foundation, Inc.
- * 59 Temple Place - Suite 330
- * Boston, MA 02111-1307, USA
- *
- * Copyright: 2005
- * The copyright to this program is held by it's authors.
- *
- * ID: $Id$
- */
-package org.crosswire.jsword.book.sword;
-
-import java.io.Serializable;
-
-import org.crosswire.jsword.book.BookException;
-
-/**
- * Data about Compression types.
- *
- * @see gnu.lgpl.License for license details.
- * The copyright to this program is held by it's authors.
- * @author Joe Walker [joe at eireneh dot com]
- * @author DM Smith [dmsmith555 at yahoo dot com]
- */
-public abstract class CompressionType implements Serializable
-{
- /**
- * The level of compression is the Book
- */
- public static final CompressionType COMPRESSION_ZIP = new CompressionType("ZIP") //$NON-NLS-1$
- {
- public boolean isSupported()
- {
- return true;
- }
- protected AbstractBackend getBackend(SwordBookMetaData sbmd) throws BookException
- {
- BlockType blockType = BlockType.fromString(sbmd.getProperty(ConfigEntryType.BLOCK_TYPE));
- return new GZIPBackend(sbmd, blockType);
- }
-
- /**
- * Serialization ID
- */
- private static final long serialVersionUID = 3977014063492642096L;
- };
-
- /**
- * The level of compression is the Book
- */
- public static final CompressionType COMPRESSION_LZSS = new CompressionType("LZSS") //$NON-NLS-1$
- {
- public boolean isSupported()
- {
- return false;
- }
- protected AbstractBackend getBackend(SwordBookMetaData sbmd) throws BookException
- {
- return new LZSSBackend(sbmd);
- }
-
- /**
- * Serialization ID
- */
- private static final long serialVersionUID = 3257847692691517494L;
- };
-
- /**
- * Simple ctor
- */
- public CompressionType(String name)
- {
- this.name = name;
- }
-
- /**
- * Returns whether this compression is implemented at this time.
- *
- * @return true if it is supported.
- */
- abstract boolean isSupported();
-
- abstract AbstractBackend getBackend(SwordBookMetaData sbmd) throws BookException;
-
- /**
- * Lookup method to convert from a String
- */
- public static CompressionType fromString(String name)
- {
- for (int i = 0; i < VALUES.length; i++)
- {
- CompressionType obj = VALUES[i];
- if (obj.name.equalsIgnoreCase(name))
- {
- return obj;
- }
- }
-
- throw new ClassCastException(Msg.UNDEFINED_DATATYPE.toString(name));
- }
-
- /**
- * Lookup method to convert from an integer
- */
- public static CompressionType fromInteger(int i)
- {
- return VALUES[i];
- }
-
- /**
- * Prevent subclasses from overriding canonical identity based Object methods
- * @see java.lang.Object#equals(java.lang.Object)
- */
- public final boolean equals(Object o)
- {
- return super.equals(o);
- }
-
- /**
- * Prevent subclasses from overriding canonical identity based Object methods
- * @see java.lang.Object#hashCode()
- */
- public final int hashCode()
- {
- return super.hashCode();
- }
-
- /* (non-Javadoc)
- * @see java.lang.Object#toString()
- */
- public String toString()
- {
- return name;
- }
-
- /**
- * The name of the CompressionType
- */
- private String name;
-
- // Support for serialization
- private static int nextObj;
- private final int obj = nextObj++;
-
- Object readResolve()
- {
- return VALUES[obj];
- }
-
- private static final CompressionType[] VALUES =
- {
- COMPRESSION_ZIP,
- COMPRESSION_LZSS,
- };
-}
Deleted: trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/GZIPBackend.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/GZIPBackend.java 2007-05-30 20:27:18 UTC (rev 1360)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/GZIPBackend.java 2007-05-30 20:29:31 UTC (rev 1361)
@@ -1,392 +0,0 @@
-/**
- * Distribution License:
- * JSword is free software; you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License, version 2.1 as published by
- * the Free Software Foundation. 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 Lesser General Public License for more details.
- *
- * The License is available on the internet at:
- * http://www.gnu.org/copyleft/lgpl.html
- * or by writing to:
- * Free Software Foundation, Inc.
- * 59 Temple Place - Suite 330
- * Boston, MA 02111-1307, USA
- *
- * Copyright: 2005
- * The copyright to this program is held by it's authors.
- *
- * ID: $Id$
- */
-package org.crosswire.jsword.book.sword;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-
-import org.crosswire.common.activate.Activator;
-import org.crosswire.common.activate.Lock;
-import org.crosswire.common.compress.CompressorType;
-import org.crosswire.common.util.FileUtil;
-import org.crosswire.common.util.Logger;
-import org.crosswire.jsword.book.BookException;
-import org.crosswire.jsword.passage.Key;
-import org.crosswire.jsword.passage.KeyUtil;
-import org.crosswire.jsword.passage.Verse;
-
-/**
- * A backend to read compressed data verse based files. While the text file contains
- * data compressed with ZIP or LZSS, it cannot be uncompressed using a stand
- * alone zip utility, such as WinZip or gzip. The reason for this is
- * that the data file is a concatenation of blocks of compressed data.
- *
- * <p>The blocks can either be "b", book (aka testament); "c", chapter
- * or "v", verse. The choice is a matter of trade offs. The program needs
- * to uncompress a block into memory. Having it at the book level is
- * very memory expensive. Having it at the verse level is very disk
- * expensive, but takes the least amount of memory. The most common is
- * chapter.</p>
- *
- * <p>In order to find the data in the text file, we need to find the
- * block. The first index (comp) is used for this. Each verse is indexed
- * to a tuple (block number, verse start, verse size). This data allows
- * us to find the correct block, and to extract the verse from the
- * uncompressed block, but it does not help us uncompress the block.</p>
- *
- * <p>Once the block is known, then the next index (idx) gives the location
- * of the compressed block, its compressed size and its uncompressed size.</p>
- *
- * <p>There are 3 files for each testament, 2 (comp and idx) are indexes into
- * the third (text) which contains the data. The key into each index is the
- * verse index within that testament, which is determined by book, chapter
- * and verse of that key.</p>
- *
- * <p>All numbers are stored 2-complement, little endian.</p>
- * <p>Then proceed as follows, at all times working on the set of files for the
- * testament in question:</p>
- *
- * <pre>
- * in the comp file, seek to the index * 10
- * read 10 bytes.
- * the block-index is the first 4 bytes (32-bit number)
- * the next bytes are the verse offset and length of the uncompressed block.
- *
- * in the idx file seek to block-index * 12
- * read 12 bytes
- * the text-block-index is the first 4 bytes
- * the data-size is the next 4 bytes
- * the uncompressed-size is the next 4 bytes
- *
- * in the text file seek to the text-block-index
- * read data-size bytes
- * decipher them if they are encrypted
- * unGZIP them into a byte array of uncompressed-size
- * </pre>
- *
- * TODO(DM): Testament 0 is used to index an README file for the bible.
- * At this time it is ignored.
- *
- * @see gnu.lgpl.License for license details.
- * The copyright to this program is held by it's authors.
- * @author Joe Walker [joe at eireneh dot com]
- */
-public class GZIPBackend extends AbstractBackend
-{
- private static final String SUFFIX_COMP = "v"; //$NON-NLS-1$
- private static final String SUFFIX_INDEX = "s"; //$NON-NLS-1$
- private static final String SUFFIX_PART1 = "z"; //$NON-NLS-1$
- private static final String SUFFIX_TEXT = "z"; //$NON-NLS-1$
-
- /**
- * Simple ctor
- */
- public GZIPBackend(SwordBookMetaData sbmd, BlockType blockType) throws BookException
- {
- super(sbmd);
-
- String path = getExpandedDataPath();
- String otAllButLast = path + File.separator + SwordConstants.FILE_OT + '.' + blockType.getIndicator() + SUFFIX_PART1;
- idxFile[SwordConstants.TESTAMENT_OLD] = new File(otAllButLast + SUFFIX_INDEX);
- textFile[SwordConstants.TESTAMENT_OLD] = new File(otAllButLast + SUFFIX_TEXT);
- compFile[SwordConstants.TESTAMENT_OLD] = new File(otAllButLast + SUFFIX_COMP);
-
- String ntAllButLast = path + File.separator + SwordConstants.FILE_NT + '.' + blockType.getIndicator() + SUFFIX_PART1;
- idxFile[SwordConstants.TESTAMENT_NEW] = new File(ntAllButLast + SUFFIX_INDEX);
- textFile[SwordConstants.TESTAMENT_NEW] = new File(ntAllButLast + SUFFIX_TEXT);
- compFile[SwordConstants.TESTAMENT_NEW] = new File(ntAllButLast + SUFFIX_COMP);
-
- // It is an error to be neither OT nor NT
- if (!textFile[SwordConstants.TESTAMENT_OLD].canRead()
- && !textFile[SwordConstants.TESTAMENT_NEW].canRead())
- {
- log.error("Failed to find OT or NT files: '" + otAllButLast + SUFFIX_TEXT + "' and '" + ntAllButLast + SUFFIX_TEXT + "'"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- throw new BookException(Msg.MISSING_FILE, new Object[] { path });
- }
- }
-
- /* (non-Javadoc)
- * @see org.crosswire.common.activate.Activatable#activate(org.crosswire.common.activate.Lock)
- */
- public final void activate(Lock lock)
- {
- if (idxFile[SwordConstants.TESTAMENT_OLD].canRead())
- {
- try
- {
- idxRaf[SwordConstants.TESTAMENT_OLD] = new RandomAccessFile(idxFile[SwordConstants.TESTAMENT_OLD], FileUtil.MODE_READ);
- textRaf[SwordConstants.TESTAMENT_OLD] = new RandomAccessFile(textFile[SwordConstants.TESTAMENT_OLD], FileUtil.MODE_READ);
- compRaf[SwordConstants.TESTAMENT_OLD] = new RandomAccessFile(compFile[SwordConstants.TESTAMENT_OLD], FileUtil.MODE_READ);
- }
- catch (FileNotFoundException ex)
- {
- assert false : ex;
- log.error("Could not open OT", ex); //$NON-NLS-1$
- idxRaf[SwordConstants.TESTAMENT_OLD] = null;
- textRaf[SwordConstants.TESTAMENT_OLD] = null;
- compRaf[SwordConstants.TESTAMENT_OLD] = null;
- }
- }
-
- if (idxFile[SwordConstants.TESTAMENT_NEW].canRead())
- {
- try
- {
- idxRaf[SwordConstants.TESTAMENT_NEW] = new RandomAccessFile(idxFile[SwordConstants.TESTAMENT_NEW], FileUtil.MODE_READ);
- textRaf[SwordConstants.TESTAMENT_NEW] = new RandomAccessFile(textFile[SwordConstants.TESTAMENT_NEW], FileUtil.MODE_READ);
- compRaf[SwordConstants.TESTAMENT_NEW] = new RandomAccessFile(compFile[SwordConstants.TESTAMENT_NEW], FileUtil.MODE_READ);
- }
- catch (FileNotFoundException ex)
- {
- assert false : ex;
- log.error("Could not open NT", ex); //$NON-NLS-1$
- idxRaf[SwordConstants.TESTAMENT_NEW] = null;
- textRaf[SwordConstants.TESTAMENT_NEW] = null;
- compRaf[SwordConstants.TESTAMENT_NEW] = null;
- }
- }
-
- active = true;
- }
-
- /* (non-Javadoc)
- * @see org.crosswire.common.activate.Activatable#deactivate(org.crosswire.common.activate.Lock)
- */
- public final void deactivate(Lock lock)
- {
- if (idxRaf[SwordConstants.TESTAMENT_NEW] != null)
- {
- try
- {
- idxRaf[SwordConstants.TESTAMENT_NEW].close();
- textRaf[SwordConstants.TESTAMENT_NEW].close();
- compRaf[SwordConstants.TESTAMENT_NEW].close();
- }
- catch (IOException ex)
- {
- log.error("failed to close nt files", ex); //$NON-NLS-1$
- }
- finally
- {
- idxRaf[SwordConstants.TESTAMENT_NEW] = null;
- textRaf[SwordConstants.TESTAMENT_NEW] = null;
- compRaf[SwordConstants.TESTAMENT_NEW] = null;
- }
- }
-
- if (idxRaf[SwordConstants.TESTAMENT_OLD] != null)
- {
- try
- {
- idxRaf[SwordConstants.TESTAMENT_OLD].close();
- textRaf[SwordConstants.TESTAMENT_OLD].close();
- compRaf[SwordConstants.TESTAMENT_OLD].close();
- }
- catch (IOException ex)
- {
- log.error("failed to close ot files", ex); //$NON-NLS-1$
- }
- finally
- {
- idxRaf[SwordConstants.TESTAMENT_OLD] = null;
- textRaf[SwordConstants.TESTAMENT_OLD] = null;
- compRaf[SwordConstants.TESTAMENT_OLD] = null;
- }
- }
-
- active = false;
- }
-
- /*
- * (non-Javadoc)
- * @see org.crosswire.jsword.book.sword.AbstractBackend#getRawText(org.crosswire.jsword.passage.Key, java.lang.String)
- */
- /* @Override */
- public String getRawText(Key key) throws BookException
- {
- checkActive();
-
- SwordBookMetaData sbmd = getBookMetaData();
- String charset = sbmd.getBookCharset();
- String compressType = sbmd.getProperty(ConfigEntryType.COMPRESS_TYPE);
-
- Verse verse = KeyUtil.getVerse(key);
-
- try
- {
- int testament = SwordConstants.getTestament(verse);
- long index = SwordConstants.getIndex(verse);
-
- // If Bible does not contain the desired testament, return nothing.
- if (compRaf[testament] == null)
- {
- return ""; //$NON-NLS-1$
- }
-
- // 10 because we the index is 10 bytes long for each verse
- byte[] temp = SwordUtil.readRAF(compRaf[testament], index * COMP_ENTRY_SIZE, COMP_ENTRY_SIZE);
-
- // If the Bible does not contain the desired verse, return nothing.
- // Some Bibles have different versification, so the requested verse
- // may not exist.
- if (temp == null || temp.length == 0)
- {
- return ""; //$NON-NLS-1$
- }
-
- // The data is little endian - extract the blockNum, verseStart and verseSize
- long blockNum = SwordUtil.decodeLittleEndian32(temp, 0);
- int verseStart = SwordUtil.decodeLittleEndian32(temp, 4);
- int verseSize = SwordUtil.decodeLittleEndian16(temp, 8);
-
- // Can we get the data from the cache
- byte[] uncompressed = null;
- if (blockNum == lastBlockNum && testament == lastTestament)
- {
- uncompressed = lastUncompressed;
- }
- else
- {
- // Then seek using this index into the idx file
- temp = SwordUtil.readRAF(idxRaf[testament], blockNum * IDX_ENTRY_SIZE, IDX_ENTRY_SIZE);
- if (temp == null || temp.length == 0)
- {
- return ""; //$NON-NLS-1$
- }
-
- int blockStart = SwordUtil.decodeLittleEndian32(temp, 0);
- int blockSize = SwordUtil.decodeLittleEndian32(temp, 4);
- int uncompressedSize = SwordUtil.decodeLittleEndian32(temp, 8);
-
- // Read from the data file.
- byte[] data = SwordUtil.readRAF(textRaf[testament], blockStart, blockSize);
-
- decipher(data);
-
- uncompressed = CompressorType.fromString(compressType).getCompressor(data).uncompress(uncompressedSize);
-
- // cache the uncompressed data for next time
- lastBlockNum = blockNum;
- lastTestament = testament;
- lastUncompressed = uncompressed;
- }
-
- // and cut out the required section.
- byte[] chopped = new byte[verseSize];
- System.arraycopy(uncompressed, verseStart, chopped, 0, verseSize);
-
- return SwordUtil.decode(key, chopped, charset);
- }
- catch (IOException e)
- {
- throw new BookException(Msg.READ_FAIL, e, new Object[] { verse.getName() });
- }
- }
-
- /* (non-Javadoc)
- * @see org.crosswire.jsword.book.sword.AbstractBackend#readIndex()
- */
- /* @Override */
- public Key readIndex()
- {
- // PENDING(joe): refactor to get rid of this
- return null;
- }
-
- /**
- * Helper method so we can quickly activate ourselves on access
- */
- protected final void checkActive()
- {
- if (!active)
- {
- Activator.activate(this);
- }
- }
-
- /**
- *
- */
- private int lastTestament = -1;
-
- /**
- *
- */
- private long lastBlockNum = -1;
-
- /**
- *
- */
- private byte[] lastUncompressed;
-
- /**
- * Are we active
- */
- private boolean active;
-
- /**
- * The log stream
- */
- private static final Logger log = Logger.getLogger(GZIPBackend.class);
-
- /**
- * The array of index random access files
- */
- private RandomAccessFile[] idxRaf = new RandomAccessFile[3];
-
- /**
- * The array of data random access files
- */
- private RandomAccessFile[] textRaf = new RandomAccessFile[3];
-
- /**
- * The array of compressed random access files
- */
- private RandomAccessFile[] compRaf = new RandomAccessFile[3];
-
- /**
- * The array of index random access files
- */
- private File[] idxFile = new File[3];
-
- /**
- * The array of data random access files
- */
- private File[] textFile = new File[3];
-
- /**
- * The array of compressed random access files
- */
- private File[] compFile = new File[3];
-
- /**
- * How many bytes in the comp index?
- */
- private static final int COMP_ENTRY_SIZE = 10;
-
- /**
- * How many bytes in the idx index?
- */
- private static final int IDX_ENTRY_SIZE = 12;
-}
Deleted: trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/LZSSBackend.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/LZSSBackend.java 2007-05-30 20:27:18 UTC (rev 1360)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/LZSSBackend.java 2007-05-30 20:29:31 UTC (rev 1361)
@@ -1,87 +0,0 @@
-/**
- * Distribution License:
- * JSword is free software; you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License, version 2.1 as published by
- * the Free Software Foundation. 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 Lesser General Public License for more details.
- *
- * The License is available on the internet at:
- * http://www.gnu.org/copyleft/lgpl.html
- * or by writing to:
- * Free Software Foundation, Inc.
- * 59 Temple Place - Suite 330
- * Boston, MA 02111-1307, USA
- *
- * Copyright: 2005
- * The copyright to this program is held by it's authors.
- *
- * ID: $Id$
- */
-package org.crosswire.jsword.book.sword;
-
-import org.crosswire.common.activate.Lock;
-import org.crosswire.jsword.book.BookException;
-import org.crosswire.jsword.passage.Key;
-
-/**
- * A backend to read LZSS compressed data files.
- *
- * @see gnu.lgpl.License for license details.
- * The copyright to this program is held by it's authors.
- * @author Joe Walker [joe at eireneh dot com]
- */
-public class LZSSBackend extends AbstractBackend
-{
- /**
- * Simple ctor
- */
- public LZSSBackend(SwordBookMetaData sbmd)
- {
- super(sbmd);
- }
-
- /* (non-Javadoc)
- * @see org.crosswire.common.activate.Activatable#activate(org.crosswire.common.activate.Lock)
- */
- public final void activate(Lock lock)
- {
- }
-
- /* (non-Javadoc)
- * @see org.crosswire.common.activate.Activatable#deactivate(org.crosswire.common.activate.Lock)
- */
- public final void deactivate(Lock lock)
- {
- }
-
- /* (non-Javadoc)
- * @see org.crosswire.jsword.book.sword.AbstractBackend#getRawText(org.crosswire.jsword.passage.Key, java.lang.String)
- */
- /* @Override */
- public String getRawText(Key key) throws BookException
- {
- // LATER(joe): implement this
- throw new BookException(Msg.COMPRESSION_UNSUPPORTED, new Object[] { getBookMetaData().getName() });
- }
-
- /* (non-Javadoc)
- * @see org.crosswire.jsword.book.sword.AbstractBackend#readIndex()
- */
- /* @Override */
- public Key readIndex()
- {
- // PENDING(joe): refactor to get rid of this
- return null;
- }
-
- /* (non-Javadoc)
- * @see org.crosswire.jsword.book.sword.AbstractBackend#isSupported()
- */
- /* @Override */
- public boolean isSupported()
- {
- return false;
- }
-}
Modified: trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/Msg.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/Msg.java 2007-05-30 20:27:18 UTC (rev 1360)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/Msg.java 2007-05-30 20:29:31 UTC (rev 1361)
@@ -36,8 +36,8 @@
static final Msg BAD_KEY = new Msg("RawLDBackend.BadKey"); //$NON-NLS-1$
static final Msg GZIP_FORMAT = new Msg("SwordUtil.GZIPFormat"); //$NON-NLS-1$
static final Msg FILTER_FAIL = new Msg("SwordDictionary.FilterFail"); //$NON-NLS-1$
- static final Msg MISSING_FILE = new Msg("GZIPBackend.MissingFile"); //$NON-NLS-1$
- static final Msg READ_FAIL = new Msg("GZIPBackend.ReadFail"); //$NON-NLS-1$
+ static final Msg MISSING_FILE = new Msg("ZVerseBackend.MissingFile"); //$NON-NLS-1$
+ static final Msg READ_FAIL = new Msg("ZVerseBackend.ReadFail"); //$NON-NLS-1$
static final Msg COMPRESSION_UNSUPPORTED = new Msg("BookType.CompressionUnsupported"); //$NON-NLS-1$
static final Msg TYPE_UNSUPPORTED = new Msg("SwordBookDriver.TypeUnsuported"); //$NON-NLS-1$
static final Msg DELETE_FAILED = new Msg("SwordBookDriver.DeleteFailed"); //$NON-NLS-1$
Copied: trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/ZVerseBackend.java (from rev 1359, trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/GZIPBackend.java)
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/ZVerseBackend.java (rev 0)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/ZVerseBackend.java 2007-05-30 20:29:31 UTC (rev 1361)
@@ -0,0 +1,392 @@
+/**
+ * Distribution License:
+ * JSword is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License, version 2.1 as published by
+ * the Free Software Foundation. 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 Lesser General Public License for more details.
+ *
+ * The License is available on the internet at:
+ * http://www.gnu.org/copyleft/lgpl.html
+ * or by writing to:
+ * Free Software Foundation, Inc.
+ * 59 Temple Place - Suite 330
+ * Boston, MA 02111-1307, USA
+ *
+ * Copyright: 2005
+ * The copyright to this program is held by it's authors.
+ *
+ * ID: $Id$
+ */
+package org.crosswire.jsword.book.sword;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+import org.crosswire.common.activate.Activator;
+import org.crosswire.common.activate.Lock;
+import org.crosswire.common.compress.CompressorType;
+import org.crosswire.common.util.FileUtil;
+import org.crosswire.common.util.Logger;
+import org.crosswire.jsword.book.BookException;
+import org.crosswire.jsword.passage.Key;
+import org.crosswire.jsword.passage.KeyUtil;
+import org.crosswire.jsword.passage.Verse;
+
+/**
+ * A backend to read compressed data verse based files. While the text file contains
+ * data compressed with ZIP or LZSS, it cannot be uncompressed using a stand
+ * alone zip utility, such as WinZip or gzip. The reason for this is
+ * that the data file is a concatenation of blocks of compressed data.
+ *
+ * <p>The blocks can either be "b", book (aka testament); "c", chapter
+ * or "v", verse. The choice is a matter of trade offs. The program needs
+ * to uncompress a block into memory. Having it at the book level is
+ * very memory expensive. Having it at the verse level is very disk
+ * expensive, but takes the least amount of memory. The most common is
+ * chapter.</p>
+ *
+ * <p>In order to find the data in the text file, we need to find the
+ * block. The first index (comp) is used for this. Each verse is indexed
+ * to a tuple (block number, verse start, verse size). This data allows
+ * us to find the correct block, and to extract the verse from the
+ * uncompressed block, but it does not help us uncompress the block.</p>
+ *
+ * <p>Once the block is known, then the next index (idx) gives the location
+ * of the compressed block, its compressed size and its uncompressed size.</p>
+ *
+ * <p>There are 3 files for each testament, 2 (comp and idx) are indexes into
+ * the third (text) which contains the data. The key into each index is the
+ * verse index within that testament, which is determined by book, chapter
+ * and verse of that key.</p>
+ *
+ * <p>All numbers are stored 2-complement, little endian.</p>
+ * <p>Then proceed as follows, at all times working on the set of files for the
+ * testament in question:</p>
+ *
+ * <pre>
+ * in the comp file, seek to the index * 10
+ * read 10 bytes.
+ * the block-index is the first 4 bytes (32-bit number)
+ * the next bytes are the verse offset and length of the uncompressed block.
+ *
+ * in the idx file seek to block-index * 12
+ * read 12 bytes
+ * the text-block-index is the first 4 bytes
+ * the data-size is the next 4 bytes
+ * the uncompressed-size is the next 4 bytes
+ *
+ * in the text file seek to the text-block-index
+ * read data-size bytes
+ * decipher them if they are encrypted
+ * unGZIP them into a byte array of uncompressed-size
+ * </pre>
+ *
+ * TODO(DM): Testament 0 is used to index an README file for the bible.
+ * At this time it is ignored.
+ *
+ * @see gnu.lgpl.License for license details.
+ * The copyright to this program is held by it's authors.
+ * @author Joe Walker [joe at eireneh dot com]
+ */
+public class ZVerseBackend extends AbstractBackend
+{
+ private static final String SUFFIX_COMP = "v"; //$NON-NLS-1$
+ private static final String SUFFIX_INDEX = "s"; //$NON-NLS-1$
+ private static final String SUFFIX_PART1 = "z"; //$NON-NLS-1$
+ private static final String SUFFIX_TEXT = "z"; //$NON-NLS-1$
+
+ /**
+ * Simple ctor
+ */
+ public ZVerseBackend(SwordBookMetaData sbmd, BlockType blockType) throws BookException
+ {
+ super(sbmd);
+
+ String path = getExpandedDataPath();
+ String otAllButLast = path + File.separator + SwordConstants.FILE_OT + '.' + blockType.getIndicator() + SUFFIX_PART1;
+ idxFile[SwordConstants.TESTAMENT_OLD] = new File(otAllButLast + SUFFIX_INDEX);
+ textFile[SwordConstants.TESTAMENT_OLD] = new File(otAllButLast + SUFFIX_TEXT);
+ compFile[SwordConstants.TESTAMENT_OLD] = new File(otAllButLast + SUFFIX_COMP);
+
+ String ntAllButLast = path + File.separator + SwordConstants.FILE_NT + '.' + blockType.getIndicator() + SUFFIX_PART1;
+ idxFile[SwordConstants.TESTAMENT_NEW] = new File(ntAllButLast + SUFFIX_INDEX);
+ textFile[SwordConstants.TESTAMENT_NEW] = new File(ntAllButLast + SUFFIX_TEXT);
+ compFile[SwordConstants.TESTAMENT_NEW] = new File(ntAllButLast + SUFFIX_COMP);
+
+ // It is an error to be neither OT nor NT
+ if (!textFile[SwordConstants.TESTAMENT_OLD].canRead()
+ && !textFile[SwordConstants.TESTAMENT_NEW].canRead())
+ {
+ log.error("Failed to find OT or NT files: '" + otAllButLast + SUFFIX_TEXT + "' and '" + ntAllButLast + SUFFIX_TEXT + "'"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ throw new BookException(Msg.MISSING_FILE, new Object[] { path });
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.crosswire.common.activate.Activatable#activate(org.crosswire.common.activate.Lock)
+ */
+ public final void activate(Lock lock)
+ {
+ if (idxFile[SwordConstants.TESTAMENT_OLD].canRead())
+ {
+ try
+ {
+ idxRaf[SwordConstants.TESTAMENT_OLD] = new RandomAccessFile(idxFile[SwordConstants.TESTAMENT_OLD], FileUtil.MODE_READ);
+ textRaf[SwordConstants.TESTAMENT_OLD] = new RandomAccessFile(textFile[SwordConstants.TESTAMENT_OLD], FileUtil.MODE_READ);
+ compRaf[SwordConstants.TESTAMENT_OLD] = new RandomAccessFile(compFile[SwordConstants.TESTAMENT_OLD], FileUtil.MODE_READ);
+ }
+ catch (FileNotFoundException ex)
+ {
+ assert false : ex;
+ log.error("Could not open OT", ex); //$NON-NLS-1$
+ idxRaf[SwordConstants.TESTAMENT_OLD] = null;
+ textRaf[SwordConstants.TESTAMENT_OLD] = null;
+ compRaf[SwordConstants.TESTAMENT_OLD] = null;
+ }
+ }
+
+ if (idxFile[SwordConstants.TESTAMENT_NEW].canRead())
+ {
+ try
+ {
+ idxRaf[SwordConstants.TESTAMENT_NEW] = new RandomAccessFile(idxFile[SwordConstants.TESTAMENT_NEW], FileUtil.MODE_READ);
+ textRaf[SwordConstants.TESTAMENT_NEW] = new RandomAccessFile(textFile[SwordConstants.TESTAMENT_NEW], FileUtil.MODE_READ);
+ compRaf[SwordConstants.TESTAMENT_NEW] = new RandomAccessFile(compFile[SwordConstants.TESTAMENT_NEW], FileUtil.MODE_READ);
+ }
+ catch (FileNotFoundException ex)
+ {
+ assert false : ex;
+ log.error("Could not open NT", ex); //$NON-NLS-1$
+ idxRaf[SwordConstants.TESTAMENT_NEW] = null;
+ textRaf[SwordConstants.TESTAMENT_NEW] = null;
+ compRaf[SwordConstants.TESTAMENT_NEW] = null;
+ }
+ }
+
+ active = true;
+ }
+
+ /* (non-Javadoc)
+ * @see org.crosswire.common.activate.Activatable#deactivate(org.crosswire.common.activate.Lock)
+ */
+ public final void deactivate(Lock lock)
+ {
+ if (idxRaf[SwordConstants.TESTAMENT_NEW] != null)
+ {
+ try
+ {
+ idxRaf[SwordConstants.TESTAMENT_NEW].close();
+ textRaf[SwordConstants.TESTAMENT_NEW].close();
+ compRaf[SwordConstants.TESTAMENT_NEW].close();
+ }
+ catch (IOException ex)
+ {
+ log.error("failed to close nt files", ex); //$NON-NLS-1$
+ }
+ finally
+ {
+ idxRaf[SwordConstants.TESTAMENT_NEW] = null;
+ textRaf[SwordConstants.TESTAMENT_NEW] = null;
+ compRaf[SwordConstants.TESTAMENT_NEW] = null;
+ }
+ }
+
+ if (idxRaf[SwordConstants.TESTAMENT_OLD] != null)
+ {
+ try
+ {
+ idxRaf[SwordConstants.TESTAMENT_OLD].close();
+ textRaf[SwordConstants.TESTAMENT_OLD].close();
+ compRaf[SwordConstants.TESTAMENT_OLD].close();
+ }
+ catch (IOException ex)
+ {
+ log.error("failed to close ot files", ex); //$NON-NLS-1$
+ }
+ finally
+ {
+ idxRaf[SwordConstants.TESTAMENT_OLD] = null;
+ textRaf[SwordConstants.TESTAMENT_OLD] = null;
+ compRaf[SwordConstants.TESTAMENT_OLD] = null;
+ }
+ }
+
+ active = false;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.crosswire.jsword.book.sword.AbstractBackend#getRawText(org.crosswire.jsword.passage.Key, java.lang.String)
+ */
+ /* @Override */
+ public String getRawText(Key key) throws BookException
+ {
+ checkActive();
+
+ SwordBookMetaData sbmd = getBookMetaData();
+ String charset = sbmd.getBookCharset();
+ String compressType = sbmd.getProperty(ConfigEntryType.COMPRESS_TYPE);
+
+ Verse verse = KeyUtil.getVerse(key);
+
+ try
+ {
+ int testament = SwordConstants.getTestament(verse);
+ long index = SwordConstants.getIndex(verse);
+
+ // If Bible does not contain the desired testament, return nothing.
+ if (compRaf[testament] == null)
+ {
+ return ""; //$NON-NLS-1$
+ }
+
+ // 10 because we the index is 10 bytes long for each verse
+ byte[] temp = SwordUtil.readRAF(compRaf[testament], index * COMP_ENTRY_SIZE, COMP_ENTRY_SIZE);
+
+ // If the Bible does not contain the desired verse, return nothing.
+ // Some Bibles have different versification, so the requested verse
+ // may not exist.
+ if (temp == null || temp.length == 0)
+ {
+ return ""; //$NON-NLS-1$
+ }
+
+ // The data is little endian - extract the blockNum, verseStart and verseSize
+ long blockNum = SwordUtil.decodeLittleEndian32(temp, 0);
+ int verseStart = SwordUtil.decodeLittleEndian32(temp, 4);
+ int verseSize = SwordUtil.decodeLittleEndian16(temp, 8);
+
+ // Can we get the data from the cache
+ byte[] uncompressed = null;
+ if (blockNum == lastBlockNum && testament == lastTestament)
+ {
+ uncompressed = lastUncompressed;
+ }
+ else
+ {
+ // Then seek using this index into the idx file
+ temp = SwordUtil.readRAF(idxRaf[testament], blockNum * IDX_ENTRY_SIZE, IDX_ENTRY_SIZE);
+ if (temp == null || temp.length == 0)
+ {
+ return ""; //$NON-NLS-1$
+ }
+
+ int blockStart = SwordUtil.decodeLittleEndian32(temp, 0);
+ int blockSize = SwordUtil.decodeLittleEndian32(temp, 4);
+ int uncompressedSize = SwordUtil.decodeLittleEndian32(temp, 8);
+
+ // Read from the data file.
+ byte[] data = SwordUtil.readRAF(textRaf[testament], blockStart, blockSize);
+
+ decipher(data);
+
+ uncompressed = CompressorType.fromString(compressType).getCompressor(data).uncompress(uncompressedSize);
+
+ // cache the uncompressed data for next time
+ lastBlockNum = blockNum;
+ lastTestament = testament;
+ lastUncompressed = uncompressed;
+ }
+
+ // and cut out the required section.
+ byte[] chopped = new byte[verseSize];
+ System.arraycopy(uncompressed, verseStart, chopped, 0, verseSize);
+
+ return SwordUtil.decode(key, chopped, charset);
+ }
+ catch (IOException e)
+ {
+ throw new BookException(Msg.READ_FAIL, e, new Object[] { verse.getName() });
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.crosswire.jsword.book.sword.AbstractBackend#readIndex()
+ */
+ /* @Override */
+ public Key readIndex()
+ {
+ // PENDING(joe): refactor to get rid of this
+ return null;
+ }
+
+ /**
+ * Helper method so we can quickly activate ourselves on access
+ */
+ protected final void checkActive()
+ {
+ if (!active)
+ {
+ Activator.activate(this);
+ }
+ }
+
+ /**
+ *
+ */
+ private int lastTestament = -1;
+
+ /**
+ *
+ */
+ private long lastBlockNum = -1;
+
+ /**
+ *
+ */
+ private byte[] lastUncompressed;
+
+ /**
+ * Are we active
+ */
+ private boolean active;
+
+ /**
+ * The log stream
+ */
+ private static final Logger log = Logger.getLogger(ZVerseBackend.class);
+
+ /**
+ * The array of index random access files
+ */
+ private RandomAccessFile[] idxRaf = new RandomAccessFile[3];
+
+ /**
+ * The array of data random access files
+ */
+ private RandomAccessFile[] textRaf = new RandomAccessFile[3];
+
+ /**
+ * The array of compressed random access files
+ */
+ private RandomAccessFile[] compRaf = new RandomAccessFile[3];
+
+ /**
+ * The array of index random access files
+ */
+ private File[] idxFile = new File[3];
+
+ /**
+ * The array of data random access files
+ */
+ private File[] textFile = new File[3];
+
+ /**
+ * The array of compressed random access files
+ */
+ private File[] compFile = new File[3];
+
+ /**
+ * How many bytes in the comp index?
+ */
+ private static final int COMP_ENTRY_SIZE = 10;
+
+ /**
+ * How many bytes in the idx index?
+ */
+ private static final int IDX_ENTRY_SIZE = 12;
+}
More information about the jsword-svn
mailing list