The SWORD Project  1.9.0.svnversion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
zverse.cpp
Go to the documentation of this file.
1 /******************************************************************************
2  *
3  * zverse.cpp - code for class 'zVerse'- a module that reads raw text
4  * files: ot and nt using indexs ??.bks ??.cps ??.vss
5  * and provides lookup and parsing functions based on
6  * class VerseKey for compressed modules
7  *
8  * $Id: zverse.cpp 3754 2020-07-10 17:45:48Z scribe $
9  *
10  * Copyright 1996-2013 CrossWire Bible Society (http://www.crosswire.org)
11  * CrossWire Bible Society
12  * P. O. Box 2528
13  * Tempe, AZ 85280-2528
14  *
15  * This program is free software; you can redistribute it and/or modify it
16  * under the terms of the GNU General Public License as published by the
17  * Free Software Foundation version 2.
18  *
19  * This program is distributed in the hope that it will be useful, but
20  * WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22  * General Public License for more details.
23  *
24  */
25 
26 
27 
28 #include <ctype.h>
29 #include <stdio.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <stdlib.h>
33 
34 #include <utilstr.h>
35 #include <versekey.h>
36 #include <zverse.h>
37 #include <sysdata.h>
38 #include <swbuf.h>
39 #include <filemgr.h>
40 #include <swcomprs.h>
41 
42 
44 
45 /******************************************************************************
46  * zVerse Statics
47  */
48 
49 int zVerse::instance = 0;
50 
51 const char zVerse::uniqueIndexID[] = {'X', 'r', 'v', 'c', 'b'};
52 
53 /******************************************************************************
54  * zVerse Constructor - Initializes data for instance of zVerse
55  *
56  * ENT: ipath - path of the directory where data and index files are located.
57  * be sure to include the trailing separator (e.g. '/' or '\')
58  * (e.g. 'modules/texts/rawtext/webster/')
59  * fileMode - open mode for the files (FileMgr::RDONLY, etc.)
60  * blockType - verse, chapter, book, etc.
61  */
62 
63 zVerse::zVerse(const char *ipath, int fileMode, int blockType, SWCompress *icomp)
64 {
65  // this line, instead of just defaulting, to keep FileMgr out of header
66  if (fileMode == -1) fileMode = FileMgr::RDONLY;
67 
68  SWBuf buf;
69 
70  path = 0;
71  cacheBufIdx = -1;
72  cacheTestament = 0;
73  cacheBuf = 0;
74  dirtyCache = false;
75  stdstr(&path, ipath);
76 
77  if ((path[strlen(path)-1] == '/') || (path[strlen(path)-1] == '\\'))
78  path[strlen(path)-1] = 0;
79 
80  compressor = (icomp) ? icomp : new SWCompress();
81 
82  if (fileMode == -1) { // try read/write if possible
83  fileMode = FileMgr::RDWR;
84  }
85 
86  buf.setFormatted("%s/ot.%czs", path, uniqueIndexID[blockType]);
87  idxfp[0] = FileMgr::getSystemFileMgr()->open(buf, fileMode, true);
88 
89  buf.setFormatted("%s/nt.%czs", path, uniqueIndexID[blockType]);
90  idxfp[1] = FileMgr::getSystemFileMgr()->open(buf, fileMode, true);
91 
92  buf.setFormatted("%s/ot.%czz", path, uniqueIndexID[blockType]);
93  textfp[0] = FileMgr::getSystemFileMgr()->open(buf, fileMode, true);
94 
95  buf.setFormatted("%s/nt.%czz", path, uniqueIndexID[blockType]);
96  textfp[1] = FileMgr::getSystemFileMgr()->open(buf, fileMode, true);
97 
98  buf.setFormatted("%s/ot.%czv", path, uniqueIndexID[blockType]);
99  compfp[0] = FileMgr::getSystemFileMgr()->open(buf, fileMode, true);
100 
101  buf.setFormatted("%s/nt.%czv", path, uniqueIndexID[blockType]);
102  compfp[1] = FileMgr::getSystemFileMgr()->open(buf, fileMode, true);
103 
104  instance++;
105 }
106 
107 
108 /******************************************************************************
109  * zVerse Destructor - Cleans up instance of zVerse
110  */
111 
113 {
114  int loop1;
115 
116  if (cacheBuf) {
117  flushCache();
118  free(cacheBuf);
119  }
120 
121  if (path)
122  delete [] path;
123 
124  if (compressor)
125  delete compressor;
126 
127  --instance;
128 
129  for (loop1 = 0; loop1 < 2; loop1++) {
133  }
134 }
135 
136 
137 /******************************************************************************
138  * zVerse::findoffset - Finds the offset of the key verse from the indexes
139  *
140  *
141  *
142  * ENT: testmt - testament to find (0 - Bible/module introduction)
143  * book - book to find (0 - testament introduction)
144  * chapter - chapter to find (0 - book introduction)
145  * verse - verse to find (0 - chapter introduction)
146  * start - address to store the starting offset
147  * size - address to store the size of the entry
148  */
149 
150 void zVerse::findOffset(char testmt, long idxoff, long *start, unsigned short *size, unsigned long *buffnum) const
151 {
152  SW_u32 ulBuffNum = 0; // buffer number
153  SW_u32 ulVerseStart = 0; // verse offset within buffer
154  SW_u16 usVerseSize = 0; // verse size
155  // set start to offset in
156  // set size to
157  // set
158  *start = *size = *buffnum = 0;
159  //fprintf(stderr, "Finding offset %ld\n", idxoff);
160  idxoff *= 10;
161  if (!testmt) {
162  testmt = ((idxfp[0]) ? 1:2);
163  }
164 
165  // assert we have and valid file descriptor
166  if (compfp[testmt-1]->getFd() < 1)
167  return;
168 
169  long newOffset = compfp[testmt-1]->seek(idxoff, SEEK_SET);
170  if (newOffset == idxoff) {
171  if (compfp[testmt-1]->read(&ulBuffNum, 4) != 4) {
172  fprintf(stderr, "Error reading ulBuffNum\n");
173  return;
174  }
175  }
176  else return;
177 
178  if (compfp[testmt-1]->read(&ulVerseStart, 4) < 2)
179  {
180  fprintf(stderr, "Error reading ulVerseStart\n");
181  return;
182  }
183  if (compfp[testmt-1]->read(&usVerseSize, 2) < 2)
184  {
185  fprintf(stderr, "Error reading usVerseSize\n");
186  return;
187  }
188 
189  *buffnum = swordtoarch32(ulBuffNum);
190  *start = swordtoarch32(ulVerseStart);
191  *size = swordtoarch16(usVerseSize);
192 
193 }
194 
195 
196 /******************************************************************************
197  * zVerse::zreadtext - gets text at a given offset
198  *
199  * ENT: testmt - testament file to search in (0 - Old; 1 - New)
200  * start - starting offset where the text is located in the file
201  * size - size of text entry + 1 (null)
202  * buf - buffer to store text
203  *
204  */
205 
206 void zVerse::zReadText(char testmt, long start, unsigned short size, unsigned long ulBuffNum, SWBuf &inBuf) const {
207  SW_u32 ulCompOffset = 0; // compressed buffer start
208  SW_u32 ulCompSize = 0; // buffer size compressed
209  SW_u32 ulUnCompSize = 0; // buffer size uncompressed
210 
211  if (!testmt) {
212  testmt = ((idxfp[0]) ? 1:2);
213  }
214 
215  // assert we have and valid file descriptor
216  if (compfp[testmt-1]->getFd() < 1)
217  return;
218 
219  if (size &&
220  !(((long) ulBuffNum == cacheBufIdx) && (testmt == cacheTestament) && (cacheBuf))) {
221  //fprintf(stderr, "Got buffer number{%ld} versestart{%ld} versesize{%d}\n", ulBuffNum, ulVerseStart, usVerseSize);
222 
223  if (idxfp[testmt-1]->seek(ulBuffNum*12, SEEK_SET)!=(long) ulBuffNum*12)
224  {
225  fprintf(stderr, "Error seeking compressed file index\n");
226  return;
227  }
228  if (idxfp[testmt-1]->read(&ulCompOffset, 4)<4)
229  {
230  fprintf(stderr, "Error reading ulCompOffset\n");
231  return;
232  }
233  if (idxfp[testmt-1]->read(&ulCompSize, 4)<4)
234  {
235  fprintf(stderr, "Error reading ulCompSize\n");
236  return;
237  }
238  if (idxfp[testmt-1]->read(&ulUnCompSize, 4)<4)
239  {
240  fprintf(stderr, "Error reading ulUnCompSize\n");
241  return;
242  }
243 
244  ulCompOffset = swordtoarch32(ulCompOffset);
245  ulCompSize = swordtoarch32(ulCompSize);
246  ulUnCompSize = swordtoarch32(ulUnCompSize);
247 
248  if (textfp[testmt-1]->seek(ulCompOffset, SEEK_SET)!=(long)ulCompOffset)
249  {
250  fprintf(stderr, "Error: could not seek to right place in compressed text\n");
251  return;
252  }
253  SWBuf pcCompText;
254  pcCompText.setSize(ulCompSize+5);
255 
256  if (textfp[testmt-1]->read(pcCompText.getRawData(), ulCompSize)<(long)ulCompSize) {
257  fprintf(stderr, "Error reading compressed text\n");
258  return;
259  }
260  pcCompText.setSize(ulCompSize);
261  rawZFilter(pcCompText, 0); // 0 = decipher
262 
263  unsigned long bufSize = ulCompSize;
264  compressor->setCompressedBuf(&bufSize, pcCompText.getRawData());
265 
266  if (cacheBuf) {
267  flushCache();
268  free(cacheBuf);
269  }
270 
271  unsigned long len = 0;
272  compressor->setUncompressedBuf(0, &len);
273  cacheBuf = (char *)calloc(len + 1, 1);
274  memcpy(cacheBuf, compressor->getUncompressedBuf(), len);
275  cacheBufSize = (int)strlen(cacheBuf); // TODO: can we just use len?
276  cacheTestament = testmt;
277  cacheBufIdx = ulBuffNum;
278  }
279 
280  inBuf = "";
281  if ((size > 0) && cacheBuf && ((unsigned)start < cacheBufSize)) {
282  inBuf.setFillByte(0);
283  inBuf.setSize(size+1);
284  strncpy(inBuf.getRawData(), &(cacheBuf[start]), size);
285  inBuf.setSize(strlen(inBuf.c_str()));
286  }
287 }
288 
289 
290 /******************************************************************************
291  * zVerse::settext - Sets text for current offset
292  *
293  * ENT: testmt - testament to find (0 - Bible/module introduction)
294  * idxoff - offset into .vss
295  * buf - buffer to store
296  * len - length of buffer (0 - null terminated)
297  */
298 
299 void zVerse::doSetText(char testmt, long idxoff, const char *buf, long len) {
300 
301  len = (len < 0) ? strlen(buf) : len;
302  if (!testmt)
303  testmt = ((idxfp[0]) ? 1:2);
304  if ((!dirtyCache) || (cacheBufIdx < 0)) {
305  cacheBufIdx = idxfp[testmt-1]->seek(0, SEEK_END) / 12;
306  cacheTestament = testmt;
307  if (cacheBuf)
308  free(cacheBuf);
309  cacheBuf = (char *)calloc(len + 1, 1);
310  }
311  else cacheBuf = (char *)((cacheBuf)?realloc(cacheBuf, strlen(cacheBuf)+(len + 1)):calloc((len + 1), 1));
312 
313  dirtyCache = true;
314 
315  SW_u32 start;
316  SW_u16 size;
317  SW_u32 outBufIdx = (SW_u32)cacheBufIdx;
318 
319  idxoff *= 10;
320  size = len;
321 
322  start = (SW_u32)strlen(cacheBuf);
323 
324  if (!size)
325  start = outBufIdx = 0;
326 
327  outBufIdx = archtosword32(outBufIdx);
328  start = archtosword32(start);
329  size = archtosword16(size);
330 
331  compfp[testmt-1]->seek(idxoff, SEEK_SET);
332  compfp[testmt-1]->write(&outBufIdx, 4);
333  compfp[testmt-1]->write(&start, 4);
334  compfp[testmt-1]->write(&size, 2);
335  strcat(cacheBuf, buf);
336 }
337 
338 
339 void zVerse::flushCache() const {
340  if (dirtyCache) {
341  SW_u32 idxoff;
342  SW_u32 start, outstart;
343  SW_u32 size, outsize;
344  SW_u32 zsize, outzsize;
345 
346  idxoff = (SW_u32)cacheBufIdx * 12;
347  if (cacheBuf) {
348  size = outsize = zsize = outzsize = (SW_u32)strlen(cacheBuf);
349  if (size) {
350  // if (compressor) {
351  // delete compressor;
352  // compressor = new LZSSCompress();
353  // }
355  unsigned long tmpSize;
356  compressor->getCompressedBuf(&tmpSize);
357  outzsize = zsize = (SW_u32)tmpSize;
358 
359  SWBuf buf;
360  buf.setSize(zsize + 5);
361  memcpy(buf.getRawData(), compressor->getCompressedBuf(&tmpSize), tmpSize);
362  outzsize = zsize = (SW_u32)tmpSize;
363  buf.setSize(zsize);
364  rawZFilter(buf, 1); // 1 = encipher
365 
366  start = outstart = (SW_u32)textfp[cacheTestament - 1]->seek(0, SEEK_END);
367 
368  outstart = archtosword32(start);
369  outsize = archtosword32(size);
370  outzsize = archtosword32(zsize);
371 
372  textfp[cacheTestament-1]->write(buf, zsize);
373 
374  idxfp[cacheTestament-1]->seek(idxoff, SEEK_SET);
375  idxfp[cacheTestament-1]->write(&outstart, 4);
376  idxfp[cacheTestament-1]->write(&outzsize, 4);
377  idxfp[cacheTestament-1]->write(&outsize, 4);
378  }
379  free(cacheBuf);
380  cacheBuf = 0;
381  }
382  dirtyCache = false;
383  }
384 }
385 
386 /******************************************************************************
387  * RawVerse::linkentry - links one entry to another
388  *
389  * ENT: testmt - testament to find (0 - Bible/module introduction)
390  * destidxoff - dest offset into .vss
391  * srcidxoff - source offset into .vss
392  */
393 
394 void zVerse::doLinkEntry(char testmt, long destidxoff, long srcidxoff) {
395  SW_s32 bufidx;
396  SW_s32 start;
397  SW_u16 size;
398 
399  destidxoff *= 10;
400  srcidxoff *= 10;
401 
402  if (!testmt)
403  testmt = ((idxfp[1]) ? 1:2);
404 
405  // get source
406  compfp[testmt-1]->seek(srcidxoff, SEEK_SET);
407  compfp[testmt-1]->read(&bufidx, 4);
408  compfp[testmt-1]->read(&start, 4);
409  compfp[testmt-1]->read(&size, 2);
410 
411  // write dest
412  compfp[testmt-1]->seek(destidxoff, SEEK_SET);
413  compfp[testmt-1]->write(&bufidx, 4);
414  compfp[testmt-1]->write(&start, 4);
415  compfp[testmt-1]->write(&size, 2);
416 }
417 
418 
419 /******************************************************************************
420  * RawVerse::CreateModule - Creates new module files
421  *
422  * ENT: path - directory to store module files
423  * RET: error status
424  */
425 
426 char zVerse::createModule(const char *ipath, int blockBound, const char *v11n)
427 {
428  char *path = 0;
429  char *buf = new char [ strlen (ipath) + 20 ];
430  char retVal = 0;
431  FileDesc *fd, *fd2;
432  SW_s32 offset = 0;
433  SW_s16 size = 0;
434  VerseKey vk;
435 
436  stdstr(&path, ipath);
437 
438  if ((path[strlen(path)-1] == '/') || (path[strlen(path)-1] == '\\'))
439  path[strlen(path)-1] = 0;
440 
441  sprintf(buf, "%s/ot.%czs", path, uniqueIndexID[blockBound]);
442  FileMgr::removeFile(buf);
444  if (fd->getFd() < 1) goto erroropen1;
446 
447  sprintf(buf, "%s/nt.%czs", path, uniqueIndexID[blockBound]);
448  FileMgr::removeFile(buf);
450  if (fd->getFd() < 1) goto erroropen1;
452 
453  sprintf(buf, "%s/ot.%czz", path, uniqueIndexID[blockBound]);
454  FileMgr::removeFile(buf);
456  if (fd->getFd() < 1) goto erroropen1;
458 
459  sprintf(buf, "%s/nt.%czz", path, uniqueIndexID[blockBound]);
460  FileMgr::removeFile(buf);
462  if (fd->getFd() < 1) goto erroropen1;
464 
465  sprintf(buf, "%s/ot.%czv", path, uniqueIndexID[blockBound]);
466  FileMgr::removeFile(buf);
468  if (fd->getFd() < 1) goto erroropen1;
469 
470  sprintf(buf, "%s/nt.%czv", path, uniqueIndexID[blockBound]);
471  FileMgr::removeFile(buf);
473  if (fd2->getFd() < 1) goto erroropen2;
474 
475  vk.setVersificationSystem(v11n);
476  vk.setIntros(true);
477 
478  offset = archtosword32(offset);
479  size = archtosword16(size);
480 
481  for (vk = TOP; !vk.popError(); vk++) {
482  if (vk.getTestament() < 2) {
483  if (fd->write(&offset, 4) != 4) goto writefailure; //compBufIdxOffset
484  if (fd->write(&offset, 4) != 4) goto writefailure;
485  if (fd->write(&size, 2) != 2) goto writefailure;
486  }
487  else {
488  if (fd2->write(&offset, 4) != 4) goto writefailure; //compBufIdxOffset
489  if (fd2->write(&offset, 4) != 4) goto writefailure;
490  if (fd2->write(&size, 2) != 2) goto writefailure;
491  }
492  }
493  fd2->write(&offset, 4); //compBufIdxOffset
494  fd2->write(&offset, 4);
495  fd2->write(&size, 2);
496 
497  goto cleanup;
498 
499 erroropen1:
500  retVal = -1;
501  goto cleanup1;
502 
503 erroropen2:
504  retVal = -1;
505  goto cleanup;
506 
507 writefailure:
508  retVal = -2;
509 
510 cleanup:
512 cleanup1:
514 
515  delete [] path;
516  delete [] buf;
517 
518  return retVal;
519 }
520 
521 
void doSetText(char testmt, long idxoff, const char *buf, long len=0)
Definition: zverse.cpp:299
SWCompress * compressor
Definition: zverse.h:38
void setFillByte(char ch)
Definition: swbuf.h:146
FileDesc * textfp[2]
Definition: zverse.h:44
#define TOP
Definition: swkey.h:68
#define SWORD_NAMESPACE_START
Definition: defs.h:39
long seek(long offset, int whence)
Definition: filemgr.cpp:143
FileDesc * open(const char *path, int mode, bool tryDowngrade)
Definition: filemgr.cpp:175
Definition: swbuf.h:47
static unsigned int RDONLY
Definition: filemgr.h:75
#define archtosword32(x)
Definition: sysdata.h:97
char cacheTestament
Definition: zverse.h:52
char * cacheBuf
Definition: zverse.h:50
bool dirtyCache
Definition: zverse.h:54
unsigned int cacheBufSize
Definition: zverse.h:51
virtual void setCompressedBuf(unsigned long *len, char *buf=0)
Definition: swcomprs.cpp:101
#define SEEK_END
Definition: zconf.h:246
static unsigned int RDWR
Definition: filemgr.h:76
signed int SW_s32
Definition: sysdata.h:40
long cacheBufIdx
Definition: zverse.h:53
virtual char * getCompressedBuf(unsigned long *len=0)
Definition: swcomprs.cpp:111
SWBuf v11n
Definition: osis2mod.cpp:107
int getFd()
Definition: filemgr.h:231
void zReadText(char testmt, long start, unsigned short size, unsigned long buffnum, SWBuf &buf) const
Definition: zverse.cpp:206
long write(const void *buf, long count)
Definition: filemgr.cpp:153
virtual char * getUncompressedBuf(unsigned long *len=0)
Definition: swcomprs.cpp:90
SWORD_NAMESPACE_START char * stdstr(char **ipstr, const char *istr, unsigned int memPadFactor=1)
Definition: utilstr.h:44
virtual void setUncompressedBuf(const char *buf=0, unsigned long *len=0)
Definition: swcomprs.cpp:75
void close(FileDesc *file)
Definition: filemgr.cpp:196
virtual void setIntros(bool val)
Definition: versekey.cpp:1663
char * getRawData()
Definition: swbuf.h:379
free(preg->fastmap)
const char * c_str() const
Definition: swbuf.h:158
virtual void setVersificationSystem(const char *name)
Definition: versekey.cpp:298
static int removeFile(const char *fName)
Definition: filemgr.cpp:517
zVerse(const char *ipath, int fileMode=-1, int blockType=CHAPTERBLOCKS, SWCompress *icomp=0)
Definition: zverse.cpp:63
void findOffset(char testmt, long idxoff, long *start, unsigned short *size, unsigned long *buffnum) const
Definition: zverse.cpp:150
char * realloc()
static char createModule(const char *path, int blockBound, const char *v11n="KJV")
Definition: zverse.cpp:426
virtual void rawZFilter(SWBuf &buf, char direction=0) const
Definition: zverse.h:70
#define swordtoarch32(x)
Definition: sysdata.h:94
unsigned short SW_u16
Definition: sysdata.h:38
virtual char popError()
Definition: swkey.cpp:147
#define SEEK_SET
Definition: zconf.h:244
int size
Definition: regex.c:5043
static unsigned int CREAT
Definition: filemgr.h:72
FileDesc * compfp[2]
Definition: zverse.h:45
#define swordtoarch16(x)
Definition: sysdata.h:93
unsigned int SW_u32
Definition: sysdata.h:41
static unsigned int IWRITE
Definition: filemgr.h:79
static unsigned int WRONLY
Definition: filemgr.h:77
long read(void *buf, long count)
Definition: filemgr.cpp:148
static unsigned int IREAD
Definition: filemgr.h:78
static const char uniqueIndexID[]
Definition: zverse.h:62
static int instance
Definition: zverse.h:41
#define SWORD_NAMESPACE_END
Definition: defs.h:40
SWBuf & setFormatted(const char *format,...)
Definition: swbuf.cpp:50
char * path
Definition: zverse.h:46
virtual ~zVerse()
Definition: zverse.cpp:112
void doLinkEntry(char testmt, long destidxoff, long srcidxoff)
Definition: zverse.cpp:394
#define archtosword16(x)
Definition: sysdata.h:96
FileDesc * idxfp[2]
Definition: zverse.h:43
void flushCache() const
Definition: zverse.cpp:339
void setSize(unsigned long len)
Definition: swbuf.h:255
virtual char getTestament() const
Definition: versekey.cpp:1498
signed short SW_s16
Definition: sysdata.h:37
static FileMgr * getSystemFileMgr()
Definition: filemgr.cpp:101