[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