1
22 package org.crosswire.jsword.book.sword;
23
24 import java.io.File;
25 import java.io.IOException;
26 import java.io.RandomAccessFile;
27 import java.net.URI;
28 import java.util.ArrayList;
29 import java.util.List;
30
31 import org.crosswire.common.activate.Activator;
32 import org.crosswire.common.activate.Lock;
33 import org.crosswire.common.util.FileUtil;
34 import org.crosswire.common.util.Logger;
35 import org.crosswire.common.util.Reporter;
36 import org.crosswire.jsword.JSMsg;
37 import org.crosswire.jsword.book.BookException;
38 import org.crosswire.jsword.passage.DefaultKeyList;
39 import org.crosswire.jsword.passage.Key;
40 import org.crosswire.jsword.passage.TreeKey;
41
42
49 public class GenBookBackend extends AbstractBackend {
50
53 public GenBookBackend(SwordBookMetaData sbmd) {
54 super(sbmd);
55 index = new TreeKeyIndex(sbmd);
56 }
57
58
61 public final void activate(Lock lock) {
62 Activator.activate(index);
63
64 URI path = null;
65 try {
66 path = getExpandedDataPath();
67 } catch (BookException e) {
68 Reporter.informUser(this, e);
69 return;
70 }
71
72 bdtFile = new File(path.getPath() + EXTENSION_BDT);
73
74 if (!bdtFile.canRead()) {
75 Reporter.informUser(this, new BookException(JSMsg.gettext("Error reading {0}", bdtFile.getAbsolutePath())));
78 return;
79 }
80
81 try {
82 bdtRaf = new RandomAccessFile(bdtFile, FileUtil.MODE_READ);
83 } catch (IOException ex) {
84 log.error("failed to open files", ex);
85 bdtRaf = null;
86 }
87 active = true;
88 }
89
90
93 public final void deactivate(Lock lock) {
94 try {
95 if (bdtRaf != null) {
96 bdtRaf.close();
97 }
98 } catch (IOException ex) {
99 log.error("failed to close gen book files", ex);
100 } finally {
101 bdtRaf = null;
102 }
103 active = false;
104
105 Activator.deactivate(index);
107 }
108
109 @Override
110 public boolean contains(Key key) {
111 checkActive();
112
113 try {
114 return null != find(key);
115 } catch (IOException e) {
116 return false;
117 }
118 }
119
120 @Override
121 public String getRawText(Key key) throws BookException {
122 checkActive();
123
124 try {
125 TreeNode node = find(key);
126
127 if (node == null) {
128 throw new BookException(JSMsg.gettext("No entry for '{0}' in {1}.", key.getName(), getBookMetaData().getInitials()));
132 }
133
134 byte[] userData = node.getUserData();
135
136 if (userData.length == 8) {
138 int start = SwordUtil.decodeLittleEndian32(userData, 0);
139 int size = SwordUtil.decodeLittleEndian32(userData, 4);
140 byte[] data = SwordUtil.readRAF(bdtRaf, start, size);
141 decipher(data);
142 return SwordUtil.decode(key.getName(), data, getBookMetaData().getBookCharset());
143 }
144
145 return "";
146 } catch (IOException e) {
147 throw new BookException(JSMsg.gettext("Error reading {0}", key.getName()), e);
150 }
151 }
152
153
161 private TreeNode find(Key key) throws IOException {
162 List<String> path = new ArrayList<String>();
165 for (Key parentKey = key; parentKey != null && parentKey.getName().length() > 0; parentKey = parentKey.getParent()) {
166 path.add(parentKey.getName());
167 }
168
169 TreeNode node = index.getRoot();
170
171 node = index.getFirstChild(node);
172
173 for (int i = path.size() - 1; i >= 0; i--) {
174 String name = path.get(i);
175
176 while (node != null && !name.equals(node.getName())) {
178 if (node.hasNextSibling()) {
179 node = index.getNextSibling(node);
180 } else {
181 log.error("Could not find " + name);
182 node = null;
183 }
184 }
185
186 if (node != null && name.equals(node.getName()) && i > 0) {
189 node = index.getFirstChild(node);
190 }
191 }
192
193 if (node != null && node.getName().equals(key.getName())) {
196 return node;
197 }
198
199 return null;
200 }
201
202 @Override
203 public Key readIndex() {
204 SwordBookMetaData bmd = getBookMetaData();
205 Key reply = new DefaultKeyList(null, bmd.getName());
206
207 try {
208 TreeNode node = index.getRoot();
209 reply = new TreeKey(node.getName(), null);
210 doReadIndex(node, reply);
211 } catch (IOException e) {
212 log.error("Could not get read GenBook index", e);
213 }
214
215 return reply;
216 }
217
218 @Override
219 public void setAliasKey(Key alias, Key source) throws IOException {
220 throw new UnsupportedOperationException();
221 }
222
223 @Override
224 public void setRawText(Key key, String text) throws BookException, IOException {
225 throw new UnsupportedOperationException();
226 }
227
228
236 private void doReadIndex(TreeNode parentNode, Key parentKey) throws IOException {
237 TreeNode currentNode = parentNode;
238 if (currentNode.hasChildren()) {
239 TreeNode childNode = index.getFirstChild(currentNode);
240 do {
241 TreeKey childKey = new TreeKey(childNode.getName(), parentKey);
242 parentKey.addAll(childKey);
243
244 doReadIndex(childNode, childKey);
246
247 if (!childNode.hasNextSibling()) {
248 break;
249 }
250
251 childNode = index.getNextSibling(childNode);
252 } while (true);
253 }
254 }
255
256
259 protected final void checkActive() {
260 if (!active) {
261 Activator.activate(this);
262 }
263 }
264
265
268 private static final String EXTENSION_BDT = ".bdt";
269
270
273 private File bdtFile;
274
275
278 private RandomAccessFile bdtRaf;
279
280
283 private TreeKeyIndex index;
284
287 private boolean active;
288
289
292 private static final Logger log = Logger.getLogger(GenBookBackend.class);
293 }
294