summaryrefslogtreecommitdiff
path: root/src/modules/common/zverse4.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/common/zverse4.cpp')
-rw-r--r--src/modules/common/zverse4.cpp516
1 files changed, 516 insertions, 0 deletions
diff --git a/src/modules/common/zverse4.cpp b/src/modules/common/zverse4.cpp
new file mode 100644
index 0000000..ff10b2d
--- /dev/null
+++ b/src/modules/common/zverse4.cpp
@@ -0,0 +1,516 @@
+/******************************************************************************
+ *
+ * zverse4.cpp - code for class 'zVerse4'- a module that reads raw text
+ * files: ot and nt using indexs ??.bks ??.cps ??.vss
+ * and provides lookup and parsing functions based on
+ * class VerseKey for compressed modules
+ *
+ * $Id: zverse4.cpp 3439 2016-10-23 08:32:02Z scribe $
+ *
+ * Copyright 1996-2014 CrossWire Bible Society (http://www.crosswire.org)
+ * CrossWire Bible Society
+ * P. O. Box 2528
+ * Tempe, AZ 85280-2528
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include <utilstr.h>
+#include <versekey.h>
+#include <zverse4.h>
+#include <sysdata.h>
+#include <swbuf.h>
+#include <filemgr.h>
+#include <swcomprs.h>
+
+
+SWORD_NAMESPACE_START
+
+/******************************************************************************
+ * zVerse4 Statics
+ */
+
+int zVerse4::instance = 0;
+
+const char zVerse4::uniqueIndexID[] = {'X', 'r', 'v', 'c', 'b'};
+
+/******************************************************************************
+ * zVerse4 Constructor - Initializes data for instance of zVerse4
+ *
+ * ENT: ipath - path of the directory where data and index files are located.
+ * be sure to include the trailing separator (e.g. '/' or '\')
+ * (e.g. 'modules/texts/rawtext/webster/')
+ * fileMode - open mode for the files (FileMgr::RDONLY, etc.)
+ * blockType - verse, chapter, book, etc.
+ */
+
+zVerse4::zVerse4(const char *ipath, int fileMode, int blockType, SWCompress *icomp)
+{
+ // this line, instead of just defaulting, to keep FileMgr out of header
+ if (fileMode == -1) fileMode = FileMgr::RDONLY;
+
+ SWBuf buf;
+
+ path = 0;
+ cacheBufIdx = -1;
+ cacheTestament = 0;
+ cacheBuf = 0;
+ dirtyCache = false;
+ stdstr(&path, ipath);
+
+ if ((path[strlen(path)-1] == '/') || (path[strlen(path)-1] == '\\'))
+ path[strlen(path)-1] = 0;
+
+ compressor = (icomp) ? icomp : new SWCompress();
+
+ if (fileMode == -1) { // try read/write if possible
+ fileMode = FileMgr::RDWR;
+ }
+
+ buf.setFormatted("%s/ot.%czs", path, uniqueIndexID[blockType]);
+ idxfp[0] = FileMgr::getSystemFileMgr()->open(buf, fileMode, true);
+
+ buf.setFormatted("%s/nt.%czs", path, uniqueIndexID[blockType]);
+ idxfp[1] = FileMgr::getSystemFileMgr()->open(buf, fileMode, true);
+
+ buf.setFormatted("%s/ot.%czz", path, uniqueIndexID[blockType]);
+ textfp[0] = FileMgr::getSystemFileMgr()->open(buf, fileMode, true);
+
+ buf.setFormatted("%s/nt.%czz", path, uniqueIndexID[blockType]);
+ textfp[1] = FileMgr::getSystemFileMgr()->open(buf, fileMode, true);
+
+ buf.setFormatted("%s/ot.%czv", path, uniqueIndexID[blockType]);
+ compfp[0] = FileMgr::getSystemFileMgr()->open(buf, fileMode, true);
+
+ buf.setFormatted("%s/nt.%czv", path, uniqueIndexID[blockType]);
+ compfp[1] = FileMgr::getSystemFileMgr()->open(buf, fileMode, true);
+
+ instance++;
+}
+
+
+/******************************************************************************
+ * zVerse4 Destructor - Cleans up instance of zVerse4
+ */
+
+zVerse4::~zVerse4()
+{
+ int loop1;
+
+ if (cacheBuf) {
+ flushCache();
+ free(cacheBuf);
+ }
+
+ if (path)
+ delete [] path;
+
+ if (compressor)
+ delete compressor;
+
+ --instance;
+
+ for (loop1 = 0; loop1 < 2; loop1++) {
+ FileMgr::getSystemFileMgr()->close(idxfp[loop1]);
+ FileMgr::getSystemFileMgr()->close(textfp[loop1]);
+ FileMgr::getSystemFileMgr()->close(compfp[loop1]);
+ }
+}
+
+
+/******************************************************************************
+ * zVerse4::findoffset - Finds the offset of the key verse from the indexes
+ *
+ *
+ *
+ * ENT: testmt - testament to find (0 - Bible/module introduction)
+ * book - book to find (0 - testament introduction)
+ * chapter - chapter to find (0 - book introduction)
+ * verse - verse to find (0 - chapter introduction)
+ * start - address to store the starting offset
+ * size - address to store the size of the entry
+ */
+
+void zVerse4::findOffset(char testmt, long idxoff, long *start, unsigned long *size, unsigned long *buffnum) const
+{
+ __u32 ulBuffNum = 0; // buffer number
+ __u32 ulVerseStart = 0; // verse offset within buffer
+ __u32 usVerseSize = 0; // verse size
+ // set start to offset in
+ // set size to
+ // set
+ *start = *size = *buffnum = 0;
+ //fprintf(stderr, "Finding offset %ld\n", idxoff);
+ idxoff *= 12; // TODO: Is this the correct size? (throughout)
+ if (!testmt) {
+ testmt = ((idxfp[0]) ? 1:2);
+ }
+
+ // assert we have and valid file descriptor
+ if (compfp[testmt-1]->getFd() < 1)
+ return;
+
+ long newOffset = compfp[testmt-1]->seek(idxoff, SEEK_SET);
+ if (newOffset == idxoff) {
+ if (compfp[testmt-1]->read(&ulBuffNum, 4) != 4) {
+ fprintf(stderr, "Error reading ulBuffNum\n");
+ return;
+ }
+ }
+ else return;
+
+ if (compfp[testmt-1]->read(&ulVerseStart, 4) < 4)
+ {
+ fprintf(stderr, "Error reading ulVerseStart\n");
+ return;
+ }
+ if (compfp[testmt-1]->read(&usVerseSize, 4) < 4)
+ {
+ fprintf(stderr, "Error reading usVerseSize\n");
+ return;
+ }
+
+ *buffnum = swordtoarch32(ulBuffNum);
+ *start = swordtoarch32(ulVerseStart);
+ *size = swordtoarch32(usVerseSize);
+
+}
+
+
+/******************************************************************************
+ * zVerse4::zreadtext - gets text at a given offset
+ *
+ * ENT: testmt - testament file to search in (0 - Old; 1 - New)
+ * start - starting offset where the text is located in the file
+ * size - size of text entry + 1 (null)
+ * buf - buffer to store text
+ *
+ */
+
+void zVerse4::zReadText(char testmt, long start, unsigned long size, unsigned long ulBuffNum, SWBuf &inBuf) const {
+ __u32 ulCompOffset = 0; // compressed buffer start
+ __u32 ulCompSize = 0; // buffer size compressed
+ __u32 ulUnCompSize = 0; // buffer size uncompressed
+
+ if (!testmt) {
+ testmt = ((idxfp[0]) ? 1:2);
+ }
+
+ // assert we have and valid file descriptor
+ if (compfp[testmt-1]->getFd() < 1)
+ return;
+
+ if (size &&
+ !(((long) ulBuffNum == cacheBufIdx) && (testmt == cacheTestament) && (cacheBuf))) {
+ //fprintf(stderr, "Got buffer number{%ld} versestart{%ld} versesize{%d}\n", ulBuffNum, ulVerseStart, usVerseSize);
+
+ if (idxfp[testmt-1]->seek(ulBuffNum*12, SEEK_SET)!=(long) ulBuffNum*12)
+ {
+ fprintf(stderr, "Error seeking compressed file index\n");
+ return;
+ }
+ if (idxfp[testmt-1]->read(&ulCompOffset, 4)<4)
+ {
+ fprintf(stderr, "Error reading ulCompOffset\n");
+ return;
+ }
+ if (idxfp[testmt-1]->read(&ulCompSize, 4)<4)
+ {
+ fprintf(stderr, "Error reading ulCompSize\n");
+ return;
+ }
+ if (idxfp[testmt-1]->read(&ulUnCompSize, 4)<4)
+ {
+ fprintf(stderr, "Error reading ulUnCompSize\n");
+ return;
+ }
+
+ ulCompOffset = swordtoarch32(ulCompOffset);
+ ulCompSize = swordtoarch32(ulCompSize);
+ ulUnCompSize = swordtoarch32(ulUnCompSize);
+
+ if (textfp[testmt-1]->seek(ulCompOffset, SEEK_SET)!=(long)ulCompOffset)
+ {
+ fprintf(stderr, "Error: could not seek to right place in compressed text\n");
+ return;
+ }
+ SWBuf pcCompText;
+ pcCompText.setSize(ulCompSize+5);
+
+ if (textfp[testmt-1]->read(pcCompText.getRawData(), ulCompSize)<(long)ulCompSize) {
+ fprintf(stderr, "Error reading compressed text\n");
+ return;
+ }
+ pcCompText.setSize(ulCompSize);
+ rawZFilter(pcCompText, 0); // 0 = decipher
+
+ unsigned long bufSize = ulCompSize;
+ compressor->zBuf(&bufSize, pcCompText.getRawData());
+
+ if (cacheBuf) {
+ flushCache();
+ free(cacheBuf);
+ }
+
+ unsigned long len = 0;
+ compressor->Buf(0, &len);
+ cacheBuf = (char *)calloc(len + 1, 1);
+ memcpy(cacheBuf, compressor->Buf(), len);
+ cacheBufSize = (int)strlen(cacheBuf); // TODO: can we just use len?
+ cacheTestament = testmt;
+ cacheBufIdx = ulBuffNum;
+ }
+
+ inBuf = "";
+ if ((size > 0) && cacheBuf && ((unsigned)start < cacheBufSize)) {
+ inBuf.setFillByte(0);
+ inBuf.setSize(size+1);
+ strncpy(inBuf.getRawData(), &(cacheBuf[start]), size);
+ inBuf.setSize(strlen(inBuf.c_str()));
+ }
+}
+
+
+/******************************************************************************
+ * zVerse4::settext - Sets text for current offset
+ *
+ * ENT: testmt - testament to find (0 - Bible/module introduction)
+ * idxoff - offset into .vss
+ * buf - buffer to store
+ * len - length of buffer (0 - null terminated)
+ */
+
+void zVerse4::doSetText(char testmt, long idxoff, const char *buf, long len) {
+
+ len = (len < 0) ? strlen(buf) : len;
+ if (!testmt)
+ testmt = ((idxfp[0]) ? 1:2);
+ if ((!dirtyCache) || (cacheBufIdx < 0)) {
+ cacheBufIdx = idxfp[testmt-1]->seek(0, SEEK_END) / 12;
+ cacheTestament = testmt;
+ if (cacheBuf)
+ free(cacheBuf);
+ cacheBuf = (char *)calloc(len + 1, 1);
+ }
+ else cacheBuf = (char *)((cacheBuf)?realloc(cacheBuf, strlen(cacheBuf)+(len + 1)):calloc((len + 1), 1));
+
+ dirtyCache = true;
+
+ __u32 start;
+ __u32 size;
+ __u32 outBufIdx = (__u32)cacheBufIdx;
+
+ idxoff *= 12;
+ size = (__u32)len;
+
+ start = (__u32)strlen(cacheBuf);
+
+ if (!size)
+ start = outBufIdx = 0;
+
+ outBufIdx = archtosword32(outBufIdx);
+ start = archtosword32(start);
+ size = archtosword32(size);
+
+ compfp[testmt-1]->seek(idxoff, SEEK_SET);
+ compfp[testmt-1]->write(&outBufIdx, 4);
+ compfp[testmt-1]->write(&start, 4);
+ compfp[testmt-1]->write(&size, 4);
+ strcat(cacheBuf, buf);
+}
+
+
+void zVerse4::flushCache() const {
+ if (dirtyCache) {
+ __u32 idxoff;
+ __u32 start, outstart;
+ __u32 size, outsize;
+ __u32 zsize, outzsize;
+
+ idxoff = (__u32)cacheBufIdx * 12;
+ if (cacheBuf) {
+ size = outsize = zsize = outzsize = (__u32)strlen(cacheBuf);
+ if (size) {
+ compressor->Buf(cacheBuf);
+ unsigned long tmpSize;
+ compressor->zBuf(&tmpSize);
+ outzsize = zsize = (__u32)tmpSize;
+
+ SWBuf buf;
+ buf.setSize(zsize + 5);
+ memcpy(buf.getRawData(), compressor->zBuf(&tmpSize), tmpSize);
+ outzsize = zsize = (__u32)tmpSize;
+ buf.setSize(zsize);
+ rawZFilter(buf, 1); // 1 = encipher
+
+ start = outstart = (__u32)textfp[cacheTestament-1]->seek(0, SEEK_END);
+
+ outstart = archtosword32(start);
+ outsize = archtosword32(size);
+ outzsize = archtosword32(zsize);
+
+ textfp[cacheTestament-1]->write(buf, zsize);
+
+ idxfp[cacheTestament-1]->seek(idxoff, SEEK_SET);
+ idxfp[cacheTestament-1]->write(&outstart, 4);
+ idxfp[cacheTestament-1]->write(&outzsize, 4);
+ idxfp[cacheTestament-1]->write(&outsize, 4);
+ }
+ free(cacheBuf);
+ cacheBuf = 0;
+ }
+ dirtyCache = false;
+ }
+}
+
+/******************************************************************************
+ * RawVerse::linkentry - links one entry to another
+ *
+ * ENT: testmt - testament to find (0 - Bible/module introduction)
+ * destidxoff - dest offset into .vss
+ * srcidxoff - source offset into .vss
+ */
+
+void zVerse4::doLinkEntry(char testmt, long destidxoff, long srcidxoff) {
+ __s32 bufidx;
+ __s32 start;
+ __u32 size;
+
+ destidxoff *= 12;
+ srcidxoff *= 12;
+
+ if (!testmt)
+ testmt = ((idxfp[1]) ? 1:2);
+
+ // get source
+ compfp[testmt-1]->seek(srcidxoff, SEEK_SET);
+ compfp[testmt-1]->read(&bufidx, 4);
+ compfp[testmt-1]->read(&start, 4);
+ compfp[testmt-1]->read(&size, 4);
+
+ // write dest
+ compfp[testmt-1]->seek(destidxoff, SEEK_SET);
+ compfp[testmt-1]->write(&bufidx, 4);
+ compfp[testmt-1]->write(&start, 4);
+ compfp[testmt-1]->write(&size, 4);
+}
+
+
+/******************************************************************************
+ * RawVerse::CreateModule - Creates new module files
+ *
+ * ENT: path - directory to store module files
+ * RET: error status
+ */
+
+char zVerse4::createModule(const char *ipath, int blockBound, const char *v11n)
+{
+ char *path = 0;
+ char *buf = new char [ strlen (ipath) + 20 ];
+ char retVal = 0;
+ FileDesc *fd, *fd2;
+ __s32 offset = 0;
+ __s32 size = 0;
+ VerseKey vk;
+
+ stdstr(&path, ipath);
+
+ if ((path[strlen(path)-1] == '/') || (path[strlen(path)-1] == '\\'))
+ path[strlen(path)-1] = 0;
+
+ sprintf(buf, "%s/ot.%czs", path, uniqueIndexID[blockBound]);
+ FileMgr::removeFile(buf);
+ fd = FileMgr::getSystemFileMgr()->open(buf, FileMgr::CREAT|FileMgr::WRONLY, FileMgr::IREAD|FileMgr::IWRITE);
+ if (fd->getFd() < 1) goto erroropen1;
+ FileMgr::getSystemFileMgr()->close(fd);
+
+ sprintf(buf, "%s/nt.%czs", path, uniqueIndexID[blockBound]);
+ FileMgr::removeFile(buf);
+ fd = FileMgr::getSystemFileMgr()->open(buf, FileMgr::CREAT|FileMgr::WRONLY, FileMgr::IREAD|FileMgr::IWRITE);
+ if (fd->getFd() < 1) goto erroropen1;
+ FileMgr::getSystemFileMgr()->close(fd);
+
+ sprintf(buf, "%s/ot.%czz", path, uniqueIndexID[blockBound]);
+ FileMgr::removeFile(buf);
+ fd = FileMgr::getSystemFileMgr()->open(buf, FileMgr::CREAT|FileMgr::WRONLY, FileMgr::IREAD|FileMgr::IWRITE);
+ if (fd->getFd() < 1) goto erroropen1;
+ FileMgr::getSystemFileMgr()->close(fd);
+
+ sprintf(buf, "%s/nt.%czz", path, uniqueIndexID[blockBound]);
+ FileMgr::removeFile(buf);
+ fd = FileMgr::getSystemFileMgr()->open(buf, FileMgr::CREAT|FileMgr::WRONLY, FileMgr::IREAD|FileMgr::IWRITE);
+ if (fd->getFd() < 1) goto erroropen1;
+ FileMgr::getSystemFileMgr()->close(fd);
+
+ sprintf(buf, "%s/ot.%czv", path, uniqueIndexID[blockBound]);
+ FileMgr::removeFile(buf);
+ fd = FileMgr::getSystemFileMgr()->open(buf, FileMgr::CREAT|FileMgr::WRONLY, FileMgr::IREAD|FileMgr::IWRITE);
+ if (fd->getFd() < 1) goto erroropen1;
+
+ sprintf(buf, "%s/nt.%czv", path, uniqueIndexID[blockBound]);
+ FileMgr::removeFile(buf);
+ fd2 = FileMgr::getSystemFileMgr()->open(buf, FileMgr::CREAT|FileMgr::WRONLY, FileMgr::IREAD|FileMgr::IWRITE);
+ if (fd2->getFd() < 1) goto erroropen2;
+
+ vk.setVersificationSystem(v11n);
+ vk.setIntros(true);
+
+ offset = archtosword32(offset);
+ size = archtosword32(size);
+
+ for (vk = TOP; !vk.popError(); vk++) {
+ if (vk.getTestament() < 2) {
+ if (fd->write(&offset, 4) != 4) goto writefailure; //compBufIdxOffset
+ if (fd->write(&offset, 4) != 4) goto writefailure;
+ if (fd->write(&size, 4) != 4) goto writefailure;
+ }
+ else {
+ if (fd2->write(&offset, 4) != 4) goto writefailure; //compBufIdxOffset
+ if (fd2->write(&offset, 4) != 4) goto writefailure;
+ if (fd2->write(&size, 4) != 4) goto writefailure;
+ }
+ }
+ fd2->write(&offset, 4); //compBufIdxOffset
+ fd2->write(&offset, 4);
+ fd2->write(&size, 4);
+
+ goto cleanup;
+
+erroropen1:
+ retVal = -1;
+ goto cleanup1;
+
+erroropen2:
+ retVal = -1;
+ goto cleanup;
+
+writefailure:
+ retVal = -2;
+
+cleanup:
+ FileMgr::getSystemFileMgr()->close(fd2);
+cleanup1:
+ FileMgr::getSystemFileMgr()->close(fd);
+
+ delete [] path;
+ delete [] buf;
+
+ return retVal;
+}
+
+
+SWORD_NAMESPACE_END