1
20 package org.crosswire.jsword.book.sword;
21
22 import java.io.IOException;
23 import java.io.RandomAccessFile;
24
25 import org.crosswire.jsword.JSMsg;
26 import org.crosswire.jsword.book.BookException;
27 import org.crosswire.jsword.book.BookMetaData;
28 import org.crosswire.jsword.book.sword.state.OpenFileStateManager;
29 import org.crosswire.jsword.book.sword.state.RawBackendState;
30 import org.crosswire.jsword.passage.BitwisePassage;
31 import org.crosswire.jsword.passage.Key;
32 import org.crosswire.jsword.passage.KeyUtil;
33 import org.crosswire.jsword.passage.RocketPassage;
34 import org.crosswire.jsword.passage.Verse;
35 import org.crosswire.jsword.versification.Testament;
36 import org.crosswire.jsword.versification.Versification;
37 import org.crosswire.jsword.versification.system.Versifications;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41
49 public class RawBackend<T extends RawBackendState> extends AbstractBackend<RawBackendState> {
50
51
57 public RawBackend(SwordBookMetaData sbmd, int datasize) {
58 super(sbmd);
59 this.datasize = datasize;
60 this.entrysize = OFFSETSIZE + datasize;
61
62 assert datasize == 2 || datasize == 4;
63 }
64
65
68 @Override
69 public boolean contains(Key key) {
70 return getRawTextLength(key) > 0;
71 }
72
73
76 @Override
77 public int getRawTextLength(Key key) {
78 String v11nName = getBookMetaData().getProperty(BookMetaData.KEY_VERSIFICATION);
79 Versification v11n = Versifications.instance().getVersification(v11nName);
80 Verse verse = KeyUtil.getVerse(key);
81
82 RawBackendState initState = null;
83 try {
84 int index = verse.getOrdinal();
85 Testament testament = v11n.getTestament(index);
86 index = v11n.getTestamentOrdinal(index);
87 initState = initState();
88 RandomAccessFile idxRaf = initState.getIdxRaf(testament);
89
90 if (idxRaf == null) {
92 return 0;
93 }
94
95 DataIndex dataIndex = getIndex(idxRaf, index);
96
97 return dataIndex.getSize();
98 } catch (IOException ex) {
99 return 0;
100 } catch (BookException e) {
101 return 0;
102 } finally {
103 OpenFileStateManager.instance().release(initState);
104 }
105 }
106
107 @Override
108 public Key getGlobalKeyList() throws BookException {
109 RawBackendState rafBook = null;
110 try {
111 rafBook = initState();
112
113 String v11nName = getBookMetaData().getProperty(BookMetaData.KEY_VERSIFICATION);
114 Versification v11n = Versifications.instance().getVersification(v11nName);
115
116 Testament[] testaments = new Testament[] {
117 Testament.OLD, Testament.NEW
118 };
119
120 BitwisePassage passage = new RocketPassage(v11n);
121 passage.raiseEventSuppresion();
122 passage.raiseNormalizeProtection();
123
124 for (Testament currentTestament : testaments) {
125 RandomAccessFile idxRaf = rafBook.getIdxRaf(currentTestament);
126
127 if (idxRaf == null) {
129 continue;
131 }
132
133 int maxIndex = v11n.getCount(currentTestament) - 1;
134
135 byte[] temp = SwordUtil.readRAF(idxRaf, 0, entrysize * maxIndex);
137
138 if (datasize == 2) {
141 for (int ii = 0; ii < temp.length; ii += entrysize) {
142 if (temp[ii + 4] != 0 || temp[ii + 5] != 0) {
146 int ordinal = ii / entrysize;
147 passage.addVersifiedOrdinal(v11n.getOrdinal(currentTestament, ordinal));
148 }
149 }
150 } else { for (int ii = 0; ii < temp.length; ii += entrysize) {
152 if (temp[ii + 4] != 0 || temp[ii + 5] != 0 || temp[ii + 6] != 0 || temp[ii + 7] != 0) {
156 int ordinal = ii / entrysize;
157 passage.addVersifiedOrdinal(v11n.getOrdinal(currentTestament, ordinal));
158 }
159 }
160 }
161 }
162
163 passage.lowerNormalizeProtection();
164 passage.lowerEventSuppressionAndTest();
165
166 return passage;
167 } catch (IOException e) {
168 throw new BookException(JSMsg.gettext("Unable to read key list from book."));
169 } finally {
170 OpenFileStateManager.instance().release(rafBook);
171 }
172 }
173
174 public T initState() throws BookException {
175 return (T) OpenFileStateManager.instance().getRawBackendState(getBookMetaData());
176 }
177
178 public String getRawText(RawBackendState state, Key key) throws IOException {
179 return readRawContent(state, key);
180 }
181
182
185 public String readRawContent(RawBackendState state, Key key) throws IOException {
186 String v11nName = getBookMetaData().getProperty(BookMetaData.KEY_VERSIFICATION);
187 Versification v11n = Versifications.instance().getVersification(v11nName);
188 Verse verse = KeyUtil.getVerse(key);
189
190 int index = verse.getOrdinal();
191
192 Testament testament = v11n.getTestament(index);
193 index = v11n.getTestamentOrdinal(index);
194 RawBackendState initState = null;
195 try {
196 initState = initState();
197 return getEntry(state, verse.getName(), testament, index);
198 } catch (BookException e) {
199 return "";
200 } finally {
201 OpenFileStateManager.instance().release(initState);
202 }
203 }
204
205
208 public void setRawText(RawBackendState state, Key key, String text) throws BookException, IOException {
209 }
210
211
214 @Override
215 public boolean isWritable() {
216 RawBackendState rawBackendState = null;
217 try {
218 rawBackendState = initState();
219 return rawBackendState.isWritable();
220 } catch (BookException e) {
221 return false;
222 } finally {
223 OpenFileStateManager.instance().release(rawBackendState);
224 }
225 }
226
227
230 public void setAliasKey(RawBackendState state, Key alias, Key source) throws IOException {
231 throw new UnsupportedOperationException();
232 }
233
234
241 protected DataIndex getIndex(RandomAccessFile raf, long entry) throws IOException {
242 byte[] buffer = SwordUtil.readRAF(raf, entry * entrysize, entrysize);
244 if (buffer == null || buffer.length == 0) {
245 return new DataIndex(0, 0);
246 }
247
248 int entryOffset = SwordUtil.decodeLittleEndian32(buffer, 0);
249 int entrySize = -1;
250 switch (datasize) {
251 case 2:
252 entrySize = SwordUtil.decodeLittleEndian16(buffer, 4);
253 break;
254 case 4:
255 entrySize = SwordUtil.decodeLittleEndian32(buffer, 4);
256 break;
257 default:
258 assert false : datasize;
259 }
260 return new DataIndex(entryOffset, entrySize);
261 }
262
263
277 protected String getEntry(RawBackendState state, String name, Testament testament, long index) throws IOException {
278 final RandomAccessFile idxRaf;
279 final RandomAccessFile txtRaf;
280 idxRaf = state.getIdxRaf(testament);
281 txtRaf = state.getTextRaf(testament);
282
283 if (idxRaf == null) {
285 return "";
286 }
287
288 DataIndex dataIndex = getIndex(idxRaf, index);
289
290 int size = dataIndex.getSize();
291 if (size == 0) {
292 return "";
293 }
294
295 if (size < 0) {
296 log.error("In {}: Verse {} has a bad index size of {}", getBookMetaData().getInitials(), name, Integer.toString(size));
297 return "";
298 }
299
300 byte[] data = SwordUtil.readRAF(txtRaf, dataIndex.getOffset(), size);
301
302 decipher(data);
303
304 return SwordUtil.decode(name, data, getBookMetaData().getBookCharset());
305 }
306
307
310 protected final int datasize;
311
312
315 protected final int entrysize;
316
317
320 protected static final int OFFSETSIZE = 4;
321
322
325 private static final Logger log = LoggerFactory.getLogger(RawBackend.class);
326
327
328 }
329