[jsword-svn] r1795 - in trunk/jsword/src: main/java/org/crosswire/jsword/book/sword main/java/org/crosswire/jsword/passage test/java/org/crosswire/jsword/bridge

dmsmith at www.crosswire.org dmsmith at www.crosswire.org
Fri Apr 11 13:21:03 MST 2008


Author: dmsmith
Date: 2008-04-11 13:21:02 -0700 (Fri, 11 Apr 2008)
New Revision: 1795

Added:
   trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/AbstractKeyBackend.java
Modified:
   trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/AbstractBackend.java
   trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/DataEntry.java
   trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/RawBackend.java
   trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/RawLDBackend.java
   trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/SwordDailyDevotion.java
   trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/SwordDictionary.java
   trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/ZLDBackend.java
   trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/ZVerseBackend.java
   trunk/jsword/src/main/java/org/crosswire/jsword/passage/AbstractKeyList.java
   trunk/jsword/src/main/java/org/crosswire/jsword/passage/DefaultKeyList.java
   trunk/jsword/src/main/java/org/crosswire/jsword/passage/DefaultLeafKeyList.java
   trunk/jsword/src/main/java/org/crosswire/jsword/passage/Key.java
   trunk/jsword/src/test/java/org/crosswire/jsword/bridge/DwrBridgeTest.java
Log:
Whoo! Hoo! Large dictionaries are now fast!!!!

Modified: trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/AbstractBackend.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/AbstractBackend.java	2008-04-11 10:48:41 UTC (rev 1794)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/AbstractBackend.java	2008-04-11 20:21:02 UTC (rev 1795)
@@ -101,9 +101,13 @@
 
     /**
      * Initialize a AbstractBackend before use. This method needs to call addKey() a
-     * number of times on SwordDictionary
+     * number of times on GenBookBackend
      */
-    public abstract Key readIndex();
+    public Key readIndex()
+    {
+        // TODO(dms): Eliminate readIndex by deriving GenBookBackend from AbstractKeyBackend
+        return null;
+    }
 
     /**
      * Get the text allotted for the given entry

Added: trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/AbstractKeyBackend.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/AbstractKeyBackend.java	                        (rev 0)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/AbstractKeyBackend.java	2008-04-11 20:21:02 UTC (rev 1795)
@@ -0,0 +1,274 @@
+/**
+ * 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: 2008
+ *     The copyright to this program is held by it's authors.
+ *
+ * ID: $Id: RawLDBackend.java 1794 2008-04-11 10:48:41Z dmsmith $
+ */
+package org.crosswire.jsword.book.sword;
+
+import java.util.Iterator;
+
+import org.crosswire.jsword.passage.Key;
+import org.crosswire.jsword.passage.RestrictionType;
+
+/**
+ * A Backend that can be used as a global key list.
+ *
+ * @see gnu.lgpl.License for license details.
+ *      The copyright to this program is held by it's authors.
+ * @author DM Smith [dmsmith555 at yahoo dot com]
+ */
+public abstract class AbstractKeyBackend extends AbstractBackend implements Key
+{
+    /**
+     * Simple ctor
+     * @param datasize We need to know how many bytes in the size portion of the index
+     */
+    public AbstractKeyBackend(SwordBookMetaData sbmd)
+    {
+        super(sbmd);
+    }
+
+    /* (non-Javadoc)
+     * @see org.crosswire.jsword.passage.Key#canHaveChildren()
+     */
+    public boolean canHaveChildren()
+    {
+        return false;
+    }
+
+    /* (non-Javadoc)
+     * @see org.crosswire.jsword.passage.Key#getChildCount()
+     */
+    public int getChildCount()
+    {
+        return 0;
+    }
+
+    /* (non-Javadoc)
+     * @see org.crosswire.jsword.passage.Key#isEmpty()
+     */
+    /* @Override */
+    public boolean isEmpty()
+    {
+        return getCardinality() == 0;
+    }
+
+    /* (non-Javadoc)
+     * @see org.crosswire.jsword.passage.Key#contains(org.crosswire.jsword.passage.Key)
+     */
+    /* @Override */
+    public boolean contains(Key key)
+    {
+        return indexOf(key) > 0;
+    }
+
+    /* (non-Javadoc)
+     * @see org.crosswire.jsword.passage.Key#iterator()
+     */
+    public Iterator iterator()
+    {
+        return new Iterator() {
+
+            /* (non-Javadoc)
+             * @see java.util.Iterator#hasNext()
+             */
+            public boolean hasNext()
+            {
+                return here < count;
+            }
+
+            /* (non-Javadoc)
+             * @see java.util.Iterator#next()
+             */
+            public Object next()
+            {
+                return get(here++);
+            }
+
+            /* (non-Javadoc)
+             * @see java.util.Iterator#remove()
+             */
+            public void remove()
+            {
+                throw new UnsupportedOperationException();
+            }
+            
+            int here = 0;
+            int count = getCardinality();
+        };
+    }
+
+    /* (non-Javadoc)
+     * @see org.crosswire.jsword.passage.Key#add(org.crosswire.jsword.passage.Key)
+     */
+    public void addAll(Key key)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /* (non-Javadoc)
+     * @see org.crosswire.jsword.passage.Key#remove(org.crosswire.jsword.passage.Key)
+     */
+    public void removeAll(Key key)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /* (non-Javadoc)
+     * @see org.crosswire.jsword.passage.Key#clear()
+     */
+    public void clear()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /* (non-Javadoc)
+     * @see org.crosswire.jsword.passage.Key#getParent()
+     */
+    public Key getParent()
+    {
+        return null;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#clone()
+     */
+    public Object clone()
+    {
+        return this;
+    }
+
+    /* (non-Javadoc)
+     * @see org.crosswire.jsword.passage.Key#getName()
+     */
+    public String getName()
+    {
+        return getBookMetaData().getInitials();
+    }
+
+    /* (non-Javadoc)
+     * @see org.crosswire.jsword.passage.Key#getName(org.crosswire.jsword.passage.Key)
+     */
+    public String getName(Key base)
+    {
+        return getName();
+    }
+
+    /* (non-Javadoc)
+     * @see org.crosswire.jsword.passage.Key#getOsisID()
+     */
+    public String getOsisID()
+    {
+        return getName();
+    }
+
+    /* (non-Javadoc)
+     * @see org.crosswire.jsword.passage.Key#getOsisRef()
+     */
+    public String getOsisRef()
+    {
+        return getName();
+    }
+
+    /* (non-Javadoc)
+     * @see org.crosswire.jsword.passage.Key#getRootName()
+     */
+    public String getRootName()
+    {
+        return getName();
+    }
+
+    /* (non-Javadoc)
+     * @see org.crosswire.jsword.passage.Key#retainAll(org.crosswire.jsword.passage.Key)
+     */
+    public void retainAll(Key key)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Comparable#compareTo(java.lang.Object)
+     */
+    public int compareTo(Object obj)
+    {
+        Key that = (Key) obj;
+
+        if (this == that)
+        {
+            return 0;
+        }
+
+        if (that == null)
+        {
+            // he is empty, we are not so he is greater
+            return -1;
+        }
+
+
+        int ret = this.getName().compareTo(that.getName());
+
+        if (ret != 0)
+        {
+            return ret;
+        }
+
+        // Compare the contents.
+        Iterator thisIter = this.iterator();
+        Iterator thatIter = that.iterator();
+
+        Key thisfirst = null;
+        Key thatfirst = null;
+
+        if (thisIter.hasNext())
+        {
+            thisfirst = (Key) thisIter.next();
+        }
+
+        if (thatIter.hasNext())
+        {
+            thatfirst = (Key) thatIter.next();
+        }
+
+        if (thisfirst == null)
+        {
+            if (thatfirst == null)
+            {
+                // we are both empty, and rank the same
+                return 0;
+            }
+            // i am empty, he is not so we are greater
+            return 1;
+        }
+
+        if (thatfirst == null)
+        {
+            // he is empty, we are not so he is greater
+            return -1;
+        }
+
+        return thisfirst.getName().compareTo(thatfirst.getName());
+    }
+
+    /* (non-Javadoc)
+     * @see org.crosswire.jsword.passage.Key#blur(int)
+     */
+    public void blur(int by, RestrictionType restrict)
+    {
+    }
+}

Modified: trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/DataEntry.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/DataEntry.java	2008-04-11 10:48:41 UTC (rev 1794)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/DataEntry.java	2008-04-11 20:21:02 UTC (rev 1795)
@@ -21,10 +21,15 @@
  */
 package org.crosswire.jsword.book.sword;
 
+import org.crosswire.common.crypt.Sapphire;
 import org.crosswire.jsword.book.DataPolice;
 
 /**
  * Data entry represents an entry in a Data file.
+ * The entry consists of a key and an optional payload.
+ * The payload may be the content, aka rawtext.
+ * The payload may be an alias for another entry.
+ * The payload may be a block locator.
  * 
  * @see gnu.lgpl.License for license details.<br>
  *      The copyright to this program is held by it's authors.
@@ -47,6 +52,15 @@
     }
 
     /**
+     * Get the name, that is, the diagnostic label, for this DataEntry.
+     * @return the diagnostic name.
+     */
+    public String getName()
+    {
+        return name;
+    }
+
+    /**
      * Get the key from this DataEntry.
      * @param name A diagnostic name. Either the module initials or the expected key name.
      * @param charset The character encoding for the String
@@ -77,6 +91,10 @@
         return key;
     }
 
+    /**
+     * Determine whether this entry is an alias for another.
+     * @return whether this is an alias entry
+     */
     public boolean isLinkEntry()
     {
         String linkCheck = SwordUtil.decode(name, data, getKeyEnd() + 1, 5, charset);
@@ -99,15 +117,28 @@
     /**
      * Get the raw text from this entry.
      * 
+     * @param cipherKey the key, if any, to (un)lock the text
      * @return the raw text
      */
-    public String getRawText()
+    public String getRawText(byte[] cipherKey)
     {
-        int textEnd = getKeyEnd() + 1;
-        return SwordUtil.decode(name, data, textEnd, data.length - textEnd, charset).trim();
+        int textStart = getKeyEnd() + 1;
+        cipher(cipherKey, textStart);
+        return SwordUtil.decode(name, data, textStart, data.length - textStart, charset).trim();
     }
 
     /**
+     * Get the block start and entry position.
+     * @return
+     */
+    public DataIndex getBlockIndex()
+    {
+        int start = getKeyEnd() + 1;
+        return new DataIndex(SwordUtil.decodeLittleEndian32(data, start),
+                             SwordUtil.decodeLittleEndian32(data, start + 4));
+    }
+
+    /**
      * Get the position of the first \n in the data. This represents the end of the key
      * and the start of the rest of the data.
      * 
@@ -138,6 +169,26 @@
     }
 
     /**
+     * Decipher/Encipher the data in place, if there
+     * is a cipher key.
+     * @param cipherKey the key to the cipher
+     */
+    public void cipher(byte[] cipherKey, int offset)
+    {
+        if (cipherKey != null && cipherKey.length > 0)
+        {
+            Sapphire cipherEngine = new Sapphire(cipherKey);
+            for (int i = offset; i < data.length; i++)
+            {
+                data[i] = cipherEngine.cipher(data[i]);
+            }
+            // destroy any evidence!
+            cipherEngine.burn();
+        }
+    }
+
+
+    /**
      * Used to separate the key name from the key value
      * Note: it may be \r\n or just \n, so only need \n.
      * ^M=CR=13=0x0d=\r

Modified: trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/RawBackend.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/RawBackend.java	2008-04-11 10:48:41 UTC (rev 1794)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/RawBackend.java	2008-04-11 20:21:02 UTC (rev 1795)
@@ -119,16 +119,6 @@
     }
 
     /* (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.common.activate.Activatable#activate(org.crosswire.common.activate.Lock)
      */
     public final void activate(Lock lock)

Modified: trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/RawLDBackend.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/RawLDBackend.java	2008-04-11 10:48:41 UTC (rev 1794)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/RawLDBackend.java	2008-04-11 20:21:02 UTC (rev 1795)
@@ -38,17 +38,18 @@
 import org.crosswire.common.util.StringUtil;
 import org.crosswire.jsword.book.BookCategory;
 import org.crosswire.jsword.book.BookException;
-import org.crosswire.jsword.passage.DefaultKeyList;
+import org.crosswire.jsword.passage.DefaultLeafKeyList;
 import org.crosswire.jsword.passage.Key;
 
 /**
- * An implementation KeyBackend to read RAW format files.
+ * An implementation AbstractKeyBackend to read RAW format 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]
+ * @author DM Smith [dmsmith555 at yahoo dot com]
  */
-public class RawLDBackend extends AbstractBackend
+public class RawLDBackend extends AbstractKeyBackend
 {
     /**
      * Simple ctor
@@ -57,29 +58,11 @@
     public RawLDBackend(SwordBookMetaData sbmd, int datasize)
     {
         super(sbmd);
+        this.size = -1;
         this.datasize = datasize;
         this.entrysize = OFFSETSIZE + datasize;
-        this.size = -1;
-
-        assert (datasize == 2 || datasize == 4);
-
     }
 
-    /**
-     * Get the number of entries in the Book.
-     * @return the number of entries in the Book
-     * @throws IOException 
-     */
-    public long getSize() throws IOException
-    {
-        checkActive();
-        if (size == -1)
-        {
-            size = idxRaf.length() / entrysize;
-        }
-        return size;
-    }
-
     /*
      * (non-Javadoc)
      * @see org.crosswire.jsword.book.sword.AbstractBackend#getRawText(org.crosswire.jsword.passage.Key, java.lang.String)
@@ -92,19 +75,22 @@
 
     public String getRawText(String key) throws BookException
     {
-        checkActive();
+        if (!checkActive())
+        {
+            return ""; //$NON-NLS-1$
+        }
 
         try
         {
-            long pos = search(key);
+            int pos = search(key);
             if (pos >= 0)
             {
-                DataEntry entry = getEntry(key, pos, true);
+                DataEntry entry = getEntry(key, pos);
                 if (entry.isLinkEntry())
                 {
                     return getRawText(entry.getLinkTarget());
                 }
-                return entry.getRawText();
+                return getRawText(entry);
             }
             throw new BookException(UserMsg.READ_FAIL);
         }
@@ -114,93 +100,99 @@
         }
     }
 
+    protected String getRawText(DataEntry entry)
+    {
+        String cipherKeyString = (String) getBookMetaData().getProperty(ConfigEntryType.CIPHER_KEY);
+        return entry.getRawText((cipherKeyString != null) ? cipherKeyString.getBytes() : null);
+    }
+
     /* (non-Javadoc)
-     * @see org.crosswire.jsword.book.sword.KeyBackend#readIndex()
+     * @see org.crosswire.jsword.passage.Key#getCardinality()
      */
-    /* @Override */
-    public Key readIndex()
+    public int getCardinality()
     {
-        checkActive();
-
-        SwordBookMetaData bmd = getBookMetaData();
-        Key reply = new DefaultKeyList(null, bmd.getName());
-
-        boolean isDailyDevotional = bmd.getBookCategory().equals(BookCategory.DAILY_DEVOTIONS);
-
-        Calendar greg = new GregorianCalendar();
-        DateFormatter nameDF = DateFormatter.getDateInstance();
-
-        long entries;
-        try
+        if (!checkActive())
         {
-            entries = getSize();
+            return 0;
         }
-        catch (IOException ex)
+
+        if (size == -1)
         {
-            Reporter.informUser(this, ex);
-            return reply;
+            try
+            {
+                size = (int) (idxRaf.length() / entrysize);
+            }
+            catch (IOException e)
+            {
+                size = 0;
+            }
         }
+        return size;
+    }
 
-        for (long entry = 0; entry < entries; entry++)
+    /* (non-Javadoc)
+     * @see org.crosswire.jsword.passage.Key#get(int)
+     */
+    public Key get(int index)
+    {
+        if (checkActive())
         {
             try
             {
-                // Read the offset and size for this key from the index
-                DataEntry dataEntry = getEntry(reply.getName(), entry, true);
-                String keytitle = dataEntry.getKey();
-
-                if (isDailyDevotional && keytitle.length() >= 3)
+                if (index < getCardinality())
                 {
-                    String[] spec = StringUtil.splitAll(keytitle, '.');
-                    greg.set(Calendar.MONTH, Integer.parseInt(spec[0]) - 1);
-                    greg.set(Calendar.DATE, Integer.parseInt(spec[1]));
-                    keytitle = nameDF.format(greg.getTime());
+                    DataEntry entry = getEntry(getBookMetaData().getInitials(), index);
+                    return new DefaultLeafKeyList(entry.getKey());
                 }
-
-                Key key = new IndexKey(keytitle);
-
-                // remove duplicates, keeping later one.
-                // This occurs under some conditions:
-                // For daily devotionals where 02.29 becomes calendarized to Mar 1 for non-leap years
-                // For modules that have been updated by appending new data.
-                if (reply.contains(key))
-                {
-                    reply.removeAll(key);
-                }
-
-                reply.addAll(key);
             }
-            catch (IOException ex)
+            catch (IOException e)
             {
-                log.error("Ignoring entry", ex); //$NON-NLS-1$
+                // fall through
             }
-            catch (NumberFormatException e)
-            {
-                log.error("Ignoring entry", e); //$NON-NLS-1$
-            }
         }
+        throw new ArrayIndexOutOfBoundsException(index);
+    }
 
-        return reply;
+    /* (non-Javadoc)
+     * @see org.crosswire.jsword.passage.Key#indexOf(org.crosswire.jsword.passage.Key)
+     */
+    public int indexOf(Key that)
+    {
+        try
+        {
+            return search(that.getName());
+        }
+        catch (IOException e)
+        {
+            return -getCardinality() - 1;
+        }
     }
 
     /* (non-Javadoc)
      * @see org.crosswire.common.activate.Activatable#activate(org.crosswire.common.activate.Lock)
      */
-    public final void activate(Lock lock)
+    public void activate(Lock lock)
     {
+        active           = false;
+        size             = -1;
+        idxFile          = null;
+        datFile          = null;
+        idxRaf           = null;
+        datRaf           = null;
+
+        URI path = null;
         try
         {
-            URI path = null;
-            try
-            {
-                path = getExpandedDataPath();
-            }
-            catch (BookException e)
-            {
-                Reporter.informUser(this, e);
-                return;
-            }
+            path = getExpandedDataPath();
+        }
+        catch (BookException e)
+        {
+            Reporter.informUser(this, e);
+            return;
+        }
 
+        try
+        {
             idxFile = new File(path.getPath() + SwordConstants.EXTENSION_INDEX);
             datFile = new File(path.getPath() + SwordConstants.EXTENSION_DATA);
 
@@ -223,9 +215,9 @@
         catch (IOException ex)
         {
             log.error("failed to open files", ex); //$NON-NLS-1$
-
             idxRaf = null;
             datRaf = null;
+            return;
         }
 
         active = true;
@@ -234,37 +226,54 @@
     /* (non-Javadoc)
      * @see org.crosswire.common.activate.Activatable#deactivate(org.crosswire.common.activate.Lock)
      */
-    public final void deactivate(Lock lock)
+    public void deactivate(Lock lock)
     {
+        size             = -1;
         try
         {
-            idxRaf.close();
-            datRaf.close();
+            if (idxRaf != null)
+            {
+                idxRaf.close();
+            }
+            if (datRaf != null)
+            {
+                datRaf.close();
+            }
         }
         catch (IOException ex)
         {
             log.error("failed to close files", ex); //$NON-NLS-1$
         }
+        finally
+        {
+            idxRaf = null;
+            datRaf = null;
+        }
 
-        idxRaf = null;
-        datRaf = null;
-        size   = -1;
-
         active = false;
     }
 
     /**
      * Helper method so we can quickly activate ourselves on access
      */
-    protected final void checkActive()
+    protected boolean checkActive()
     {
-        if (!active)
+        if (!isActive())
         {
             Activator.activate(this);
         }
+        return isActive();
     }
 
     /**
+     * Determine whether we are active.
+     */
+    protected boolean isActive()
+    {
+        return active;
+    }
+    
+    /**
      * Get the Index (that is offset and size) for an entry.
      * @param entry
      * @return
@@ -297,17 +306,12 @@
      * @return the text for the entry.
      * @throws IOException 
      */
-    private DataEntry getEntry(String reply, long index, boolean decipher) throws IOException
+    private DataEntry getEntry(String reply, int index) throws IOException
     {
         DataIndex dataIndex = getIndex(index);
         // Now read the data file for this key using the offset and size
         byte[] data = SwordUtil.readRAF(datRaf, dataIndex.getOffset(), dataIndex.getSize());
 
-        if (decipher)
-        {
-            decipher(data);
-        }
-
         return new DataEntry(reply, data, getBookMetaData().getBookCharset());
     }
 
@@ -318,8 +322,13 @@
      * @return
      * @throws IOException
      */
-    private long search(String key) throws IOException
+    private int search(String key) throws IOException
     {
+        if (!checkActive())
+        {
+            return -1;
+        }
+
         SwordBookMetaData bmd = getBookMetaData();
 
         boolean isDailyDevotional = bmd.getBookCategory().equals(BookCategory.DAILY_DEVOTIONS);
@@ -329,15 +338,15 @@
 
         String target = key.toUpperCase(Locale.US);
 
-        long low = 1;
-        long high = getSize() - 1;
+        int low = 1;
+        int high = getCardinality() - 1;
 
         while (low <= high)
         {
-            long mid = (low + high) >> 1;
+            int mid = (low + high) >> 1;
 
             // Get the key for the item at "mid"
-            DataEntry entry = getEntry(key, mid, true);
+            DataEntry entry = getEntry(key, mid);
             String midVal = entry.getKey();
 
             // Massage midVal if can be.
@@ -367,7 +376,7 @@
 
         // Strong's Greek And Hebrew dictionaries have an introductory entry, so check it for a match.
         // Get the key for the item at "mid"
-        DataEntry entry = getEntry(key, 0, true);
+        DataEntry entry = getEntry(key, 0);
         String midVal = entry.getKey();
 
         // Massage midVal if can be.
@@ -411,7 +420,7 @@
     /**
      * The number of entries in the book.
      */
-    private long size;
+    private int size;
 
     /**
      * The index file
@@ -434,6 +443,11 @@
     private RandomAccessFile datRaf;
 
     /**
+     * Serialization ID
+     */
+    private static final long serialVersionUID = 818089833394450383L;
+
+    /**
      * The log stream
      */
     private static final Logger log = Logger.getLogger(RawLDBackend.class);

Modified: trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/SwordDailyDevotion.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/SwordDailyDevotion.java	2008-04-11 10:48:41 UTC (rev 1794)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/SwordDailyDevotion.java	2008-04-11 20:21:02 UTC (rev 1795)
@@ -22,6 +22,7 @@
 import java.util.Date;
 
 import org.crosswire.common.icu.DateFormatter;
+import org.crosswire.jsword.passage.DefaultLeafKeyList;
 import org.crosswire.jsword.passage.Key;
 import org.crosswire.jsword.passage.PreferredKey;
 
@@ -47,6 +48,6 @@
      */
     public Key getPreferred()
     {
-        return new IndexKey(DateFormatter.getDateInstance().format(new Date()));
+        return new DefaultLeafKeyList(DateFormatter.getDateInstance().format(new Date()));
     }
 }

Modified: trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/SwordDictionary.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/SwordDictionary.java	2008-04-11 10:48:41 UTC (rev 1794)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/SwordDictionary.java	2008-04-11 20:21:02 UTC (rev 1795)
@@ -23,10 +23,8 @@
 
 import java.text.DecimalFormat;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -37,9 +35,9 @@
 import org.crosswire.jsword.book.basic.AbstractBook;
 import org.crosswire.jsword.book.filter.FilterException;
 import org.crosswire.jsword.passage.DefaultKeyList;
+import org.crosswire.jsword.passage.DefaultLeafKeyList;
 import org.crosswire.jsword.passage.Key;
 import org.crosswire.jsword.passage.NoSuchKeyException;
-import org.crosswire.jsword.passage.ReadOnlyKeyList;
 import org.jdom.Element;
 
 /**
@@ -60,57 +58,11 @@
         super(sbmd);
 
         this.sbmd = sbmd;
-        this.backend = backend;
-        map = null;
-        set = null;
-        global = null;
+        this.backend = (AbstractKeyBackend) backend;
         active = false;
     }
 
     /* (non-Javadoc)
-     * @see org.crosswire.common.activate.Activatable#activate(org.crosswire.common.activate.Lock)
-     */
-    /* @Override */
-    public final void activate(Lock lock)
-    {
-        super.activate(lock);
-
-        set = backend.readIndex();
-
-        map = new HashMap();
-        Iterator iter = set.iterator();
-        while (iter.hasNext())
-        {
-            Key key = (Key) iter.next();
-            map.put(key.getName(), key);
-        }
-
-        global = new ReadOnlyKeyList(set, false);
-
-        active = true;
-
-        // We don't need to activate the backend because it should be capable
-        // of doing it for itself.
-    }
-
-    /* (non-Javadoc)
-     * @see org.crosswire.common.activate.Activatable#deactivate(org.crosswire.common.activate.Lock)
-     */
-    /* @Override */
-    public final void deactivate(Lock lock)
-    {
-        super.deactivate(lock);
-
-        map = null;
-        set = null;
-        global = null;
-
-        Activator.deactivate(backend);
-
-        active = false;
-    }
-
-    /* (non-Javadoc)
      * @see org.crosswire.jsword.book.Book#getOsisIterator(org.crosswire.jsword.passage.Key, boolean)
      */
     public Iterator getOsisIterator(Key key, boolean allowEmpty) throws BookException
@@ -184,7 +136,7 @@
     {
         checkActive();
 
-        return global;
+        return backend;
     }
 
     /* (non-Javadoc)
@@ -209,55 +161,25 @@
     {
         checkActive();
 
-        Key key = (Key) map.get(text);
-        if (key != null)
-        {
-            return key;
-        }
-
         // So we need to find a matching key.
         // TODO(DM): This is a hack.
-        key = getStrongsKey(text);
+        Key key = getStrongsKey(text);
 
         if (key != null)
         {
             return key;
         }
 
-        // First check for keys that match ignoring case
-        Iterator iter = map.keySet().iterator();
-        while (iter.hasNext())
+        int pos = backend.indexOf(new DefaultLeafKeyList(text));
+        if (pos < 0)
         {
-            String keyName = (String) iter.next();
-            if (keyName.equalsIgnoreCase(text))
+            if (backend.getCardinality() > -pos - 1)
             {
-                return (Key) map.get(keyName);
+                return backend.get(-pos - 1);
             }
+            return backend.get(backend.getCardinality() - 1);
         }
-
-        // Next keys that start with the given text
-        iter = map.keySet().iterator();
-        while (iter.hasNext())
-        {
-            String keyName = (String) iter.next();
-            if (keyName.startsWith(text))
-            {
-                return (Key) map.get(keyName);
-            }
-        }
-
-        // Next try keys that contain the given text
-        iter = map.keySet().iterator();
-        while (iter.hasNext())
-        {
-            String keyName = (String) iter.next();
-            if (keyName.indexOf(text) != -1)
-            {
-                return (Key) map.get(keyName);
-            }
-        }
-
-        throw new NoSuchKeyException(UserMsg.NO_KEY, new Object[] { text, getInitials() });
+        return backend.get(pos);
     }
 
     // TODO(DM): Hack alert!!! This is not in the right place!!!
@@ -277,6 +199,7 @@
         {
             text = text.substring(0, pos);
         }
+
         // Get the number after the G or H
         int strongsNumber = Integer.parseInt(text.substring(1));
 
@@ -284,11 +207,11 @@
         String internalName = sbmd.getInitials();
         if ("StrongsGreek".equals(internalName)) //$NON-NLS-1$
         {
-            key = (Key) map.get(ZERO_PAD.format(strongsNumber));
+            key = backend.get(backend.indexOf(new DefaultLeafKeyList(ZERO_PAD.format(strongsNumber))));
         }
         else if ("StrongsHebrew".equals(internalName)) //$NON-NLS-1$
         {
-            key = (Key) map.get(ZERO_PAD.format(strongsNumber));
+            key = backend.get(backend.indexOf(new DefaultLeafKeyList(ZERO_PAD.format(strongsNumber))));
         }
         return key;
     }
@@ -301,6 +224,30 @@
         return new DefaultKeyList();
     }
 
+    /* (non-Javadoc)
+     * @see org.crosswire.common.activate.Activatable#activate(org.crosswire.common.activate.Lock)
+     */
+    /* @Override */
+    public final void activate(Lock lock)
+    {
+        super.activate(lock);
+        active = true;
+
+        // We don't need to activate the backend because it should be capable
+        // of doing it for itself.
+    }
+
+    /* (non-Javadoc)
+     * @see org.crosswire.common.activate.Activatable#deactivate(org.crosswire.common.activate.Lock)
+     */
+    /* @Override */
+    public final void deactivate(Lock lock)
+    {
+        super.deactivate(lock);
+        Activator.deactivate(backend);
+        active = false;
+    }
+
     /**
      * Helper method so we can quickly activate ourselves on access
      */
@@ -317,29 +264,14 @@
     private static final DecimalFormat ZERO_PAD = new DecimalFormat("00000"); //$NON-NLS-1$
 
     /**
-     * The global key list
-     */
-    private Key global;
-
-    /**
      * Are we active
      */
     private boolean active;
 
     /**
-     * So we can quickly find a Key given the text for the key
-     */
-    private Map map;
-
-    /**
-     * So we can implement getIndex() easily
-     */
-    private Key set;
-
-    /**
      * To read the data from the disk
      */
-    private AbstractBackend backend;
+    private AbstractKeyBackend backend;
 
     /**
      * The Sword configuration file

Modified: trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/ZLDBackend.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/ZLDBackend.java	2008-04-11 10:48:41 UTC (rev 1794)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/ZLDBackend.java	2008-04-11 20:21:02 UTC (rev 1795)
@@ -24,165 +24,168 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.RandomAccessFile;
-import java.util.Calendar;
-import java.util.GregorianCalendar;
+import java.net.URI;
 
-import org.crosswire.common.activate.Activator;
 import org.crosswire.common.activate.Lock;
 import org.crosswire.common.compress.CompressorType;
-import org.crosswire.common.icu.DateFormatter;
-import org.crosswire.common.util.ClassUtil;
 import org.crosswire.common.util.FileUtil;
 import org.crosswire.common.util.Logger;
 import org.crosswire.common.util.Reporter;
-import org.crosswire.common.util.StringUtil;
-import org.crosswire.jsword.book.BookCategory;
 import org.crosswire.jsword.book.BookException;
-import org.crosswire.jsword.book.DataPolice;
-import org.crosswire.jsword.passage.DefaultKeyList;
-import org.crosswire.jsword.passage.Key;
 
 /**
- * An implementation KeyBackend to read Z format files.
- *
- * @see gnu.lgpl.License for license details.
- *      The copyright to this program is held by it's authors.
+ * An extension of RawLDBackend to read Z format 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]
+ * @author DM Smith [dmsmith555 at yahoo dot com]
  */
-public class ZLDBackend extends AbstractBackend
+public class ZLDBackend extends RawLDBackend
 {
-    private static final String EXTENSION_INDEX = ".idx"; //$NON-NLS-1$
-    private static final String EXTENSION_DATA = ".dat"; //$NON-NLS-1$
-    private static final String EXTENSION_Z_INDEX = ".zdx"; //$NON-NLS-1$
-    private static final String EXTENSION_Z_DATA = ".zdt"; //$NON-NLS-1$
-
-    private static final int IDX_ENTRY_SIZE = 8;
-    private static final int ZDX_ENTRY_SIZE = 8;
-    private static final int BLOCK_ENTRY_COUNT = 4;
-    private static final int BLOCK_ENTRY_SIZE = 8;
-
     /**
-     * Used to separate the key name from the key value
+     * Simple ctor
      */
-    private static final byte SEPARATOR = 10; // ^M=CR=13=0x0d=\r ^J=LF=10=0x0a=\n
+    public ZLDBackend(SwordBookMetaData sbmd)
+    {
+        super(sbmd, 4);
+        this.lastBlockNum = -1;
+        this.lastUncompressed = EMPTY_BYTES;
+    }
 
-    /**
-     * The log stream
-     */
-    private static final Logger log = Logger.getLogger(ZLDBackend.class);
+    protected String getRawText(DataEntry entry)
+    {
+        DataIndex blockIndex = entry.getBlockIndex();
+        long blockNum = blockIndex.getOffset();
+        int blockEntry = blockIndex.getSize();
 
-    private File idxFile;
+        // Can we get the data from the cache
+        byte[] uncompressed = null;
+        if (blockNum == lastBlockNum)
+        {
+            uncompressed = lastUncompressed;
+        }
+        else
+        {
+            byte[] temp;
+            try
+            {
+                temp = SwordUtil.readRAF(zdxRaf, blockNum * ZDX_ENTRY_SIZE, ZDX_ENTRY_SIZE);
+                if (temp == null || temp.length == 0)
+                {
+                    return ""; //$NON-NLS-1$
+                }
 
-    private File datFile;
+                int blockStart = SwordUtil.decodeLittleEndian32(temp, 0);
+                int blockSize = SwordUtil.decodeLittleEndian32(temp, 4);
 
-    /**
-     * The compressed index.
-     */
-    private File zdxFile;
+                temp = SwordUtil.readRAF(zdtRaf, blockStart, blockSize);
 
-    /**
-     * The compressed text.
-     */
-    private File zdtFile;
+                decipher(temp);
 
-    private RandomAccessFile idxRaf;
-    private RandomAccessFile datRaf;
-    private RandomAccessFile zdxRaf;
-    private RandomAccessFile zdtRaf;
-    private boolean active;
-    private Key keys;
-    private long lastBlockNum = -1;
-    private static final byte[] EMPTY_BYTES = new byte[0];
-    private byte[] lastUncompressed = EMPTY_BYTES;
+                String compressType = (String) getBookMetaData().getProperty(ConfigEntryType.COMPRESS_TYPE);
+                uncompressed = CompressorType.fromString(compressType).getCompressor(temp).uncompress().toByteArray();
 
-    /**
-     * Simple ctor
-     * @throws BookException
-     */
-    public ZLDBackend(SwordBookMetaData sbmd)
-    {
-        super(sbmd);
+                // cache the uncompressed data for next time
+                lastBlockNum = blockNum;
+                lastUncompressed = uncompressed;
+            }
+            catch (IOException e)
+            {
+                return ""; //$NON-NLS-1$
+            }
+        }
 
+        // get the "entry" from this block.
+        int entryCount = SwordUtil.decodeLittleEndian32(uncompressed, 0);
+        if (blockEntry >= entryCount)
+        {
+            return ""; //$NON-NLS-1$
+        }
+
+        int entryOffset = BLOCK_ENTRY_COUNT + (BLOCK_ENTRY_SIZE * blockEntry);
+        int entryStart = SwordUtil.decodeLittleEndian32(uncompressed, entryOffset);
+        // Note: the actual entry is '\0' terminated
+        int entrySize = SwordUtil.decodeLittleEndian32(uncompressed, entryOffset + 4);
+        byte[] entryBytes = new byte[entrySize];
+        System.arraycopy(uncompressed, entryStart, entryBytes, 0, entrySize);
+
+        return SwordUtil.decode(entry.getName(), entryBytes, getBookMetaData().getBookCharset()).trim();
     }
 
-    /* (non-Javadoc)
+    /*
+     * (non-Javadoc)
+     * 
      * @see org.crosswire.common.activate.Activatable#activate(org.crosswire.common.activate.Lock)
      */
-    public final void activate(Lock lock)
+    public void activate(Lock lock)
     {
+        super.activate(lock);
+
+        active = false;
+        zdxFile = null;
+        zdtFile = null;
+        zdxRaf = null;
+        zdtRaf = null;
+        lastBlockNum = -1;
+        lastUncompressed = EMPTY_BYTES;
+
+        URI path = null;
         try
         {
-            String path = null;
-            try
-            {
-                path = getExpandedDataPath().getPath();
-            }
-            catch (BookException e)
-            {
-                Reporter.informUser(this, e);
-                return;
-            }
+            path = getExpandedDataPath();
+        }
+        catch (BookException e)
+        {
+            Reporter.informUser(this, e);
+            return;
+        }
 
-            idxFile = new File(path + EXTENSION_INDEX);
-            datFile = new File(path + EXTENSION_DATA);
-            zdxFile = new File(path + EXTENSION_Z_INDEX);
-            zdtFile = new File(path + EXTENSION_Z_DATA);
+        try
+        {
+            zdxFile = new File(path.getPath() + EXTENSION_Z_INDEX);
+            zdtFile = new File(path.getPath() + EXTENSION_Z_DATA);
 
-            if (!idxFile.canRead())
+            if ( !zdxFile.canRead())
             {
-                Reporter.informUser(this, new BookException(UserMsg.READ_FAIL, new Object[] { idxFile.getAbsolutePath() }));
+                Reporter.informUser(this, new BookException(UserMsg.READ_FAIL, new Object[] { zdtFile.getAbsolutePath() }));
                 return;
             }
 
-            if (!datFile.canRead())
+            if ( !zdtFile.canRead())
             {
-                Reporter.informUser(this, new BookException(UserMsg.READ_FAIL, new Object[] { datFile.getAbsolutePath() }));
-                return;
-            }
-
-            if (!zdxFile.canRead())
-            {
-                Reporter.informUser(this, new BookException(UserMsg.READ_FAIL, new Object[] { zdxFile.getAbsolutePath() }));
-                return;
-            }
-
-            if (!zdtFile.canRead())
-            {
                 Reporter.informUser(this, new BookException(UserMsg.READ_FAIL, new Object[] { zdtFile.getAbsolutePath() }));
                 return;
             }
 
-            idxRaf = new RandomAccessFile(idxFile, FileUtil.MODE_READ);
-            datRaf = new RandomAccessFile(datFile, FileUtil.MODE_READ);
+            // Open the files
             zdxRaf = new RandomAccessFile(zdxFile, FileUtil.MODE_READ);
             zdtRaf = new RandomAccessFile(zdtFile, FileUtil.MODE_READ);
         }
         catch (IOException ex)
         {
             log.error("failed to open files", ex); //$NON-NLS-1$
-            idxRaf = null;
-            datRaf = null;
             zdxRaf = null;
             zdtRaf = null;
+            return;
         }
+
         active = true;
     }
 
-    /* (non-Javadoc)
+    /*
+     * (non-Javadoc)
+     * 
      * @see org.crosswire.common.activate.Activatable#deactivate(org.crosswire.common.activate.Lock)
      */
-    public final void deactivate(Lock lock)
+    public void deactivate(Lock lock)
     {
+        super.deactivate(lock);
+        lastBlockNum = -1;
+        lastUncompressed = EMPTY_BYTES;
+
         try
         {
-            if (idxRaf != null)
-            {
-                idxRaf.close();
-            }
-            if (datRaf != null)
-            {
-                datRaf.close();
-            }
             if (zdxRaf != null)
             {
                 zdxRaf.close();
@@ -194,213 +197,75 @@
         }
         catch (IOException ex)
         {
-            log.error("failed to close nt files", ex); //$NON-NLS-1$
+            log.error("failed to close files", ex); //$NON-NLS-1$
         }
         finally
         {
-            idxRaf = null;
-            datRaf = null;
             zdxRaf = null;
             zdtRaf = null;
         }
+
         active = false;
-   }
+    }
 
-    /* (non-Javadoc)
-     * @see org.crosswire.jsword.book.sword.KeyBackend#readIndex()
+    /**
+     * Determine whether we are active.
      */
-    /* @Override */
-    public Key readIndex()
+    protected boolean isActive()
     {
-        checkActive();
-        SwordBookMetaData bmd = getBookMetaData();
-        String charset = bmd.getBookCharset();
+        return active && super.isActive();
+    }
 
-        keys = new DefaultKeyList(null, bmd.getName());
+    private static final String EXTENSION_Z_INDEX = ".zdx"; //$NON-NLS-1$
+    private static final String EXTENSION_Z_DATA  = ".zdt"; //$NON-NLS-1$
 
-        boolean isDailyDevotional = bmd.getBookCategory().equals(BookCategory.DAILY_DEVOTIONS);
+    private static final int    ZDX_ENTRY_SIZE    = 8;
+    private static final int    BLOCK_ENTRY_COUNT = 4;
+    private static final int    BLOCK_ENTRY_SIZE  = 8;
+    private static final byte[] EMPTY_BYTES       = new byte[0];
 
-        Calendar greg = new GregorianCalendar();
-        DateFormatter nameDF = DateFormatter.getDateInstance();
+    /**
+     * Flags whether there are open files or not
+     */
+    private boolean             active;
 
-        long entries;
-        try
-        {
-            entries = idxRaf.length() / IDX_ENTRY_SIZE;
-        }
-        catch (IOException ex)
-        {
-            Reporter.informUser(this, ex);
-            return keys;
-        }
+    /**
+     * The compressed index.
+     */
+    private File                zdxFile;
 
-        for (long entry = 0; entry < entries; entry++)
-        {
-            try
-            {
-                // Read the offset and size for this key from the index
-                byte[] buffer = SwordUtil.readRAF(idxRaf, entry * IDX_ENTRY_SIZE, IDX_ENTRY_SIZE);
-                int offset = SwordUtil.decodeLittleEndian32(buffer, 0);
-                int size = SwordUtil.decodeLittleEndian32(buffer, 4);
+    /**
+     * The compressed index random access file.
+     */
+    private RandomAccessFile    zdxRaf;
 
-                // Now read the data file for this key using the offset and size
-                byte[] data = SwordUtil.readRAF(datRaf, offset, size);
+    /**
+     * The compressed text.
+     */
+    private File                zdtFile;
 
-                int keyend = SwordUtil.findByte(data, SEPARATOR);
-                if (keyend == -1)
-                {
-                    DataPolice.report("Failed to find keyname. offset=" + offset + " data='" + new String(data) + "'"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-                    continue;
-                }
+    /**
+     * The compressed text random access file.
+     */
+    private RandomAccessFile    zdtRaf;
 
-                byte[] keydata = new byte[keyend];
-                System.arraycopy(data, 0, keydata, 0, keyend);
+    /**
+     * The index of the block that is cached.
+     */
+    private long                lastBlockNum;
 
-                String keytitle = SwordUtil.decode(keys.getName(), keydata, charset).trim();
+    /**
+     * The cache for a read of a compressed block.
+     */
+    private byte[]              lastUncompressed;
 
-                // for some weird reason plain text (i.e. SourceType=0) dicts
-                // all get \ added to the ends of the index entries.
-                if (keytitle.endsWith("\\")) //$NON-NLS-1$
-                {
-                    keytitle = keytitle.substring(0, keytitle.length() - 1);
-                }
-
-                if (isDailyDevotional)
-                {
-                    String[] parts = StringUtil.splitAll(keytitle, '.');
-                    greg.set(Calendar.MONTH, Integer.parseInt(parts[0]) - 1);
-                    greg.set(Calendar.DATE, Integer.parseInt(parts[1]));
-                    keytitle = nameDF.format(greg.getTime());
-                }
-
-                Key key = new IndexKey(keytitle, new DataIndex(offset, size), keys);
-
-                // remove duplicates, keeping later one.
-                // This occurs under some conditions:
-                // For daily devotionals where 02.29 becomes calendarized to Mar 1 for non-leap years
-                // For modules that have been updated by appending new data.
-                if (keys.contains(key))
-                {
-                    keys.removeAll(key);
-                }
-
-                keys.addAll(key);
-            }
-            catch (IOException ex)
-            {
-                log.error("Ignoring entry", ex); //$NON-NLS-1$
-            }
-            catch (NumberFormatException e)
-            {
-                log.error("Ignoring entry", e); //$NON-NLS-1$
-            }
-        }
-
-        return keys;
-    }
-
-    /* (non-Javadoc)
-     * @see org.crosswire.jsword.book.sword.AbstractBackend#getRawText(org.crosswire.jsword.passage.Key, java.lang.String)
+    /**
+     * Serialization ID
      */
-    /* @Override */
-    public String getRawText(Key key) throws BookException
-    {
-        checkActive();
+    private static final long   serialVersionUID  = 3536098410391064446L;
 
-        SwordBookMetaData sbmd = getBookMetaData();
-        String charset = sbmd.getBookCharset();
-        String compressType = (String) sbmd.getProperty(ConfigEntryType.COMPRESS_TYPE);
-
-        if (!(key instanceof IndexKey))
-        {
-            throw new BookException(Msg.BAD_KEY, new Object[] { ClassUtil.getShortClassName(key.getClass()), key.getName() });
-        }
-
-        IndexKey ikey = (IndexKey) key;
-
-        try
-        {
-            byte[] data = SwordUtil.readRAF(datRaf, ikey.getOffset(), ikey.getSize());
-
-            int keyend = SwordUtil.findByte(data, SEPARATOR);
-            if (keyend == -1)
-            {
-                throw new BookException(UserMsg.READ_FAIL);
-            }
-
-            int remainder = data.length - (keyend + 1);
-            byte[] temp = new byte[remainder];
-            System.arraycopy(data, keyend + 1, temp, 0, remainder);
-
-            String linkCheck = new String(temp, 0, 5, charset);
-            if ("@LINK".equals(linkCheck)) //$NON-NLS-1$
-            {
-                keyend = SwordUtil.findByte(temp, SEPARATOR);
-                String linkKey = new String(temp, 6, temp.length - (keyend + 1), charset).trim();
-                ikey = (IndexKey) keys.get(keys.indexOf(new IndexKey(linkKey)));
-                return getRawText(ikey);
-            }
-
-            long blockNum = SwordUtil.decodeLittleEndian32(temp, 0);
-            int entry = SwordUtil.decodeLittleEndian32(temp, 4);
-
-            // Can we get the data from the cache
-            byte[] uncompressed = null;
-            if (blockNum == lastBlockNum)
-            {
-                uncompressed = lastUncompressed;
-            }
-            else
-            {
-                temp = SwordUtil.readRAF(zdxRaf, blockNum * ZDX_ENTRY_SIZE, ZDX_ENTRY_SIZE);
-                if (temp == null || temp.length == 0)
-                {
-                    return ""; //$NON-NLS-1$
-                }
-
-                int blockStart = SwordUtil.decodeLittleEndian32(temp, 0);
-                int blockSize = SwordUtil.decodeLittleEndian32(temp, 4);
-
-                temp = SwordUtil.readRAF(zdtRaf, blockStart, blockSize);
-
-                decipher(temp);
-
-                uncompressed = CompressorType.fromString(compressType).getCompressor(temp).uncompress().toByteArray();
-
-                // cache the uncompressed data for next time
-                lastBlockNum = blockNum;
-                lastUncompressed = uncompressed;
-            }
-
-            // get the "entry" from this block.
-            int entryCount = SwordUtil.decodeLittleEndian32(uncompressed, 0);
-            if (entry >= entryCount)
-            {
-                return ""; //$NON-NLS-1$
-            }
-            int entryOffset = BLOCK_ENTRY_COUNT + (BLOCK_ENTRY_SIZE * entry);
-            int entryStart = SwordUtil.decodeLittleEndian32(uncompressed, entryOffset);
-            // Note: the actual entry is '\0' terminated
-            int entrySize = SwordUtil.decodeLittleEndian32(uncompressed, entryOffset + 4);
-            byte[] entryBytes = new byte[entrySize];
-            System.arraycopy(uncompressed, entryStart, entryBytes, 0, entrySize);
-
-            return SwordUtil.decode(key.getName(), entryBytes, charset).trim();
-        }
-        catch (IOException e)
-        {
-            throw new BookException(UserMsg.READ_FAIL, e);
-        }
-    }
-
     /**
-     * Helper method so we can quickly activate ourselves on access
+     * The log stream
      */
-    protected final void checkActive()
-    {
-        if (!active)
-        {
-            Activator.activate(this);
-        }
-    }
+    private static final Logger log               = Logger.getLogger(ZLDBackend.class);
 }

Modified: trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/ZVerseBackend.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/ZVerseBackend.java	2008-04-11 10:48:41 UTC (rev 1794)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/book/sword/ZVerseBackend.java	2008-04-11 20:21:02 UTC (rev 1795)
@@ -317,16 +317,6 @@
         }
     }
 
-    /* (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
      */

Modified: trunk/jsword/src/main/java/org/crosswire/jsword/passage/AbstractKeyList.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/passage/AbstractKeyList.java	2008-04-11 10:48:41 UTC (rev 1794)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/passage/AbstractKeyList.java	2008-04-11 20:21:02 UTC (rev 1795)
@@ -54,16 +54,7 @@
      */
     public boolean contains(Key key)
     {
-        for (Iterator it = iterator(); it.hasNext(); )
-        {
-            Key temp = (Key) it.next();
-            if (key.equals(temp))
-            {
-                return true;
-            }
-        }
-
-        return false;
+        return indexOf(key) >= 0;
     }
 
     /* (non-Javadoc)

Modified: trunk/jsword/src/main/java/org/crosswire/jsword/passage/DefaultKeyList.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/passage/DefaultKeyList.java	2008-04-11 10:48:41 UTC (rev 1794)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/passage/DefaultKeyList.java	2008-04-11 20:21:02 UTC (rev 1795)
@@ -30,7 +30,7 @@
 /**
  * A default implementation of Key.
  *
- * <p>This implementation uses <tt>java.util.TreeSet</tt> to store keys.
+ * <p>This implementation uses <tt>java.util.List</tt> to store keys.
  *
  * @see gnu.lgpl.License for license details.
  *      The copyright to this program is held by it's authors.

Modified: trunk/jsword/src/main/java/org/crosswire/jsword/passage/DefaultLeafKeyList.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/passage/DefaultLeafKeyList.java	2008-04-11 10:48:41 UTC (rev 1794)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/passage/DefaultLeafKeyList.java	2008-04-11 20:21:02 UTC (rev 1795)
@@ -37,6 +37,14 @@
     /**
      * Default ctor
      */
+    public DefaultLeafKeyList(String name)
+    {
+        this(name, name, null);
+    }
+
+    /**
+     * Default ctor
+     */
     public DefaultLeafKeyList(String name, String osisName)
     {
         this(name, osisName, null);

Modified: trunk/jsword/src/main/java/org/crosswire/jsword/passage/Key.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/passage/Key.java	2008-04-11 10:48:41 UTC (rev 1794)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/passage/Key.java	2008-04-11 20:21:02 UTC (rev 1795)
@@ -162,7 +162,7 @@
     /**
      * Reverse a Key into the position the key holds in the list of children
      * @param that The Key to find
-     * @return The index of the key or -1 if the key is not in the list
+     * @return The index of the key or < 0 if the key is not in the list
      */
     int indexOf(Key that);
 

Modified: trunk/jsword/src/test/java/org/crosswire/jsword/bridge/DwrBridgeTest.java
===================================================================
--- trunk/jsword/src/test/java/org/crosswire/jsword/bridge/DwrBridgeTest.java	2008-04-11 10:48:41 UTC (rev 1794)
+++ trunk/jsword/src/test/java/org/crosswire/jsword/bridge/DwrBridgeTest.java	2008-04-11 20:21:02 UTC (rev 1795)
@@ -59,7 +59,7 @@
             String verse = dwrBridge.getOSISString("KJV", "Gen 1:1", 100); //$NON-NLS-1$ //$NON-NLS-2$
             assertEquals(verse, "<div><title type=\"x-gen\">Genesis 1:1</title><verse osisID=\"Gen.1.1\"><w lemma=\"strong:H07225\">In the beginning</w> <w lemma=\"strong:H0430\">God</w> <w lemma=\"strong:H0853 strong:H01254\" morph=\"strongMorph:TH8804\">created</w> <w lemma=\"strong:H08064\">the heaven</w> <w lemma=\"strong:H0853\">and</w> <w lemma=\"strong:H0776\">the earth</w>.</verse></div>"); //$NON-NLS-1$
             String hdef = dwrBridge.getOSISString("StrongsHebrew", "H07225", 100); //$NON-NLS-1$ //$NON-NLS-2$
-            assertEquals(hdef, "<div><title>07225</title> 7225  re'shiyth  ray-sheeth'\r<lb></lb>\r<lb></lb> from the same as 7218; the first, in place, time, order or\r<lb></lb> rank (specifically, a firstfruit):--beginning, chief(-est),\r<lb></lb> first(-fruits, part, time), principal thing.\r<lb></lb> see HEBREW for 07218</div>"); //$NON-NLS-1$
+            assertEquals(hdef, "<div><title>07225</title>7225  re'shiyth  ray-sheeth'\r<lb></lb>\r<lb></lb> from the same as 7218; the first, in place, time, order or\r<lb></lb> rank (specifically, a firstfruit):--beginning, chief(-est),\r<lb></lb> first(-fruits, part, time), principal thing.\r<lb></lb> see HEBREW for 07218</div>"); //$NON-NLS-1$
         }
         catch (BookException e)
         {




More information about the jsword-svn mailing list