1
/******************************************************************************
2
* rawstr.cpp - code for class 'RawStr'- a module that reads raw text
3
* files: ot and nt using indexs ??.bks ??.cps ??.vss
4
* and provides lookup and parsing functions based on
8
* Copyright 2009 CrossWire Bible Society (http://www.crosswire.org)
9
* CrossWire Bible Society
11
* Tempe, AZ 85280-2528
13
* This program is free software; you can redistribute it and/or modify it
14
* under the terms of the GNU General Public License as published by the
15
* Free Software Foundation version 2.
17
* This program is distributed in the hope that it will be useful, but
18
* WITHOUT ANY WARRANTY; without even the implied warranty of
19
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20
* General Public License for more details.
35
#include <stringmgr.h>
39
/******************************************************************************
43
int RawStr::instance = 0;
44
char RawStr::nl = '\n';
45
const int RawStr::IDXENTRYSIZE = 6;
49
/******************************************************************************
50
* RawStr Constructor - Initializes data for instance of RawStr
52
* ENT: ipath - path of the directory where data and index files are located.
53
* be sure to include the trailing separator (e.g. '/' or '\')
54
* (e.g. 'modules/texts/rawtext/webster/')
57
RawStr::RawStr(const char *ipath, int fileMode)
65
if (fileMode == -1) { // try read/write if possible
66
fileMode = FileMgr::RDWR;
69
buf.setFormatted("%s.idx", path);
70
idxfd = FileMgr::getSystemFileMgr()->open(buf, fileMode, true);
72
buf.setFormatted("%s.dat", path);
73
datfd = FileMgr::getSystemFileMgr()->open(buf, fileMode, true);
76
SWLog::getSystemLog()->logError("%d", errno);
83
/******************************************************************************
84
* RawStr Destructor - Cleans up instance of RawStr
94
FileMgr::getSystemFileMgr()->close(idxfd);
95
FileMgr::getSystemFileMgr()->close(datfd);
99
/******************************************************************************
100
* RawStr::getidxbufdat - Gets the index string at the given idx offset
101
* NOTE: buf is allocated and must be freed by
104
* ENT: ioffset - offset in dat file to lookup
105
* buf - address of pointer to allocate for storage of string
108
void RawStr::getIDXBufDat(long ioffset, char **buf) const
113
datfd->seek(ioffset, SEEK_SET);
114
for (size = 0; datfd->read(&ch, 1) == 1; size++) {
115
if ((ch == '\\') || (ch == 10) || (ch == 13))
118
*buf = (*buf) ? (char *)realloc(*buf, size*2 + 1) : (char *)malloc(size*2 + 1);
120
datfd->seek(ioffset, SEEK_SET);
121
datfd->read(*buf, size);
124
toupperstr_utf8(*buf, size*2);
127
*buf = (*buf) ? (char *)realloc(*buf, 1) : (char *)malloc(1);
133
/******************************************************************************
134
* RawStr::getidxbuf - Gets the index string at the given idx offset
135
* NOTE: buf is allocated and must be freed by
138
* ENT: ioffset - offset in idx file to lookup
139
* buf - address of pointer to allocate for storage of string
142
void RawStr::getIDXBuf(long ioffset, char **buf) const
147
idxfd->seek(ioffset, SEEK_SET);
148
idxfd->read(&offset, 4);
150
offset = swordtoarch32(offset);
152
getIDXBufDat(offset, buf);
157
/******************************************************************************
158
* RawStr::findoffset - Finds the offset of the key string from the indexes
160
* ENT: key - key string to lookup
161
* start - address to store the starting offset
162
* size - address to store the size of the entry
163
* away - number of entries before of after to jump
166
* RET: error status -1 general error; -2 new file
169
signed char RawStr::findOffset(const char *ikey, __u32 *start, __u16 *size, long away, __u32 *idxoff) const
171
char *trybuf, *maxbuf, *key = 0, quitflag = 0;
172
signed char retval = -1;
173
long headoff, tailoff, tryoff = 0, maxoff = 0;
175
bool awayFromSubstrCheck = false;
177
if (idxfd->getFd() >=0) {
178
tailoff = maxoff = idxfd->seek(0, SEEK_END) - 6;
179
retval = (tailoff >= 0) ? 0 : -2; // if NOT new file
180
if (*ikey && retval != -2) {
183
stdstr(&key, ikey, 3);
184
toupperstr_utf8(key, strlen(key)*3);
186
int keylen = strlen(key);
190
getIDXBuf(maxoff, &maxbuf);
192
while (headoff < tailoff) {
193
tryoff = (lastoff == -1) ? headoff + ((((tailoff / 6) - (headoff / 6))) / 2) * 6 : lastoff;
195
getIDXBuf(tryoff, &trybuf);
197
if (!*trybuf && tryoff) { // In case of extra entry at end of idx (not first entry)
198
tryoff += (tryoff > (maxoff / 2))?-6:6;
203
diff = strcmp(key, trybuf);
208
if (!strncmp(trybuf, key, keylen)) substr = true;
211
tailoff = (tryoff == headoff) ? headoff : tryoff;
212
else headoff = tryoff;
214
if (tailoff == headoff + 6) {
220
// didn't find exact match
221
if (headoff >= tailoff) {
223
if (!substr && ((tryoff != maxoff)||(strncmp(key, maxbuf, keylen)<0))) {
224
awayFromSubstrCheck = true;
225
away--; // if our entry doesn't startwith our key, prefer the previous entry over the next
236
idxfd->seek(tryoff, SEEK_SET);
240
*start = *size = tmpStart = tmpSize = 0;
241
idxfd->read(&tmpStart, 4);
242
idxfd->read(&tmpSize, 2);
246
*start = swordtoarch32(tmpStart);
247
*size = swordtoarch16(tmpSize);
250
unsigned long laststart = *start;
251
unsigned short lastsize = *size;
252
long lasttry = tryoff;
253
tryoff += (away > 0) ? 6 : -6;
256
if (((tryoff + (away*6)) < -6) || (tryoff + (away*6) > (maxoff+6)))
258
else if (idxfd->seek(tryoff, SEEK_SET) < 0)
261
if(!awayFromSubstrCheck)
270
idxfd->read(&tmpStart, 4);
271
idxfd->read(&tmpSize, 2);
275
*start = swordtoarch32(tmpStart);
276
*size = swordtoarch16(tmpSize);
278
if (((laststart != *start) || (lastsize != *size)) && (*size))
279
away += (away < 0) ? 1 : -1;
295
/******************************************************************************
296
* RawStr::readtext - gets text at a given offset
299
* start - starting offset where the text is located in the file
300
* size - size of text entry
301
* buf - buffer to store text
305
void RawStr::readText(__u32 istart, __u16 *isize, char **idxbuf, SWBuf &buf)
308
char *idxbuflocal = 0;
309
getIDXBufDat(istart, &idxbuflocal);
310
__u32 start = istart;
318
buf.setSize(++(*isize));
320
*idxbuf = new char [ (*isize) ];
322
datfd->seek(start, SEEK_SET);
323
datfd->read(buf.getRawData(), (int)((*isize) - 1));
325
for (ch = 0; buf[ch]; ch++) { // skip over index string
331
buf = SWBuf(buf.c_str()+ch);
333
if (!strncmp(buf.c_str(), "@LINK", 5)) {
334
for (ch = 0; buf[ch]; ch++) { // null before nl
340
findOffset(buf.c_str() + 6, &start, isize);
344
while (true); // while we're resolving links
347
int localsize = strlen(idxbuflocal);
348
localsize = (localsize < (*isize - 1)) ? localsize : (*isize - 1);
349
strncpy(*idxbuf, idxbuflocal, localsize);
350
(*idxbuf)[localsize] = 0;
356
/******************************************************************************
357
* RawLD::settext - Sets text for current offset
359
* ENT: key - key for this entry
360
* buf - buffer to store
361
* len - length of buffer (0 - null terminated)
364
void RawStr::doSetText(const char *ikey, const char *buf, long len)
367
__u32 start, outstart;
373
static const char nl[] = {13, 10};
381
char errorStatus = findOffset(ikey, &start, &size, 0, &idxoff);
382
stdstr(&key, ikey, 2);
383
toupperstr_utf8(key, strlen(key)*2);
385
len = (len < 0) ? strlen(buf) : len;
387
getIDXBufDat(start, &dbKey);
389
if (strcmp(key, dbKey) < 0) {
391
else if (strcmp(key, dbKey) > 0) {
392
if (errorStatus != (char)-2) // not a new file
396
else if ((!strcmp(key, dbKey)) && (len>0 /*we're not deleting*/)) { // got absolute entry
398
tmpbuf = new char [ size + 2 ];
399
memset(tmpbuf, 0, size + 2);
400
datfd->seek(start, SEEK_SET);
401
datfd->read(tmpbuf, (int)(size - 1));
403
for (ch = tmpbuf; *ch; ch++) { // skip over index string
409
memmove(tmpbuf, ch, size - (unsigned short)(ch-tmpbuf));
412
if (!strncmp(tmpbuf, "@LINK", 5) && (len)) {
413
for (ch = tmpbuf; *ch; ch++) { // null before nl
419
findOffset(tmpbuf + 6, &start, &size, 0, &idxoff);
423
while (true); // while we're resolving links
426
endoff = idxfd->seek(0, SEEK_END);
428
shiftSize = endoff - idxoff;
431
idxBytes = new char [ shiftSize ];
432
idxfd->seek(idxoff, SEEK_SET);
433
idxfd->read(idxBytes, shiftSize);
436
outbuf = new char [ len + strlen(key) + 5 ];
437
sprintf(outbuf, "%s%c%c", key, 13, 10);
438
size = strlen(outbuf);
439
memcpy(outbuf + size, buf, len);
440
size = outsize = size + (len);
442
start = outstart = datfd->seek(0, SEEK_END);
444
outstart = archtosword32(start);
445
outsize = archtosword16(size);
447
idxfd->seek(idxoff, SEEK_SET);
449
datfd->seek(start, SEEK_SET);
450
datfd->write(outbuf, (int)size);
452
// add a new line to make data file easier to read in an editor
453
datfd->write(&nl, 2);
455
idxfd->write(&outstart, 4);
456
idxfd->write(&outsize, 2);
458
idxfd->write(idxBytes, shiftSize);
462
else { // delete entry
464
idxfd->write(idxBytes+6, shiftSize-6);
465
idxfd->seek(-1, SEEK_CUR); // last valid byte
466
FileMgr::getSystemFileMgr()->trunc(idxfd); // truncate index
477
/******************************************************************************
478
* RawLD::linkentry - links one entry to another
480
* ENT: testmt - testament to find (0 - Bible/module introduction)
481
* destidxoff - dest offset into .vss
482
* srcidxoff - source offset into .vss
485
void RawStr::doLinkEntry(const char *destkey, const char *srckey) {
486
char *text = new char [ strlen(destkey) + 7 ];
487
sprintf(text, "@LINK %s", destkey);
488
doSetText(srckey, text);
492
/******************************************************************************
493
* RawLD::CreateModule - Creates new module files
495
* ENT: path - directory to store module files
499
signed char RawStr::createModule(const char *ipath)
502
char *buf = new char [ strlen (ipath) + 20 ];
505
stdstr(&path, ipath);
507
if ((path[strlen(path)-1] == '/') || (path[strlen(path)-1] == '\\'))
508
path[strlen(path)-1] = 0;
510
sprintf(buf, "%s.dat", path);
511
FileMgr::removeFile(buf);
512
fd = FileMgr::getSystemFileMgr()->open(buf, FileMgr::CREAT|FileMgr::WRONLY, FileMgr::IREAD|FileMgr::IWRITE);
514
FileMgr::getSystemFileMgr()->close(fd);
516
sprintf(buf, "%s.idx", path);
517
FileMgr::removeFile(buf);
518
fd2 = FileMgr::getSystemFileMgr()->open(buf, FileMgr::CREAT|FileMgr::WRONLY, FileMgr::IREAD|FileMgr::IWRITE);
520
FileMgr::getSystemFileMgr()->close(fd2);