diff options
Diffstat (limited to 'src/modules/common/zverse4.cpp')
-rw-r--r-- | src/modules/common/zverse4.cpp | 516 |
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 |