Coverage Report - org.crosswire.jsword.book.sword.GenBookBackend
 
Classes in this File Line Coverage Branch Coverage Complexity
GenBookBackend
0%
0/66
0%
0/36
3.8
 
 1  
 /**
 2  
  * Distribution License:
 3  
  * JSword is free software; you can redistribute it and/or modify it under
 4  
  * the terms of the GNU Lesser General Public License, version 2.1 or later
 5  
  * as published by the Free Software Foundation. This program is distributed
 6  
  * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 7  
  * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 8  
  * See the GNU Lesser General Public License for more details.
 9  
  *
 10  
  * The License is available on the internet at:
 11  
  *      http://www.gnu.org/copyleft/lgpl.html
 12  
  * or by writing to:
 13  
  *      Free Software Foundation, Inc.
 14  
  *      59 Temple Place - Suite 330
 15  
  *      Boston, MA 02111-1307, USA
 16  
  *
 17  
  * © CrossWire Bible Society, 2005 - 2016
 18  
  *
 19  
  */
 20  
 package org.crosswire.jsword.book.sword;
 21  
 
 22  
 import java.io.IOException;
 23  
 import java.util.ArrayList;
 24  
 import java.util.List;
 25  
 
 26  
 import org.crosswire.jsword.JSMsg;
 27  
 import org.crosswire.jsword.book.BookException;
 28  
 import org.crosswire.jsword.book.BookMetaData;
 29  
 import org.crosswire.jsword.book.sword.state.GenBookBackendState;
 30  
 import org.crosswire.jsword.book.sword.state.OpenFileStateManager;
 31  
 import org.crosswire.jsword.passage.DefaultKeyList;
 32  
 import org.crosswire.jsword.passage.Key;
 33  
 import org.crosswire.jsword.passage.TreeKey;
 34  
 import org.slf4j.Logger;
 35  
 import org.slf4j.LoggerFactory;
 36  
 
 37  
 /**
 38  
  * Backend for General Books.
 39  
  * 
 40  
  * @see gnu.lgpl.License The GNU Lesser General Public License for details.
 41  
  * @author DM Smith
 42  
  */
 43  0
 public class GenBookBackend extends AbstractBackend<GenBookBackendState> {
 44  
     /**
 45  
      * Simple ctor
 46  
      * 
 47  
      * @param sbmd 
 48  
      */
 49  
     public GenBookBackend(SwordBookMetaData sbmd) {
 50  0
         super(sbmd);
 51  0
         index = new TreeKeyIndex(sbmd);
 52  0
     }
 53  
 
 54  
     public GenBookBackendState initState() throws BookException {
 55  0
         return OpenFileStateManager.instance().getGenBookBackendState(getBookMetaData());
 56  
     }
 57  
 
 58  
     /* (non-Javadoc)
 59  
      * @see org.crosswire.jsword.book.sword.AbstractBackend#contains(org.crosswire.jsword.passage.Key)
 60  
      */
 61  
     @Override
 62  
     public boolean contains(Key key) {
 63  0
         return getRawTextLength(key) > 0;
 64  
     }
 65  
 
 66  
     /* (non-Javadoc)
 67  
      * @see org.crosswire.jsword.book.sword.AbstractBackend#size(org.crosswire.jsword.passage.Key)
 68  
      */
 69  
     @Override
 70  
     public int getRawTextLength(Key key) {
 71  
         try {
 72  0
             TreeNode node = find(key);
 73  
 
 74  0
             if (node == null) {
 75  0
                 return 0;
 76  
             }
 77  
 
 78  0
             byte[] userData = node.getUserData();
 79  
 
 80  
             // Some entries may be empty.
 81  0
             if (userData.length == 8) {
 82  0
                 return SwordUtil.decodeLittleEndian32(userData, 4);
 83  
             }
 84  
 
 85  0
             return 0;
 86  
 
 87  0
         } catch (IOException e) {
 88  0
             return 0;
 89  
         }
 90  
     }
 91  
 
 92  
     /* (non-Javadoc)
 93  
      * @see org.crosswire.jsword.book.sword.StatefulFileBackedBackend#readRawContent(org.crosswire.jsword.book.sword.state.OpenFileState, org.crosswire.jsword.passage.Key)
 94  
      */
 95  
     public String readRawContent(GenBookBackendState state, Key key) throws IOException, BookException {
 96  0
         TreeNode node = find(key);
 97  
 
 98  0
         if (node == null) {
 99  
             // TRANSLATOR: Error condition: Indicates that something could
 100  
             // not be found in the book.
 101  
             // {0} is a placeholder for the unknown key.
 102  
             // {1} is the short name of the book
 103  0
             throw new BookException(JSMsg.gettext("No entry for '{0}' in {1}.", key.getName(), getBookMetaData().getInitials()));
 104  
         }
 105  
 
 106  0
         byte[] userData = node.getUserData();
 107  
 
 108  
         // Some entries may be empty.
 109  0
         if (userData.length == 8) {
 110  0
             int start = SwordUtil.decodeLittleEndian32(userData, 0);
 111  0
             int size = SwordUtil.decodeLittleEndian32(userData, 4);
 112  0
             byte[] data = SwordUtil.readRAF(state.getBdtRaf(), start, size);
 113  0
             decipher(data);
 114  0
             return SwordUtil.decode(key.getName(), data, getBookMetaData().getBookCharset());
 115  
         }
 116  
 
 117  0
         return "";
 118  
     }
 119  
 
 120  
     /**
 121  
      * Given a Key, find the TreeNode for it.
 122  
      * 
 123  
      * @param key
 124  
      *            The key to use for searching
 125  
      * @return the found node, null otherwise
 126  
      * @throws IOException
 127  
      */
 128  
     private TreeNode find(Key key) throws IOException {
 129  
         // We need to search from the root, so navigate to the root, saving as
 130  
         // we go.
 131  0
         List<String> path = new ArrayList<String>();
 132  0
         for (Key parentKey = key; parentKey != null && parentKey.getName().length() > 0; parentKey = parentKey.getParent()) {
 133  0
             path.add(parentKey.getName());
 134  
         }
 135  
 
 136  0
         TreeNode node = index.getRoot();
 137  
 
 138  0
         node = index.getFirstChild(node);
 139  
 
 140  0
         for (int i = path.size() - 1; i >= 0; i--) {
 141  0
             String name = path.get(i);
 142  
 
 143  
             // Search among the siblings for the current level.
 144  0
             while (node != null && !name.equals(node.getName())) {
 145  0
                 if (node.hasNextSibling()) {
 146  0
                     node = index.getNextSibling(node);
 147  
                 } else {
 148  0
                     log.error("Could not find {}", name);
 149  0
                     node = null;
 150  
                 }
 151  
             }
 152  
 
 153  
             // If we have found it but have not exhausted the path
 154  
             // we need to get more
 155  0
             if (node != null && name.equals(node.getName()) && i > 0) {
 156  0
                 node = index.getFirstChild(node);
 157  
             }
 158  
         }
 159  
 
 160  
         // At this point we have either found it, returning it or have not,
 161  
         // returning null
 162  0
         if (node != null && node.getName().equals(key.getName())) {
 163  0
             return node;
 164  
         }
 165  
 
 166  0
         return null;
 167  
     }
 168  
 
 169  
     @Override
 170  
     public Key readIndex() {
 171  0
         BookMetaData bmd = getBookMetaData();
 172  0
         Key reply = new DefaultKeyList(null, bmd.getName());
 173  
 
 174  
         try {
 175  0
             TreeNode node = index.getRoot();
 176  0
             reply = new TreeKey(node.getName(), null);
 177  0
             doReadIndex(node, reply);
 178  0
         } catch (IOException e) {
 179  0
             log.error("Could not get read GenBook index", e);
 180  0
         }
 181  
 
 182  0
         return reply;
 183  
     }
 184  
 
 185  
     /* (non-Javadoc)
 186  
      * @see org.crosswire.jsword.book.sword.AbstractBackend#setAliasKey(org.crosswire.jsword.passage.Key, org.crosswire.jsword.passage.Key)
 187  
      */
 188  
     public void setAliasKey(GenBookBackendState state, Key alias, Key source) throws IOException {
 189  0
         throw new UnsupportedOperationException();
 190  
     }
 191  
 
 192  
     /* (non-Javadoc)
 193  
      * @see org.crosswire.jsword.book.sword.AbstractBackend#setRawText(org.crosswire.jsword.passage.Key, java.lang.String)
 194  
      */
 195  
     public void setRawText(GenBookBackendState rafBook, Key key, String text) throws BookException, IOException {
 196  0
         throw new UnsupportedOperationException();
 197  
     }
 198  
 
 199  
     /**
 200  
      * A helper function to recursively read the entire tree.
 201  
      * 
 202  
      * @param parentNode
 203  
      *            the current node whose children are being sought
 204  
      * @param parentKey
 205  
      * @throws IOException
 206  
      */
 207  
     private void doReadIndex(TreeNode parentNode, Key parentKey) throws IOException {
 208  0
         TreeNode currentNode = parentNode;
 209  0
         if (currentNode.hasChildren()) {
 210  0
             TreeNode childNode = index.getFirstChild(currentNode);
 211  
             do {
 212  0
                 TreeKey childKey = new TreeKey(childNode.getName(), parentKey);
 213  0
                 parentKey.addAll(childKey);
 214  
 
 215  
                 // Build the tree as deep as possible
 216  0
                 doReadIndex(childNode, childKey);
 217  
 
 218  0
                 if (!childNode.hasNextSibling()) {
 219  0
                     break;
 220  
                 }
 221  
 
 222  0
                 childNode = index.getNextSibling(childNode);
 223  0
             } while (true);
 224  
         }
 225  0
     }
 226  
 
 227  
     /**
 228  
      * The raw index file
 229  
      */
 230  
     private final TreeKeyIndex index;
 231  
 
 232  
     /**
 233  
      * The log stream
 234  
      */
 235  0
     private static final Logger log = LoggerFactory.getLogger(GenBookBackend.class);
 236  
 }