/****************************************************************************** * zstr.cpp - code for class 'zStr'- a module that reads compressed text * files and provides lookup and parsing functions based on * class StrKey */ #include #include #include #ifndef __GNUC__ #include #else #include #endif #include #include #include #include #include #include #include SWORD_NAMESPACE_START /****************************************************************************** * zStr Statics */ int zStr::instance = 0; const int zStr::IDXENTRYSIZE = 8; const int zStr::ZDXENTRYSIZE = 8; /****************************************************************************** * zStr Constructor - Initializes data for instance of zStr * * ENT: ipath - path of the directory where data and index files are located. */ zStr::zStr(const char *ipath, int fileMode, long blockCount, SWCompress *icomp) { char buf[127]; nl = '\n'; lastoff = -1; path = 0; stdstr(&path, ipath); compressor = (icomp) ? icomp : new SWCompress(); this->blockCount = blockCount; #ifndef O_BINARY // O_BINARY is needed in Borland C++ 4.53 #define O_BINARY 0 // If it hasn't been defined than we probably #endif // don't need it. if (fileMode == -1) { // try read/write if possible fileMode = O_RDWR; } sprintf(buf, "%s.idx", path); idxfd = FileMgr::systemFileMgr.open(buf, fileMode|O_BINARY, true); sprintf(buf, "%s.dat", path); datfd = FileMgr::systemFileMgr.open(buf, fileMode|O_BINARY, true); sprintf(buf, "%s.zdx", path); zdxfd = FileMgr::systemFileMgr.open(buf, fileMode|O_BINARY, true); sprintf(buf, "%s.zdt", path); zdtfd = FileMgr::systemFileMgr.open(buf, fileMode|O_BINARY, true); if (datfd <= 0) { sprintf(buf, "Error: %d", errno); perror(buf); } cacheBlock = 0; cacheBlockIndex = -1; cacheDirty = false; instance++; } /****************************************************************************** * zStr Destructor - Cleans up instance of zStr */ zStr::~zStr() { flushCache(); if (path) delete [] path; --instance; FileMgr::systemFileMgr.close(idxfd); FileMgr::systemFileMgr.close(datfd); FileMgr::systemFileMgr.close(zdxfd); FileMgr::systemFileMgr.close(zdtfd); if (compressor) delete compressor; } /****************************************************************************** * zStr::getidxbufdat - Gets the index string at the given dat offset * NOTE: buf is calloc'd, or if not null, realloc'd and must * be free'd by calling function * * ENT: ioffset - offset in dat file to lookup * buf - address of pointer to allocate for storage of string */ void zStr::getKeyFromDatOffset(long ioffset, char **buf) { int size; char ch; if (datfd > 0) { lseek(datfd->getFd(), ioffset, SEEK_SET); for (size = 0; read(datfd->getFd(), &ch, 1) == 1; size++) { if ((ch == '\\') || (ch == 10) || (ch == 13)) break; } *buf = (*buf) ? (char *)realloc(*buf, size*2 + 1) : (char *)malloc(size*2 + 1); if (size) { lseek(datfd->getFd(), ioffset, SEEK_SET); read(datfd->getFd(), *buf, size); } (*buf)[size] = 0; toupperstr_utf8(*buf); } else { *buf = (*buf) ? (char *)realloc(*buf, 1) : (char *)malloc(1); **buf = 0; } } /****************************************************************************** * zStr::getidxbuf - Gets the index string at the given idx offset * NOTE: buf is calloc'd, or if not null, realloc'd * and must be freed by calling function * * ENT: ioffset - offset in idx file to lookup * buf - address of pointer to allocate for storage of string */ void zStr::getKeyFromIdxOffset(long ioffset, char **buf) { __u32 offset; if (idxfd > 0) { lseek(idxfd->getFd(), ioffset, SEEK_SET); read(idxfd->getFd(), &offset, sizeof(__u32)); offset = swordtoarch32(offset); getKeyFromDatOffset(offset, buf); } } /****************************************************************************** * zStr::findoffset - Finds the offset of the key string from the indexes * * ENT: key - key string to lookup * offset - address to store the starting offset * size - address to store the size of the entry * away - number of entries before of after to jump * (default = 0) * * RET: error status */ signed char zStr::findKeyIndex(const char *ikey, long *idxoff, long away) { char *trybuf = 0, *key = 0, quitflag = 0; signed char retval = 0; __s32 headoff, tailoff, tryoff = 0, maxoff = 0; __u32 start, size; if (idxfd->getFd() >= 0) { tailoff = maxoff = lseek(idxfd->getFd(), 0, SEEK_END) - IDXENTRYSIZE; if (*ikey) { headoff = 0; stdstr(&key, ikey); toupperstr_utf8(key); while (headoff < tailoff) { tryoff = (lastoff == -1) ? headoff + (((((tailoff / IDXENTRYSIZE) - (headoff / IDXENTRYSIZE))) / 2) * IDXENTRYSIZE) : lastoff; lastoff = -1; getKeyFromIdxOffset(tryoff, &trybuf); if (!*trybuf && tryoff) { // In case of extra entry at end of idx (not first entry) tryoff += (tryoff > (maxoff / 2))?-IDXENTRYSIZE:IDXENTRYSIZE; retval = -1; break; } int diff = strcmp(key, trybuf); if (!diff) break; if (diff < 0) tailoff = (tryoff == headoff) ? headoff : tryoff; else headoff = tryoff; if (tailoff == headoff + IDXENTRYSIZE) { if (quitflag++) headoff = tailoff; } } if (headoff >= tailoff) tryoff = headoff; if (trybuf) free(trybuf); delete [] key; } else { tryoff = 0; } lseek(idxfd->getFd(), tryoff, SEEK_SET); start = size = 0; retval = (read(idxfd->getFd(), &start, sizeof(__u32))==sizeof(__u32)) ? retval : -1; retval = (read(idxfd->getFd(), &size, sizeof(__u32))==sizeof(__u32)) ? retval : -1; start = swordtoarch32(start); size = swordtoarch32(size); if (idxoff) *idxoff = tryoff; while (away) { __u32 laststart = start; __u32 lastsize = size; __s32 lasttry = tryoff; tryoff += (away > 0) ? IDXENTRYSIZE : -IDXENTRYSIZE; bool bad = false; if (((long)(tryoff + (away*IDXENTRYSIZE)) < -IDXENTRYSIZE) || (tryoff + (away*IDXENTRYSIZE) > (maxoff+IDXENTRYSIZE))) bad = true; else if (lseek(idxfd->getFd(), tryoff, SEEK_SET) < 0) bad = true; if (bad) { retval = -1; start = laststart; size = lastsize; tryoff = lasttry; if (idxoff) *idxoff = tryoff; break; } read(idxfd->getFd(), &start, sizeof(__u32)); read(idxfd->getFd(), &size, sizeof(__u32)); start = swordtoarch32(start); size = swordtoarch32(size); if (idxoff) *idxoff = tryoff; if (((laststart != start) || (lastsize != size)) && (start >= 0) && (size)) away += (away < 0) ? 1 : -1; } lastoff = tryoff; } else { if (idxoff) *idxoff = 0; retval = -1; } return retval; } /****************************************************************************** * zStr::preptext - Prepares the text before returning it to external * objects * * ENT: buf - buffer where text is stored and where to store the prep'd * text. */ void zStr::prepText(char *buf) { char *to, *from, space = 0, cr = 0, realdata = 0, nlcnt = 0; for (to = from = buf; *from; from++) { switch (*from) { case 10: if (!realdata) continue; space = (cr) ? 0 : 1; cr = 0; nlcnt++; if (nlcnt > 1) { // *to++ = nl; *to++ = nl; // nlcnt = 0; } continue; case 13: if (!realdata) continue; *to++ = nl; space = 0; cr = 1; continue; } realdata = 1; nlcnt = 0; if (space) { space = 0; if (*from != ' ') { *to++ = ' '; from--; continue; } } *to++ = *from; } *to = 0; while (to > (buf+1)) { // remove trailing excess to--; if ((*to == 10) || (*to == ' ')) *to = 0; else break; } } /****************************************************************************** * zStr::getText - gets text at a given offset * * ENT: * offset - idxoffset where the key is located. * buf - buffer to store text * idxbuf - buffer to store index key * NOTE: buffer will be alloc'd / realloc'd and * should be free'd by the client * */ void zStr::getText(long offset, char **idxbuf, char **buf) { char *ch; char *idxbuflocal = 0; getKeyFromIdxOffset(offset, &idxbuflocal); __u32 start; __u32 size; do { lseek(idxfd->getFd(), offset, SEEK_SET); read(idxfd->getFd(), &start, sizeof(__u32)); read(idxfd->getFd(), &size, sizeof(__u32)); start = swordtoarch32(start); size = swordtoarch32(size); *buf = (*buf) ? (char *)realloc(*buf, size*2 + 1) : (char *)malloc(size*2 + 1); *idxbuf = (*idxbuf) ? (char *)realloc(*idxbuf, size*2 + 1) : (char *)malloc(size*2 + 1); memset(*buf, 0, size + 1); memset(*idxbuf, 0, size + 1); lseek(datfd->getFd(), start, SEEK_SET); read(datfd->getFd(), *buf, (int)(size)); for (ch = *buf; *ch; ch++) { // skip over index string if (*ch == 10) { ch++; break; } } memmove(*buf, ch, size - (unsigned long)(ch-*buf)); // resolve link if (!strncmp(*buf, "@LINK", 5)) { for (ch = *buf; *ch; ch++) { // null before nl if (*ch == 10) { *ch = 0; break; } } findKeyIndex(*buf + 6, &offset); } else break; } while (true); // while we're resolving links if (idxbuflocal) { __u32 localsize = strlen(idxbuflocal); localsize = (localsize < (size - 1)) ? localsize : (size - 1); strncpy(*idxbuf, idxbuflocal, localsize); (*idxbuf)[localsize] = 0; free(idxbuflocal); } __u32 block = 0; __u32 entry = 0; memmove(&block, *buf, sizeof(__u32)); memmove(&entry, *buf + sizeof(__u32), sizeof(__u32)); block = swordtoarch32(block); entry = swordtoarch32(entry); getCompressedText(block, entry, buf); } /****************************************************************************** * zStr::getCompressedText - Get text entry from a compressed index / zdata * file. */ void zStr::getCompressedText(long block, long entry, char **buf) { __u32 size = 0; if (cacheBlockIndex != block) { __u32 start = 0; lseek(zdxfd->getFd(), block * ZDXENTRYSIZE, SEEK_SET); read(zdxfd->getFd(), &start, sizeof(__u32)); read(zdxfd->getFd(), &size, sizeof(__u32)); start = swordtoarch32(start); size = swordtoarch32(size); *buf = (*buf) ? (char *)realloc(*buf, size*2 + 1) : (char *)malloc(size*2 + 1); lseek(zdtfd->getFd(), start, SEEK_SET); read(zdtfd->getFd(), *buf, size); flushCache(); unsigned long len = size; rawZFilter(*buf, len, 0); // 0 = decipher compressor->zBuf(&len, *buf); char * rawBuf = compressor->Buf(0, &len); cacheBlock = new EntriesBlock(rawBuf, len); cacheBlockIndex = block; } size = cacheBlock->getEntrySize(entry); *buf = (*buf) ? (char *)realloc(*buf, size*2 + 1) : (char *)malloc(size*2 + 1); strcpy(*buf, cacheBlock->getEntry(entry)); } /****************************************************************************** * zLD::settext - Sets text for current offset * * ENT: key - key for this entry * buf - buffer to store * len - length of buffer (0 - null terminated) */ void zStr::setText(const char *ikey, const char *buf, long len) { __u32 start, outstart; __u32 size, outsize; __s32 endoff; long idxoff = 0; __s32 shiftSize; static const char nl[] = {13, 10}; char *tmpbuf = 0; char *key = 0; char *dbKey = 0; char *idxBytes = 0; char *outbuf = 0; char *ch = 0; len = (len < 0) ? strlen(buf) : len; stdstr(&key, ikey); toupperstr_utf8(key); char notFound = findKeyIndex(ikey, &idxoff, 0); if (!notFound) { getKeyFromIdxOffset(idxoff, &dbKey); int diff = strcmp(key, dbKey); if (diff < 0) { } else if (diff > 0) { idxoff += IDXENTRYSIZE; } else if ((!diff) && (len > 0 /*we're not deleting*/)) { // got absolute entry do { lseek(idxfd->getFd(), idxoff, SEEK_SET); read(idxfd->getFd(), &start, sizeof(__u32)); read(idxfd->getFd(), &size, sizeof(__u32)); start = swordtoarch32(start); size = swordtoarch32(size); tmpbuf = new char [ size + 2 ]; memset(tmpbuf, 0, size + 2); lseek(datfd->getFd(), start, SEEK_SET); read(datfd->getFd(), tmpbuf, size); for (ch = tmpbuf; *ch; ch++) { // skip over index string if (*ch == 10) { ch++; break; } } memmove(tmpbuf, ch, size - (unsigned long)(ch-tmpbuf)); // resolve link if (!strncmp(tmpbuf, "@LINK", 5) && (len)) { for (ch = tmpbuf; *ch; ch++) { // null before nl if (*ch == 10) { *ch = 0; break; } } findKeyIndex(tmpbuf + IDXENTRYSIZE, &idxoff); delete [] tmpbuf; } else break; } while (true); // while we're resolving links } } endoff = lseek(idxfd->getFd(), 0, SEEK_END); shiftSize = endoff - idxoff; if (shiftSize > 0) { idxBytes = new char [ shiftSize ]; lseek(idxfd->getFd(), idxoff, SEEK_SET); read(idxfd->getFd(), idxBytes, shiftSize); } outbuf = new char [ len + strlen(key) + 5 ]; sprintf(outbuf, "%s%c%c", key, 13, 10); size = strlen(outbuf); if (len > 0) { // NOT a link if (!cacheBlock) { flushCache(); cacheBlock = new EntriesBlock(); cacheBlockIndex = (lseek(zdxfd->getFd(), 0, SEEK_END) / ZDXENTRYSIZE); } else if (cacheBlock->getCount() >= blockCount) { flushCache(); cacheBlock = new EntriesBlock(); cacheBlockIndex = (lseek(zdxfd->getFd(), 0, SEEK_END) / ZDXENTRYSIZE); } __u32 entry = cacheBlock->addEntry(buf); cacheDirty = true; outstart = archtosword32(cacheBlockIndex); outsize = archtosword32(entry); memcpy (outbuf + size, &outstart, sizeof(__u32)); memcpy (outbuf + size + sizeof(__u32), &outsize, sizeof(__u32)); size += (sizeof(__u32) * 2); } else { // link memcpy(outbuf + size, buf, len); size += len; } start = lseek(datfd->getFd(), 0, SEEK_END); outstart = archtosword32(start); outsize = archtosword32(size); lseek(idxfd->getFd(), idxoff, SEEK_SET); if (len > 0) { lseek(datfd->getFd(), start, SEEK_SET); write(datfd->getFd(), outbuf, size); // add a new line to make data file easier to read in an editor write(datfd->getFd(), &nl, 2); write(idxfd->getFd(), &outstart, sizeof(__u32)); write(idxfd->getFd(), &outsize, sizeof(__u32)); if (idxBytes) { write(idxfd->getFd(), idxBytes, shiftSize); } } else { // delete entry if (idxBytes) { write(idxfd->getFd(), idxBytes+IDXENTRYSIZE, shiftSize-IDXENTRYSIZE); lseek(idxfd->getFd(), -1, SEEK_CUR); // last valid byte FileMgr::systemFileMgr.trunc(idxfd); // truncate index } } if (idxBytes) delete [] idxBytes; delete [] key; delete [] outbuf; free(dbKey); } /****************************************************************************** * zLD::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 zStr::linkEntry(const char *destkey, const char *srckey) { char *text = new char [ strlen(destkey) + 7 ]; sprintf(text, "@LINK %s", destkey); setText(srckey, text); delete [] text; } void zStr::flushCache() { if (cacheBlock) { if (cacheDirty) { __u32 start = 0; unsigned long size = 0; __u32 outstart = 0, outsize = 0; const char *rawBuf = cacheBlock->getRawData(&size); compressor->Buf(rawBuf, &size); compressor->zBuf(&size); char *buf = new char [ size * 2 ]; memcpy(buf, compressor->zBuf(&size), size); // 1 = encipher rawZFilter(buf, size, 1); // 1 = encipher long zdxSize = lseek(zdxfd->getFd(), 0, SEEK_END); long zdtSize = lseek(zdtfd->getFd(), 0, SEEK_END); if ((cacheBlockIndex * ZDXENTRYSIZE) > (zdxSize - ZDXENTRYSIZE)) { // New Block start = zdtSize; } else { lseek(zdxfd->getFd(), cacheBlockIndex * ZDXENTRYSIZE, SEEK_SET); read(zdxfd->getFd(), &start, sizeof(__u32)); read(zdxfd->getFd(), &outsize, sizeof(__u32)); start = swordtoarch32(start); outsize = swordtoarch32(outsize); if (start + outsize >= zdtSize) { // last entry, just overwrite // start is already set } else if (size < outsize) { // middle entry, but smaller, that's fine and let's preserve bigger size size = outsize; } else { // middle and bigger-- we have serious problems, for now let's put it at the end = lots of wasted space start = zdtSize; } } outstart = archtosword32(start); outsize = archtosword32((__u32)size); lseek(zdxfd->getFd(), cacheBlockIndex * ZDXENTRYSIZE, SEEK_SET); lseek(zdtfd->getFd(), start, SEEK_SET); write(zdtfd->getFd(), buf, size); // add a new line to make data file easier to read in an editor write(zdtfd->getFd(), &nl, 2); write(zdxfd->getFd(), &outstart, sizeof(__u32)); write(zdxfd->getFd(), &outsize, sizeof(__u32)); delete cacheBlock; } } cacheBlockIndex = -1; cacheBlock = 0; cacheDirty = false; } /****************************************************************************** * zLD::CreateModule - Creates new module files * * ENT: path - directory to store module files * RET: error status */ signed char zStr::createModule(const char *ipath) { char *path = 0; char *buf = new char [ strlen (ipath) + 20 ]; FileDesc *fd, *fd2; stdstr(&path, ipath); if ((path[strlen(path)-1] == '/') || (path[strlen(path)-1] == '\\')) path[strlen(path)-1] = 0; sprintf(buf, "%s.dat", path); unlink(buf); fd = FileMgr::systemFileMgr.open(buf, O_CREAT|O_WRONLY|O_BINARY, S_IREAD|S_IWRITE); fd->getFd(); FileMgr::systemFileMgr.close(fd); sprintf(buf, "%s.idx", path); unlink(buf); fd2 = FileMgr::systemFileMgr.open(buf, O_CREAT|O_WRONLY|O_BINARY, S_IREAD|S_IWRITE); fd2->getFd(); FileMgr::systemFileMgr.close(fd2); sprintf(buf, "%s.zdt", path); unlink(buf); fd2 = FileMgr::systemFileMgr.open(buf, O_CREAT|O_WRONLY|O_BINARY, S_IREAD|S_IWRITE); fd2->getFd(); FileMgr::systemFileMgr.close(fd2); sprintf(buf, "%s.zdx", path); unlink(buf); fd2 = FileMgr::systemFileMgr.open(buf, O_CREAT|O_WRONLY|O_BINARY, S_IREAD|S_IWRITE); fd2->getFd(); FileMgr::systemFileMgr.close(fd2); delete [] path; return 0; } SWORD_NAMESPACE_END