1
20 package org.crosswire.jsword.book.sword;
21
22 import java.io.IOException;
23 import java.io.RandomAccessFile;
24
25 import org.crosswire.common.compress.CompressorType;
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.OpenFileStateManager;
30 import org.crosswire.jsword.book.sword.state.ZVerseBackendState;
31 import org.crosswire.jsword.passage.BitwisePassage;
32 import org.crosswire.jsword.passage.Key;
33 import org.crosswire.jsword.passage.KeyUtil;
34 import org.crosswire.jsword.passage.RocketPassage;
35 import org.crosswire.jsword.passage.Verse;
36 import org.crosswire.jsword.versification.Testament;
37 import org.crosswire.jsword.versification.Versification;
38 import org.crosswire.jsword.versification.system.Versifications;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42
132 public class ZVerseBackend extends AbstractBackend<ZVerseBackendState> {
133
138 public ZVerseBackend(SwordBookMetaData sbmd, BlockType blockType) {
139 super(sbmd);
140 this.blockType = blockType;
141 }
142
143
149 @Override
150 public boolean contains(Key key) {
151 return getRawTextLength(key) > 0;
152 }
153
154
157 @Override
158 public int getRawTextLength(Key key) {
159 ZVerseBackendState rafBook = null;
160 try {
161 rafBook = initState();
162
163 String v11nName = getBookMetaData().getProperty(BookMetaData.KEY_VERSIFICATION);
164 Versification v11n = Versifications.instance().getVersification(v11nName);
165 Verse verse = KeyUtil.getVerse(key);
166
167 int index = verse.getOrdinal();
168 Testament testament = v11n.getTestament(index);
169 index = v11n.getTestamentOrdinal(index);
170
171 RandomAccessFile idxRaf = rafBook.getIdxRaf(testament);
172
173 if (idxRaf == null) {
175 return 0;
176 }
177
178 byte[] temp = SwordUtil.readRAF(idxRaf, 1L * index * IDX_ENTRY_SIZE, IDX_ENTRY_SIZE);
180
181 if (temp == null || temp.length == 0) {
185 return 0;
186 }
187
188 return SwordUtil.decodeLittleEndian16(temp, 8);
190
191 } catch (IOException e) {
192 return 0;
193 } catch (BookException e) {
194 log.error("Unable to ascertain key validity", e);
197 return 0;
198 } finally {
199 OpenFileStateManager.instance().release(rafBook);
200 }
201 }
202
203
206 @Override
207 public Key getGlobalKeyList() throws BookException {
208 ZVerseBackendState rafBook = null;
209 try {
210 rafBook = initState();
211
212 String v11nName = getBookMetaData().getProperty(BookMetaData.KEY_VERSIFICATION);
213 Versification v11n = Versifications.instance().getVersification(v11nName);
214
215 Testament[] testaments = new Testament[] {
216 Testament.OLD, Testament.NEW
217 };
218
219 BitwisePassage passage = new RocketPassage(v11n);
220 passage.raiseEventSuppresion();
221 passage.raiseNormalizeProtection();
222
223 for (Testament currentTestament : testaments) {
224 RandomAccessFile idxRaf = rafBook.getIdxRaf(currentTestament);
225
226 if (idxRaf == null) {
228 continue;
230 }
231
232 int maxIndex = v11n.getCount(currentTestament) - 1;
233
234 byte[] temp = SwordUtil.readRAF(idxRaf, 0, IDX_ENTRY_SIZE * maxIndex);
236
237 for (int ii = 0; ii < temp.length; ii += IDX_ENTRY_SIZE) {
240 if (temp[ii + 8] != 0 || temp[ii + 9] != 0) {
244 int ordinal = ii / IDX_ENTRY_SIZE;
245 passage.addVersifiedOrdinal(v11n.getOrdinal(currentTestament, ordinal));
246 }
247 }
248 }
249
250 passage.lowerNormalizeProtection();
251 passage.lowerEventSuppressionAndTest();
252
253 return passage;
254 } catch (IOException e) {
255 throw new BookException(JSMsg.gettext("Unable to read key list from book."));
256 } finally {
257 OpenFileStateManager.instance().release(rafBook);
258 }
259 }
260
261
264 public ZVerseBackendState initState() throws BookException {
265 return OpenFileStateManager.instance().getZVerseBackendState(getBookMetaData(), blockType);
266 }
267
268
271 public String readRawContent(ZVerseBackendState rafBook, Key key) throws IOException {
272
273 BookMetaData bookMetaData = getBookMetaData();
274 final String charset = bookMetaData.getBookCharset();
275 final String compressType = bookMetaData.getProperty(SwordBookMetaData.KEY_COMPRESS_TYPE);
276
277 final String v11nName = getBookMetaData().getProperty(BookMetaData.KEY_VERSIFICATION);
278 final Versification v11n = Versifications.instance().getVersification(v11nName);
279 Verse verse = KeyUtil.getVerse(key);
280
281 int index = verse.getOrdinal();
282 final Testament testament = v11n.getTestament(index);
283 index = v11n.getTestamentOrdinal(index);
284 final RandomAccessFile idxRaf;
285 final RandomAccessFile compRaf;
286 final RandomAccessFile textRaf;
287
288 idxRaf = rafBook.getIdxRaf(testament);
289 compRaf = rafBook.getCompRaf(testament);
290 textRaf = rafBook.getTextRaf(testament);
291
292 if (idxRaf == null) {
294 return "";
295 }
296
297 byte[] temp = SwordUtil.readRAF(idxRaf, 1L * index * IDX_ENTRY_SIZE, IDX_ENTRY_SIZE);
301
302 if (temp == null || temp.length == 0) {
306 return "";
307 }
308
309 final long blockNum = SwordUtil.decodeLittleEndian32(temp, 0);
313 final int verseStart = SwordUtil.decodeLittleEndian32(temp, 4);
314 final int verseSize = SwordUtil.decodeLittleEndian16(temp, 8);
315
316 byte[] uncompressed = null;
318 if (blockNum == rafBook.getLastBlockNum() && testament == rafBook.getLastTestament()) {
319 uncompressed = rafBook.getLastUncompressed();
320 } else {
321 temp = SwordUtil.readRAF(compRaf, blockNum * COMP_ENTRY_SIZE, COMP_ENTRY_SIZE);
323 if (temp == null || temp.length == 0) {
324 return "";
325 }
326
327 final int blockStart = SwordUtil.decodeLittleEndian32(temp, 0);
328 final int blockSize = SwordUtil.decodeLittleEndian32(temp, 4);
329 final int uncompressedSize = SwordUtil.decodeLittleEndian32(temp, 8);
330
331 final byte[] data = SwordUtil.readRAF(textRaf, blockStart, blockSize);
333
334 decipher(data);
335
336 uncompressed = CompressorType.fromString(compressType).getCompressor(data).uncompress(uncompressedSize).toByteArray();
337
338 rafBook.setLastBlockNum(blockNum);
340 rafBook.setLastTestament(testament);
341 rafBook.setLastUncompressed(uncompressed);
342 }
343
344 final byte[] chopped = new byte[verseSize];
346 System.arraycopy(uncompressed, verseStart, chopped, 0, verseSize);
347
348 return SwordUtil.decode(key.getName(), chopped, charset);
349
350 }
351
352
355 public void setAliasKey(ZVerseBackendState rafBook, Key alias, Key source) throws IOException {
356 throw new UnsupportedOperationException();
357 }
358
359
362 public void setRawText(ZVerseBackendState rafBook, Key key, String text) throws BookException, IOException {
363 throw new UnsupportedOperationException();
364 }
365
366
373 public void dumpIdxRaf(Versification v11n, int ordinalStart, RandomAccessFile raf) {
374 long end = -1;
375 try {
376 end = raf.length();
377 } catch (IOException e) {
378 e.printStackTrace();
380 }
381
382 int i = ordinalStart;
383 StringBuilder buf = new StringBuilder();
384 System.out.println("osisID\tblock\tstart\tsize");
385 for (long offset = 0; offset < end; offset += IDX_ENTRY_SIZE) {
386 byte[] temp = null;
388 try {
389 temp = SwordUtil.readRAF(raf, offset, IDX_ENTRY_SIZE);
390 } catch (IOException e) {
391 e.printStackTrace();
392 }
393
394 long blockNum = -1;
398 int verseStart = -1;
399 int verseSize = -1;
400 if (temp != null && temp.length > 0) {
401 blockNum = SwordUtil.decodeLittleEndian32(temp, 0);
403 verseStart = SwordUtil.decodeLittleEndian32(temp, 4);
404 verseSize = SwordUtil.decodeLittleEndian16(temp, 8);
405 }
406 buf.setLength(0);
407 buf.append(v11n.decodeOrdinal(i++).getOsisID());
408 buf.append('\t');
409 buf.append(blockNum);
410 buf.append('\t');
411 buf.append(verseStart);
412 buf.append('\t');
413 buf.append(verseSize);
414 System.out.println(buf.toString());
415 }
416 }
417
418
423 public void dumpCompRaf(RandomAccessFile raf) {
424 long end = -1;
425 try {
426 end = raf.length();
427 } catch (IOException e) {
428 e.printStackTrace();
430 }
431
432 int blockNum = 0;
433 StringBuilder buf = new StringBuilder();
434 System.out.println("block\tstart\tsize\tuncompressed");
435 for (long offset = 0; offset < end; offset += COMP_ENTRY_SIZE) {
436 byte[] temp = null;
438 try {
439 temp = SwordUtil.readRAF(raf, offset, COMP_ENTRY_SIZE);
440 } catch (IOException e) {
441 e.printStackTrace();
442 }
443
444 int blockStart = -1;
448 int blockSize = -1;
449 int uncompressedSize = -1;
450 if (temp != null && temp.length > 0) {
451 blockStart = SwordUtil.decodeLittleEndian32(temp, 0);
453 blockSize = SwordUtil.decodeLittleEndian32(temp, 4);
454 uncompressedSize = SwordUtil.decodeLittleEndian32(temp, 8);
455 }
456 buf.setLength(0);
457 buf.append(blockNum);
458 buf.append('\t');
459 buf.append(blockStart);
460 buf.append('\t');
461 buf.append(blockSize);
462 buf.append('\t');
463 buf.append(uncompressedSize);
464 System.out.println(buf.toString());
465 }
466 }
467
468
471 private final BlockType blockType;
472
473
476 private static final int IDX_ENTRY_SIZE = 10;
477
478
481 private static final int COMP_ENTRY_SIZE = 12;
482
483
486 private static final Logger log = LoggerFactory.getLogger(ZVerseBackend.class);
487 }
488