1
20 package org.crosswire.jsword.book.sword;
21
22 import java.io.IOException;
23 import java.io.ObjectInputStream;
24
25 import org.crosswire.common.compress.CompressorType;
26 import org.crosswire.jsword.book.BookException;
27 import org.crosswire.jsword.book.sword.state.OpenFileStateManager;
28 import org.crosswire.jsword.book.sword.state.RawLDBackendState;
29 import org.crosswire.jsword.book.sword.state.ZLDBackendState;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33
40 public class ZLDBackend extends RawLDBackend<ZLDBackendState> {
41
45 public ZLDBackend(SwordBookMetaData sbmd) {
46 super(sbmd, 4);
47 }
48
49
52 @Override
53 public ZLDBackendState initState() throws BookException {
54 return OpenFileStateManager.instance().getZLDBackendState(getBookMetaData());
55 }
56
57
60 @Override
61 protected DataEntry getEntry(RawLDBackendState fileState, DataEntry entry) {
62 ZLDBackendState state = null;
63 if (fileState instanceof ZLDBackendState) {
64 state = (ZLDBackendState) fileState;
65 } else {
66 log.error("Backend State was not of type ZLDBackendState. Ignoring this entry and exiting.");
68 return new DataEntry(entry.getName(), new byte[0], entry.getCharset());
69 }
70
71 DataIndex blockIndex = entry.getBlockIndex();
72 long blockNum = blockIndex.getOffset();
73 int blockEntry = blockIndex.getSize();
74
75 byte[] uncompressed = null;
77 if (blockNum == state.getLastBlockNum()) {
78 uncompressed = state.getLastUncompressed();
79 } else {
80 byte[] temp;
81 try {
82 temp = SwordUtil.readRAF(state.getZdxRaf(), blockNum * ZDX_ENTRY_SIZE, ZDX_ENTRY_SIZE);
83 if (temp == null || temp.length == 0) {
84 return new DataEntry(entry.getName(), new byte[0], entry.getCharset());
85 }
86
87 int blockStart = SwordUtil.decodeLittleEndian32(temp, 0);
88 int blockSize = SwordUtil.decodeLittleEndian32(temp, 4);
89
90 temp = SwordUtil.readRAF(state.getZdtRaf(), blockStart, blockSize);
91
92 decipher(temp);
93
94 String compressType = getBookMetaData().getProperty(SwordBookMetaData.KEY_COMPRESS_TYPE);
95 uncompressed = CompressorType.fromString(compressType).getCompressor(temp).uncompress().toByteArray();
96
97 state.setLastBlockNum(blockNum);
99 state.setLastUncompressed(uncompressed);
100 } catch (IOException e) {
101 return new DataEntry(entry.getName(), new byte[0], entry.getCharset());
102 }
103 }
104
105 int entryCount = SwordUtil.decodeLittleEndian32(uncompressed, 0);
107 if (blockEntry >= entryCount) {
108 return new DataEntry(entry.getName(), new byte[0], entry.getCharset());
109 }
110
111 int entryOffset = BLOCK_ENTRY_COUNT + (BLOCK_ENTRY_SIZE * blockEntry);
112 int entryStart = SwordUtil.decodeLittleEndian32(uncompressed, entryOffset);
113 int entrySize = SwordUtil.decodeLittleEndian32(uncompressed, entryOffset + 4);
114 int nullTerminator = SwordUtil.findByte(uncompressed, entryStart, (byte) 0x00);
116 if (nullTerminator - entryStart + 1 == entrySize) {
117 entrySize -= 1;
118 }
119 byte[] entryBytes = new byte[entrySize];
120 System.arraycopy(uncompressed, entryStart, entryBytes, 0, entrySize);
121 DataEntry finalEntry = new DataEntry(entry.getName(), entryBytes, getBookMetaData().getBookCharset());
122
123 return finalEntry;
124 }
125
126
133 private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException {
134 is.defaultReadObject();
135 }
136
139 @Override
140 public void dumpIdxRaf() {
141 RawLDBackendState state = null;
142 long end = -1;
143 try {
144 state = initState();
145 end = getCardinality();
146 StringBuilder buf = new StringBuilder();
147 System.out.println("index\toffset\tsize\tkey\tvalue");
148 for (long i = 0; i < end; ++i) {
149 DataIndex index = getIndex(state, i);
150 int offset = index.getOffset();
151 int size = index.getSize();
152 buf.setLength(0);
153 buf.append(i);
154 buf.append('\t');
155 buf.append(offset);
156 buf.append('\t');
157 buf.append(size);
158 if (size > 0) {
159 byte[] data = SwordUtil.readRAF(state.getDatRaf(), offset, size);
161 DataEntry blockEntry = new DataEntry(Long.toString(i), data, getBookMetaData().getBookCharset());
162 DataIndex block = blockEntry.getBlockIndex();
163 DataEntry dataEntry = getEntry(state, blockEntry);
164 String key = blockEntry.getKey();
165 buf.append('\t');
166 buf.append(key);
167 buf.append('\t');
168 buf.append(block.getOffset());
169 buf.append('\t');
170 buf.append(block.getSize());
171 String raw;
172 buf.append('\t');
173 if (dataEntry.isLinkEntry()) {
174 raw = dataEntry.getLinkTarget();
175 buf.append("Linked to: ").append(raw.replace('\n', ' '));
176 } else {
177 raw = getRawText(dataEntry);
178 if (raw.length() > 43) {
179 buf.append(raw.substring(0, 40).replace('\n', ' '));
180 buf.append("...");
181 } else {
182 buf.append(raw);
183 }
184 }
185 }
186 System.out.println(buf.toString());
187 }
188 } catch (IOException e) {
189 e.printStackTrace();
191 } catch (BookException e) {
192 e.printStackTrace();
194 } finally {
195 OpenFileStateManager.instance().release(state);
196 }
197 }
198
199 private static final int ZDX_ENTRY_SIZE = 8;
200 private static final int BLOCK_ENTRY_COUNT = 4;
201 private static final int BLOCK_ENTRY_SIZE = 8;
202
203
206 private static final Logger log = LoggerFactory.getLogger(ZLDBackend.class);
207 private static final long serialVersionUID = 3536098410391064446L;
208 }
209