1
22 package org.crosswire.jsword.book.sword;
23
24 import java.io.File;
25 import java.io.IOException;
26 import java.io.ObjectInputStream;
27 import java.io.RandomAccessFile;
28 import java.net.URI;
29
30 import org.crosswire.common.activate.Lock;
31 import org.crosswire.common.compress.CompressorType;
32 import org.crosswire.common.util.FileUtil;
33 import org.crosswire.common.util.Logger;
34 import org.crosswire.common.util.Reporter;
35 import org.crosswire.jsword.JSMsg;
36 import org.crosswire.jsword.book.BookException;
37
38
46 public class ZLDBackend extends RawLDBackend {
47
50 public ZLDBackend(SwordBookMetaData sbmd) {
51 super(sbmd, 4);
52 this.lastBlockNum = -1;
53 this.lastUncompressed = EMPTY_BYTES;
54 }
55
56 @Override
57 protected String getRawText(DataEntry entry) {
58 DataIndex blockIndex = entry.getBlockIndex();
59 long blockNum = blockIndex.getOffset();
60 int blockEntry = blockIndex.getSize();
61
62 byte[] uncompressed = null;
64 if (blockNum == lastBlockNum) {
65 uncompressed = lastUncompressed;
66 } else {
67 byte[] temp;
68 try {
69 temp = SwordUtil.readRAF(zdxRaf, blockNum * ZDX_ENTRY_SIZE, ZDX_ENTRY_SIZE);
70 if (temp == null || temp.length == 0) {
71 return "";
72 }
73
74 int blockStart = SwordUtil.decodeLittleEndian32(temp, 0);
75 int blockSize = SwordUtil.decodeLittleEndian32(temp, 4);
76
77 temp = SwordUtil.readRAF(zdtRaf, blockStart, blockSize);
78
79 decipher(temp);
80
81 String compressType = (String) getBookMetaData().getProperty(ConfigEntryType.COMPRESS_TYPE);
82 uncompressed = CompressorType.fromString(compressType).getCompressor(temp).uncompress().toByteArray();
83
84 lastBlockNum = blockNum;
86 lastUncompressed = uncompressed;
87 } catch (IOException e) {
88 return "";
89 }
90 }
91
92 int entryCount = SwordUtil.decodeLittleEndian32(uncompressed, 0);
94 if (blockEntry >= entryCount) {
95 return "";
96 }
97
98 int entryOffset = BLOCK_ENTRY_COUNT + (BLOCK_ENTRY_SIZE * blockEntry);
99 int entryStart = SwordUtil.decodeLittleEndian32(uncompressed, entryOffset);
100 int entrySize = SwordUtil.decodeLittleEndian32(uncompressed, entryOffset + 4);
102 byte[] entryBytes = new byte[entrySize];
103 System.arraycopy(uncompressed, entryStart, entryBytes, 0, entrySize);
104
105 return SwordUtil.decode(entry.getName(), entryBytes, getBookMetaData().getBookCharset()).trim();
106 }
107
108
115 @Override
116 public void activate(Lock lock) {
117 super.activate(lock);
118
119 active = false;
120 zdxFile = null;
121 zdtFile = null;
122 zdxRaf = null;
123 zdtRaf = null;
124 lastBlockNum = -1;
125 lastUncompressed = EMPTY_BYTES;
126
127 URI path = null;
128 try {
129 path = getExpandedDataPath();
130 } catch (BookException e) {
131 Reporter.informUser(this, e);
132 return;
133 }
134
135 try {
136 zdxFile = new File(path.getPath() + EXTENSION_Z_INDEX);
137 zdtFile = new File(path.getPath() + EXTENSION_Z_DATA);
138
139 if (!zdxFile.canRead()) {
140 Reporter.informUser(this, new BookException(JSMsg.gettext("Error reading {0}", zdtFile.getAbsolutePath())));
143 return;
144 }
145
146 if (!zdtFile.canRead()) {
147 Reporter.informUser(this, new BookException(JSMsg.gettext("Error reading {0}", zdtFile.getAbsolutePath())));
150 return;
151 }
152
153 zdxRaf = new RandomAccessFile(zdxFile, FileUtil.MODE_READ);
155 zdtRaf = new RandomAccessFile(zdtFile, FileUtil.MODE_READ);
156 } catch (IOException ex) {
157 log.error("failed to open files", ex);
158 zdxRaf = null;
159 zdtRaf = null;
160 return;
161 }
162
163 active = true;
164 }
165
166
173 @Override
174 public void deactivate(Lock lock) {
175 super.deactivate(lock);
176 lastBlockNum = -1;
177 lastUncompressed = EMPTY_BYTES;
178
179 try {
180 if (zdxRaf != null) {
181 zdxRaf.close();
182 }
183 if (zdtRaf != null) {
184 zdtRaf.close();
185 }
186 } catch (IOException ex) {
187 log.error("failed to close files", ex);
188 } finally {
189 zdxRaf = null;
190 zdtRaf = null;
191 }
192
193 active = false;
194 }
195
196
199 @Override
200 protected boolean isActive() {
201 return active && super.isActive();
202 }
203
204
211 private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException {
212 active = false;
213 zdxFile = null;
214 zdtFile = null;
215 zdxRaf = null;
216 zdtRaf = null;
217 lastBlockNum = -1;
218 lastUncompressed = EMPTY_BYTES;
219 is.defaultReadObject();
220 }
221
222 private static final String EXTENSION_Z_INDEX = ".zdx";
223 private static final String EXTENSION_Z_DATA = ".zdt";
224
225 private static final int ZDX_ENTRY_SIZE = 8;
226 private static final int BLOCK_ENTRY_COUNT = 4;
227 private static final int BLOCK_ENTRY_SIZE = 8;
228 private static final byte[] EMPTY_BYTES = new byte[0];
229
230
233 private transient boolean active;
234
235
238 private transient File zdxFile;
239
240
243 private transient RandomAccessFile zdxRaf;
244
245
248 private transient File zdtFile;
249
250
253 private transient RandomAccessFile zdtRaf;
254
255
258 private transient long lastBlockNum;
259
260
263 private transient byte[] lastUncompressed;
264
265
268 private static final long serialVersionUID = 3536098410391064446L;
269
270
273 private static final Logger log = Logger.getLogger(ZLDBackend.class);
274 }
275