summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRoberto C. Sanchez <roberto@connexer.com>2014-03-29 10:53:33 -0400
committerRoberto C. Sanchez <roberto@connexer.com>2014-03-29 10:53:33 -0400
commit8d3fc864d094eeadc721f8e93436b37a5fab173e (patch)
tree05e201c67dca55b4ccdf90ad479a25d95e3b1e63 /src
Imported Upstream version 1.5.3
Diffstat (limited to 'src')
-rw-r--r--src/Makefile5
-rw-r--r--src/frontend/Makefile5
-rw-r--r--src/frontend/Makefile.am6
-rw-r--r--src/frontend/X11/Makefile5
-rw-r--r--src/frontend/framework/Makefile4
-rw-r--r--src/frontend/framework/femain.cpp12
-rw-r--r--src/frontend/im/Makefile5
-rw-r--r--src/frontend/im/hebrewmcim.cpp653
-rw-r--r--src/frontend/im/nullim.cpp11
-rw-r--r--src/frontend/im/swinputmeth.cpp26
-rw-r--r--src/frontend/swdisp.cpp25
-rw-r--r--src/frontend/swlog.cpp95
-rw-r--r--src/frontend/windoze/Makefile5
-rw-r--r--src/keys/Makefile4
-rw-r--r--src/keys/Makefile.am9
-rw-r--r--src/keys/genarray.c33
-rw-r--r--src/keys/listkey.cpp256
-rw-r--r--src/keys/nt.bksbin0 -> 112 bytes
-rw-r--r--src/keys/nt.cpsbin0 -> 1152 bytes
-rw-r--r--src/keys/ot.bksbin0 -> 160 bytes
-rw-r--r--src/keys/ot.cpsbin0 -> 3876 bytes
-rw-r--r--src/keys/strkey.cpp41
-rw-r--r--src/keys/swkey.cpp195
-rw-r--r--src/keys/treekey.cpp27
-rw-r--r--src/keys/treekeyidx.cpp581
-rw-r--r--src/keys/versekey.cpp1405
-rw-r--r--src/mgr/Makefile4
-rw-r--r--src/mgr/Makefile.am19
-rw-r--r--src/mgr/encfiltmgr.cpp148
-rw-r--r--src/mgr/filemgr.cpp264
-rw-r--r--src/mgr/localemgr.cpp181
-rw-r--r--src/mgr/markupfiltmgr.cpp234
-rw-r--r--src/mgr/swcacher.cpp43
-rw-r--r--src/mgr/swconfig.cpp150
-rw-r--r--src/mgr/swfiltermgr.cpp90
-rw-r--r--src/mgr/swlocale.cpp141
-rw-r--r--src/mgr/swmgr.cpp1054
-rw-r--r--src/modules/Makefile5
-rw-r--r--src/modules/Makefile.am10
-rw-r--r--src/modules/comments/Makefile5
-rw-r--r--src/modules/comments/Makefile.am8
-rw-r--r--src/modules/comments/hrefcom/Makefile5
-rw-r--r--src/modules/comments/hrefcom/Makefile.am4
-rw-r--r--src/modules/comments/hrefcom/hrefcom.cpp97
-rw-r--r--src/modules/comments/hrefcom/jfbgen.cpp242
-rw-r--r--src/modules/comments/rawcom/Makefile5
-rw-r--r--src/modules/comments/rawcom/Makefile.am4
-rw-r--r--src/modules/comments/rawcom/mhcidx.cpp292
-rw-r--r--src/modules/comments/rawcom/rawcom.cpp275
-rw-r--r--src/modules/comments/rawcom/rtfidx.cpp292
-rw-r--r--src/modules/comments/rawcom/rwpidx.cpp266
-rw-r--r--src/modules/comments/rawfiles/Makefile5
-rw-r--r--src/modules/comments/rawfiles/Makefile.am3
-rw-r--r--src/modules/comments/rawfiles/rawfiles.cpp291
-rw-r--r--src/modules/comments/rawfiles/rawfilesgen.cpp236
-rw-r--r--src/modules/comments/swcom.cpp30
-rw-r--r--src/modules/comments/zcom/Makefile5
-rw-r--r--src/modules/comments/zcom/Makefile.am4
-rw-r--r--src/modules/comments/zcom/makeidx.c146
-rw-r--r--src/modules/comments/zcom/rawtxt2z.cpp83
-rw-r--r--src/modules/comments/zcom/zcom.cpp290
-rw-r--r--src/modules/common/Makefile4
-rw-r--r--src/modules/common/Makefile.am22
-rw-r--r--src/modules/common/compress.cpp767
-rw-r--r--src/modules/common/entriesblk.cpp166
-rw-r--r--src/modules/common/lzsscomprs.cpp665
-rw-r--r--src/modules/common/rawstr.cpp565
-rw-r--r--src/modules/common/rawstr4.cpp562
-rw-r--r--src/modules/common/rawverse.cpp345
-rw-r--r--src/modules/common/sapphire.cpp228
-rw-r--r--src/modules/common/swcipher.cpp123
-rw-r--r--src/modules/common/swcomprs.cpp190
-rw-r--r--src/modules/common/swcomprs.doc802
-rw-r--r--src/modules/common/zipcomprs.cpp158
-rw-r--r--src/modules/common/zstr.cpp705
-rw-r--r--src/modules/common/zverse.cpp513
-rw-r--r--src/modules/filters/Makefile5
-rw-r--r--src/modules/filters/Makefile.am65
-rw-r--r--src/modules/filters/cipherfil.cpp38
-rw-r--r--src/modules/filters/gbffootnotes.cpp118
-rw-r--r--src/modules/filters/gbfheadings.cpp107
-rw-r--r--src/modules/filters/gbfhtml.cpp536
-rw-r--r--src/modules/filters/gbfhtmlhref.cpp148
-rw-r--r--src/modules/filters/gbfmorph.cpp98
-rw-r--r--src/modules/filters/gbfplain.cpp106
-rw-r--r--src/modules/filters/gbfrtf.cpp277
-rw-r--r--src/modules/filters/gbfstrongs.cpp98
-rw-r--r--src/modules/filters/gbfthml.cpp463
-rw-r--r--src/modules/filters/greeklexattribs.cpp58
-rw-r--r--src/modules/filters/latin1utf16.cpp120
-rw-r--r--src/modules/filters/latin1utf8.cpp179
-rw-r--r--src/modules/filters/plainfootnotes.cpp102
-rw-r--r--src/modules/filters/plainhtml.cpp134
-rw-r--r--src/modules/filters/rtfhtml.cpp99
-rw-r--r--src/modules/filters/rwphtml.cpp187
-rw-r--r--src/modules/filters/rwprtf.cpp107
-rw-r--r--src/modules/filters/scsuutf8.cpp220
-rw-r--r--src/modules/filters/swbasicfilter.cpp299
-rw-r--r--src/modules/filters/thmlfootnotes.cpp103
-rw-r--r--src/modules/filters/thmlgbf.cpp330
-rw-r--r--src/modules/filters/thmlheadings.cpp107
-rw-r--r--src/modules/filters/thmlhtml.cpp211
-rw-r--r--src/modules/filters/thmlhtmlhref.cpp269
-rw-r--r--src/modules/filters/thmllemma.cpp97
-rw-r--r--src/modules/filters/thmlmorph.cpp98
-rw-r--r--src/modules/filters/thmlolb.cpp243
-rw-r--r--src/modules/filters/thmlplain.cpp201
-rw-r--r--src/modules/filters/thmlrtf.cpp219
-rw-r--r--src/modules/filters/thmlscripref.cpp103
-rw-r--r--src/modules/filters/thmlstrongs.cpp138
-rw-r--r--src/modules/filters/thmlvariants.cpp183
-rw-r--r--src/modules/filters/unicodertf.cpp70
-rw-r--r--src/modules/filters/utf16utf8.cpp95
-rw-r--r--src/modules/filters/utf8arshaping.cpp48
-rw-r--r--src/modules/filters/utf8bidireorder.cpp55
-rw-r--r--src/modules/filters/utf8cantillation.cpp64
-rw-r--r--src/modules/filters/utf8greekaccents.cpp252
-rw-r--r--src/modules/filters/utf8hebrewpoints.cpp55
-rw-r--r--src/modules/filters/utf8html.cpp66
-rw-r--r--src/modules/filters/utf8latin1.cpp74
-rw-r--r--src/modules/filters/utf8nfc.cpp46
-rw-r--r--src/modules/filters/utf8nfkd.cpp46
-rw-r--r--src/modules/filters/utf8transliterator.cpp479
-rw-r--r--src/modules/filters/utf8utf16.cpp79
-rw-r--r--src/modules/genbook/Makefile5
-rw-r--r--src/modules/genbook/Makefile.am5
-rw-r--r--src/modules/genbook/rawgenbook/Makefile4
-rw-r--r--src/modules/genbook/rawgenbook/Makefile.am4
-rw-r--r--src/modules/genbook/rawgenbook/rawgenbook.cpp242
-rw-r--r--src/modules/genbook/swgenbook.cpp27
-rw-r--r--src/modules/lexdict/Makefile5
-rw-r--r--src/modules/lexdict/Makefile.am7
-rw-r--r--src/modules/lexdict/rawld/Makefile5
-rw-r--r--src/modules/lexdict/rawld/Makefile.am4
-rw-r--r--src/modules/lexdict/rawld/no13.c34
-rw-r--r--src/modules/lexdict/rawld/rawld.cpp204
-rw-r--r--src/modules/lexdict/rawld/rawldidx.c96
-rw-r--r--src/modules/lexdict/rawld/strongsidx.c90
-rw-r--r--src/modules/lexdict/rawld4/Makefile5
-rw-r--r--src/modules/lexdict/rawld4/Makefile.am4
-rw-r--r--src/modules/lexdict/rawld4/rawld4.cpp204
-rw-r--r--src/modules/lexdict/swld.cpp55
-rw-r--r--src/modules/lexdict/zld/Makefile5
-rw-r--r--src/modules/lexdict/zld/Makefile.am4
-rw-r--r--src/modules/lexdict/zld/zld.cpp205
-rw-r--r--src/modules/readme9
-rw-r--r--src/modules/swmodule.cpp677
-rw-r--r--src/modules/tests/Makefile4
-rw-r--r--src/modules/tests/echomod.cpp21
-rw-r--r--src/modules/texts/Makefile5
-rw-r--r--src/modules/texts/Makefile.am7
-rw-r--r--src/modules/texts/rawgbf/Gbf.c485
-rw-r--r--src/modules/texts/rawgbf/Gbf.pas735
-rw-r--r--src/modules/texts/rawgbf/Gbfmain.pas1267
-rw-r--r--src/modules/texts/rawgbf/Makefile5
-rw-r--r--src/modules/texts/rawgbf/Makefile.am4
-rw-r--r--src/modules/texts/rawgbf/gbf.cpp735
-rw-r--r--src/modules/texts/rawgbf/gbf.h67
-rw-r--r--src/modules/texts/rawgbf/gbfidx.cpp294
-rw-r--r--src/modules/texts/rawgbf/rawgbf.cpp84
-rw-r--r--src/modules/texts/rawtext/Makefile5
-rw-r--r--src/modules/texts/rawtext/Makefile.am4
-rw-r--r--src/modules/texts/rawtext/kjvidx.cpp169
-rw-r--r--src/modules/texts/rawtext/makebnds.c86
-rw-r--r--src/modules/texts/rawtext/nuidx.cpp238
-rw-r--r--src/modules/texts/rawtext/ojbtxidx.c166
-rw-r--r--src/modules/texts/rawtext/rawtext.cpp630
-rw-r--r--src/modules/texts/rawtext/rawtxidx.c146
-rw-r--r--src/modules/texts/rawtext/rtfidx.cpp164
-rw-r--r--src/modules/texts/rawtext/svetxidx.c153
-rw-r--r--src/modules/texts/rawtext/vntidx.cpp185
-rw-r--r--src/modules/texts/swtext.cpp39
-rw-r--r--src/modules/texts/ztext/Makefile5
-rw-r--r--src/modules/texts/ztext/Makefile.am4
-rw-r--r--src/modules/texts/ztext/gbfidx.cpp661
-rw-r--r--src/modules/texts/ztext/makeidx.c146
-rw-r--r--src/modules/texts/ztext/nasb.cpp107
-rw-r--r--src/modules/texts/ztext/rawtxt2z.cpp457
-rw-r--r--src/modules/texts/ztext/ztext.cpp347
-rw-r--r--src/utilfuns/Greek2Greek.cpp901
-rw-r--r--src/utilfuns/Makefile4
-rw-r--r--src/utilfuns/Makefile.am19
-rw-r--r--src/utilfuns/greekpatch19
-rw-r--r--src/utilfuns/regex.c5725
-rw-r--r--src/utilfuns/roman.c82
-rw-r--r--src/utilfuns/sub.c36
-rw-r--r--src/utilfuns/swunicod.cpp139
-rw-r--r--src/utilfuns/swversion.cpp78
-rw-r--r--src/utilfuns/unixstr.cpp7
-rw-r--r--src/utilfuns/utilconf.cpp19
-rw-r--r--src/utilfuns/utilstr.cpp152
-rw-r--r--src/utilfuns/win32/dirent.cpp131
-rw-r--r--src/utilfuns/win32/dirent.h32
-rw-r--r--src/utilfuns/zlib/adler32.c48
-rw-r--r--src/utilfuns/zlib/compress.c68
-rw-r--r--src/utilfuns/zlib/crc32.c162
-rw-r--r--src/utilfuns/zlib/deflate.c1350
-rw-r--r--src/utilfuns/zlib/deflate.h318
-rw-r--r--src/utilfuns/zlib/gzio.c875
-rw-r--r--src/utilfuns/zlib/infblock.c398
-rw-r--r--src/utilfuns/zlib/infblock.h39
-rw-r--r--src/utilfuns/zlib/infcodes.c260
-rw-r--r--src/utilfuns/zlib/infcodes.h27
-rw-r--r--src/utilfuns/zlib/inffast.c170
-rw-r--r--src/utilfuns/zlib/inffast.h17
-rw-r--r--src/utilfuns/zlib/inffixed.h151
-rw-r--r--src/utilfuns/zlib/inflate.c366
-rw-r--r--src/utilfuns/zlib/inftrees.c455
-rw-r--r--src/utilfuns/zlib/inftrees.h58
-rw-r--r--src/utilfuns/zlib/infutil.c87
-rw-r--r--src/utilfuns/zlib/infutil.h98
-rw-r--r--src/utilfuns/zlib/maketree.c85
-rw-r--r--src/utilfuns/zlib/trees.c1214
-rw-r--r--src/utilfuns/zlib/trees.h128
-rw-r--r--src/utilfuns/zlib/uncompr.c58
-rw-r--r--src/utilfuns/zlib/untgz.c436
-rw-r--r--src/utilfuns/zlib/zutil.c225
-rw-r--r--src/utilfuns/zlib/zutil.h220
218 files changed, 45431 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..fc04b62
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,5 @@
+
+root := ..
+
+all:
+ make -C ${root}
diff --git a/src/frontend/Makefile b/src/frontend/Makefile
new file mode 100644
index 0000000..ef8eccd
--- /dev/null
+++ b/src/frontend/Makefile
@@ -0,0 +1,5 @@
+
+root := ../..
+
+all:
+ make -C ${root}
diff --git a/src/frontend/Makefile.am b/src/frontend/Makefile.am
new file mode 100644
index 0000000..df82518
--- /dev/null
+++ b/src/frontend/Makefile.am
@@ -0,0 +1,6 @@
+frontenddir = $(top_srcdir)/src/frontend
+
+libsword_la_SOURCES += $(frontenddir)/swdisp.cpp
+libsword_la_SOURCES += $(frontenddir)/swlog.cpp
+
+
diff --git a/src/frontend/X11/Makefile b/src/frontend/X11/Makefile
new file mode 100644
index 0000000..1a2d00d
--- /dev/null
+++ b/src/frontend/X11/Makefile
@@ -0,0 +1,5 @@
+
+root := ../../..
+
+all:
+ make -C ${root}
diff --git a/src/frontend/framework/Makefile b/src/frontend/framework/Makefile
new file mode 100644
index 0000000..81f7721
--- /dev/null
+++ b/src/frontend/framework/Makefile
@@ -0,0 +1,4 @@
+root := ../../..
+
+all:
+ make -C ${root}
diff --git a/src/frontend/framework/femain.cpp b/src/frontend/framework/femain.cpp
new file mode 100644
index 0000000..415ab6f
--- /dev/null
+++ b/src/frontend/framework/femain.cpp
@@ -0,0 +1,12 @@
+#include <femain.h>
+
+FEMain::FEMain() {
+}
+
+FEMain::~FEMain() {
+ list <SWDisplay *>::iterator it;
+
+ for (it = displays.begin(); it != displays.end(); it++)
+ delete *it;
+
+}
diff --git a/src/frontend/im/Makefile b/src/frontend/im/Makefile
new file mode 100644
index 0000000..1a2d00d
--- /dev/null
+++ b/src/frontend/im/Makefile
@@ -0,0 +1,5 @@
+
+root := ../../..
+
+all:
+ make -C ${root}
diff --git a/src/frontend/im/hebrewmcim.cpp b/src/frontend/im/hebrewmcim.cpp
new file mode 100644
index 0000000..9ec55a9
--- /dev/null
+++ b/src/frontend/im/hebrewmcim.cpp
@@ -0,0 +1,653 @@
+
+/**
+ * Title: Keyboard mapping for Michigan-Claremont Hebrew input
+ * Description:
+ * Copyright: Copyright (c) 2001 CrossWire Bible Society under the terms of the GNU GPL
+ * Company:
+ * @author Troy A. Griffitts
+ * @version 1.0
+ */
+
+#include <hebrewmcim.h>
+
+HebrewMCIM::HebrewMCIM()
+ :SWInputMethod() {
+
+ init();
+}
+
+
+int *HebrewMCIM::translate(char in) {
+ int retVal = 0;
+ static int retString[5];
+ int retStringIndex = 0;
+
+ memset(retString, 0, 5);
+
+ if (getState() > 1) {
+ if (getState() >= 12) { // serious issue with internal structure
+ setState(0);
+ retString[retStringIndex++] = in;
+ return retString;
+ }
+ map<int, int>::iterator find = subst2[getState()].find(in);
+ if (find != subst2[getState()].end())
+ retVal = find->second;
+ else retVal = in;
+
+ setState(0);
+ retString[retStringIndex++] = retVal;
+ return retString;
+ }
+ else {
+ retVal = subst[in];
+
+ if (retVal == 0) {
+ setState(0);
+ retString[retStringIndex++] = in;
+ return retString;
+ }
+ if (retVal > 100) {
+ setState(1);
+ retString[retStringIndex++] = retVal;
+ return retString;
+ }
+ if (retVal == 50) { // multiChar
+ setState(1);
+ int *chars = multiChars[in];
+ if (chars != 0) {
+ retString[retStringIndex++] = chars[0];
+ retString[retStringIndex++] = chars[1];
+ return retString;
+ }
+ }
+ }
+ setState(retVal);
+ return 0;
+}
+
+
+void HebrewMCIM::init() {
+ memset(subst, 0, 255);
+
+ subst[')'] = 1488;
+ subst['B'] = 1489;
+ subst['G'] = 1490;
+ subst['D'] = 1491;
+ subst['H'] = 1492;
+ subst['W'] = 1493;
+ subst['Z'] = 1494;
+ subst['X'] = 1495;
+ subst['+'] = 1496;
+ subst['Y'] = 1497;
+
+ subst['k'] = 1498; // finals
+ subst['m'] = 1501;
+ subst['n'] = 1503;
+ subst['c'] = 1509;
+
+ subst['P'] = 1508;
+ subst['K'] = 1499;
+ subst['L'] = 1500;
+ subst['M'] = 1502;
+ subst['N'] = 1504;
+ subst['S'] = 1505;
+ subst['('] = 1506;
+ subst['p'] = 1507;
+ subst['C'] = 1510;
+ subst['Q'] = 1511;
+ subst['R'] = 1512;
+ subst['#'] = 1513;
+
+ // special multiChars
+ subst['&'] = 50;
+ subst['$'] = 50;
+
+ static int x[] = {1513, 1474};
+ multiChars['&'] = x;
+ static int y[] = {1513, 1473};
+ multiChars['$'] = y;
+
+ subst['T'] = 1514;
+
+ // VOWELS
+ subst['A'] = 1463;
+ subst['F'] = 1464;
+ subst['E'] = 1462;
+ subst['"'] = 1461;
+ subst['I'] = 1460;
+ subst['O'] = 1465;
+ subst['U'] = 1467;
+
+
+
+ // OTHER DIACRITICS
+ subst['.'] = 1468;
+ subst['-'] = 1470;
+ subst[','] = 1471;
+
+ // Compound input
+
+ // CANTILLATION
+
+ subst[':'] = 2;
+ subst2[2]['A'] = 1458;
+ subst2[2]['E'] = 1457;
+ subst2[2]['F'] = 1459;
+
+
+ /* Telisha qetana is postpositive as in '04' above. However, Michigan
+# code '24' is for a medial telisha. Graphically, there is no
+# difference.
+ */
+ subst['2'] = 5;
+ subst2[5]['4'] = 1449;
+
+
+ /* Note Michigan encoding distinguishes between medial metheg '35' (occuring
+# on the left of the vowel), and the ordinary meteg '95' (occuring on the
+# right of the vowel). It is also used for silluq.
+ */
+ subst['3'] = 6;
+ subst2[6]['3'] = 1433;
+ subst2[6]['5'] = 1469;
+
+
+ /* The Michigan code of telisha gedola in medial position. Graphically,
+# there is no difference.
+ */
+ subst['4'] = 7;
+ subst2[7]['4'] = 1440;
+
+ subst['6'] = 8;
+ subst2[8]['0'] = 1451;
+ subst2[8]['1'] = 1436;
+
+ subst['1'] = 4;
+ subst2[4]['0'] = 1434;
+
+ /* In the poetic books, prepositive dehi occurs; it's unclear whether
+# tipeha also occurs in the poetic books. Otherwise, we could simply
+# check for what book in the Tanach we are in. Michigan uses the same
+# code for each.
+ */
+
+ subst2[4]['3'] = 1430;
+
+ /* This is the poetic accent mugrash, which also includes rebia, but is
+# encoded separately as '81' in the Michigan text.
+ */
+ subst2[4]['1'] = 1437;
+ subst2[4]['4'] = 1440;
+
+
+ subst['0'] = 3;
+ subst2[3]['0'] = 1475;
+ subst2[3]['1'] = 1426;
+
+ /* According to BHS, zarqa and sinnor are both postpositive. However,
+# the Michigan encoding uses one code for both. The Unicode zarqa
+# (0x0598) is definitely NOT postpositive. And further, the shape of
+# the symbol is different in BHS and Uniocde. This needs further
+# research to determine what's going on here. For now, we follow BHS
+# and use the postpositive Unicode zinor or both accents.
+ */
+
+ subst2[3]['2'] = 1454;
+
+ /* Pashta is postpositive, and the Unicode equivalent reflects
+# this. However, there is a poetic equivalent -- azla legarmeh --
+# which is not postpositive, but no equivalent code point exists in
+# Unicode. The Michigan encoding does not distinguish between the two,
+# although it could be algorithmically determined.
+ */
+
+ subst2[3]['3'] = 1433;
+ subst2[3]['4'] = 1449;
+ subst2[3]['5'] = 1472;
+
+
+ /* This is the Unicode Hebrew *accent*; there is also another Hebrew
+# *punctuation* called GERSHAYIM 0x05F4. I'm using the more
+# traditional rounded marks, rather than the alternate straight
+# marks.
+ */
+
+ subst2[8]['2'] = 1438;
+
+ // Also known as azla
+ subst2[8]['3'] = 1448;
+ subst2[8]['4'] = 1452;
+ subst2[8]['5'] = 1427;
+
+
+ subst['8'] = 9;
+ subst2[9]['0'] = 1428;
+ subst2[9]['1'] = 1431;
+
+ /* Note, this accent is actually sinnorit, but it does not exist as a
+# separate glyph in the Unicode standard. The 'ZINOR' Unicode accent
+# is postpositive, while sinnorit is not. ZARQA is as close as I can
+# get to this.
+ */
+ subst2[9]['2'] = 1432;
+
+ /* The Unicode form does not match the form used by BHS, but the names
+# are the same.
+ */
+ subst2[9]['3'] = 1441;
+ subst2[9]['4'] = 1439;
+ subst2[9]['5'] = 1429;
+
+ subst['7'] = 10;
+ subst2[10]['0'] = 1444;
+ subst2[10]['1'] = 1445;
+ subst2[10]['2'] = 1446;
+ subst2[10]['3'] = 1430; // also '13', '73' also is used for majela
+ subst2[10]['4'] = 1443;
+ subst2[10]['5'] = 1469; // this is silluq; should appear to the left of the vowel
+
+ subst['9'] = 11;
+ subst2[11]['1'] = 1435;
+ subst2[11]['2'] = 1425;
+ subst2[11]['3'] = 1450;
+ subst2[11]['4'] = 1447;
+ subst2[11]['5'] = 1469; // should appear to the right of the vowel
+
+}
+
+ /*
+
+
+# CANTILLION MARKS
+
+ my $ETNAHTA = '&#1425;';
+# officially the Unicode name for this symbol was "SEGOL." However, that is
+# not a unique name, conflicting with the vowel of the same name. Further,
+# the position of the symbol is different. I have changed the name of the
+# accent to "SEGOLTA," the traditional name for this accent.
+ my $SEGOLTA = '&#1426;';
+ my $SHALSHELET = '&#1427;';
+ my $ZAQEF_QATAN = '&#1428;';
+ my $ZAQEF_GADOL = '&#1429;';
+ my $TIPEHA = '&#1430;';
+ my $REVIA = '&#1431;';
+ my $ZARQA = '&#1432;';
+ my $PASHTA = '&#1433;';
+ my $YETIV = '&#1434;';
+ my $TEVIR = '&#1435;';
+ my $GERESH = '&#1436;';
+ my $GERESH_MUQDAM = '&#1437;';
+ my $GERSHAYIM = '&#1438;';
+ my $QARNEY_PARA = '&#1439;';
+ my $TELISHA_GEDOLA = '&#1440;';
+ my $PAZER = '&#1441;';
+ my $MUNAH = '&#1443;';
+ my $MAHAPAKH = '&#1444;';
+ my $MERKHA = '&#1445;';
+ my $MERKHA_KEFULA = '&#1446;';
+ my $DARGA = '&#1447;';
+ my $QADMA = '&#1448;';
+ my $TELISHA_QETANA = '&#1449;';
+ my $YERAH_BEN_YOMO = '&#1450;';
+ my $OLE = '&#1451;';
+ my $ILUY = '&#1452;';
+ my $DEHI = '&#1453;';
+ my $ZINOR = '&#1454;';
+# HEBREW MARK
+ my $MASORA_CIRCLE = '&#1455;';
+# HEBREW EXTENDED-A points and punctuation
+ my $SHEVA = '&#1456;';
+ my $HATAF_SEGOL = '&#1457;';
+ my $HATAF_PATAH = '&#1458;';
+ my $HATAF_QAMATS = '&#1459;';
+ my $HIRIQ = '&#1460;';
+ my $TSERE = '&#1461;';
+ my $SEGOL = '&#1462;';
+# furtive Patah is not a distinct character
+ my $PATAH = '&#1463;';
+ my $QAMATS = '&#1464;';
+ my $HOLAM = '&#1465;';
+ my $QUBUTS = '&#1467;';
+# also used as shuruq
+# falls within the base letter
+ my $DAGESH_OR_MAPIQ = '&#1468;';
+# also used as siluq
+ my $METAG = '&#1469;';
+ my $MAQAF = '&#1470;';
+ my $RAFE = '&#1471;';
+# Also used for legarmeh
+# may be treated as spacing punctuation, not as a point
+ my $PASEQ = '&#1472;';
+ my $SHIN_DOT = '&#1473;';
+ my $SIN_DOT = '&#1474;';
+ my $SOF_PASUQ = '&#1475;';
+# HEBREW MARK
+ my $UPPER_DOT = '&#1476;';
+# HEBREW LETTERS based on ISO 8859-8
+# aleph
+# x (alef symbol - 2135)
+ my $ALEF = '&#1488;';
+# x (bet symbol - 2136)
+ my $BET = '&#1489;';
+# x (gimel symbol - 2137)
+ my $GIMEL = '&#1490;';
+# x (dalet symbol - 2138)
+ my $DALET = '&#1491;';
+ my $HE = '&#1492;';
+ my $VAV = '&#1493;';
+ my $ZAYIN = '&#1494;';
+ my $HET = '&#1495;';
+ my $TET = '&#1496;';
+ my $YOD = '&#1497;';
+ my $FINAL_KAF = '&#1498;';
+ my $KAF = '&#1499;';
+ my $LAMED = '&#1500;';
+ my $FINAL_MEM = '&#1501;';
+ my $MEM = '&#1502;';
+ my $FINAL_NUN = '&#1503;';
+ my $NUN = '&#1504;';
+ my $SAMEKH = '&#1505;';
+ my $AYIN = '&#1506;';
+ my $FINAL_PE = '&#1507;';
+ my $PE = '&#1508;';
+ my $FINAL_TSADI = '&#1509;';
+# also known as zade
+ my $TSADI = '&#1510;';
+ my $QOF = '&#1511;';
+ my $RESH = '&#1512;';
+ my $SHIN = '&#1513;';
+ my $TAV = '&#1514;';
+# Yiddish digraphs
+# Hebrew Ligature
+# tsvey vovn
+ my $DOUBLE_VAV = '&#1520;';
+ my $VAV_YOD = '&#1521;';
+# tsvey yudn
+ my $DOUBLE_YOD = '&#1522;';
+
+# Additional punctuation
+ my $PUNCT_GERESH = '&#1523;';
+ my $PUNCT_GERSHAYIM = '&#1524;';
+# Reserved: 0x05F5"
+# x (hebrew point judeo-spanish varika - FB1E)
+#my $JUDEO_SPANISH_VARIKA = pack("U",0xFB1E); # UTF-8 OxFB1E
+
+#############################
+# End of Unicode 2.0 Hebrew #
+#############################
+
+# A hash whose key is a Michagan code, and whose value is a Unicode
+# equvalent
+
+ char subst[] = new char [255];
+ subst[')'] = 1488;
+ 'B' => $BET,
+ 'G' => $GIMEL,
+ 'D' => $DALET,
+ 'H' => $HE,
+ 'W' => $VAV,
+ 'Z' => $ZAYIN,
+ 'X' => $HET,
+ '+' => $TET,
+ 'Y' => $YOD,
+ 'K' => $KAF,
+ 'L' => $LAMED,
+ 'M' => $MEM,
+ 'N' => $NUN,
+ 'S' => $SAMEKH,
+ '(' => $AYIN,
+ 'P' => $PE,
+ 'C' => $TSADI,
+ 'Q' => $QOF,
+ 'R' => $RESH,
+ '#' => $SHIN, # the letter shin without a point
+ '&' => ($SHIN . $SIN_DOT),
+ '$' => ($SHIN . $SHIN_DOT), # '
+ 'T' => $TAV,
+# VOWELS
+ 'A' => $PATAH,
+ 'F' => $QAMATS,
+ 'E' => $SEGOL,
+ '"' => $TSERE,
+ 'I' => $HIRIQ,
+ 'O' => $HOLAM,
+ 'U' => $QUBUTS,
+ ':' => $SHEVA,
+ ':A' => $HATAF_PATAH,
+ ':E' => $HATAF_SEGOL,
+ ':F' => $HATAF_QAMATS,
+# OTHER DIACRITICS
+ '.' => $DAGESH_OR_MAPIQ,
+ '-' => $MAQAF,
+ ',' => $RAFE,
+# CANTILLATION
+ '00' => $SOF_PASUQ,
+ '01' => $SEGOLTA,
+# According to BHS, zarqa and sinnor are both postpositive. However,
+# the Michigan encoding uses one code for both. The Unicode zarqa
+# (0x0598) is definitely NOT postpositive. And further, the shape of
+# the symbol is different in BHS and Uniocde. This needs further
+# research to determine what's going on here. For now, we follow BHS
+# and use the postpositive Unicode zinor or both accents.
+ '02' => $ZINOR,
+# Pashta is postpositive, and the Unicode equivalent reflects
+# this. However, there is a poetic equivalent -- azla legarmeh --
+# which is not postpositive, but no equivalent code point exists in
+# Unicode. The Michigan encoding does not distinguish between the two,
+# although it could be algorithmically determined.
+ '03' => $PASHTA,
+ '04' => $TELISHA_QETANA,
+ '05' => $PASEQ,
+ '10' => $YETIV,
+# In the poetic books, prepositive dehi occurs; it's unclear whether
+# tipeha also occurs in the poetic books. Otherwise, we could simply
+# check for what book in the Tanach we are in. Michigan uses the same
+# code for each.
+ '13' => $TIPEHA, # also $DEHI
+# This is the poetic accent mugrash, which also includes rebia, but is
+# encoded separately as '81' in the Michigan text.
+ '11' => $GERESH_MUQDAM,
+ '14' => $TELISHA_GEDOLA,
+# Telisha qetana is postpositive as in '04' above. However, Michigan
+# code '24' is for a medial telisha. Graphically, there is no
+# difference.
+ '24' => $TELISHA_QETANA,
+ '33' => $PASHTA,
+# The Michigan code of telisha gedola in medial position. Graphically,
+# there is no difference.
+ '44' => $TELISHA_GEDOLA,
+ '60' => $OLE,
+ '61' => $GERESH,
+# This is the Unicode Hebrew *accent*; there is also another Hebrew
+# *punctuation* called GERSHAYIM 0x05F4. I'm using the more
+# traditional rounded marks, rather than the alternate straight
+# marks.
+ '62' => $GERSHAYIM,
+# Also known as azla
+ '63' => $QADMA,
+ '64' => $ILUY,
+ '65' => $SHALSHELET,
+ '80' => $ZAQEF_QATAN,
+ '81' => $REVIA,
+# Note, this accent is actually sinnorit, but it does not exist as a
+# separate glyph in the Unicode standard. The 'ZINOR' Unicode accent
+# is postpositive, while sinnorit is not. ZARQA is as close as I can
+# get to this.
+ '82' => $ZARQA,
+# The Unicode form does not match the form used by BHS, but the names
+# are the same.
+ '83' => $PAZER,
+ '84' => $QARNEY_PARA,
+ '85' => $ZAQEF_GADOL,
+# Note Michigan encoding distinguishes between medial metheg '35' (occuring
+# on the left of the vowel), and the ordinary meteg '95' (occuring on the
+# right of the vowel). It is also used for silluq.
+ '35' => $METAG,
+ '70' => $MAHAPAKH,
+ '71' => $MERKHA,
+ '72' => $MERKHA_KEFULA,
+ '73' => $TIPEHA, # also '13', '73' also is used for majela
+ '74' => $MUNAH,
+ '75' => $METAG, # this is silluq; should appear to the left of the vowel
+ '91' => $TEVIR,
+ '92' => $ETNAHTA,
+ '93' => $YERAH_BEN_YOMO,
+ '94' => $DARGA,
+ '95' => $METAG, # should appear to the right of the vowel
+
+# Not used by the Michigan Encoding
+# $UPPER_DOT = '05C4';
+ );
+
+# declare other variables
+ my (@bhsLines,
+ @bhsVerse,
+ @entity_line) = ();
+
+ my ($i,
+ $verse,
+ $word,
+ $character) = 0;
+
+ my ($element,
+ $saveGuttural) = "";
+
+# read in a line
+ while (<>) {
+# Process one verse
+# iterate over every character and change to XML decimal entity
+ CHAR: for ( $i = 0; ($i < scalar(@bhsVerse)); $i++) {
+ # find and convert final kaf, mem, nun, pe, tsade
+ ( # if final form
+ $bhsVerse[$i] =~ /[KMNPC]/
+ )
+ &&
+ (
+ ( # whitespace or
+ $bhsVerse[$i+1] =~ /[ \-?]/
+ )
+ ||
+ ( # EOL or
+ $i == ( scalar(@bhsVerse) - 1 )
+ )
+ ||
+ ( # sof pasuq or
+ ( $bhsVerse[$i+1] =~ /0/ ) &&
+ ( $bhsVerse[$i+2] =~ /0/ )
+ )
+ ||
+ ( # one accent followed by white, eol or
+ (
+ ( $bhsVerse[$i+1] =~ /\d/ ) &&
+ ( $bhsVerse[$i+2] =~ /\d/ )
+ ) &&
+ (
+ ( $bhsVerse[$i+3] =~ /[ \-?]/ ) ||
+ ( $i == ( scalar(@bhsVerse) - 1 ) )
+ )
+ )
+ ||
+ ( # two accents followed by white, eol
+ (
+ ( $bhsVerse[$i+1] =~ /\d/ ) &&
+ ( $bhsVerse[$i+2] =~ /\d/ ) &&
+ ( $bhsVerse[$i+3] =~ /\d/ ) &&
+ ( $bhsVerse[$i+4] =~ /\d/ )
+ ) &&
+ (
+ ( $bhsVerse[$i+5] =~ /[ \-?]/ ) ||
+ ( $i == ( scalar(@bhsVerse) - 1 ) )
+ )
+ )
+ ||
+ ( # followed by a vowel and white, eol, sof pasuq
+ ( $bhsVerse[$i+1] =~ /[:F]/ ) &&
+ ( # followed by
+ ( $bhsVerse[$i+2] =~ /[ \-?]/ ) || # whitespace or
+ ( $i == ( scalar(@bhsVerse) - 1 ) ) || # eol or
+ ( # sof pasuq
+ ( $bhsVerse[$i+2] =~ /0/ ) &&
+ ( $bhsVerse[$i+3] =~ /0/ )
+ )
+ )
+ )
+ ) # end of what follows after final letter
+ &&
+ do {
+ $bhsVerse[$i] =~ /K/ && eval { push @entity_line,$FINAL_KAF; }
+ && next CHAR;
+ $bhsVerse[$i] =~ /M/ && eval { push @entity_line,$FINAL_MEM; }
+ && next CHAR;
+ $bhsVerse[$i] =~ /N/ && eval { push @entity_line,$FINAL_NUN; }
+ && next CHAR;
+ $bhsVerse[$i] =~ /P/ && eval { push @entity_line,$FINAL_PE; }
+ && next CHAR;
+ $bhsVerse[$i] =~ /C/ && eval { push @entity_line,$FINAL_TSADI; }
+ && next CHAR;
+ };
+ # find and convert "furtive patach"
+ ( $bhsVerse[$i] =~ /A/ ) && # If the letter is a patach
+ ( $bhsVerse[$i-1] =~ /[)HX(]/ ) && # and is preceeded by a guttural
+ ( ( $bhsVerse[$i-2] =~ /[AEFOU]/ ) || # and is preceeded by a vowel
+ ( ( $bhsVerse[$i-2] =~ /\./ ) && # or by suruq
+ ( $bhsVerse[$i-3] =~ /W/ ) ) || #
+ ( ( $bhsVerse[$i-2] =~ /W/ ) && # or by holem (written plene)
+ ( $bhsVerse[$i-3] =~ /O/ ) ) || #
+ ( ( $bhsVerse[$i-2] =~ /Y/ ) && # or by hiriq-yod
+ ( $bhsVerse[$i-3] =~ /I/ ) ) ) &&
+ do {
+ $saveGuttural = pop @entity_line; # snip off the gutteral
+ push @entity_line,$PATAH; # push on the patach
+ push @entity_line,$saveGuttural; # push back on the gutteral
+ next CHAR;
+ };
+ # convert cantillation
+ # since we have previously dealt with all other cases of
+ # numbers, two digit patterns are all we have to search for
+ $bhsVerse[$i] =~ /\d/ && $bhsVerse[$i+1] =~ /\d/ && do {
+ push @entity_line,$Michigan2XMLentity{"$bhsVerse[$i]$bhsVerse[$i+1]"};
+ $i++; # accents are two digits long, so advance past the 2nd digit
+ next CHAR;
+ };
+ # convert katef vowels, which are two characters long
+ $bhsVerse[$i] =~ /:/ && $bhsVerse[$i+1] =~ /[AEF]/ && do {
+ push @entity_line,$Michigan2XMLentity{"$bhsVerse[$i]$bhsVerse[$i+1]"};
+ $i++;
+ next CHAR;
+ };
+ # convert everything else
+ push @entity_line,$Michigan2XMLentity{"$bhsVerse[$i]"};
+ } # end CHAR
+# print the line to standard output with XML character-level encoding
+# each character has the following format:
+# <c id="1kg1.verse#.word#.character#">&#1234;</c>
+
+# set up the verse element
+ $word = 1;
+ $character = 1;
+ print "<verse>\n<word>\n";
+# print each character element
+# if there is a space, then close the word entity, open a new word
+# entity, increment the word number, reset the character number to
+# zero.
+ foreach $element (@entity_line) {
+ if ( $element =~ " " ) {
+ $word++;
+ $character = 1;
+ print "</word>\n<word>\n";
+ next;
+ }
+ print "<c id=\"1kg1.$verse.$word.$character\">$element</c>\n";
+ $character++;
+ }
+# close the verse element
+ print "</word></verse>\n";
+# reinitialize variables
+ @bhsVerse = ();
+ @entity_line = ();
+ @bhsLines = ();
+ } # end while
+# close the XML document
+ print "</body>\n";
+ */
diff --git a/src/frontend/im/nullim.cpp b/src/frontend/im/nullim.cpp
new file mode 100644
index 0000000..a4f4aad
--- /dev/null
+++ b/src/frontend/im/nullim.cpp
@@ -0,0 +1,11 @@
+#include <nullim.h>
+
+
+NullIM::NullIM() {
+}
+
+int *NullIM::translate(char ch) {
+ static int retVal[1];
+ *retVal = ch;
+ return retVal;
+}
diff --git a/src/frontend/im/swinputmeth.cpp b/src/frontend/im/swinputmeth.cpp
new file mode 100644
index 0000000..7f64865
--- /dev/null
+++ b/src/frontend/im/swinputmeth.cpp
@@ -0,0 +1,26 @@
+/**
+ * Title:
+ * Description:
+ * Copyright: Copyright (c) 2001 CrossWire Bible Society under the terms of the GNU GPL
+ * Company:
+ * @author Troy A. Griffitts
+ * @version 1.0
+ */
+
+#include <swinputmeth.h>
+
+SWInputMethod::SWInputMethod() {
+ state = 0;
+}
+
+void SWInputMethod::setState(int state) {
+ this->state = state;
+}
+
+int SWInputMethod::getState() {
+ return state;
+}
+
+void SWInputMethod::clearState() {
+ state = 0;
+}
diff --git a/src/frontend/swdisp.cpp b/src/frontend/swdisp.cpp
new file mode 100644
index 0000000..30be052
--- /dev/null
+++ b/src/frontend/swdisp.cpp
@@ -0,0 +1,25 @@
+/******************************************************************************
+ * swdisp.cpp - code for base class 'swdisp'. swdisp is the basis for all
+ * types of displays (e.g. raw textout, curses, xwindow, etc.)
+ */
+
+#include <iostream.h>
+#include <swmodule.h>
+#include <swdisp.h>
+
+
+/******************************************************************************
+ * SWDisplay::Display - casts a module to a character pointer and displays it to
+ * raw output (overriden for different display types and
+ * module types if necessary)
+ *
+ * ENT: imodule - module to display
+ *
+ * RET: error status
+ */
+
+char SWDisplay::Display(SWModule &imodule)
+{
+ cout << (const char *)imodule;
+ return 0;
+}
diff --git a/src/frontend/swlog.cpp b/src/frontend/swlog.cpp
new file mode 100644
index 0000000..d3efbfc
--- /dev/null
+++ b/src/frontend/swlog.cpp
@@ -0,0 +1,95 @@
+//---------------------------------------------------------------------------
+
+#include <stdarg.h>
+#include <stdio.h>
+#ifndef _MSC_VER
+#include <iostream.h>
+#endif
+#include "swlog.h"
+//---------------------------------------------------------------------------
+
+
+SWLog *SWLog::systemlog = 0;
+
+
+class __staticsystemlog {
+public:
+ __staticsystemlog() {
+ SWLog::systemlog = new SWLog();
+ }
+ ~__staticsystemlog() {
+ delete SWLog::systemlog;
+ }
+} _staticsystemlog;
+
+
+void SWLog::LogWarning(char *fmt, ...)
+{
+ char msg[2048];
+ va_list argptr;
+
+ if (log) {
+ va_start(argptr, fmt);
+ vsprintf(msg, fmt, argptr);
+ va_end(argptr);
+
+#ifndef _MSC_VER
+ cerr << msg;
+ cerr << "\n";
+#endif
+ }
+}
+
+
+void SWLog::LogError(char *fmt, ...)
+{
+ char msg[2048];
+ va_list argptr;
+
+ if (log) {
+ va_start(argptr, fmt);
+ vsprintf(msg, fmt, argptr);
+ va_end(argptr);
+
+#ifndef _MSC_VER
+ cerr << msg;
+ cerr << "\n";
+#endif
+ }
+}
+
+
+void SWLog::LogTimedInformation(char *fmt, ...)
+{
+ char msg[2048];
+ va_list argptr;
+
+ if (log) {
+ va_start(argptr, fmt);
+ vsprintf(msg, fmt, argptr);
+ va_end(argptr);
+
+#ifndef _MSC_VER
+ cout << msg;
+ cout << "\n";
+#endif
+ }
+}
+
+
+void SWLog::LogInformation(char *fmt, ...)
+{
+ char msg[2048];
+ va_list argptr;
+
+ if (log) {
+ va_start(argptr, fmt);
+ vsprintf(msg, fmt, argptr);
+ va_end(argptr);
+
+#ifndef _MSC_VER
+ cout << msg;
+ cout << "\n";
+#endif
+ }
+}
diff --git a/src/frontend/windoze/Makefile b/src/frontend/windoze/Makefile
new file mode 100644
index 0000000..1a2d00d
--- /dev/null
+++ b/src/frontend/windoze/Makefile
@@ -0,0 +1,5 @@
+
+root := ../../..
+
+all:
+ make -C ${root}
diff --git a/src/keys/Makefile b/src/keys/Makefile
new file mode 100644
index 0000000..339f87a
--- /dev/null
+++ b/src/keys/Makefile
@@ -0,0 +1,4 @@
+root := ../..
+
+all:
+ make -C ${root}
diff --git a/src/keys/Makefile.am b/src/keys/Makefile.am
new file mode 100644
index 0000000..ddeab6a
--- /dev/null
+++ b/src/keys/Makefile.am
@@ -0,0 +1,9 @@
+keysdir = $(top_srcdir)/src/keys
+
+libsword_la_SOURCES += $(keysdir)/swkey.cpp
+libsword_la_SOURCES += $(keysdir)/listkey.cpp
+libsword_la_SOURCES += $(keysdir)/versekey.cpp
+libsword_la_SOURCES += $(keysdir)/strkey.cpp
+libsword_la_SOURCES += $(keysdir)/treekey.cpp
+libsword_la_SOURCES += $(keysdir)/treekeyidx.cpp
+
diff --git a/src/keys/genarray.c b/src/keys/genarray.c
new file mode 100644
index 0000000..f519950
--- /dev/null
+++ b/src/keys/genarray.c
@@ -0,0 +1,33 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+main()
+{
+ int fd, l1, l2, l3;
+ char *fnames[] = {"ot.bks", "ot.cps", "nt.bks", "nt.cps"};
+ long val;
+ char buf[64];
+
+#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.
+
+
+ for (l1 = 0; l1 < 2; l1++) {
+ for (l2 = 0; l2 < 2; l2++) {
+ l3 = 1;
+ sprintf(buf, "%s", fnames[(l1*2)+l2]);
+ printf(" // %s\n", fnames[(l1*2)+l2]);
+ fd = open(buf, O_RDONLY|O_BINARY);
+ while (read(fd, &val, 4) == 4) {
+ l3++;
+ printf("%ld, ", val/(4 + (l2*2)));
+ if (!(l3%7))
+ printf("\n");
+ }
+ close(fd);
+ printf("}, \n");
+ }
+ }
+}
diff --git a/src/keys/listkey.cpp b/src/keys/listkey.cpp
new file mode 100644
index 0000000..2d87f80
--- /dev/null
+++ b/src/keys/listkey.cpp
@@ -0,0 +1,256 @@
+/******************************************************************************
+ * listkey.cpp - code for base class 'ListKey'. ListKey is the basis for all
+ * types of keys that have lists of specified indexes
+ * (e.g. a list of verses, place, etc.)
+ */
+
+#include <utilfuns.h>
+#include <string.h>
+#include <stdlib.h>
+#include <swkey.h>
+#include <listkey.h>
+
+static const char *classes[] = {"ListKey", "SWKey", "SWObject", 0};
+SWClass ListKey::classdef(classes);
+
+/******************************************************************************
+ * ListKey Constructor - initializes instance of ListKey
+ *
+ * ENT: ikey - text key
+ */
+
+ListKey::ListKey(const char *ikey): SWKey(ikey) {
+ arraymax = 0;
+ ClearList();
+ init();
+}
+
+
+ListKey::ListKey(ListKey const &k) : SWKey(k.keytext) {
+ arraymax = k.arraymax;
+ arraypos = k.arraypos;
+ arraycnt = k.arraycnt;
+ array = (arraymax)?(SWKey **)malloc(k.arraymax * sizeof(SWKey *)):0;
+ for (int i = 0; i < arraycnt; i++)
+ array[i] = k.array[i]->clone();
+ init();
+}
+
+
+void ListKey::init() {
+ myclass = &classdef;
+}
+
+
+SWKey *ListKey::clone() const
+{
+ return new ListKey(*this);
+}
+
+/******************************************************************************
+ * ListKey Destructor - cleans up instance of ListKey
+ */
+
+ListKey::~ListKey()
+{
+ ClearList();
+}
+
+
+/******************************************************************************
+ * ListKey::ClearList - Clears out elements of list
+ */
+
+void ListKey::ClearList()
+{
+ int loop;
+
+ if (arraymax) {
+ for (loop = 0; loop < arraycnt; loop++)
+ delete array[loop];
+
+ free(array);
+ arraymax = 0;
+ }
+ arraycnt = 0;
+ arraypos = 0;
+ array = 0;
+}
+
+
+/******************************************************************************
+ * ListKey::copyFrom Equates this ListKey to another ListKey object
+ *
+ * ENT: ikey - other ListKey object
+ */
+
+void ListKey::copyFrom(const ListKey &ikey) {
+ ClearList();
+
+ arraymax = ikey.arraymax;
+ arraypos = ikey.arraypos;
+ arraycnt = ikey.arraycnt;
+ array = (arraymax)?(SWKey **)malloc(ikey.arraymax * sizeof(SWKey *)):0;
+ for (int i = 0; i < arraycnt; i++)
+ array[i] = ikey.array[i]->clone();
+
+ SetToElement(0);
+}
+
+
+/******************************************************************************
+ * ListKey::add - Adds an element to the list
+ */
+
+void ListKey::add(const SWKey &ikey) {
+ if (++arraycnt > arraymax) {
+ array = (SWKey **) ((array) ? realloc(array, (arraycnt + 32) * sizeof(SWKey *)) : calloc(arraycnt + 32, sizeof(SWKey *)));
+ arraymax = arraycnt + 32;
+ }
+ array[arraycnt-1] = ikey.clone();
+ SetToElement(arraycnt-1);
+}
+
+
+
+/******************************************************************************
+ * ListKey::setPosition(SW_POSITION) - Positions this key
+ *
+ * ENT: p - position
+ *
+ * RET: *this
+ */
+
+void ListKey::setPosition(SW_POSITION p) {
+ switch (p) {
+ case 1: // GCC won't compile P_TOP
+ SetToElement(0);
+ break;
+ case 2: // GCC won't compile P_BOTTOM
+ SetToElement(arraycnt-1);
+ break;
+ }
+}
+
+
+/******************************************************************************
+ * ListKey::increment - Increments a number of elements
+ */
+
+void ListKey::increment(int step) {
+ if (step < 0) {
+ decrement(step*-1);
+ return;
+ }
+ Error(); // clear error
+ for(; step && !Error(); step--) {
+ if (arraypos < arraycnt) {
+ (*(array[arraypos]))++;
+ if (array[arraypos]->Error()) {
+ SetToElement(arraypos+1);
+ }
+ else *this = (const char *)(*array[arraypos]);
+ }
+ else error = KEYERR_OUTOFBOUNDS;
+ }
+}
+
+
+/******************************************************************************
+ * ListKey::decrement - Decrements a number of elements
+ */
+
+void ListKey::decrement(int step) {
+ if (step < 0) {
+ increment(step*-1);
+ return;
+ }
+ Error(); // clear error
+ for(; step && !Error(); step--) {
+ if (arraypos > -1) {
+ (*(array[arraypos]))--;
+ if (array[arraypos]->Error()) {
+ SetToElement(arraypos-1, BOTTOM);
+ }
+ else *this = (const char *)(*array[arraypos]);
+ }
+ else error = KEYERR_OUTOFBOUNDS;
+ }
+}
+
+
+/******************************************************************************
+ * ListKey::Count - Returns number of elements in list
+ */
+
+int ListKey::Count() {
+ return arraycnt;
+}
+
+
+/******************************************************************************
+ * ListKey::SetToElement - Sets key to element number
+ *
+ * ENT: ielement - element number to set to
+ *
+ * RET: error status
+ */
+
+char ListKey::SetToElement(int ielement, SW_POSITION pos) {
+ arraypos = ielement;
+ if (arraypos >= arraycnt) {
+ arraypos = (arraycnt>0)?arraycnt - 1:0;
+ error = KEYERR_OUTOFBOUNDS;
+ }
+ else {
+ if (arraypos < 0) {
+ arraypos = 0;
+ error = KEYERR_OUTOFBOUNDS;
+ }
+ else {
+ error = 0;
+ }
+ }
+
+ if (arraycnt) {
+ (*array[arraypos]) = pos;
+ *this = (const char *)(*array[arraypos]);
+ }
+ else *this = "";
+
+ return error;
+}
+
+
+/******************************************************************************
+ * ListKey::GetElement - Gets a key element number
+ *
+ * ENT: pos - element number to get (or default current)
+ *
+ * RET: Key or null on error
+ */
+
+SWKey *ListKey::GetElement(int pos) {
+ if (pos >=0) {
+ if (pos >=arraycnt)
+ error = KEYERR_OUTOFBOUNDS;
+ }
+ else pos = arraypos;
+ return (error) ? 0:array[pos];
+}
+
+
+/******************************************************************************
+ * ListKey::Remove - Removes current element from list
+ */
+
+void ListKey::Remove() {
+ if ((arraypos > -1) && (arraypos < arraycnt)) {
+ delete array[arraypos];
+ if (arraypos < arraycnt - 1)
+ memmove(&array[arraypos], &array[arraypos+1], (arraycnt - arraypos - 1) * sizeof(SWKey *));
+ arraycnt--;
+
+ SetToElement((arraypos)?arraypos-1:0);
+ }
+}
diff --git a/src/keys/nt.bks b/src/keys/nt.bks
new file mode 100644
index 0000000..6a3cf92
--- /dev/null
+++ b/src/keys/nt.bks
Binary files differ
diff --git a/src/keys/nt.cps b/src/keys/nt.cps
new file mode 100644
index 0000000..fdaa6f4
--- /dev/null
+++ b/src/keys/nt.cps
Binary files differ
diff --git a/src/keys/ot.bks b/src/keys/ot.bks
new file mode 100644
index 0000000..512f064
--- /dev/null
+++ b/src/keys/ot.bks
Binary files differ
diff --git a/src/keys/ot.cps b/src/keys/ot.cps
new file mode 100644
index 0000000..f4bf66b
--- /dev/null
+++ b/src/keys/ot.cps
Binary files differ
diff --git a/src/keys/strkey.cpp b/src/keys/strkey.cpp
new file mode 100644
index 0000000..7e2d539
--- /dev/null
+++ b/src/keys/strkey.cpp
@@ -0,0 +1,41 @@
+/******************************************************************************
+ * StrKey.cpp - code for class 'StrKey'- a standard string key class (used
+ * for modules that index on single strings (eg. cities,
+ * names, words, etc.)
+ */
+
+#include <swmacs.h>
+#include <utilfuns.h>
+#include <strkey.h>
+#include <string.h>
+#include <stdio.h>
+
+
+static const char *classes[] = {"StrKey", "SWKey", "SWObject", 0};
+SWClass StrKey::classdef(classes);
+
+/******************************************************************************
+ * StrKey Constructor - initializes instance of StrKey
+ *
+ * ENT: ikey - text key (word, city, name, etc.)
+ */
+
+StrKey::StrKey(const char *ikey) : SWKey(ikey)
+{
+ init();
+}
+
+
+void StrKey::init() {
+ myclass = &classdef;
+}
+
+
+/******************************************************************************
+ * StrKey Destructor - cleans up instance of StrKey
+ *
+ * ENT: ikey - text key
+ */
+
+StrKey::~StrKey() {
+}
diff --git a/src/keys/swkey.cpp b/src/keys/swkey.cpp
new file mode 100644
index 0000000..0ed2e75
--- /dev/null
+++ b/src/keys/swkey.cpp
@@ -0,0 +1,195 @@
+/******************************************************************************
+ * swkey.cpp - code for base class 'SWKey'. SWKey is the basis for all
+ * types of keys for indexing into modules (e.g. verse, word,
+ * place, etc.)
+ */
+
+#include <swkey.h>
+#include <utilfuns.h>
+#include <string.h>
+
+static const char *classes[] = {"SWKey", "SWObject", 0};
+SWClass SWKey::classdef(classes);
+
+/******************************************************************************
+ * SWKey Constructor - initializes instance of SWKey
+ *
+ * ENT: ikey - text key
+ */
+
+SWKey::SWKey(const char *ikey)
+{
+ index = 0;
+ persist = 0;
+ keytext = 0;
+ error = 0;
+ stdstr(&keytext, ikey);
+ init();
+}
+
+SWKey::SWKey(SWKey const &k)
+{
+ index = k.index;
+ persist = k.persist;
+ keytext = 0;
+ error = k.error;
+ stdstr(&keytext, k.keytext);
+ init();
+}
+
+void SWKey::init() {
+ myclass = &classdef;
+}
+
+SWKey *SWKey::clone() const
+{
+ return new SWKey(*this);
+}
+
+/******************************************************************************
+ * SWKey Destructor - cleans up instance of SWKey
+ */
+
+SWKey::~SWKey() {
+ if (keytext)
+ delete [] keytext;
+}
+
+
+/******************************************************************************
+ * SWKey::Persist - Gets whether this object itself persists within a
+ * module that it was used to SetKey or just a copy.
+ * (1 - persists in module; 0 - a copy is attempted
+ *
+ * RET: value of persist
+ */
+
+char SWKey::Persist() const
+{
+ return persist;
+}
+
+
+/******************************************************************************
+ * SWKey::Persist - Set/gets whether this object itself persists within a
+ * module that it was used to SetKey or just a copy.
+ * (1 - persists in module; 0 - a copy is attempted
+ *
+ * ENT: ipersist - value which to set persist
+ * [-1] - only get
+ *
+ * RET: value of persist
+ */
+
+char SWKey::Persist(signed char ipersist)
+{
+ if (ipersist != -1)
+ persist = ipersist;
+
+ return persist;
+}
+
+
+/******************************************************************************
+ * SWKey::Error - Gets and clears error status
+ *
+ * RET: error status
+ */
+
+char SWKey::Error()
+{
+ char retval = error;
+
+ error = 0;
+ return retval;
+}
+
+
+/******************************************************************************
+ * SWKey::setText Equates this SWKey to a character string
+ *
+ * ENT: ikey - other swkey object
+ */
+
+void SWKey::setText(const char *ikey) {
+ stdstr(&keytext, ikey);
+}
+
+
+/******************************************************************************
+ * SWKey::copyFrom Equates this SWKey to another SWKey object
+ *
+ * ENT: ikey - other swkey object
+ */
+
+void SWKey::copyFrom(const SWKey &ikey) {
+// not desirable Persist(ikey.Persist());
+ setText((const char *)ikey);
+}
+
+
+/******************************************************************************
+ * SWKey::getText - returns text key if (char *) cast is requested
+ */
+
+const char *SWKey::getText() const {
+ return keytext;
+}
+
+
+/******************************************************************************
+ * SWKey::compare - Compares another VerseKey object
+ *
+ * ENT: ikey - key to compare with this one
+ *
+ * RET: > 0 if this key is greater than compare key
+ * < 0
+ * 0
+ */
+
+int SWKey::compare(const SWKey &ikey)
+{
+ return strcmp((const char *)*this, (const char *)ikey);
+}
+
+
+/******************************************************************************
+ * SWKey::setPosition(SW_POSITION) - Positions this key if applicable
+ */
+
+void SWKey::setPosition(SW_POSITION p) {
+ switch (p) {
+ case POS_TOP:
+// *this = "";
+ break;
+ case POS_BOTTOM:
+// *this = "zzzzzzzzz";
+ break;
+ }
+}
+
+
+/******************************************************************************
+ * SWKey::increment - Increments key a number of entries
+ *
+ * ENT: increment - Number of entries to jump forward
+ *
+ * RET: *this
+ */
+
+void SWKey::increment(int) {
+ error = KEYERR_OUTOFBOUNDS;
+}
+
+
+/******************************************************************************
+ * SWKey::decrement - Decrements key a number of entries
+ *
+ * ENT: decrement - Number of entries to jump backward
+ *
+ * RET: *this
+ */
+
+void SWKey::decrement(int) {
+ error = KEYERR_OUTOFBOUNDS;
+}
diff --git a/src/keys/treekey.cpp b/src/keys/treekey.cpp
new file mode 100644
index 0000000..c9eddb4
--- /dev/null
+++ b/src/keys/treekey.cpp
@@ -0,0 +1,27 @@
+/******************************************************************************
+ * versekey.h - code for class 'versekey'- a standard Biblical verse key
+ *
+ * $Id: treekey.cpp,v 1.1 2002/01/24 08:55:27 scribe Exp $
+ *
+ * Copyright 1998 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 <treekey.h>
+
+static const char *classes[] = {"TreeKey", "SWKey", "SWObject", 0};
+SWClass TreeKey::classdef(classes);
+
diff --git a/src/keys/treekeyidx.cpp b/src/keys/treekeyidx.cpp
new file mode 100644
index 0000000..e0d0fc7
--- /dev/null
+++ b/src/keys/treekeyidx.cpp
@@ -0,0 +1,581 @@
+/******************************************************************************
+ * versekey.h - code for class 'versekey'- a standard Biblical verse key
+ *
+ * $Id: treekeyidx.cpp,v 1.5 2002/03/18 20:52:45 scribe Exp $
+ *
+ * Copyright 1998 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 <treekeyidx.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string>
+
+#ifndef __GNUC__
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+using namespace std;
+static const char *classes[] = {"TreeKeyIdx", "TreeKey", "SWKey", "SWObject", 0};
+static const char nl = '\n';
+SWClass TreeKeyIdx::classdef(classes);
+
+
+TreeKeyIdx::TreeKeyIdx(const TreeKeyIdx &ikey) : currentNode() {
+ path = 0;
+ idxfd = 0;
+ datfd = 0;
+ copyFrom(ikey);
+}
+
+TreeKeyIdx::TreeKeyIdx(const char *idxPath, int fileMode) : currentNode() {
+ char buf[127];
+
+ path = 0;
+ stdstr(&path, idxPath);
+
+#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);
+
+ if (datfd <= 0) {
+ sprintf(buf, "Error: %d", errno);
+ perror(buf);
+ error = errno;
+ }
+ else {
+ root();
+ }
+}
+
+
+TreeKeyIdx::~TreeKeyIdx () {
+ if (path)
+ delete [] path;
+
+ FileMgr::systemFileMgr.close(idxfd);
+ FileMgr::systemFileMgr.close(datfd);
+}
+
+
+const char *TreeKeyIdx::getLocalName() {
+ return currentNode.name;
+}
+
+
+const char *TreeKeyIdx::getUserData(int *size) {
+ if (size)
+ *size = (int)currentNode.dsize;
+ return currentNode.userData;
+}
+
+
+void TreeKeyIdx::setUserData(const char *userData, int size) {
+ if (currentNode.userData)
+ delete currentNode.userData;
+
+ if (!size)
+ size = strlen(userData) + 1;
+
+ currentNode.userData = new char [ size ];
+ memcpy(currentNode.userData, userData, size);
+ currentNode.dsize = size;
+}
+
+const char *TreeKeyIdx::setLocalName(const char *newName) {
+ stdstr(&(currentNode.name), newName);
+ return currentNode.name;
+}
+
+
+void TreeKeyIdx::save() {
+ saveTreeNode(&currentNode);
+}
+
+
+const char *TreeKeyIdx::getFullName() const {
+ TreeNode parent;
+ static string fullPath;
+ fullPath = currentNode.name;
+ parent.parent = currentNode.parent;
+ while (parent.parent > -1) {
+ getTreeNodeFromIdxOffset(parent.parent, &parent);
+ fullPath = ((string)parent.name) + (string) "/" + fullPath;
+ }
+ return fullPath.c_str();
+}
+
+
+void TreeKeyIdx::root() {
+ error = getTreeNodeFromIdxOffset(0, &currentNode);
+}
+
+
+bool TreeKeyIdx::parent() {
+ if (currentNode.parent > -1) {
+ error = getTreeNodeFromIdxOffset(currentNode.parent, &currentNode);
+ return true;
+ }
+ return false;
+}
+
+
+bool TreeKeyIdx::firstChild() {
+ if (currentNode.firstChild > -1) {
+ error = getTreeNodeFromIdxOffset(currentNode.firstChild, &currentNode);
+ return true;
+ }
+ return false;
+}
+
+
+bool TreeKeyIdx::nextSibling() {
+ if (currentNode.next > -1) {
+ error = getTreeNodeFromIdxOffset(currentNode.next, &currentNode);
+ return true;
+ }
+ return false;
+}
+
+
+bool TreeKeyIdx::previousSibling() {
+ TreeNode iterator;
+ __u32 target = currentNode.offset;
+ if (currentNode.parent > -1) {
+ getTreeNodeFromIdxOffset(currentNode.parent, &iterator);
+ getTreeNodeFromIdxOffset(iterator.firstChild, &iterator);
+ if (iterator.offset != target) {
+ while ((iterator.next != target) && (iterator.next > -1))
+ getTreeNodeFromIdxOffset(iterator.next, &iterator);
+ if (iterator.next > -1) {
+ error = getTreeNodeFromIdxOffset(iterator.offset, &currentNode);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+bool TreeKeyIdx::hasChildren() {
+ return (currentNode.firstChild > -1);
+}
+
+
+void TreeKeyIdx::append() {
+ TreeNode lastSib;
+ if (currentNode.offset) {
+ getTreeNodeFromIdxOffset(currentNode.offset, &lastSib);
+ while (lastSib.next > -1) {
+ getTreeNodeFromIdxOffset(lastSib.next, &lastSib);
+ }
+ __u32 idxOffset = lseek(idxfd->getFd(), 0, SEEK_END);
+ lastSib.next = idxOffset;
+ saveTreeNodeOffsets(&lastSib);
+ __u32 parent = currentNode.parent;
+ currentNode.clear();
+ currentNode.offset = idxOffset;
+ currentNode.parent = parent;
+ }
+}
+
+
+void TreeKeyIdx::appendChild() {
+ if (firstChild()) {
+ append();
+ }
+ else {
+ __u32 idxOffset = lseek(idxfd->getFd(), 0, SEEK_END);
+ currentNode.firstChild = idxOffset;
+ saveTreeNodeOffsets(&currentNode);
+ __u32 parent = currentNode.offset;
+ currentNode.clear();
+ currentNode.offset = idxOffset;
+ currentNode.parent = parent;
+ }
+}
+
+
+void TreeKeyIdx::insertBefore() {
+}
+
+
+void TreeKeyIdx::remove() {
+}
+
+
+/******************************************************************************
+ * TreeKeyIdx::Create - Creates new key idx/dat files
+ *
+ * ENT: path - directory to store module files
+ * RET: error status
+ */
+
+signed char TreeKeyIdx::create(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);
+
+ TreeKeyIdx newTree(path);
+ TreeKeyIdx::TreeNode root;
+ stdstr(&(root.name), "");
+ newTree.saveTreeNode(&root);
+
+ delete [] path;
+
+ return 0;
+}
+
+
+/******************************************************************************
+ * 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
+ * node - address of pointer to allocate for storage of string
+ */
+
+void TreeKeyIdx::getTreeNodeFromDatOffset(long ioffset, TreeNode *node) const {
+ char ch;
+ __s32 tmp;
+ __u16 tmp2;
+
+ if (datfd > 0) {
+
+ lseek(datfd->getFd(), ioffset, SEEK_SET);
+
+ read(datfd->getFd(), &tmp, 4);
+ node->parent = swordtoarch32(tmp);
+
+ read(datfd->getFd(), &tmp, 4);
+ node->next = swordtoarch32(tmp);
+
+ read(datfd->getFd(), &tmp, 4);
+ node->firstChild = swordtoarch32(tmp);
+
+ string name;
+ do {
+ read(datfd->getFd(), &ch, 1);
+ name += ch;
+ } while (ch);
+
+ stdstr(&(node->name), name.c_str());
+
+ read(datfd->getFd(), &tmp2, 2);
+ node->dsize = swordtoarch16(tmp2);
+
+ if (node->dsize) {
+ if (node->userData)
+ delete [] node->userData;
+ node->userData = new char [node->dsize];
+ read(datfd->getFd(), node->userData, node->dsize);
+ }
+ }
+}
+
+
+/******************************************************************************
+ * 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
+ */
+
+char TreeKeyIdx::getTreeNodeFromIdxOffset(long ioffset, TreeNode *node) const {
+ __u32 offset;
+ char error = 0;
+
+ if (ioffset < 0) {
+ ioffset = 0;
+ error = KEYERR_OUTOFBOUNDS;
+ }
+
+ node->offset = ioffset;
+ if (idxfd > 0) {
+ lseek(idxfd->getFd(), ioffset, SEEK_SET);
+ if (read(idxfd->getFd(), &offset, 4) == 4) {
+ offset = swordtoarch32(offset);
+ getTreeNodeFromDatOffset(offset, node);
+ }
+ else {
+ lseek(idxfd->getFd(), -4, SEEK_END);
+ if (read(idxfd->getFd(), &offset, 4) == 4) {
+ offset = swordtoarch32(offset);
+ getTreeNodeFromDatOffset(offset, node);
+ }
+ error = KEYERR_OUTOFBOUNDS;
+ }
+ }
+ return error;
+}
+
+
+unsigned long TreeKeyIdx::getOffset() const {
+ return currentNode.offset;
+}
+
+void TreeKeyIdx::setOffset(unsigned long offset) {
+ error = getTreeNodeFromIdxOffset(offset, &currentNode);
+}
+
+
+void TreeKeyIdx::saveTreeNodeOffsets(TreeNode *node) {
+ long datOffset = 0;
+ __s32 tmp;
+
+ if (idxfd > 0) {
+ lseek(idxfd->getFd(), node->offset, SEEK_SET);
+ if (read(idxfd->getFd(), &tmp, 4) != 4) {
+ datOffset = lseek(datfd->getFd(), 0, SEEK_END);
+ tmp = archtosword32(datOffset);
+ write(idxfd->getFd(), &tmp, 4);
+ }
+ else {
+ datOffset = swordtoarch32(tmp);
+ lseek(datfd->getFd(), datOffset, SEEK_SET);
+ }
+
+ tmp = archtosword32(node->parent);
+ write(datfd->getFd(), &tmp, 4);
+
+ tmp = archtosword32(node->next);
+ write(datfd->getFd(), &tmp, 4);
+
+ tmp = archtosword32(node->firstChild);
+ write(datfd->getFd(), &tmp, 4);
+ }
+}
+
+
+void TreeKeyIdx::copyFrom(const TreeKeyIdx &ikey) {
+
+ currentNode.offset = ikey.currentNode.offset;
+ currentNode.parent = ikey.currentNode.parent;
+ currentNode.next = ikey.currentNode.next;
+ currentNode.firstChild = ikey.currentNode.firstChild;
+ stdstr(&(currentNode.name), ikey.currentNode.name);
+ currentNode.dsize = ikey.currentNode.dsize;
+
+ if (currentNode.userData)
+ delete [] currentNode.userData;
+ if (currentNode.dsize) {
+ currentNode.userData = new char [ currentNode.dsize ];
+ memcpy(currentNode.userData, ikey.currentNode.userData, currentNode.dsize);
+ }
+ else currentNode.userData = 0;
+
+ bool newFiles = true;
+
+ if (path && ikey.path)
+ newFiles = strcmp(path, ikey.path);
+
+ if (newFiles) {
+ stdstr(&path, ikey.path);
+
+ if (idxfd) {
+ FileMgr::systemFileMgr.close(idxfd);
+ FileMgr::systemFileMgr.close(datfd);
+ }
+ idxfd = FileMgr::systemFileMgr.open(ikey.idxfd->path, ikey.idxfd->mode, ikey.idxfd->perms);
+ datfd = FileMgr::systemFileMgr.open(ikey.datfd->path, ikey.datfd->mode, ikey.datfd->perms);
+ }
+}
+
+
+void TreeKeyIdx::saveTreeNode(TreeNode *node) {
+ long datOffset = 0;
+ __s32 tmp;
+ if (idxfd > 0) {
+
+ lseek(idxfd->getFd(), node->offset, SEEK_SET);
+ datOffset = lseek(datfd->getFd(), 0, SEEK_END);
+ tmp = archtosword32(datOffset);
+ write(idxfd->getFd(), &tmp, 4);
+
+ saveTreeNodeOffsets(node);
+
+ write(datfd->getFd(), node->name, strlen(node->name));
+ char null = 0;
+ write(datfd->getFd(), &null, 1);
+
+ __u16 tmp2 = archtosword16(node->dsize);
+ write(datfd->getFd(), &tmp2, 2);
+
+ if (node->dsize) {
+ write(datfd->getFd(), node->userData, node->dsize);
+ }
+ }
+}
+
+
+void TreeKeyIdx::setText(const char *ikey) {
+ char *buf = 0;
+ stdstr(&buf, ikey);
+ char *leaf = strtok(buf, "/");
+ root();
+ while ((leaf) && (!Error())) {
+ bool ok, inChild = false;
+ for (ok = firstChild(); ok; ok = nextSibling()) {
+ inChild = true;
+ if (!stricmp(leaf, getLocalName()))
+ break;
+ }
+ leaf = strtok(0, "/");
+ if (!ok) {
+ if (inChild) { // if we didn't find a matching child node, default to first child
+ parent();
+ firstChild();
+ }
+ if (leaf)
+ error = KEYERR_OUTOFBOUNDS;
+ break;
+ }
+ }
+ delete [] buf;
+}
+
+
+
+void TreeKeyIdx::copyFrom(const SWKey &ikey) {
+ SWKey::copyFrom(ikey);
+}
+
+void TreeKeyIdx::setPosition(SW_POSITION p) {
+ switch (p) {
+ case POS_TOP:
+ root();
+ break;
+ case POS_BOTTOM:
+ error = getTreeNodeFromIdxOffset(lseek(idxfd->getFd(), -4, SEEK_END), &currentNode);
+ break;
+ }
+ Error(); // clear error from normalize
+}
+
+const char *TreeKeyIdx::getText() const {
+ return getFullName();
+}
+
+
+int TreeKeyIdx::_compare (const TreeKeyIdx & ikey) {
+ return (getOffset() - ikey.getOffset());
+}
+
+
+int TreeKeyIdx::compare(const SWKey &ikey) {
+ TreeKeyIdx *treeKey = SWDYNAMIC_CAST(TreeKeyIdx, (&ikey));
+ if (treeKey)
+ return _compare(*treeKey);
+ return SWKey::compare(ikey);
+}
+
+
+void TreeKeyIdx::decrement(int steps) {
+ error = getTreeNodeFromIdxOffset(currentNode.offset - (4*steps), &currentNode);
+}
+
+void TreeKeyIdx::increment(int steps) {
+ error = getTreeNodeFromIdxOffset(currentNode.offset + (4*steps), &currentNode);
+
+/*
+ // assert positive
+ if (steps < 0) {
+ decrement(steps * -1);
+ return;
+ }
+
+ while (steps > 0) {
+ if (!firstChild()) {
+ if (!nextSibbling() {
+ error = KEYERR_OUTOFBOUNDS;
+ return;
+ }
+ }
+ steps--;
+ }
+*/
+}
+
+
+
+TreeKeyIdx::TreeNode::TreeNode() {
+
+ name = 0;
+ stdstr(&name, "");
+ userData = 0;
+
+ clear();
+}
+
+
+void TreeKeyIdx::TreeNode::clear() {
+ offset = 0;
+ parent = -1;
+ next = -1;
+ firstChild = -1;
+ dsize = 0;
+
+ if (name)
+ delete [] name;
+ name = 0;
+ stdstr(&name, "");
+
+ if (userData)
+ delete [] userData;
+ userData = 0;
+}
+
+
+TreeKeyIdx::TreeNode::~TreeNode() {
+ if (name)
+ delete [] name;
+
+ if (userData)
+ delete [] userData;
+}
diff --git a/src/keys/versekey.cpp b/src/keys/versekey.cpp
new file mode 100644
index 0000000..1d5adcb
--- /dev/null
+++ b/src/keys/versekey.cpp
@@ -0,0 +1,1405 @@
+/******************************************************************************
+ * VerseKey.cpp - code for class 'VerseKey'- a standard Biblical verse key
+ */
+
+#include <swmacs.h>
+#include <utilfuns.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#ifndef __GNUC__
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <utilstr.h>
+#include <swkey.h>
+#include <swlog.h>
+#include <versekey.h>
+#include <localemgr.h>
+extern "C" {
+#include <roman.h>
+}
+
+
+static const char *classes[] = {"VerseKey", "SWKey", "SWObject", 0};
+SWClass VerseKey::classdef(classes);
+
+/******************************************************************************
+ * Initialize static members of VerseKey
+ */
+
+#include <canon.h> // Initialize static members of canonical books structure
+
+struct sbook *VerseKey::builtin_books[2] = {0,0};
+const char VerseKey::builtin_BMAX[2] = {39, 27};
+long *VerseKey::offsets[2][2] = {{VerseKey::otbks, VerseKey::otcps}, {VerseKey::ntbks, VerseKey::ntcps}};
+int VerseKey::instance = 0;
+VerseKey::LocaleCache VerseKey::localeCache;
+
+
+/******************************************************************************
+ * VerseKey::init - initializes instance of VerseKey
+ */
+
+void VerseKey::init() {
+ myclass = &classdef;
+ if (!instance)
+ initstatics();
+
+ instance++;
+ autonorm = 1; // default auto normalization to true
+ headings = 0; // default display headings option is false
+ upperBound = 0;
+ lowerBound = 0;
+ testament = 0;
+ book = 0;
+ chapter = 0;
+ verse = 0;
+ locale = 0;
+
+ setLocale(LocaleMgr::systemLocaleMgr.getDefaultLocaleName());
+}
+
+/******************************************************************************
+ * VerseKey Constructor - initializes instance of VerseKey
+ *
+ * ENT: ikey - base key (will take various forms of 'BOOK CH:VS'. See
+ * VerseKey::parse for more detailed information)
+ */
+
+VerseKey::VerseKey(const SWKey *ikey) : SWKey(*ikey)
+{
+ init();
+ if (ikey)
+ parse();
+}
+
+
+/******************************************************************************
+ * VerseKey Constructor - initializes instance of VerseKey
+ *
+ * ENT: ikey - text key (will take various forms of 'BOOK CH:VS'. See
+ * VerseKey::parse for more detailed information)
+ */
+
+VerseKey::VerseKey(const char *ikey) : SWKey(ikey)
+{
+ init();
+ if (ikey)
+ parse();
+}
+
+
+VerseKey::VerseKey(VerseKey const &k) : SWKey(k.keytext)
+{
+ init();
+ autonorm = k.autonorm;
+ headings = k.headings;
+ testament = k.Testament();
+ book = k.Book();
+ chapter = k.Chapter();
+ verse = k.Verse();
+ LowerBound(k.LowerBound());
+ UpperBound(k.UpperBound());
+}
+
+
+VerseKey::VerseKey(const char *min, const char *max) : SWKey()
+{
+ init();
+ LowerBound(min);
+ UpperBound(max);
+ setPosition(TOP);
+}
+
+
+SWKey *VerseKey::clone() const
+{
+ return new VerseKey(*this);
+}
+
+
+/******************************************************************************
+ * VerseKey Destructor - cleans up instance of VerseKey
+ *
+ * ENT: ikey - text key
+ */
+
+VerseKey::~VerseKey() {
+ if (upperBound)
+ delete upperBound;
+ if (lowerBound)
+ delete lowerBound;
+ if (locale)
+ delete [] locale;
+
+ --instance;
+}
+
+
+void VerseKey::setLocale(const char *name) {
+ char *BMAX;
+ struct sbook **books;
+ bool useCache = false;
+
+ if (localeCache.name)
+ useCache = (!strcmp(localeCache.name, name));
+
+ if (!useCache) { // if we're setting params for a new locale
+ stdstr(&(localeCache.name), name);
+ localeCache.abbrevsCnt = 0;
+ }
+
+ SWLocale *locale = (useCache) ? localeCache.locale : LocaleMgr::systemLocaleMgr.getLocale(name);
+ localeCache.locale = locale;
+
+ if (locale) {
+ locale->getBooks(&BMAX, &books);
+ setBooks(BMAX, books);
+ setBookAbbrevs(locale->getBookAbbrevs(), localeCache.abbrevsCnt);
+ localeCache.abbrevsCnt = abbrevsCnt;
+ }
+ else {
+ setBooks(builtin_BMAX, builtin_books);
+ setBookAbbrevs(builtin_abbrevs, localeCache.abbrevsCnt);
+ localeCache.abbrevsCnt = abbrevsCnt;
+ }
+ stdstr(&(this->locale), localeCache.name);
+}
+
+
+void VerseKey::setBooks(const char *iBMAX, struct sbook **ibooks) {
+ BMAX = iBMAX;
+ books = ibooks;
+}
+
+
+void VerseKey::setBookAbbrevs(const struct abbrev *bookAbbrevs, unsigned int size) {
+ abbrevs = bookAbbrevs;
+ if (!size) {
+ for (abbrevsCnt = 1; *abbrevs[abbrevsCnt].ab; abbrevsCnt++) {
+ /*
+ if (strcmp(abbrevs[abbrevsCnt-1].ab, abbrevs[abbrevsCnt].ab) > 0) {
+ fprintf(stderr, "ERROR: book abbreviation (canon.h or locale) misordered at entry: %s\n", abbrevs[abbrevsCnt].ab);
+ exit(-1);
+ }
+ */
+ }
+ for (int t = 0; t < 2; t++) {
+ for (int i = 0; i < BMAX[t]; i++) {
+ int bn = getBookAbbrev(books[t][i].name);
+ if ((bn-1)%39 != i) {
+ SWLog::systemlog->LogError("Book: %s does not have a matching toupper abbrevs entry! book number returned was: %d", books[t][i].name, bn);
+ }
+ }
+ }
+ }
+ else abbrevsCnt = size;
+}
+
+
+/******************************************************************************
+ * VerseKey::initstatics - initializes statics. Performed only when first
+ * instance on VerseKey (or descendent) is created.
+ */
+
+void VerseKey::initstatics() {
+ int l1, l2, chaptmp = 0;
+
+ builtin_books[0] = otbooks;
+ builtin_books[1] = ntbooks;
+
+ for (l1 = 0; l1 < 2; l1++) {
+ for (l2 = 0; l2 < builtin_BMAX[l1]; l2++) {
+ builtin_books[l1][l2].versemax = &vm[chaptmp];
+ chaptmp += builtin_books[l1][l2].chapmax;
+ }
+ }
+}
+
+
+/******************************************************************************
+ * VerseKey::parse - parses keytext into testament|book|chapter|verse
+ *
+ * RET: error status
+ */
+
+char VerseKey::parse()
+{
+
+
+ testament = 1;
+ book = 1;
+ chapter = 1;
+ verse = 1;
+
+ error = 0;
+
+ if (keytext) {
+ ListKey tmpListKey = VerseKey::ParseVerseList(keytext);
+ if (tmpListKey.Count()) {
+ SWKey::setText((const char *)tmpListKey);
+ for (testament = 1; testament < 3; testament++) {
+ for (book = 1; book <= BMAX[testament-1]; book++) {
+ if (!strncmp(keytext, books[testament-1][book-1].name, strlen(books[testament-1][book-1].name)))
+ break;
+ }
+ if (book <= BMAX[testament-1])
+ break;
+ }
+
+ if (testament < 3) {
+ sscanf(&keytext[strlen(books[testament-1][book-1].name)], "%d:%d", &chapter, &verse);
+ }
+ else error = 1;
+ }
+ }
+ Normalize(1);
+ freshtext();
+
+ return error;
+}
+
+
+/******************************************************************************
+ * VerseKey::freshtext - refreshes keytext based on
+ * testament|book|chapter|verse
+ */
+
+void VerseKey::freshtext() const
+{
+ char buf[2024];
+ int realtest = testament;
+ int realbook = book;
+
+ if (book < 1) {
+ if (testament < 1)
+ sprintf(buf, "[ Module Heading ]");
+ else sprintf(buf, "[ Testament %d Heading ]", (int)testament);
+ }
+ else {
+ if (realbook > BMAX[realtest-1]) {
+ realbook -= BMAX[realtest-1];
+ if (realtest < 2)
+ realtest++;
+ if (realbook > BMAX[realtest-1])
+ realbook = BMAX[realtest-1];
+ }
+ sprintf(buf, "%s %d:%d", books[realtest-1][realbook-1].name, chapter, verse);
+ }
+
+ stdstr((char **)&keytext, buf);
+}
+
+
+
+/******************************************************************************
+ * VerseKey::getBookAbbrev - Attempts to find a book abbreviation for a buffer
+ *
+ * ENT: abbr - key for which to search;
+ * RET: book number or < 0 = not valid
+ */
+
+int VerseKey::getBookAbbrev(const char *iabbr)
+{
+ int loop, diff, abLen, min, max, target, retVal = -1;
+
+ char *abbr = 0;
+
+ stdstr(&abbr, iabbr);
+ strstrip(abbr);
+ abLen = strlen(abbr);
+ for (loop = 0; loop < abLen; loop++)
+ abbr[loop] = SW_toupper(abbr[loop]);
+
+ if (abLen) {
+ min = 0;
+// max = abbrevsCnt - 1;
+ max = abbrevsCnt;
+ while(1) {
+ target = min + ((max - min) / 2);
+ diff = strncmp(abbr, abbrevs[target].ab, abLen);
+ if ((!diff)||(target >= max)||(target <= min))
+ break;
+ if (diff > 0)
+ min = target;
+ else max = target;
+ }
+ for (; target > 0; target--) {
+ if (strncmp(abbr, abbrevs[target-1].ab, abLen))
+ break;
+ }
+
+ retVal = (!diff) ? abbrevs[target].book : -1;
+ }
+ delete [] abbr;
+ return retVal;
+}
+
+/******************************************************************************
+ * VerseKey::ParseVerseList - Attempts to parse a buffer into separate
+ * verse entries returned in a ListKey
+ *
+ * ENT: buf - buffer to parse;
+ * defaultKey - if verse, chap, book, or testament is left off,
+ * pull info from this key (ie. Gen 2:3; 4:5;
+ * Gen would be used when parsing the 4:5 section)
+ * expandRange - whether or not to expand eg. John 1:10-12 or just
+ * save John 1:10
+ *
+ * RET: ListKey reference filled with verse entries contained in buf
+ *
+ * COMMENT: This code works but wreaks. Rewrite to make more maintainable.
+ */
+
+ListKey VerseKey::ParseVerseList(const char *buf, const char *defaultKey, bool expandRange) {
+ SWKey textkey;
+
+ char book[255];
+ char number[255];
+ int tobook = 0;
+ int tonumber = 0;
+ int chap = -1, verse = -1;
+ int bookno = 0;
+ VerseKey curkey, lBound;
+ curkey.setLocale(getLocale());
+ lBound.setLocale(getLocale());
+ int loop;
+ char comma = 0;
+ char dash = 0;
+ const char *orig = buf;
+ ListKey tmpListKey;
+ ListKey internalListKey;
+ SWKey tmpDefaultKey = defaultKey;
+ char lastPartial = 0;
+
+ curkey.AutoNormalize(0);
+ tmpListKey << tmpDefaultKey;
+
+ while (*buf) {
+ switch (*buf) {
+ case ':':
+ number[tonumber] = 0;
+ tonumber = 0;
+ if (*number)
+ chap = atoi(number);
+ *number = 0;
+ break;
+
+ case '-':
+ case ',': // on number new verse
+ case ';': // on number new chapter
+ number[tonumber] = 0;
+ tonumber = 0;
+ if (*number) {
+ if (chap >= 0)
+ verse = atoi(number);
+ else chap = atoi(number);
+ }
+ *number = 0;
+ book[tobook] = 0;
+ tobook = 0;
+ bookno = -1;
+ if (*book) {
+ for (loop = strlen(book) - 1; loop+1; loop--) {
+ if ((isdigit(book[loop])) || (book[loop] == ' ')) {
+ book[loop] = 0;
+ continue;
+ }
+ else {
+ if ((SW_toupper(book[loop])=='F')&&(loop)) {
+ if ((isdigit(book[loop-1])) || (book[loop-1] == ' ') || (SW_toupper(book[loop-1]) == 'F')) {
+ book[loop] = 0;
+ continue;
+ }
+ }
+ }
+ break;
+ }
+
+ for (loop = strlen(book) - 1; loop+1; loop--) {
+ if (book[loop] == ' ') {
+ if (isroman(&book[loop+1])) {
+ if (verse == -1) {
+ verse = chap;
+ chap = from_rom(&book[loop+1]);
+ book[loop] = 0;
+ }
+ }
+ break;
+ }
+ }
+
+ if ((!stricmp(book, "V")) || (!stricmp(book, "VER"))) { // Verse abbrev
+ if (verse == -1) {
+ verse = chap;
+ chap = VerseKey(tmpListKey).Chapter();
+ *book = 0;
+ }
+ }
+ bookno = getBookAbbrev(book);
+ }
+ if (((bookno > -1) || (!*book)) && ((*book) || (chap >= 0) || (verse >= 0))) {
+ char partial = 0;
+ curkey.Verse(1);
+ curkey.Chapter(1);
+ curkey.Book(1);
+
+ if (bookno < 0) {
+ curkey.Testament(VerseKey(tmpListKey).Testament());
+ curkey.Book(VerseKey(tmpListKey).Book());
+ }
+ else {
+ curkey.Testament(1);
+ curkey.Book(bookno);
+ }
+
+ if (((comma)||((verse < 0)&&(bookno < 0)))&&(!lastPartial)) {
+// if (comma) {
+ curkey.Chapter(VerseKey(tmpListKey).Chapter());
+ curkey.Verse(chap); // chap because this is the first number captured
+ }
+ else {
+ if (chap >= 0) {
+ curkey.Chapter(chap);
+ }
+ else {
+ partial++;
+ curkey.Chapter(1);
+ }
+ if (verse >= 0) {
+ curkey.Verse(verse);
+ }
+ else {
+ partial++;
+ curkey.Verse(1);
+ }
+ }
+
+ if ((*buf == '-') && (expandRange)) { // if this is a dash save lowerBound and wait for upper
+ VerseKey newElement;
+ newElement.LowerBound(curkey);
+ newElement.setPosition(TOP);
+ tmpListKey << newElement;
+ }
+ else {
+ if (!dash) { // if last separator was not a dash just add
+ if (expandRange && partial) {
+ VerseKey newElement;
+ newElement.LowerBound(curkey);
+ if (partial > 1)
+ curkey.setPosition(MAXCHAPTER);
+ if (partial > 0)
+ curkey = MAXVERSE;
+ newElement.UpperBound(curkey);
+ newElement = TOP;
+ tmpListKey << newElement;
+ }
+ else tmpListKey << (const SWKey &)(const SWKey)(const char *)curkey;
+ }
+ else if (expandRange) {
+ VerseKey *newElement = SWDYNAMIC_CAST(VerseKey, tmpListKey.GetElement());
+ if (newElement) {
+ if (partial > 1)
+ curkey = MAXCHAPTER;
+ if (partial > 0)
+ curkey = MAXVERSE;
+ newElement->UpperBound(curkey);
+ *newElement = TOP;
+ }
+ }
+ }
+ lastPartial = partial;
+ }
+ *book = 0;
+ chap = -1;
+ verse = -1;
+ if (*buf == ',')
+ comma = 1;
+ else comma = 0;
+ if (*buf == '-')
+ dash = 1;
+ else dash = 0;
+ break;
+ case 10: // ignore these
+ case 13:
+ break;
+ case '.':
+ if (buf > orig) // ignore (break) if preceeding char is not a digit
+ if (!isdigit(*(buf-1)))
+ break;
+
+ default:
+ if (isdigit(*buf)) {
+ number[tonumber++] = *buf;
+ }
+ else {
+ switch (*buf) {
+ case ' ': // ignore these and don't reset number
+ case 'f':
+ case 'F':
+ break;
+ default:
+ number[tonumber] = 0;
+ tonumber = 0;
+ break;
+ }
+ }
+ if (chap == -1)
+ book[tobook++] = SW_toupper(*buf);
+ }
+ buf++;
+ }
+ number[tonumber] = 0;
+ tonumber = 0;
+ if (*number) {
+ if (chap >= 0)
+ verse = atoi(number);
+ else chap = atoi(number);
+ }
+ *number = 0;
+ book[tobook] = 0;
+ tobook = 0;
+ if (*book) {
+ for (loop = strlen(book) - 1; loop+1; loop--) {
+ if ((isdigit(book[loop])) || (book[loop] == ' ')) {
+ book[loop] = 0;
+ continue;
+ }
+ else {
+ if ((SW_toupper(book[loop])=='F')&&(loop)) {
+ if ((isdigit(book[loop-1])) || (book[loop-1] == ' ') || (SW_toupper(book[loop-1]) == 'F')) {
+ book[loop] = 0;
+ continue;
+ }
+ }
+ }
+ break;
+ }
+
+ for (loop = strlen(book) - 1; loop+1; loop--) {
+ if (book[loop] == ' ') {
+ if (isroman(&book[loop+1])) {
+ if (verse == -1) {
+ verse = chap;
+ chap = from_rom(&book[loop+1]);
+ book[loop] = 0;
+ }
+ }
+ break;
+ }
+ }
+
+ if ((!stricmp(book, "V")) || (!stricmp(book, "VER"))) { // Verse abbrev.
+ if (verse == -1) {
+ verse = chap;
+ chap = VerseKey(tmpListKey).Chapter();
+ *book = 0;
+ }
+ }
+
+ bookno = getBookAbbrev(book);
+ }
+ if (((bookno > -1) || (!*book)) && ((*book) || (chap >= 0) || (verse >= 0))) {
+ char partial = 0;
+ curkey.Verse(1);
+ curkey.Chapter(1);
+ curkey.Book(1);
+
+ if (bookno < 0) {
+ curkey.Testament(VerseKey(tmpListKey).Testament());
+ curkey.Book(VerseKey(tmpListKey).Book());
+ }
+ else {
+ curkey.Testament(1);
+ curkey.Book(bookno);
+ }
+
+ if (((comma)||((verse < 0)&&(bookno < 0)))&&(!lastPartial)) {
+// if (comma) {
+ curkey.Chapter(VerseKey(tmpListKey).Chapter());
+ curkey.Verse(chap); // chap because this is the first number captured
+ }
+ else {
+ if (chap >= 0) {
+ curkey.Chapter(chap);
+ }
+ else {
+ partial++;
+ curkey.Chapter(1);
+ }
+ if (verse >= 0) {
+ curkey.Verse(verse);
+ }
+ else {
+ partial++;
+ curkey.Verse(1);
+ }
+ }
+
+ if ((*buf == '-') && (expandRange)) { // if this is a dash save lowerBound and wait for upper
+ VerseKey newElement;
+ newElement.LowerBound(curkey);
+ newElement = TOP;
+ tmpListKey << newElement;
+ }
+ else {
+ if (!dash) { // if last separator was not a dash just add
+ if (expandRange && partial) {
+ VerseKey newElement;
+ newElement.LowerBound(curkey);
+ if (partial > 1)
+ curkey = MAXCHAPTER;
+ if (partial > 0)
+ curkey = MAXVERSE;
+ newElement.UpperBound(curkey);
+ newElement = TOP;
+ tmpListKey << newElement;
+ }
+ else tmpListKey << (const SWKey &)(const SWKey)(const char *)curkey;
+ }
+ else if (expandRange) {
+ VerseKey *newElement = SWDYNAMIC_CAST(VerseKey, tmpListKey.GetElement());
+ if (newElement) {
+ if (partial > 1)
+ curkey = MAXCHAPTER;
+ if (partial > 0)
+ curkey = MAXVERSE;
+ newElement->UpperBound(curkey);
+ *newElement = TOP;
+ }
+ }
+ }
+ }
+ *book = 0;
+ tmpListKey = TOP;
+ tmpListKey.Remove(); // remove defaultKey
+ internalListKey = tmpListKey;
+ internalListKey = TOP; // Align internalListKey to first element before passing back;
+
+ return internalListKey;
+}
+
+
+/******************************************************************************
+ * VerseKey::LowerBound - sets / gets the lower boundary for this key
+ */
+
+VerseKey &VerseKey::LowerBound(const char *lb)
+{
+ if (!lowerBound)
+ initBounds();
+
+ (*lowerBound) = lb;
+ lowerBound->Normalize();
+
+ return (*lowerBound);
+}
+
+
+/******************************************************************************
+ * VerseKey::UpperBound - sets / gets the upper boundary for this key
+ */
+
+VerseKey &VerseKey::UpperBound(const char *ub)
+{
+ if (!upperBound)
+ initBounds();
+
+// need to set upperbound parsing to resolve to max verse/chap if not specified
+ (*upperBound) = ub;
+ if (*upperBound < *lowerBound)
+ *upperBound = *lowerBound;
+ upperBound->Normalize();
+
+// until we have a proper method to resolve max verse/chap use this kludge
+ int len = strlen(ub);
+ bool alpha = false;
+ bool versespec = false;
+ bool chapspec = false;
+ for (int i = 0; i < len; i++) {
+ if (isalpha(ub[i]))
+ alpha = true;
+ if (ub[i] == ':') // if we have a : we assume verse spec
+ versespec = true;
+ if ((isdigit(ub[i])) && (alpha)) // if digit after alpha assume chap spec
+ chapspec = true;
+ }
+ if (!chapspec)
+ *upperBound = MAXCHAPTER;
+ if (!versespec)
+ *upperBound = MAXVERSE;
+
+
+// -- end kludge
+
+ return (*upperBound);
+}
+
+
+/******************************************************************************
+ * VerseKey::LowerBound - sets / gets the lower boundary for this key
+ */
+
+VerseKey &VerseKey::LowerBound() const
+{
+ if (!lowerBound)
+ initBounds();
+
+ return (*lowerBound);
+}
+
+
+/******************************************************************************
+ * VerseKey::UpperBound - sets / gets the upper boundary for this key
+ */
+
+VerseKey &VerseKey::UpperBound() const
+{
+ if (!upperBound)
+ initBounds();
+
+ return (*upperBound);
+}
+
+
+/******************************************************************************
+ * VerseKey::ClearBounds - clears bounds for this VerseKey
+ */
+
+void VerseKey::ClearBounds()
+{
+ initBounds();
+}
+
+
+void VerseKey::initBounds() const
+{
+ if (!upperBound) {
+ upperBound = new VerseKey();
+ upperBound->AutoNormalize(0);
+ upperBound->Headings(1);
+ }
+ if (!lowerBound) {
+ lowerBound = new VerseKey();
+ lowerBound->AutoNormalize(0);
+ lowerBound->Headings(1);
+ }
+
+ lowerBound->Testament(0);
+ lowerBound->Book(0);
+ lowerBound->Chapter(0);
+ lowerBound->Verse(0);
+
+ upperBound->Testament(2);
+ upperBound->Book(BMAX[1]);
+ upperBound->Chapter(books[1][BMAX[1]-1].chapmax);
+ upperBound->Verse(books[1][BMAX[1]-1].versemax[upperBound->Chapter()-1]);
+}
+
+
+/******************************************************************************
+ * VerseKey::copyFrom - Equates this VerseKey to another VerseKey
+ */
+
+void VerseKey::copyFrom(const VerseKey &ikey) {
+ SWKey::copyFrom(ikey);
+
+ parse();
+}
+
+
+/******************************************************************************
+ * VerseKey::copyFrom - Equates this VerseKey to another SWKey
+ */
+
+void VerseKey::copyFrom(const SWKey &ikey) {
+ SWKey::copyFrom(ikey);
+
+ parse();
+}
+
+
+/******************************************************************************
+ * VerseKey::getText - refreshes keytext before returning if cast to
+ * a (char *) is requested
+ */
+
+const char *VerseKey::getText() const {
+ freshtext();
+ return keytext;
+}
+
+
+const char *VerseKey::getShortText() const {
+ static char *stext = 0;
+ char buf[2047];
+ freshtext();
+ if (book < 1) {
+ if (testament < 1)
+ sprintf(buf, "[ Module Heading ]");
+ else sprintf(buf, "[ Testament %d Heading ]", (int)testament);
+ }
+ else {
+ sprintf(buf, "%s %d:%d", books[testament-1][book-1].prefAbbrev, chapter, verse);
+ }
+ stdstr(&stext, buf);
+ return stext;
+}
+
+
+const char *VerseKey::getBookName() const {
+ return books[testament-1][book-1].name;
+}
+
+
+const char *VerseKey::getBookAbbrev() const {
+ return books[testament-1][book-1].prefAbbrev;
+}
+/******************************************************************************
+ * VerseKey::setPosition(SW_POSITION) - Positions this key
+ *
+ * ENT: p - position
+ *
+ * RET: *this
+ */
+
+void VerseKey::setPosition(SW_POSITION p) {
+ switch (p) {
+ case POS_TOP:
+ testament = LowerBound().Testament();
+ book = LowerBound().Book();
+ chapter = LowerBound().Chapter();
+ verse = LowerBound().Verse();
+ break;
+ case POS_BOTTOM:
+ testament = UpperBound().Testament();
+ book = UpperBound().Book();
+ chapter = UpperBound().Chapter();
+ verse = UpperBound().Verse();
+ break;
+ case POS_MAXVERSE:
+ Normalize();
+ verse = books[testament-1][book-1].versemax[chapter-1];
+ break;
+ case POS_MAXCHAPTER:
+ verse = 1;
+ Normalize();
+ chapter = books[testament-1][book-1].chapmax;
+ break;
+ }
+ Normalize(1);
+ Error(); // clear error from normalize
+}
+
+
+/******************************************************************************
+ * VerseKey::increment - Increments key a number of verses
+ *
+ * ENT: step - Number of verses to jump forward
+ *
+ * RET: *this
+ */
+
+void VerseKey::increment(int step) {
+ char ierror = 0;
+ Index(Index() + step);
+ while ((!verse) && (!headings) && (!ierror)) {
+ Index(Index() + 1);
+ ierror = Error();
+ }
+
+ error = (ierror) ? ierror : error;
+}
+
+
+/******************************************************************************
+ * VerseKey::decrement - Decrements key a number of verses
+ *
+ * ENT: step - Number of verses to jump backward
+ *
+ * RET: *this
+ */
+
+void VerseKey::decrement(int step) {
+ char ierror = 0;
+
+ Index(Index() - step);
+ while ((!verse) && (!headings) && (!ierror)) {
+ Index(Index() - 1);
+ ierror = Error();
+ }
+ if ((ierror) && (!headings))
+ (*this)++;
+
+ error = (ierror) ? ierror : error;
+}
+
+
+/******************************************************************************
+ * VerseKey::Normalize - checks limits and normalizes if necessary (e.g.
+ * Matthew 29:47 = Mark 2:2). If last verse is
+ * exceeded, key is set to last Book CH:VS
+ * RET: *this
+ */
+
+void VerseKey::Normalize(char autocheck)
+{
+ error = 0;
+
+ if ((autocheck) && (!autonorm)) // only normalize if we were explicitely called or if autonorm is turned on
+ return;
+
+ if ((headings) && (!verse)) // this is cheeze and temporary until deciding what actions should be taken.
+ return; // so headings should only be turned on when positioning with Index() or incrementors
+
+ while ((testament < 3) && (testament > 0)) {
+
+ if (book > BMAX[testament-1]) {
+ book -= BMAX[testament-1];
+ testament++;
+ continue;
+ }
+
+ if (book < 1) {
+ if (--testament > 0) {
+ book += BMAX[testament-1];
+ }
+ continue;
+ }
+
+ if (chapter > books[testament-1][book-1].chapmax) {
+ chapter -= books[testament-1][book-1].chapmax;
+ book++;
+ continue;
+ }
+
+ if (chapter < 1) {
+ if (--book > 0) {
+ chapter += books[testament-1][book-1].chapmax;
+ }
+ else {
+ if (testament > 1) {
+ chapter += books[0][BMAX[0]-1].chapmax;
+ }
+ }
+ continue;
+ }
+
+ if (verse > books[testament-1][book-1].versemax[chapter-1]) { // -1 because e.g chapter 1 of Matthew is books[1][0].versemax[0]
+ verse -= books[testament-1][book-1].versemax[chapter++ - 1];
+ continue;
+ }
+
+ if (verse < 1) {
+ if (--chapter > 0) {
+ verse += books[testament-1][book-1].versemax[chapter-1];
+ }
+ else {
+ if (book > 1) {
+ verse += books[testament-1][book-2].versemax[books[testament-1][book-2].chapmax-1];
+ }
+ else {
+ if (testament > 1) {
+ verse += books[0][BMAX[0]-1].versemax[books[0][BMAX[0]-1].chapmax-1];
+ }
+ }
+ }
+ continue;
+ }
+
+ break; // If we've made it this far (all failure checks continue) we're ok
+ }
+
+ if (testament > 2) {
+ testament = 2;
+ book = BMAX[testament-1];
+ chapter = books[testament-1][book-1].chapmax;
+ verse = books[testament-1][book-1].versemax[chapter-1];
+ error = KEYERR_OUTOFBOUNDS;
+ }
+
+ if (testament < 1) {
+ error = ((!headings) || (testament < 0) || (book < 0)) ? KEYERR_OUTOFBOUNDS : 0;
+ testament = ((headings) ? 0 : 1);
+ book = ((headings) ? 0 : 1);
+ chapter = ((headings) ? 0 : 1);
+ verse = ((headings) ? 0 : 1);
+ }
+ if (_compare(UpperBound()) > 0) {
+ *this = UpperBound();
+ error = KEYERR_OUTOFBOUNDS;
+ }
+ if (_compare(LowerBound()) < 0) {
+ *this = LowerBound();
+ error = KEYERR_OUTOFBOUNDS;
+ }
+}
+
+
+/******************************************************************************
+ * VerseKey::Testament - Gets testament
+ *
+ * RET: value of testament
+ */
+
+char VerseKey::Testament() const
+{
+ return testament;
+}
+
+
+/******************************************************************************
+ * VerseKey::Book - Gets book
+ *
+ * RET: value of book
+ */
+
+char VerseKey::Book() const
+{
+ return book;
+}
+
+
+/******************************************************************************
+ * VerseKey::Chapter - Gets chapter
+ *
+ * RET: value of chapter
+ */
+
+int VerseKey::Chapter() const
+{
+ return chapter;
+}
+
+
+/******************************************************************************
+ * VerseKey::Verse - Gets verse
+ *
+ * RET: value of verse
+ */
+
+int VerseKey::Verse() const
+{
+ return verse;
+}
+
+
+/******************************************************************************
+ * VerseKey::Testament - Sets/gets testament
+ *
+ * ENT: itestament - value which to set testament
+ * [MAXPOS(char)] - only get
+ *
+ * RET: if unchanged -> value of testament
+ * if changed -> previous value of testament
+ */
+
+char VerseKey::Testament(char itestament)
+{
+ char retval = testament;
+
+ if (itestament != MAXPOS(char)) {
+ testament = itestament;
+ Normalize(1);
+ }
+ return retval;
+}
+
+
+/******************************************************************************
+ * VerseKey::Book - Sets/gets book
+ *
+ * ENT: ibook - value which to set book
+ * [MAXPOS(char)] - only get
+ *
+ * RET: if unchanged -> value of book
+ * if changed -> previous value of book
+ */
+
+char VerseKey::Book(char ibook)
+{
+ char retval = book;
+
+ Chapter(1);
+ book = ibook;
+ Normalize(1);
+
+ return retval;
+}
+
+
+/******************************************************************************
+ * VerseKey::Chapter - Sets/gets chapter
+ *
+ * ENT: ichapter - value which to set chapter
+ * [MAXPOS(int)] - only get
+ *
+ * RET: if unchanged -> value of chapter
+ * if changed -> previous value of chapter
+ */
+
+int VerseKey::Chapter(int ichapter)
+{
+ int retval = chapter;
+
+ Verse(1);
+ chapter = ichapter;
+ Normalize(1);
+
+ return retval;
+}
+
+
+/******************************************************************************
+ * VerseKey::Verse - Sets/gets verse
+ *
+ * ENT: iverse - value which to set verse
+ * [MAXPOS(int)] - only get
+ *
+ * RET: if unchanged -> value of verse
+ * if changed -> previous value of verse
+ */
+
+int VerseKey::Verse(int iverse)
+{
+ int retval = verse;
+
+ verse = iverse;
+ Normalize(1);
+
+ return retval;
+}
+
+
+/******************************************************************************
+ * VerseKey::AutoNormalize - Sets/gets flag that tells VerseKey to auto-
+ * matically normalize itself when modified
+ *
+ * ENT: iautonorm - value which to set autonorm
+ * [MAXPOS(char)] - only get
+ *
+ * RET: if unchanged -> value of autonorm
+ * if changed -> previous value of autonorm
+ */
+
+char VerseKey::AutoNormalize(char iautonorm)
+{
+ char retval = autonorm;
+
+ if (iautonorm != MAXPOS(char)) {
+ autonorm = iautonorm;
+ Normalize(1);
+ }
+ return retval;
+}
+
+
+/******************************************************************************
+ * VerseKey::Headings - Sets/gets flag that tells VerseKey to include
+ * chap/book/testmnt/module headings
+ *
+ * ENT: iheadings - value which to set headings
+ * [MAXPOS(char)] - only get
+ *
+ * RET: if unchanged -> value of headings
+ * if changed -> previous value of headings
+ */
+
+char VerseKey::Headings(char iheadings)
+{
+ char retval = headings;
+
+ if (iheadings != MAXPOS(char)) {
+ headings = iheadings;
+ Normalize(1);
+ }
+ return retval;
+}
+
+
+/******************************************************************************
+ * VerseKey::findindex - binary search to find the index closest, but less
+ * than the given value.
+ *
+ * ENT: array - long * to array to search
+ * size - number of elements in the array
+ * value - value to find
+ *
+ * RET: the index into the array that is less than but closest to value
+ */
+
+int VerseKey::findindex(long *array, int size, long value)
+{
+ int lbound, ubound, tval;
+
+ lbound = 0;
+ ubound = size - 1;
+ while ((ubound - lbound) > 1) {
+ tval = lbound + (ubound-lbound)/2;
+ if (array[tval] <= value)
+ lbound = tval;
+ else ubound = tval;
+ }
+ return (array[ubound] <= value) ? ubound : lbound;
+}
+
+
+/******************************************************************************
+ * VerseKey::Index - Gets index based upon current verse
+ *
+ * RET: offset
+ */
+
+long VerseKey::Index() const
+{
+ long offset;
+
+ if (!testament) { // if we want module heading
+ offset = 0;
+ verse = 0;
+ }
+ else {
+ if (!book)
+ chapter = 0;
+ if (!chapter)
+ verse = 0;
+
+ offset = offsets[testament-1][0][book];
+ offset = offsets[testament-1][1][(int)offset + chapter];
+ if (!(offset|verse)) // if we have a testament but nothing else.
+ offset = 1;
+ }
+ return (offset + verse);
+}
+
+
+/******************************************************************************
+ * VerseKey::Index - Gets index based upon current verse
+ *
+ * RET: offset
+ */
+
+long VerseKey::NewIndex() const
+{
+ static long otMaxIndex = 32300 - 8245; // total positions - new testament positions
+// static long otMaxIndex = offsets[0][1][(int)offsets[0][0][BMAX[0]] + books[0][BMAX[0]].chapmax];
+ return ((testament-1) * otMaxIndex) + Index();
+}
+
+
+/******************************************************************************
+ * VerseKey::Index - Sets index based upon current verse
+ *
+ * ENT: iindex - value to set index to
+ *
+ * RET: offset
+ */
+
+long VerseKey::Index(long iindex)
+{
+ long offset;
+
+// This is the dirty stuff --------------------------------------------
+
+ if (!testament)
+ testament = 1;
+
+ if (iindex < 1) { // if (-) or module heading
+ if (testament < 2) {
+ if (iindex < 0) {
+ testament = 0; // previously we changed 0 -> 1
+ error = KEYERR_OUTOFBOUNDS;
+ }
+ else testament = 0; // we want module heading
+ }
+ else {
+ testament--;
+ iindex = (offsets[testament-1][1][offsize[testament-1][1]-1] + books[testament-1][BMAX[testament-1]-1].versemax[books[testament-1][BMAX[testament-1]-1].chapmax-1]) + iindex; // What a doozy! ((offset of last chapter + number of verses in the last chapter) + iindex)
+ }
+ }
+
+// --------------------------------------------------------------------
+
+
+ if (testament) {
+ if ((!error) && (iindex)) {
+ offset = findindex(offsets[testament-1][1], offsize[testament-1][1], iindex);
+ verse = iindex - offsets[testament-1][1][offset];
+ book = findindex(offsets[testament-1][0], offsize[testament-1][0], offset);
+ chapter = offset - offsets[testament-1][0][VerseKey::book];
+ verse = (chapter) ? verse : 0; // funny check. if we are index=1 (testmt header) all gets set to 0 exept verse. Don't know why. Fix if you figure out. Think its in the offsets table.
+ if (verse) { // only check if -1 won't give negative
+ if (verse > books[testament-1][book-1].versemax[chapter-1]) {
+ if (testament > 1) {
+ verse = books[testament-1][book-1].versemax[chapter-1];
+ error = KEYERR_OUTOFBOUNDS;
+ }
+ else {
+ testament++;
+ Index(verse - books[testament-2][book-1].versemax[chapter-1]);
+ }
+ }
+ }
+ }
+ }
+ if (_compare(UpperBound()) > 0) {
+ *this = UpperBound();
+ error = KEYERR_OUTOFBOUNDS;
+ }
+ if (_compare(LowerBound()) < 0) {
+ *this = LowerBound();
+ error = KEYERR_OUTOFBOUNDS;
+ }
+ return Index();
+}
+
+
+/******************************************************************************
+ * VerseKey::compare - Compares another SWKey object
+ *
+ * ENT: ikey - key to compare with this one
+ *
+ * RET: >0 if this versekey is greater than compare versekey
+ * <0 <
+ * 0 =
+ */
+
+int VerseKey::compare(const SWKey &ikey)
+{
+ VerseKey ivkey = (const char *)ikey;
+ return _compare(ivkey);
+}
+
+
+/******************************************************************************
+ * VerseKey::_compare - Compares another VerseKey object
+ *
+ * ENT: ikey - key to compare with this one
+ *
+ * RET: >0 if this versekey is greater than compare versekey
+ * <0 <
+ * 0 =
+ */
+
+int VerseKey::_compare(const VerseKey &ivkey)
+{
+ long keyval1 = 0;
+ long keyval2 = 0;
+
+ keyval1 += Testament() * 1000000000;
+ keyval2 += ivkey.Testament() * 1000000000;
+ keyval1 += Book() * 1000000;
+ keyval2 += ivkey.Book() * 1000000;
+ keyval1 += Chapter() * 1000;
+ keyval2 += ivkey.Chapter() * 1000;
+ keyval1 += Verse();
+ keyval2 += ivkey.Verse();
+ keyval1 -= keyval2;
+ keyval1 = (keyval1) ? ((keyval1 > 0) ? 1 : -1) /*keyval1/labs(keyval1)*/:0; // -1 | 0 | 1
+ return keyval1;
+}
diff --git a/src/mgr/Makefile b/src/mgr/Makefile
new file mode 100644
index 0000000..339f87a
--- /dev/null
+++ b/src/mgr/Makefile
@@ -0,0 +1,4 @@
+root := ../..
+
+all:
+ make -C ${root}
diff --git a/src/mgr/Makefile.am b/src/mgr/Makefile.am
new file mode 100644
index 0000000..e312702
--- /dev/null
+++ b/src/mgr/Makefile.am
@@ -0,0 +1,19 @@
+mgrdir = $(top_srcdir)/src/mgr
+
+if CONFDEF
+globdef = -DGLOBCONFPATH=\"${globalconfdir}/sword.conf\"
+else
+globdef =
+endif
+
+DEFS += $(globdef)
+
+libsword_la_SOURCES += $(mgrdir)/swconfig.cpp
+libsword_la_SOURCES += $(mgrdir)/swmgr.cpp
+libsword_la_SOURCES += $(mgrdir)/swfiltermgr.cpp
+libsword_la_SOURCES += $(mgrdir)/encfiltmgr.cpp
+libsword_la_SOURCES += $(mgrdir)/markupfiltmgr.cpp
+libsword_la_SOURCES += $(mgrdir)/filemgr.cpp
+libsword_la_SOURCES += $(mgrdir)/swlocale.cpp
+libsword_la_SOURCES += $(mgrdir)/localemgr.cpp
+libsword_la_SOURCES += $(mgrdir)/swcacher.cpp
diff --git a/src/mgr/encfiltmgr.cpp b/src/mgr/encfiltmgr.cpp
new file mode 100644
index 0000000..ab55de9
--- /dev/null
+++ b/src/mgr/encfiltmgr.cpp
@@ -0,0 +1,148 @@
+/******************************************************************************
+ * swencodingmgr.cpp - implementaion of class EncodingFilterMgr, subclass of
+ * used to transcode all module text to a requested
+ * encoding.
+ *
+ * Copyright 1998 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 <encfiltmgr.h>
+
+#include <scsuutf8.h>
+#include <latin1utf8.h>
+
+#include <unicodertf.h>
+#include <utf8latin1.h>
+#include <utf8utf16.h>
+#include <utf8html.h>
+
+#include <swmgr.h>
+
+/******************************************************************************
+ * EncodingFilterMgr Constructor - initializes instance of EncodingFilterMgr
+ *
+ * ENT:
+ * enc - Encoding format to emit
+ */
+
+EncodingFilterMgr::EncodingFilterMgr (char enc)
+ : SWFilterMgr() {
+
+ scsuutf8 = new SCSUUTF8();
+ latin1utf8 = new Latin1UTF8();
+
+ encoding = enc;
+
+ switch (encoding) {
+ case ENC_LATIN1:
+ targetenc = new UTF8Latin1();
+ break;
+ case ENC_UTF16:
+ targetenc = new UTF8UTF16();
+ break;
+ case ENC_RTF:
+ targetenc = new UnicodeRTF();
+ break;
+ case ENC_HTML:
+ targetenc = new UTF8HTML();
+ break;
+ default: // i.e. case ENC_UTF8
+ targetenc = NULL;
+ }
+}
+
+/******************************************************************************
+ * EncodingFilterMgr Destructor - Cleans up instance of EncodingFilterMgr
+ */
+EncodingFilterMgr::~EncodingFilterMgr() {
+ if (scsuutf8)
+ delete scsuutf8;
+ if (latin1utf8)
+ delete latin1utf8;
+ if (targetenc)
+ delete targetenc;
+}
+
+void EncodingFilterMgr::AddRawFilters(SWModule *module, ConfigEntMap &section) {
+
+ ConfigEntMap::iterator entry;
+
+ string encoding = ((entry = section.find("Encoding")) != section.end()) ? (*entry).second : (string)"";
+ if (encoding.empty() || !stricmp(encoding.c_str(), "Latin-1")) {
+ module->AddRawFilter(latin1utf8);
+ }
+ else if (!stricmp(encoding.c_str(), "SCSU")) {
+ module->AddRawFilter(scsuutf8);
+ }
+}
+
+void EncodingFilterMgr::AddEncodingFilters(SWModule *module, ConfigEntMap &section) {
+ if (targetenc)
+ module->AddEncodingFilter(targetenc);
+}
+
+/******************************************************************************
+ * EncodingFilterMgr::Encoding - sets/gets encoding
+ *
+ * ENT: enc - new encoding or 0 to simply get the current encoding
+ *
+ * RET: encoding
+ */
+char EncodingFilterMgr::Encoding(char enc) {
+ if (enc && enc != encoding) {
+ encoding = enc;
+ SWFilter * oldfilter = targetenc;
+
+ switch (encoding) {
+ case ENC_LATIN1:
+ targetenc = new UTF8Latin1();
+ break;
+ case ENC_UTF16:
+ targetenc = new UTF8UTF16();
+ break;
+ case ENC_RTF:
+ targetenc = new UnicodeRTF();
+ break;
+ case ENC_HTML:
+ targetenc = new UTF8HTML();
+ break;
+ default: // i.e. case ENC_UTF8
+ targetenc = NULL;
+ }
+
+ ModMap::const_iterator module;
+
+ if (oldfilter != targetenc) {
+ if (oldfilter) {
+ if (!targetenc) {
+ for (module = getParentMgr()->Modules.begin(); module != getParentMgr()->Modules.end(); module++)
+ module->second->RemoveRenderFilter(oldfilter);
+ }
+ else {
+ for (module = getParentMgr()->Modules.begin(); module != getParentMgr()->Modules.end(); module++)
+ module->second->ReplaceRenderFilter(oldfilter, targetenc);
+ }
+ delete oldfilter;
+ }
+ else if (targetenc) {
+ for (module = getParentMgr()->Modules.begin(); module != getParentMgr()->Modules.end(); module++)
+ module->second->AddRenderFilter(targetenc);
+ }
+ }
+
+ }
+ return encoding;
+}
diff --git a/src/mgr/filemgr.cpp b/src/mgr/filemgr.cpp
new file mode 100644
index 0000000..e380514
--- /dev/null
+++ b/src/mgr/filemgr.cpp
@@ -0,0 +1,264 @@
+/******************************************************************************
+ * filemgr.cpp - implementation of class FileMgr used for pooling file
+ * handles
+ *
+ * $Id: filemgr.cpp,v 1.21 2002/03/16 17:34:41 scribe Exp $
+ *
+ * Copyright 1998 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 <filemgr.h>
+#include <utilstr.h>
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef __GNUC__
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+// ---------------- statics -----------------
+FileMgr FileMgr::systemFileMgr;
+
+// --------------- end statics --------------
+
+
+FileDesc::FileDesc(FileMgr *parent, char *path, int mode, int perms, bool tryDowngrade) {
+ this->parent = parent;
+ this->path = 0;
+ stdstr(&this->path, path);
+ this->mode = mode;
+ this->perms = perms;
+ this->tryDowngrade = tryDowngrade;
+ offset = 0;
+ fd = -77;
+}
+
+
+FileDesc::~FileDesc() {
+ if (fd > 0)
+ close(fd);
+
+ if (path)
+ delete [] path;
+}
+
+
+int FileDesc::getFd() {
+ if (fd == -77)
+ fd = parent->sysOpen(this);
+ return fd;
+}
+
+
+FileMgr::FileMgr(int maxFiles) {
+ this->maxFiles = maxFiles; // must be at least 2
+ files = 0;
+}
+
+
+FileMgr::~FileMgr() {
+ FileDesc *tmp;
+
+ while(files) {
+ tmp = files->next;
+ delete files;
+ files = tmp;
+ }
+}
+
+
+FileDesc *FileMgr::open(char *path, int mode, bool tryDowngrade) {
+ return open(path, mode, S_IREAD | S_IWRITE, tryDowngrade);
+}
+
+FileDesc *FileMgr::open(char *path, int mode, int perms, bool tryDowngrade) {
+ FileDesc **tmp, *tmp2;
+
+ for (tmp = &files; *tmp; tmp = &((*tmp)->next)) {
+ if ((*tmp)->fd < 0) // insert as first non-system_open file
+ break;
+ }
+
+ tmp2 = new FileDesc(this, path, mode, perms, tryDowngrade);
+ tmp2->next = *tmp;
+ *tmp = tmp2;
+
+ return tmp2;
+}
+
+
+void FileMgr::close(FileDesc *file) {
+ FileDesc **loop;
+
+ for (loop = &files; *loop; loop = &((*loop)->next)) {
+ if (*loop == file) {
+ *loop = (*loop)->next;
+ delete file;
+ break;
+ }
+ }
+}
+
+
+// to truncate a file at its current position
+// leaving byte at current possition intact
+// deleting everything afterward.
+signed char FileMgr::trunc(FileDesc *file) {
+
+ static const char *writeTest = "x";
+ long size = lseek(file->getFd(), 1, SEEK_CUR);
+ char nibble [ 32767 ];
+ bool writable = write(file->getFd(), writeTest, 1);
+ int bytes = 0;
+
+ if (writable) {
+ // get tmpfilename
+ char *buf = new char [ strlen(file->path) + 10 ];
+ int i;
+ for (i = 0; i < 9999; i++) {
+ sprintf(buf, "%stmp%.4d", file->path, i);
+ if (!existsFile(buf))
+ break;
+ }
+ if (i == 9999)
+ return -2;
+
+ int fd = ::open(buf, O_CREAT|O_RDWR, S_IREAD|S_IWRITE);
+ if (fd < 0)
+ return -3;
+
+ lseek(file->getFd(), 0, SEEK_SET);
+ while (size > 0) {
+ bytes = read(file->getFd(), nibble, 32767);
+ write(fd, nibble, (bytes < size)?bytes:size);
+ size -= bytes;
+ }
+ // zero out the file
+ ::close(file->fd);
+ file->fd = ::open(file->path, O_TRUNC, S_IREAD|S_IWRITE);
+ ::close(file->fd);
+ file->fd = -77; // force file open by filemgr
+ // copy tmp file back (dumb, but must preserve file permissions)
+ lseek(fd, 0, SEEK_SET);
+ do {
+ bytes = read(fd, nibble, 32767);
+ write(file->getFd(), nibble, bytes);
+ } while (bytes == 32767);
+
+ ::close(fd);
+ ::close(file->fd);
+ unlink(buf); // remove our tmp file
+ file->fd = -77; // causes file to be swapped out forcing open on next call to getFd()
+ }
+ else { // put offset back and return failure
+ lseek(file->getFd(), -1, SEEK_CUR);
+ return -1;
+ }
+ return 0;
+}
+
+
+int FileMgr::sysOpen(FileDesc *file) {
+ FileDesc **loop;
+ int openCount = 1; // because we are presently opening 1 file, and we need to be sure to close files to accomodate, if necessary
+
+ for (loop = &files; *loop; loop = &((*loop)->next)) {
+
+ if ((*loop)->fd > 0) {
+ if (++openCount > maxFiles) {
+ (*loop)->offset = lseek((*loop)->fd, 0, SEEK_CUR);
+ ::close((*loop)->fd);
+ (*loop)->fd = -77;
+ }
+ }
+
+ if (*loop == file) {
+ if (*loop != files) {
+ *loop = (*loop)->next;
+ file->next = files;
+ files = file;
+ }
+ if ((!access(file->path, 04)) || ((file->mode & O_CREAT) == O_CREAT)) { // check for at least file exists / read access before we try to open
+ char tries = (((file->mode & O_RDWR) == O_RDWR) && (file->tryDowngrade)) ? 2 : 1; // try read/write if possible
+ for (int i = 0; i < tries; i++) {
+ if (i > 0) {
+ file->mode = (file->mode & ~O_RDWR); // remove write access
+ file->mode = (file->mode | O_RDONLY);// add read access
+ }
+ file->fd = ::open(file->path, file->mode, file->perms);
+
+ if (file->fd >= 0)
+ break;
+ }
+
+ if (file->fd >= 0)
+ lseek(file->fd, file->offset, SEEK_SET);
+ }
+ else file->fd = -1;
+ if (!*loop)
+ break;
+ }
+ }
+ return file->fd;
+}
+
+
+signed char FileMgr::existsFile(const char *ipath, const char *ifileName)
+{
+ int len = strlen(ipath) + ((ifileName)?strlen(ifileName):0) + 3;
+ char *ch;
+ char *path = new char [ len ];
+ strcpy(path, ipath);
+
+ if ((path[strlen(path)-1] == '\\') || (path[strlen(path)-1] == '/'))
+ path[strlen(path)-1] = 0;
+
+ if (ifileName) {
+ ch = path + strlen(path);
+ sprintf(ch, "/%s", ifileName);
+ }
+ signed char retVal = !access(path, 04);
+ delete [] path;
+ return retVal;
+}
+
+
+signed char FileMgr::existsDir(const char *ipath, const char *idirName)
+{
+ char *ch;
+ int len = strlen(ipath) + ((idirName)?strlen(idirName):0) + 1;
+ if (idirName)
+ len += strlen(idirName);
+ char *path = new char [ len ];
+ strcpy(path, ipath);
+
+ if ((path[strlen(path)-1] == '\\') || (path[strlen(path)-1] == '/'))
+ path[strlen(path)-1] = 0;
+
+ if (idirName) {
+ ch = path + strlen(path);
+ sprintf(ch, "/%s", idirName);
+ }
+ signed char retVal = !access(path, 04);
+ delete [] path;
+ return retVal;
+}
diff --git a/src/mgr/localemgr.cpp b/src/mgr/localemgr.cpp
new file mode 100644
index 0000000..a21896d
--- /dev/null
+++ b/src/mgr/localemgr.cpp
@@ -0,0 +1,181 @@
+/******************************************************************************
+ * localemgr.cpp - implementation of class LocaleMgr used to interact with
+ * registered locales for a sword installation
+ *
+ * $Id: localemgr.cpp,v 1.11 2002/03/15 07:47:35 scribe Exp $
+ *
+ * Copyright 1998 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 <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#ifndef __GNUC__
+#include <io.h>
+#else
+#include <unistd.h>
+#include <unixstr.h>
+#endif
+#include <sys/stat.h>
+#include <dirent.h>
+
+#include <swmgr.h>
+#include <utilfuns.h>
+
+#include <localemgr.h>
+#include <filemgr.h>
+
+
+LocaleMgr LocaleMgr::systemLocaleMgr;
+
+
+LocaleMgr::LocaleMgr(const char *iConfigPath) {
+ char *prefixPath = 0;
+ char *configPath = 0;
+ char configType = 0;
+ string path;
+
+ defaultLocaleName = 0;
+
+ char *lang = getenv ("LANG");
+ if (lang) {
+ if (strlen(lang) > 0)
+ setDefaultLocaleName(lang);
+ else setDefaultLocaleName("en_us");
+ }
+ else setDefaultLocaleName("en_us");
+
+ if (!iConfigPath)
+ SWMgr::findConfig(&configType, &prefixPath, &configPath);
+ else configPath = (char *)iConfigPath;
+
+ if (prefixPath) {
+ switch (configType) {
+ case 2:
+ int i;
+ for (i = strlen(configPath)-1; ((i) && (configPath[i] != '/') && (configPath[i] != '\\')); i--);
+ configPath[i] = 0;
+ path = configPath;
+ path += "/";
+ break;
+ default:
+ path = prefixPath;
+ if ((prefixPath[strlen(prefixPath)-1] != '\\') && (prefixPath[strlen(prefixPath)-1] != '/'))
+ path += "/";
+
+ break;
+ }
+ if (FileMgr::existsDir(path.c_str(), "locales.d")) {
+ path += "locales.d";
+ loadConfigDir(path.c_str());
+ }
+ }
+
+ if (prefixPath)
+ delete [] prefixPath;
+
+ if (configPath)
+ delete [] configPath;
+}
+
+
+LocaleMgr::~LocaleMgr() {
+ if (defaultLocaleName)
+ delete [] defaultLocaleName;
+ deleteLocales();
+}
+
+
+void LocaleMgr::loadConfigDir(const char *ipath) {
+ DIR *dir;
+ struct dirent *ent;
+ string newmodfile;
+ LocaleMap::iterator it;
+
+ if ((dir = opendir(ipath))) {
+ rewinddir(dir);
+ while ((ent = readdir(dir))) {
+ if ((strcmp(ent->d_name, ".")) && (strcmp(ent->d_name, ".."))) {
+ newmodfile = ipath;
+ if ((ipath[strlen(ipath)-1] != '\\') && (ipath[strlen(ipath)-1] != '/'))
+ newmodfile += "/";
+ newmodfile += ent->d_name;
+ SWLocale *locale = new SWLocale(newmodfile.c_str());
+ if (locale->getName()) {
+ it = locales.find(locale->getName());
+ if (it != locales.end()) {
+ *((*it).second) += *locale;
+ delete locale;
+ }
+ else locales.insert(LocaleMap::value_type(locale->getName(), locale));
+ }
+ else delete locale;
+ }
+ }
+ closedir(dir);
+ }
+}
+
+
+void LocaleMgr::deleteLocales() {
+
+ LocaleMap::iterator it;
+
+ for (it = locales.begin(); it != locales.end(); it++)
+ delete (*it).second;
+
+ locales.erase(locales.begin(), locales.end());
+}
+
+
+SWLocale *LocaleMgr::getLocale(const char *name) {
+ LocaleMap::iterator it;
+
+ it = locales.find(name);
+ if (it != locales.end())
+ return (*it).second;
+
+ return 0;
+}
+
+
+list <string> LocaleMgr::getAvailableLocales() {
+ list <string> retVal;
+ for (LocaleMap::iterator it = locales.begin(); it != locales.end(); it++)
+ retVal.push_back((*it).second->getName());
+
+ return retVal;
+}
+
+
+const char *LocaleMgr::translate(const char *name, const char *text) {
+ SWLocale *target;
+ target = getLocale(name);
+ if (target)
+ return target->translate(text);
+ return text;
+}
+
+
+const char *LocaleMgr::getDefaultLocaleName() {
+ return defaultLocaleName;
+}
+
+
+void LocaleMgr::setDefaultLocaleName(const char *name) {
+ stdstr(&defaultLocaleName, name);
+}
diff --git a/src/mgr/markupfiltmgr.cpp b/src/mgr/markupfiltmgr.cpp
new file mode 100644
index 0000000..22a34c5
--- /dev/null
+++ b/src/mgr/markupfiltmgr.cpp
@@ -0,0 +1,234 @@
+/******************************************************************************
+ * swmarkupmgr.cpp - implementaion of class MarkupFilterMgr, subclass of
+ * used to transcode all module text to a requested
+ * markup.
+ *
+ * Copyright 1998 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 <thmlplain.h>
+#include <gbfplain.h>
+#include <thmlgbf.h>
+#include <gbfthml.h>
+#include <thmlhtml.h>
+#include <gbfhtml.h>
+#include <plainhtml.h>
+#include <thmlhtmlhref.h>
+#include <gbfhtmlhref.h>
+#include <thmlrtf.h>
+#include <gbfrtf.h>
+
+#include <markupfiltmgr.h>
+
+#include <swmgr.h>
+
+
+/******************************************************************************
+ * MarkupFilterMgr Constructor - initializes instance of MarkupFilterMgr
+ *
+ * ENT:
+ * enc - Encoding format to emit
+ * mark - Markup format to emit
+ */
+
+MarkupFilterMgr::MarkupFilterMgr (char mark, char enc)
+ : EncodingFilterMgr(enc) {
+
+ markup = mark;
+
+ CreateFilters(markup);
+}
+
+
+/******************************************************************************
+ * MarkupFilterMgr Destructor - Cleans up instance of MarkupFilterMgr
+ */
+
+MarkupFilterMgr::~MarkupFilterMgr() {
+ if (fromthml)
+ delete (fromthml);
+ if (fromgbf)
+ delete (fromgbf);
+ if (fromplain)
+ delete (fromplain);
+ if (fromosis)
+ delete (fromosis);
+}
+
+/******************************************************************************
+ * MarkupFilterMgr::Markup - sets/gets markup
+ *
+ * ENT: mark - new encoding or 0 to simply get the current markup
+ *
+ * RET: markup
+ */
+char MarkupFilterMgr::Markup(char mark) {
+ if (mark && mark != markup) {
+ markup = mark;
+ ModMap::const_iterator module;
+
+ SWFilter * oldplain = fromplain;
+ SWFilter * oldthml = fromthml;
+ SWFilter * oldgbf = fromgbf;
+ SWFilter * oldosis = fromosis;
+
+ CreateFilters(markup);
+
+ for (module = getParentMgr()->Modules.begin(); module != getParentMgr()->Modules.end(); module++)
+ switch (module->second->Markup()) {
+ case FMT_THML:
+ if (oldthml != fromthml) {
+ if (oldthml) {
+ if (!fromthml) {
+ module->second->RemoveRenderFilter(oldthml);
+ }
+ else {
+ module->second->ReplaceRenderFilter(oldthml, fromthml);
+ }
+ }
+ else if (fromthml) {
+ module->second->AddRenderFilter(fromthml);
+ }
+ }
+ break;
+ case FMT_GBF:
+ if (oldgbf != fromgbf) {
+ if (oldgbf) {
+ if (!fromgbf) {
+ module->second->RemoveRenderFilter(oldgbf);
+ }
+ else {
+ module->second->ReplaceRenderFilter(oldgbf, fromgbf);
+ }
+ }
+ else if (fromgbf) {
+ module->second->AddRenderFilter(fromgbf);
+ }
+ break;
+ }
+ case FMT_PLAIN:
+ if (oldplain != fromplain) {
+ if (oldplain) {
+ if (!fromplain) {
+ module->second->RemoveRenderFilter(oldplain);
+ }
+ else {
+ module->second->ReplaceRenderFilter(oldplain, fromplain);
+ }
+ }
+ else if (fromplain) {
+ module->second->AddRenderFilter(fromplain);
+ }
+ break;
+ }
+ case FMT_OSIS:
+ if (oldosis != fromosis) {
+ if (oldosis) {
+ if (!fromosis) {
+ module->second->RemoveRenderFilter(oldosis);
+ }
+ else {
+ module->second->ReplaceRenderFilter(oldosis, fromosis);
+ }
+ }
+ else if (fromosis) {
+ module->second->AddRenderFilter(fromosis);
+ }
+ break;
+ }
+ }
+
+ if (oldthml)
+ delete oldthml;
+ if (oldgbf)
+ delete oldgbf;
+ if (oldplain)
+ delete oldplain;
+ if (oldosis)
+ delete oldosis;
+ }
+ return markup;
+}
+
+void MarkupFilterMgr::AddRenderFilters(SWModule *module, ConfigEntMap &section) {
+ switch (module->Markup()) {
+ case FMT_THML:
+ if (fromthml)
+ module->AddRenderFilter(fromthml);
+ break;
+ case FMT_GBF:
+ if (fromgbf)
+ module->AddRenderFilter(fromgbf);
+ break;
+ case FMT_PLAIN:
+ if (fromplain)
+ module->AddRenderFilter(fromplain);
+ break;
+ case FMT_OSIS:
+ if (fromosis)
+ module->AddRenderFilter(fromosis);
+ break;
+ }
+}
+
+void MarkupFilterMgr::CreateFilters(char markup) {
+
+ switch (markup) {
+ case FMT_PLAIN:
+ fromplain = NULL;
+ fromthml = new ThMLPlain();
+ fromgbf = new GBFPlain();
+ fromosis = NULL;
+ break;
+ case FMT_THML:
+ fromplain = NULL;
+ fromthml = NULL;
+ fromgbf = new GBFThML();
+ fromosis = NULL;
+ break;
+ case FMT_GBF:
+ fromplain = NULL;
+ fromthml = new ThMLGBF();
+ fromgbf = NULL;
+ fromosis = NULL;
+ break;
+ case FMT_HTML:
+ fromplain = new PLAINHTML();
+ fromthml = new ThMLHTML();
+ fromgbf = new GBFHTML();
+ fromosis = NULL;
+ break;
+ case FMT_HTMLHREF:
+ fromplain = NULL;
+ fromthml = new ThMLHTMLHREF();
+ fromgbf = new GBFHTMLHREF();
+ fromosis = NULL;
+ break;
+ case FMT_RTF:
+ fromplain = NULL;
+ fromthml = new ThMLRTF();
+ fromgbf = new GBFRTF();
+ fromosis = NULL;
+ break;
+ case FMT_OSIS:
+ fromplain = NULL;
+ fromthml = NULL;
+ fromgbf = NULL;
+ fromosis = NULL;
+ break;
+ }
+
+}
diff --git a/src/mgr/swcacher.cpp b/src/mgr/swcacher.cpp
new file mode 100644
index 0000000..8128a70
--- /dev/null
+++ b/src/mgr/swcacher.cpp
@@ -0,0 +1,43 @@
+/******************************************************************************
+ * swcacher.h - definition of class SWCacher used to provide an interface for
+ * objects that cache and want a standard interface for cleaning up.
+ *
+ * $Id: swcacher.cpp,v 1.1 2002/03/16 01:12:37 scribe Exp $
+ *
+ * Copyright 1998 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 <swcacher.h>
+
+
+SWCacher::SWCacher() {
+}
+
+
+SWCacher::~SWCacher() {
+}
+
+
+void SWCacher::flush() {
+}
+
+long SWCacher::resourceConsumption() {
+ return 0;
+}
+
+long SWCacher::lastAccess() {
+ return 0;
+}
diff --git a/src/mgr/swconfig.cpp b/src/mgr/swconfig.cpp
new file mode 100644
index 0000000..ad97d00
--- /dev/null
+++ b/src/mgr/swconfig.cpp
@@ -0,0 +1,150 @@
+/******************************************************************************
+ * swconfig.cpp - implementation of Class SWConfig used for saving and
+ * retrieval of configuration information
+ *
+ * $Id: swconfig.cpp,v 1.5 2001/03/11 22:34:58 scribe Exp $
+ *
+ * Copyright 1998 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 <swconfig.h>
+#include <utilfuns.h>
+
+
+SWConfig::SWConfig(const char * ifilename) {
+ filename = ifilename;
+ Load();
+}
+
+
+SWConfig::~SWConfig() {
+}
+
+
+char SWConfig::getline(FILE *fp, string &line)
+{
+ char retval = 0;
+ char buf[255];
+
+ line = "";
+
+ while (fgets(buf, 254, fp)) {
+ while (buf[strlen(buf)-1] == '\n' || buf[strlen(buf)-1] == '\r')
+ buf[strlen(buf)-1] = 0;
+
+ if (buf[strlen(buf)-1] == '\\') {
+ buf[strlen(buf)-1] = 0;
+ line += buf;
+ continue;
+ }
+ line += buf;
+
+ if (strlen(buf) < 253) {
+ retval = 1;
+ break;
+ }
+ }
+ return retval;
+}
+
+
+void SWConfig::Load() {
+ FILE *cfile;
+ char *buf, *data;
+ string line;
+ ConfigEntMap cursect;
+ string sectname;
+ bool first = true;
+
+ Sections.erase(Sections.begin(), Sections.end());
+
+ if ((cfile = fopen(filename.c_str(), "r"))) {
+ while (getline(cfile, line)) {
+ buf = new char [ line.length() + 1 ];
+ strcpy(buf, line.c_str());
+ if (*strstrip(buf) == '[') {
+ if (!first)
+ Sections.insert(SectionMap::value_type(sectname, cursect));
+ else first = false;
+
+ cursect.erase(cursect.begin(), cursect.end());
+
+ strtok(buf, "]");
+ sectname = buf+1;
+ }
+ else {
+ strtok(buf, "=");
+ if ((*buf) && (*buf != '=')) {
+ if ((data = strtok(NULL, "")))
+ cursect.insert(ConfigEntMap::value_type(buf, strstrip(data)));
+ else cursect.insert(ConfigEntMap::value_type(buf, ""));
+ }
+ }
+ delete [] buf;
+ }
+ if (!first)
+ Sections.insert(SectionMap::value_type(sectname, cursect));
+
+ fclose(cfile);
+ }
+}
+
+
+void SWConfig::Save() {
+ FILE *cfile;
+ string buf;
+ SectionMap::iterator sit;
+ ConfigEntMap::iterator entry;
+ string sectname;
+
+ if ((cfile = fopen(filename.c_str(), "w"))) {
+
+ for (sit = Sections.begin(); sit != Sections.end(); sit++) {
+ buf = "\n[";
+ buf += (*sit).first.c_str();
+ buf += "]\n";
+ fputs(buf.c_str(), cfile);
+ for (entry = (*sit).second.begin(); entry != (*sit).second.end(); entry++) {
+ buf = (*entry).first.c_str();
+ buf += "=";
+ buf += (*entry).second.c_str();
+ buf += "\n";
+ fputs(buf.c_str(), cfile);
+ }
+ }
+ fputs("\n", cfile); // so getline will find last line
+ fclose(cfile);
+ }
+}
+
+
+SWConfig &SWConfig::operator +=(SWConfig &addFrom)
+{
+
+ SectionMap::iterator section;
+ ConfigEntMap::iterator entry;
+
+ for (section = addFrom.Sections.begin(); section != addFrom.Sections.end(); section++) {
+ for (entry = (*section).second.begin(); entry != (*section).second.end(); entry++) {
+ Sections[(*section).first].insert(ConfigEntMap::value_type((*entry).first, (*entry).second));
+ }
+ }
+ return *this;
+}
+
+ConfigEntMap & SWConfig::operator [] (const char *section) {
+ return Sections[section];
+}
diff --git a/src/mgr/swfiltermgr.cpp b/src/mgr/swfiltermgr.cpp
new file mode 100644
index 0000000..264b5a6
--- /dev/null
+++ b/src/mgr/swfiltermgr.cpp
@@ -0,0 +1,90 @@
+/******************************************************************************
+ * swfiltermgr.cpp - definition of class SWFilterMgr used as an interface to
+ * manage filters on a module
+ *
+ * $Id: swfiltermgr.cpp,v 1.2 2001/11/30 12:04:34 scribe Exp $
+ *
+ * Copyright 1998 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 <swfiltermgr.h>
+
+
+SWFilterMgr::SWFilterMgr() {
+}
+
+
+SWFilterMgr::~SWFilterMgr() {
+}
+
+
+void SWFilterMgr::setParentMgr(SWMgr *parentMgr) {
+ this->parentMgr = parentMgr;
+}
+
+
+SWMgr *SWFilterMgr::getParentMgr() {
+ return parentMgr;
+}
+
+
+void SWFilterMgr::AddGlobalOptions(SWModule * module, ConfigEntMap & section, ConfigEntMap::iterator start, ConfigEntMap::iterator end) {
+}
+
+
+void SWFilterMgr::AddLocalOptions(SWModule * module, ConfigEntMap & section, ConfigEntMap::iterator start, ConfigEntMap::iterator end) {
+}
+
+
+/**
+* Adds the encoding filters which are defined in "section" to the SWModule object "module".
+* @param module To this module the encoding filter(s) are added
+* @param section We use this section to get a list of filters we should apply to the module
+*/
+
+void SWFilterMgr::AddEncodingFilters(SWModule * module, ConfigEntMap & section) {
+}
+
+
+/**
+* Adds the render filters which are defined in "section" to the SWModule object "module".
+* @param module To this module the render filter(s) are added
+* @param section We use this section to get a list of filters we should apply to the module
+*/
+
+void SWFilterMgr::AddRenderFilters(SWModule * module, ConfigEntMap & section) {
+}
+
+
+/**
+* Adds the strip filters which are defined in "section" to the SWModule object "module".
+* @param module To this module the strip filter(s) are added
+* @param section We use this section to get a list of filters we should apply to the module
+*/
+
+void SWFilterMgr::AddStripFilters(SWModule * module, ConfigEntMap & section) {
+}
+
+
+/**
+* Adds the raw filters which are defined in "section" to the SWModule object "module".
+* @param module To this module the raw filter(s) are added
+* @param section We use this section to get a list of filters we should apply to the module
+*/
+
+void SWFilterMgr::AddRawFilters(SWModule * module, ConfigEntMap & section) {
+}
+
diff --git a/src/mgr/swlocale.cpp b/src/mgr/swlocale.cpp
new file mode 100644
index 0000000..b630383
--- /dev/null
+++ b/src/mgr/swlocale.cpp
@@ -0,0 +1,141 @@
+/******************************************************************************
+ * swlocale.cpp - implementation of Class SWLocale used for retrieval
+ * of locale lookups
+ *
+ * $Id: swlocale.cpp,v 1.3 2000/03/13 09:36:03 scribe Exp $
+ *
+ * Copyright 2000 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 <swlocale.h>
+#include <utilfuns.h>
+
+
+SWLocale::SWLocale(const char * ifilename) {
+ ConfigEntMap::iterator confEntry;
+
+ name = 0;
+ description = 0;
+ bookAbbrevs = 0;
+ BMAX = 0;
+ books = 0;
+ localeSource = new SWConfig(ifilename);
+
+ confEntry = localeSource->Sections["Meta"].find("Name");
+ if (confEntry != localeSource->Sections["Meta"].end())
+ stdstr(&name, (*confEntry).second.c_str());
+
+ confEntry = localeSource->Sections["Meta"].find("Description");
+ if (confEntry != localeSource->Sections["Meta"].end())
+ stdstr(&description, (*confEntry).second.c_str());
+}
+
+
+SWLocale::~SWLocale() {
+
+ delete localeSource;
+
+ if (description)
+ delete [] description;
+
+ if (name)
+ delete [] name;
+
+ if (bookAbbrevs)
+ delete [] bookAbbrevs;
+
+ if (BMAX) {
+ for (int i = 0; i < 2; i++)
+ delete [] books[i];
+ delete [] BMAX;
+ delete [] books;
+ }
+}
+
+
+const char *SWLocale::translate(const char *text) {
+ LookupMap::iterator entry;
+
+ entry = lookupTable.find(text);
+
+ if (entry == lookupTable.end()) {
+ ConfigEntMap::iterator confEntry;
+ confEntry = localeSource->Sections["Text"].find(text);
+ if (confEntry == localeSource->Sections["Text"].end())
+ lookupTable.insert(LookupMap::value_type(text, text));
+ else lookupTable.insert(LookupMap::value_type(text, (*confEntry).second.c_str()));
+ entry = lookupTable.find(text);
+ }
+ return (*entry).second.c_str();
+}
+
+
+const char *SWLocale::getName() {
+ return name;
+}
+
+
+const char *SWLocale::getDescription() {
+ return description;
+}
+
+
+SWLocale &SWLocale::operator +=(SWLocale &addFrom) {
+ *localeSource += *addFrom.localeSource;
+ return *this;
+}
+
+
+const struct abbrev *SWLocale::getBookAbbrevs() {
+ static const char *nullstr = "";
+ if (!bookAbbrevs) {
+ ConfigEntMap::iterator it;
+ int i;
+ int size = localeSource->Sections["Book Abbrevs"].size();
+ bookAbbrevs = new struct abbrev[size + 1];
+ for (i = 0, it = localeSource->Sections["Book Abbrevs"].begin(); it != localeSource->Sections["Book Abbrevs"].end(); it++, i++) {
+ bookAbbrevs[i].ab = (*it).first.c_str();
+ bookAbbrevs[i].book = atoi((*it).second.c_str());
+ }
+ bookAbbrevs[i].ab = nullstr;
+ bookAbbrevs[i].book = -1;
+ }
+
+ return bookAbbrevs;
+}
+
+
+void SWLocale::getBooks(char **iBMAX, struct sbook ***ibooks) {
+ if (!BMAX) {
+ BMAX = new char [2];
+ BMAX[0] = VerseKey::builtin_BMAX[0];
+ BMAX[1] = VerseKey::builtin_BMAX[1];
+
+ books = new struct sbook *[2];
+ books[0] = new struct sbook[BMAX[0]];
+ books[1] = new struct sbook[BMAX[1]];
+
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < BMAX[i]; j++) {
+ books[i][j] = VerseKey::builtin_books[i][j];
+ books[i][j].name = translate(VerseKey::builtin_books[i][j].name);
+ }
+ }
+ }
+
+ *iBMAX = BMAX;
+ *ibooks = books;
+}
diff --git a/src/mgr/swmgr.cpp b/src/mgr/swmgr.cpp
new file mode 100644
index 0000000..36aecb0
--- /dev/null
+++ b/src/mgr/swmgr.cpp
@@ -0,0 +1,1054 @@
+/******************************************************************************
+ * swmgr.cpp - implementaion of class SWMgr used to interact with an install
+ * base of sword modules.
+ *
+ * $Id: swmgr.cpp,v 1.70 2002/03/22 05:26:34 scribe Exp $
+ *
+ * Copyright 1998 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 <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#ifndef __GNUC__
+#include <io.h>
+#else
+#include <unistd.h>
+#include <unixstr.h>
+#endif
+#include <sys/stat.h>
+#ifndef _MSC_VER
+#include <iostream.h>
+#endif
+#include <dirent.h>
+
+#include <swmgr.h>
+#include <rawtext.h>
+#include <rawgenbook.h>
+#include <rawcom.h>
+#include <hrefcom.h>
+#include <rawld.h>
+#include <rawld4.h>
+#include <utilfuns.h>
+#include <gbfplain.h>
+#include <thmlplain.h>
+#include <gbfstrongs.h>
+#include <gbffootnotes.h>
+#include <gbfheadings.h>
+#include <gbfmorph.h>
+#include <thmlstrongs.h>
+#include <thmlfootnotes.h>
+#include <thmlheadings.h>
+#include <thmlmorph.h>
+#include <thmllemma.h>
+#include <thmlscripref.h>
+#include <cipherfil.h>
+#include <rawfiles.h>
+#include <ztext.h>
+#include <zld.h>
+#include <zcom.h>
+#include <lzsscomprs.h>
+#include <utf8greekaccents.h>
+#include <utf8cantillation.h>
+#include <utf8hebrewpoints.h>
+#include <greeklexattribs.h>
+#include <swfiltermgr.h>
+
+
+
+#ifdef ICU
+#include <utf8transliterator.h>
+#endif
+
+#ifndef EXCLUDEZLIB
+#include <zipcomprs.h>
+#endif
+
+bool SWMgr::debug = false;
+
+#ifdef GLOBCONFPATH
+const char *SWMgr::globalConfPath = GLOBCONFPATH;
+#else
+const char *SWMgr::globalConfPath = "/etc/sword.conf:/usr/local/etc/sword.conf";
+#endif
+
+void SWMgr::init() {
+ SWFilter *tmpFilter = 0;
+ configPath = 0;
+ prefixPath = 0;
+ configType = 0;
+ myconfig = 0;
+ mysysconfig = 0;
+ homeConfig = 0;
+
+
+ cipherFilters.clear();
+ optionFilters.clear();
+ cleanupFilters.clear();
+
+ tmpFilter = new GBFStrongs();
+ optionFilters.insert(FilterMap::value_type("GBFStrongs", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new GBFFootnotes();
+ optionFilters.insert(FilterMap::value_type("GBFFootnotes", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new GBFMorph();
+ optionFilters.insert(FilterMap::value_type("GBFMorph", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new GBFHeadings();
+ optionFilters.insert(FilterMap::value_type("GBFHeadings", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new ThMLStrongs();
+ optionFilters.insert(FilterMap::value_type("ThMLStrongs", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new ThMLFootnotes();
+ optionFilters.insert(FilterMap::value_type("ThMLFootnotes", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new ThMLMorph();
+ optionFilters.insert(FilterMap::value_type("ThMLMorph", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new ThMLHeadings();
+ optionFilters.insert(FilterMap::value_type("ThMLHeadings", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new ThMLLemma();
+ optionFilters.insert(FilterMap::value_type("ThMLLemma", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new ThMLScripref();
+ optionFilters.insert(FilterMap::value_type("ThMLScripref", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new UTF8GreekAccents();
+ optionFilters.insert(FilterMap::value_type("UTF8GreekAccents", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new UTF8HebrewPoints();
+ optionFilters.insert(FilterMap::value_type("UTF8HebrewPoints", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new UTF8Cantillation();
+ optionFilters.insert(FilterMap::value_type("UTF8Cantillation", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ tmpFilter = new GreekLexAttribs();
+ optionFilters.insert(FilterMap::value_type("GreekLexAttribs", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+/* UTF8Transliterator needs to be handled differently because it should always available as an option, for all modules
+#ifdef ICU
+ tmpFilter = new UTF8Transliterator();
+ optionFilters.insert(FilterMap::value_type("UTF8Transliterator", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+#endif
+*/
+ gbfplain = new GBFPlain();
+ cleanupFilters.push_back(gbfplain);
+
+ thmlplain = new ThMLPlain();
+ cleanupFilters.push_back(thmlplain);
+}
+
+
+SWMgr::SWMgr(SWFilterMgr *filterMgr) {
+ commonInit(0, 0, true, filterMgr);
+}
+
+
+SWMgr::SWMgr(SWConfig *iconfig, SWConfig *isysconfig, bool autoload, SWFilterMgr *filterMgr) {
+ commonInit(iconfig, isysconfig, autoload, filterMgr);
+}
+
+
+void SWMgr::commonInit(SWConfig * iconfig, SWConfig * isysconfig, bool autoload, SWFilterMgr *filterMgr) {
+ this->filterMgr = filterMgr;
+ if (filterMgr)
+ filterMgr->setParentMgr(this);
+
+ init();
+
+ if (iconfig) {
+ config = iconfig;
+ myconfig = 0;
+ }
+ else config = 0;
+ if (isysconfig) {
+ sysconfig = isysconfig;
+ mysysconfig = 0;
+ }
+ else sysconfig = 0;
+
+ if (autoload)
+ Load();
+}
+
+
+SWMgr::SWMgr(const char *iConfigPath, bool autoload, SWFilterMgr *filterMgr) {
+
+ string path;
+
+ this->filterMgr = filterMgr;
+ if (filterMgr)
+ filterMgr->setParentMgr(this);
+
+ init();
+
+ path = iConfigPath;
+ if ((iConfigPath[strlen(iConfigPath)-1] != '\\') && (iConfigPath[strlen(iConfigPath)-1] != '/'))
+ path += "/";
+ if (FileMgr::existsFile(path.c_str(), "mods.conf")) {
+ stdstr(&prefixPath, path.c_str());
+ path += "mods.conf";
+ stdstr(&configPath, path.c_str());
+ }
+ else {
+ if (FileMgr::existsDir(path.c_str(), "mods.d")) {
+ stdstr(&prefixPath, path.c_str());
+ path += "mods.d";
+ stdstr(&configPath, path.c_str());
+ configType = 1;
+ }
+ }
+
+ config = 0;
+ sysconfig = 0;
+
+ if (autoload && configPath)
+ Load();
+}
+
+
+SWMgr::~SWMgr() {
+
+ DeleteMods();
+
+ for (FilterList::iterator it = cleanupFilters.begin(); it != cleanupFilters.end(); it++)
+ delete (*it);
+
+ if (homeConfig)
+ delete homeConfig;
+
+ if (myconfig)
+ delete myconfig;
+
+ if (prefixPath)
+ delete [] prefixPath;
+
+ if (configPath)
+ delete [] configPath;
+
+ if (filterMgr)
+ delete filterMgr;
+}
+
+
+void SWMgr::findConfig(char *configType, char **prefixPath, char **configPath) {
+ string path;
+ ConfigEntMap::iterator entry;
+
+ char *envsworddir = getenv ("SWORD_PATH");
+ char *envhomedir = getenv ("HOME");
+
+ *configType = 0;
+
+#ifndef _MSC_VER
+ // check working directory
+if (debug)
+ cerr << "Checking working directory for mods.conf...";
+#endif
+
+ if (FileMgr::existsFile(".", "mods.conf")) {
+
+#ifndef _MSC_VER
+if (debug)
+ cerr << "found\n";
+#endif
+
+ stdstr(prefixPath, "./");
+ stdstr(configPath, "./mods.conf");
+ return;
+ }
+
+#ifndef _MSC_VER
+if (debug)
+ cerr << "\nChecking working directory for mods.d...";
+#endif
+
+ if (FileMgr::existsDir(".", "mods.d")) {
+
+#ifndef _MSC_VER
+if (debug)
+ cerr << "found\n";
+#endif
+
+ stdstr(prefixPath, "./");
+ stdstr(configPath, "./mods.d");
+ *configType = 1;
+ return;
+ }
+
+
+ // check environment variable SWORD_PATH
+#ifndef _MSC_VER
+if (debug)
+ cerr << "\nChecking SWORD_PATH...";
+#endif
+
+ if (envsworddir != NULL) {
+
+#ifndef _MSC_VER
+if (debug)
+ cerr << "found (" << envsworddir << ")\n";
+#endif
+
+ path = envsworddir;
+ if ((envsworddir[strlen(envsworddir)-1] != '\\') && (envsworddir[strlen(envsworddir)-1] != '/'))
+ path += "/";
+
+#ifndef _MSC_VER
+if (debug)
+ cerr << "\nChecking $SWORD_PATH for mods.conf...";
+#endif
+
+ if (FileMgr::existsFile(path.c_str(), "mods.conf")) {
+
+#ifndef _MSC_VER
+if (debug)
+ cerr << "found\n";
+#endif
+
+ stdstr(prefixPath, path.c_str());
+ path += "mods.conf";
+ stdstr(configPath, path.c_str());
+ return;
+ }
+
+#ifndef _MSC_VER
+if (debug)
+ cerr << "\nChecking $SWORD_PATH for mods.d...";
+#endif
+
+ if (FileMgr::existsDir(path.c_str(), "mods.d")) {
+
+#ifndef _MSC_VER
+if (debug)
+ cerr << "found\n";
+#endif
+
+ stdstr(prefixPath, path.c_str());
+ path += "mods.d";
+ stdstr(configPath, path.c_str());
+ *configType = 1;
+ return;
+ }
+ }
+
+
+ // check for systemwide globalConfPath
+
+#ifndef _MSC_VER
+if (debug)
+ cerr << "\nParsing " << globalConfPath << "...";
+#endif
+
+ char *globPaths = 0;
+ char *gfp;
+ stdstr(&globPaths, globalConfPath);
+ for (gfp = strtok(globPaths, ":"); gfp; gfp = strtok(0, ":")) {
+
+ #ifndef _MSC_VER
+if (debug)
+ cerr << "\nChecking for " << gfp << "...";
+#endif
+
+ if (FileMgr::existsFile(gfp))
+ break;
+ }
+
+ if (gfp) {
+
+#ifndef _MSC_VER
+if (debug)
+ cerr << "found\n";
+#endif
+
+ SWConfig etcconf(gfp);
+ if ((entry = etcconf.Sections["Install"].find("DataPath")) != etcconf.Sections["Install"].end()) {
+ path = (*entry).second;
+ if (((*entry).second.c_str()[strlen((*entry).second.c_str())-1] != '\\') && ((*entry).second.c_str()[strlen((*entry).second.c_str())-1] != '/'))
+ path += "/";
+
+#ifndef _MSC_VER
+if (debug)
+ cerr << "DataPath in " << gfp << " is set to: " << path;
+#endif
+
+#ifndef _MSC_VER
+if (debug)
+ cerr << "\nChecking for mods.conf in DataPath ";
+#endif
+ if (FileMgr::existsFile(path.c_str(), "mods.conf")) {
+
+#ifndef _MSC_VER
+if (debug)
+ cerr << "found\n";
+#endif
+
+ stdstr(prefixPath, path.c_str());
+ path += "mods.conf";
+ stdstr(configPath, path.c_str());
+ delete [] globPaths;
+ return;
+ }
+
+#ifndef _MSC_VER
+if (debug)
+ cerr << "\nChecking for mods.d in DataPath ";
+#endif
+
+ if (FileMgr::existsDir(path.c_str(), "mods.d")) {
+
+#ifndef _MSC_VER
+if (debug)
+ cerr << "found\n";
+#endif
+
+ stdstr(prefixPath, path.c_str());
+ path += "mods.d";
+ stdstr(configPath, path.c_str());
+ *configType = 1;
+ delete [] globPaths;
+ return;
+ }
+ }
+ }
+
+ delete [] globPaths;
+
+ // check ~/.sword/
+
+#ifndef _MSC_VER
+if (debug)
+ cerr << "\nChecking home directory for ~/.sword/mods.conf" << path;
+#endif
+
+ if (envhomedir != NULL) {
+ path = envhomedir;
+ if ((envhomedir[strlen(envhomedir)-1] != '\\') && (envhomedir[strlen(envhomedir)-1] != '/'))
+ path += "/";
+ path += ".sword/";
+ if (FileMgr::existsFile(path.c_str(), "mods.conf")) {
+
+#ifndef _MSC_VER
+if (debug)
+ cerr << " found\n";
+#endif
+
+ stdstr(prefixPath, path.c_str());
+ path += "mods.conf";
+ stdstr(configPath, path.c_str());
+ return;
+ }
+
+#ifndef _MSC_VER
+if (debug)
+ cerr << "\nChecking home directory for ~/.sword/mods.d" << path;
+#endif
+
+ if (FileMgr::existsDir(path.c_str(), "mods.d")) {
+
+#ifndef _MSC_VER
+if (debug)
+ cerr << "found\n";
+#endif
+
+ stdstr(prefixPath, path.c_str());
+ path += "mods.d";
+ stdstr(configPath, path.c_str());
+ *configType = 2;
+ return;
+ }
+ }
+}
+
+
+void SWMgr::loadConfigDir(const char *ipath)
+{
+ DIR *dir;
+ struct dirent *ent;
+ string newmodfile;
+
+ if ((dir = opendir(ipath))) {
+ rewinddir(dir);
+ while ((ent = readdir(dir))) {
+ if ((strcmp(ent->d_name, ".")) && (strcmp(ent->d_name, ".."))) {
+ newmodfile = ipath;
+ if ((ipath[strlen(ipath)-1] != '\\') && (ipath[strlen(ipath)-1] != '/'))
+ newmodfile += "/";
+ newmodfile += ent->d_name;
+ if (config) {
+ SWConfig tmpConfig(newmodfile.c_str());
+ *config += tmpConfig;
+ }
+ else config = myconfig = new SWConfig(newmodfile.c_str());
+ }
+ }
+ closedir(dir);
+ if (!config) { // if no .conf file exist yet, create a default
+ newmodfile = ipath;
+ if ((ipath[strlen(ipath)-1] != '\\') && (ipath[strlen(ipath)-1] != '/'))
+ newmodfile += "/";
+ newmodfile += "globals.conf";
+ config = myconfig = new SWConfig(newmodfile.c_str());
+ }
+ }
+}
+
+
+/***********************************************************************
+ * SWMgr::Load - loads actual modules
+ *
+ * RET: status - 0 = ok; -1 no config found; 1 = no modules installed
+ *
+ */
+
+signed char SWMgr::Load() {
+ signed char ret = 0;
+
+ if (!config) { // If we weren't passed a config object at construction, find a config file
+ if (!configPath) // If we weren't passed a config path at construction...
+ findConfig(&configType, &prefixPath, &configPath);
+ if (configPath) {
+ if (configType)
+ loadConfigDir(configPath);
+ else config = myconfig = new SWConfig(configPath);
+ }
+ }
+
+ if (config) {
+ SectionMap::iterator Sectloop, Sectend;
+ ConfigEntMap::iterator Entryloop, Entryend;
+
+ DeleteMods();
+
+ for (Sectloop = config->Sections.lower_bound("Globals"), Sectend = config->Sections.upper_bound("Globals"); Sectloop != Sectend; Sectloop++) { // scan thru all 'Globals' sections
+ for (Entryloop = (*Sectloop).second.lower_bound("AutoInstall"), Entryend = (*Sectloop).second.upper_bound("AutoInstall"); Entryloop != Entryend; Entryloop++) // scan thru all AutoInstall entries
+ InstallScan((*Entryloop).second.c_str()); // Scan AutoInstall entry directory for new modules and install
+ }
+ if (configType) { // force reload on config object because we may have installed new modules
+ delete myconfig;
+ config = myconfig = 0;
+ loadConfigDir(configPath);
+ }
+ else config->Load();
+
+ CreateMods();
+
+// augment config with ~/.sword/mods.d if it exists ---------------------
+ char *envhomedir = getenv ("HOME");
+ if (envhomedir != NULL && configType != 2) { // 2 = user only
+ string path = envhomedir;
+ if ((envhomedir[strlen(envhomedir)-1] != '\\') && (envhomedir[strlen(envhomedir)-1] != '/'))
+ path += "/";
+ path += ".sword/";
+ if (FileMgr::existsDir(path.c_str(), "mods.d")) {
+ char *savePrefixPath = 0;
+ char *saveConfigPath = 0;
+ SWConfig *saveConfig = 0;
+ stdstr(&savePrefixPath, prefixPath);
+ stdstr(&prefixPath, path.c_str());
+ path += "mods.d";
+ stdstr(&saveConfigPath, configPath);
+ stdstr(&configPath, path.c_str());
+ saveConfig = config;
+ config = myconfig = 0;
+ loadConfigDir(configPath);
+
+ CreateMods();
+
+ stdstr(&prefixPath, savePrefixPath);
+ delete []savePrefixPath;
+ stdstr(&configPath, saveConfigPath);
+ delete []saveConfigPath;
+ (*saveConfig) += *config;
+ homeConfig = myconfig;
+ config = myconfig = saveConfig;
+ }
+ }
+// -------------------------------------------------------------------------
+ if ( !Modules.size() ) // config exists, but no modules
+ ret = 1;
+
+ }
+ else {
+ SWLog::systemlog->LogError("SWMgr: Can't find 'mods.conf' or 'mods.d'. Try setting:\n\tSWORD_PATH=<directory containing mods.conf>\n\tOr see the README file for a full description of setup options (%s)", (configPath) ? configPath : "<configPath is null>");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+SWModule *SWMgr::CreateMod(string name, string driver, ConfigEntMap &section)
+{
+ string description, datapath, misc1;
+ ConfigEntMap::iterator entry;
+ SWModule *newmod = 0;
+ string lang, sourceformat, encoding;
+ signed char direction, enc, markup;
+
+ description = ((entry = section.find("Description")) != section.end()) ? (*entry).second : (string)"";
+ lang = ((entry = section.find("Lang")) != section.end()) ? (*entry).second : (string)"en";
+ sourceformat = ((entry = section.find("SourceType")) != section.end()) ? (*entry).second : (string)"";
+ encoding = ((entry = section.find("Encoding")) != section.end()) ? (*entry).second : (string)"";
+ datapath = prefixPath;
+ if ((prefixPath[strlen(prefixPath)-1] != '\\') && (prefixPath[strlen(prefixPath)-1] != '/'))
+ datapath += "/";
+ misc1 += ((entry = section.find("DataPath")) != section.end()) ? (*entry).second : (string)"";
+ char *buf = new char [ strlen(misc1.c_str()) + 1 ];
+ char *buf2 = buf;
+ strcpy(buf, misc1.c_str());
+// for (; ((*buf2) && ((*buf2 == '.') || (*buf2 == '/') || (*buf2 == '\\'))); buf2++);
+ for (; ((*buf2) && ((*buf2 == '/') || (*buf2 == '\\'))); buf2++);
+ if (*buf2)
+ datapath += buf2;
+ delete [] buf;
+
+ section["AbsoluteDataPath"] = datapath;
+
+ if (!stricmp(sourceformat.c_str(), "GBF"))
+ markup = FMT_GBF;
+ else if (!stricmp(sourceformat.c_str(), "ThML"))
+ markup = FMT_THML;
+ else if (!stricmp(sourceformat.c_str(), "OSIS"))
+ markup = FMT_OSIS;
+ else
+ markup = FMT_PLAIN;
+
+ if (!stricmp(encoding.c_str(), "SCSU"))
+ enc = ENC_SCSU;
+ else if (!stricmp(encoding.c_str(), "UTF-8"))
+ enc = ENC_UTF8;
+ else enc = ENC_LATIN1;
+
+ if ((entry = section.find("Direction")) == section.end()) {
+ direction = DIRECTION_LTR;
+ }
+ else if (!stricmp((*entry).second.c_str(), "rtol")) {
+ direction = DIRECTION_RTL;
+ }
+ else if (!stricmp((*entry).second.c_str(), "bidi")) {
+ direction = DIRECTION_BIDI;
+ }
+ else {
+ direction = DIRECTION_LTR;
+ }
+
+ if ((!stricmp(driver.c_str(), "zText")) || (!stricmp(driver.c_str(), "zCom"))) {
+ SWCompress *compress = 0;
+ int blockType = CHAPTERBLOCKS;
+ misc1 = ((entry = section.find("BlockType")) != section.end()) ? (*entry).second : (string)"CHAPTER";
+ if (!stricmp(misc1.c_str(), "VERSE"))
+ blockType = VERSEBLOCKS;
+ else if (!stricmp(misc1.c_str(), "CHAPTER"))
+ blockType = CHAPTERBLOCKS;
+ else if (!stricmp(misc1.c_str(), "BOOK"))
+ blockType = BOOKBLOCKS;
+
+ misc1 = ((entry = section.find("CompressType")) != section.end()) ? (*entry).second : (string)"LZSS";
+#ifndef EXCLUDEZLIB
+ if (!stricmp(misc1.c_str(), "ZIP"))
+ compress = new ZipCompress();
+ else
+#endif
+ if (!stricmp(misc1.c_str(), "LZSS"))
+ compress = new LZSSCompress();
+
+ if (compress) {
+ if (!stricmp(driver.c_str(), "zText"))
+ newmod = new zText(datapath.c_str(), name.c_str(), description.c_str(), blockType, compress, 0, enc, direction, markup, lang.c_str());
+ else newmod = new zCom(datapath.c_str(), name.c_str(), description.c_str(), blockType, compress, 0, enc, direction, markup, lang.c_str());
+ }
+ }
+
+ if (!stricmp(driver.c_str(), "RawText")) {
+ newmod = new RawText(datapath.c_str(), name.c_str(), description.c_str(), 0, enc, direction, markup, lang.c_str());
+ }
+
+ // backward support old drivers
+ if (!stricmp(driver.c_str(), "RawGBF")) {
+ newmod = new RawText(datapath.c_str(), name.c_str(), description.c_str(), 0, enc, direction, markup, lang.c_str());
+ }
+
+ if (!stricmp(driver.c_str(), "RawCom")) {
+ newmod = new RawCom(datapath.c_str(), name.c_str(), description.c_str(), 0, enc, direction, markup, lang.c_str());
+ }
+
+ if (!stricmp(driver.c_str(), "RawFiles")) {
+ newmod = new RawFiles(datapath.c_str(), name.c_str(), description.c_str(), 0, enc, direction, markup, lang.c_str());
+ }
+
+ if (!stricmp(driver.c_str(), "HREFCom")) {
+ misc1 = ((entry = section.find("Prefix")) != section.end()) ? (*entry).second : (string)"";
+ newmod = new HREFCom(datapath.c_str(), misc1.c_str(), name.c_str(), description.c_str());
+ }
+
+ if (!stricmp(driver.c_str(), "RawLD"))
+ newmod = new RawLD(datapath.c_str(), name.c_str(), description.c_str(), 0, enc, direction, markup, lang.c_str());
+
+ if (!stricmp(driver.c_str(), "RawLD4"))
+ newmod = new RawLD4(datapath.c_str(), name.c_str(), description.c_str(), 0, enc, direction, markup, lang.c_str());
+
+ if (!stricmp(driver.c_str(), "zLD")) {
+ SWCompress *compress = 0;
+ int blockCount;
+ misc1 = ((entry = section.find("BlockCount")) != section.end()) ? (*entry).second : (string)"200";
+ blockCount = atoi(misc1.c_str());
+ blockCount = (blockCount) ? blockCount : 200;
+
+ misc1 = ((entry = section.find("CompressType")) != section.end()) ? (*entry).second : (string)"LZSS";
+#ifndef EXCLUDEZLIB
+ if (!stricmp(misc1.c_str(), "ZIP"))
+ compress = new ZipCompress();
+ else
+#endif
+ if (!stricmp(misc1.c_str(), "LZSS"))
+ compress = new LZSSCompress();
+
+ if (compress) {
+ newmod = new zLD(datapath.c_str(), name.c_str(), description.c_str(), blockCount, compress, 0, enc, direction, markup, lang.c_str());
+ }
+ }
+
+ if (!stricmp(driver.c_str(), "RawGenBook")) {
+ newmod = new RawGenBook(datapath.c_str(), name.c_str(), description.c_str(), 0, enc, direction, markup, lang.c_str());
+ }
+ // if a specific module type is set in the config, use this
+ if ((entry = section.find("Type")) != section.end())
+ newmod->Type(entry->second.c_str());
+
+ newmod->setConfig(&section);
+ return newmod;
+}
+
+
+void SWMgr::AddGlobalOptions(SWModule *module, ConfigEntMap &section, ConfigEntMap::iterator start, ConfigEntMap::iterator end) {
+ for (;start != end; start++) {
+ FilterMap::iterator it;
+ it = optionFilters.find((*start).second);
+ if (it != optionFilters.end()) {
+ module->AddOptionFilter((*it).second); // add filter to module and option as a valid option
+ OptionsList::iterator loop;
+ for (loop = options.begin(); loop != options.end(); loop++) {
+ if (!strcmp((*loop).c_str(), (*it).second->getOptionName()))
+ break;
+ }
+ if (loop == options.end()) // if we have not yet included the option
+ options.push_back((*it).second->getOptionName());
+ }
+ }
+ if (filterMgr)
+ filterMgr->AddGlobalOptions(module, section, start, end);
+}
+
+
+void SWMgr::AddLocalOptions(SWModule *module, ConfigEntMap &section, ConfigEntMap::iterator start, ConfigEntMap::iterator end)
+{
+ for (;start != end; start++) {
+ FilterMap::iterator it;
+ it = optionFilters.find((*start).second);
+ if (it != optionFilters.end()) {
+ module->AddOptionFilter((*it).second); // add filter to module
+ }
+ }
+
+ if (filterMgr)
+ filterMgr->AddLocalOptions(module, section, start, end);
+}
+
+
+void SWMgr::AddRawFilters(SWModule *module, ConfigEntMap &section) {
+ string sourceformat, cipherKey;
+ ConfigEntMap::iterator entry;
+
+ cipherKey = ((entry = section.find("CipherKey")) != section.end()) ? (*entry).second : (string)"";
+ if (!cipherKey.empty()) {
+ SWFilter *cipherFilter = new CipherFilter(cipherKey.c_str());
+ cipherFilters.insert(FilterMap::value_type(module->Name(), cipherFilter));
+ cleanupFilters.push_back(cipherFilter);
+ module->AddRawFilter(cipherFilter);
+ }
+
+ if (filterMgr)
+ filterMgr->AddRawFilters(module, section);
+}
+
+
+void SWMgr::AddEncodingFilters(SWModule *module, ConfigEntMap &section) {
+
+ if (filterMgr)
+ filterMgr->AddEncodingFilters(module, section);
+}
+
+
+void SWMgr::AddRenderFilters(SWModule *module, ConfigEntMap &section) {
+ string sourceformat;
+ ConfigEntMap::iterator entry;
+
+ sourceformat = ((entry = section.find("SourceType")) != section.end()) ? (*entry).second : (string)"";
+
+ // Temporary: To support old module types
+ // TODO: Remove at 1.6.0 release?
+ if (sourceformat.empty()) {
+ sourceformat = ((entry = section.find("ModDrv")) != section.end()) ? (*entry).second : (string)"";
+ if (!stricmp(sourceformat.c_str(), "RawGBF"))
+ sourceformat = "GBF";
+ else sourceformat = "";
+ }
+
+// process module - eg. follows
+// if (!stricmp(sourceformat.c_str(), "GBF")) {
+// module->AddRenderFilter(gbftortf);
+// }
+
+ if (filterMgr)
+ filterMgr->AddRenderFilters(module, section);
+
+}
+
+
+void SWMgr::AddStripFilters(SWModule *module, ConfigEntMap &section)
+{
+ string sourceformat;
+ ConfigEntMap::iterator entry;
+
+ sourceformat = ((entry = section.find("SourceType")) != section.end()) ? (*entry).second : (string)"";
+ // Temporary: To support old module types
+ if (sourceformat.empty()) {
+ sourceformat = ((entry = section.find("ModDrv")) != section.end()) ? (*entry).second : (string)"";
+ if (!stricmp(sourceformat.c_str(), "RawGBF"))
+ sourceformat = "GBF";
+ else sourceformat = "";
+ }
+
+ if (!stricmp(sourceformat.c_str(), "GBF")) {
+ module->AddStripFilter(gbfplain);
+ }
+ else if (!stricmp(sourceformat.c_str(), "ThML")) {
+ module->AddStripFilter(thmlplain);
+ }
+
+ if (filterMgr)
+ filterMgr->AddStripFilters(module, section);
+
+}
+
+
+void SWMgr::CreateMods() {
+ SectionMap::iterator it;
+ ConfigEntMap::iterator start;
+ ConfigEntMap::iterator end;
+ ConfigEntMap::iterator entry;
+ SWModule *newmod;
+ string driver, misc1;
+ for (it = config->Sections.begin(); it != config->Sections.end(); it++) {
+ ConfigEntMap &section = (*it).second;
+ newmod = 0;
+
+ driver = ((entry = section.find("ModDrv")) != section.end()) ? (*entry).second : (string)"";
+ if (!driver.empty()) {
+ newmod = CreateMod((*it).first, driver, section);
+ if (newmod) {
+ start = (*it).second.lower_bound("GlobalOptionFilter");
+ end = (*it).second.upper_bound("GlobalOptionFilter");
+ AddGlobalOptions(newmod, section, start, end);
+
+ start = (*it).second.lower_bound("LocalOptionFilter");
+ end = (*it).second.upper_bound("LocalOptionFilter");
+ AddLocalOptions(newmod, section, start, end);
+
+ AddRawFilters(newmod, section);
+ AddStripFilters(newmod, section);
+ AddRenderFilters(newmod, section);
+ AddEncodingFilters(newmod, section);
+
+ Modules.insert(ModMap::value_type(newmod->Name(), newmod));
+ }
+ }
+ }
+}
+
+
+void SWMgr::DeleteMods() {
+
+ ModMap::iterator it;
+
+ for (it = Modules.begin(); it != Modules.end(); it++)
+ delete (*it).second;
+
+ Modules.clear();
+}
+
+
+void SWMgr::InstallScan(const char *dirname)
+{
+ DIR *dir;
+ struct dirent *ent;
+ int conffd = 0;
+ string newmodfile;
+ string targetName;
+
+ if (!access(dirname, 04)) {
+ if ((dir = opendir(dirname))) {
+ rewinddir(dir);
+ while ((ent = readdir(dir))) {
+ if ((strcmp(ent->d_name, ".")) && (strcmp(ent->d_name, ".."))) {
+ newmodfile = dirname;
+ if ((dirname[strlen(dirname)-1] != '\\') && (dirname[strlen(dirname)-1] != '/'))
+ newmodfile += "/";
+ newmodfile += ent->d_name;
+ if (configType) {
+ if (config > 0)
+ close(conffd);
+ targetName = configPath;
+ if ((configPath[strlen(configPath)-1] != '\\') && (configPath[strlen(configPath)-1] != '/'))
+ targetName += "/";
+ targetName += ent->d_name;
+ conffd = open(targetName.c_str(), O_WRONLY|O_CREAT, S_IREAD|S_IWRITE);
+ }
+ else {
+ if (conffd < 1) {
+ conffd = open(config->filename.c_str(), O_WRONLY|O_APPEND);
+ if (conffd > 0)
+ lseek(conffd, 0L, SEEK_END);
+ }
+ }
+ AddModToConfig(conffd, newmodfile.c_str());
+ unlink(newmodfile.c_str());
+ }
+ }
+ if (conffd > 0)
+ close(conffd);
+ closedir(dir);
+ }
+ }
+}
+
+
+char SWMgr::AddModToConfig(int conffd, const char *fname)
+{
+ int modfd;
+ char ch;
+
+ SWLog::systemlog->LogTimedInformation("Found new module [%s]. Installing...", fname);
+ modfd = open(fname, O_RDONLY);
+ ch = '\n';
+ write(conffd, &ch, 1);
+ while (read(modfd, &ch, 1) == 1)
+ write(conffd, &ch, 1);
+ ch = '\n';
+ write(conffd, &ch, 1);
+ close(modfd);
+ return 0;
+}
+
+
+void SWMgr::setGlobalOption(const char *option, const char *value)
+{
+ for (FilterMap::iterator it = optionFilters.begin(); it != optionFilters.end(); it++) {
+ if ((*it).second->getOptionName()) {
+ if (!stricmp(option, (*it).second->getOptionName()))
+ (*it).second->setOptionValue(value);
+ }
+ }
+}
+
+
+const char *SWMgr::getGlobalOption(const char *option)
+{
+ for (FilterMap::iterator it = optionFilters.begin(); it != optionFilters.end(); it++) {
+ if ((*it).second->getOptionName()) {
+ if (!stricmp(option, (*it).second->getOptionName()))
+ return (*it).second->getOptionValue();
+ }
+ }
+ return 0;
+}
+
+
+const char *SWMgr::getGlobalOptionTip(const char *option)
+{
+ for (FilterMap::iterator it = optionFilters.begin(); it != optionFilters.end(); it++) {
+ if ((*it).second->getOptionName()) {
+ if (!stricmp(option, (*it).second->getOptionName()))
+ return (*it).second->getOptionTip();
+ }
+ }
+ return 0;
+}
+
+
+OptionsList SWMgr::getGlobalOptions()
+{
+ return options;
+}
+
+
+OptionsList SWMgr::getGlobalOptionValues(const char *option)
+{
+ OptionsList options;
+ for (FilterMap::iterator it = optionFilters.begin(); it != optionFilters.end(); it++) {
+ if ((*it).second->getOptionName()) {
+ if (!stricmp(option, (*it).second->getOptionName())) {
+ options = (*it).second->getOptionValues();
+ break; // just find the first one. All option filters with the same option name should expect the same values
+ }
+ }
+ }
+ return options;
+}
+
+
+signed char SWMgr::setCipherKey(const char *modName, const char *key) {
+ FilterMap::iterator it;
+ ModMap::iterator it2;
+
+ // check for filter that already exists
+ it = cipherFilters.find(modName);
+ if (it != cipherFilters.end()) {
+ ((CipherFilter *)(*it).second)->getCipher()->setCipherKey(key);
+ return 0;
+ }
+ // check if module exists
+ else {
+ it2 = Modules.find(modName);
+ if (it2 != Modules.end()) {
+ SWFilter *cipherFilter = new CipherFilter(key);
+ cipherFilters.insert(FilterMap::value_type(modName, cipherFilter));
+ cleanupFilters.push_back(cipherFilter);
+ (*it2).second->AddRawFilter(cipherFilter);
+ return 0;
+ }
+ }
+ return -1;
+}
diff --git a/src/modules/Makefile b/src/modules/Makefile
new file mode 100644
index 0000000..ef8eccd
--- /dev/null
+++ b/src/modules/Makefile
@@ -0,0 +1,5 @@
+
+root := ../..
+
+all:
+ make -C ${root}
diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am
new file mode 100644
index 0000000..944dc18
--- /dev/null
+++ b/src/modules/Makefile.am
@@ -0,0 +1,10 @@
+modulesdir = $(top_srcdir)/src/modules
+
+libsword_la_SOURCES += $(modulesdir)/swmodule.cpp
+
+include ../src/modules/common/Makefile.am
+include ../src/modules/filters/Makefile.am
+include ../src/modules/genbook/Makefile.am
+include ../src/modules/texts/Makefile.am
+include ../src/modules/comments/Makefile.am
+include ../src/modules/lexdict/Makefile.am
diff --git a/src/modules/comments/Makefile b/src/modules/comments/Makefile
new file mode 100644
index 0000000..1a2d00d
--- /dev/null
+++ b/src/modules/comments/Makefile
@@ -0,0 +1,5 @@
+
+root := ../../..
+
+all:
+ make -C ${root}
diff --git a/src/modules/comments/Makefile.am b/src/modules/comments/Makefile.am
new file mode 100644
index 0000000..1568544
--- /dev/null
+++ b/src/modules/comments/Makefile.am
@@ -0,0 +1,8 @@
+commentsdir = $(top_srcdir)/src/modules/comments
+
+libsword_la_SOURCES += $(commentsdir)/swcom.cpp
+
+include ../src/modules/comments/rawcom/Makefile.am
+include ../src/modules/comments/rawfiles/Makefile.am
+include ../src/modules/comments/zcom/Makefile.am
+include ../src/modules/comments/hrefcom/Makefile.am
diff --git a/src/modules/comments/hrefcom/Makefile b/src/modules/comments/hrefcom/Makefile
new file mode 100644
index 0000000..35d6648
--- /dev/null
+++ b/src/modules/comments/hrefcom/Makefile
@@ -0,0 +1,5 @@
+
+root := ../../../..
+
+all:
+ make -C ${root}
diff --git a/src/modules/comments/hrefcom/Makefile.am b/src/modules/comments/hrefcom/Makefile.am
new file mode 100644
index 0000000..a6a2115
--- /dev/null
+++ b/src/modules/comments/hrefcom/Makefile.am
@@ -0,0 +1,4 @@
+hrefcomdir = $(top_srcdir)/src/modules/comments/hrefcom
+
+libsword_la_SOURCES += $(hrefcomdir)/hrefcom.cpp
+
diff --git a/src/modules/comments/hrefcom/hrefcom.cpp b/src/modules/comments/hrefcom/hrefcom.cpp
new file mode 100644
index 0000000..a80e5b6
--- /dev/null
+++ b/src/modules/comments/hrefcom/hrefcom.cpp
@@ -0,0 +1,97 @@
+/******************************************************************************
+ * hrefcom.cpp - code for class 'HREFCom'- a module that produces HTML HREFs
+ * pointing to actual text desired. Uses standard
+ * files: ot and nt using indexs ??.bks ??.cps ??.vss
+ */
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#ifndef __GNUC__
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <string.h>
+#include <utilfuns.h>
+#include <rawverse.h>
+#include <hrefcom.h>
+
+
+ /******************************************************************************
+ * HREFCom Constructor - Initializes data for instance of HREFCom
+ *
+ * ENT: iname - Internal name for module
+ * iprefix - string to prepend to each HREF (e.g. "file://mods/com/jfb/")
+ * idesc - Name to display to user for module
+ * idisp - Display object to use for displaying
+ */
+
+HREFCom::HREFCom(const char *ipath, const char *iprefix, const char *iname, const char *idesc, SWDisplay *idisp) : RawVerse(ipath), SWCom(iname, idesc, idisp)
+{
+ prefix = 0;
+ stdstr(&prefix, iprefix);
+}
+
+
+/******************************************************************************
+ * HREFCom Destructor - Cleans up instance of HREFCom
+ */
+
+HREFCom::~HREFCom()
+{
+ if (prefix)
+ delete [] prefix;
+}
+
+
+/******************************************************************************
+ * HREFCom::operator char * - Returns the correct verse when char * cast
+ * is requested
+ *
+ * RET: string buffer with verse
+ */
+
+char *HREFCom::getRawEntry() {
+ long start;
+ unsigned short size;
+ char *tmpbuf;
+ VerseKey *key = 0;
+
+#ifndef _WIN32_WCE
+ try {
+#endif
+ key = SWDYNAMIC_CAST(VerseKey, this->key);
+#ifndef _WIN32_WCE
+ }
+ catch ( ... ) {}
+#endif
+ if (!key)
+ key = new VerseKey(this->key);
+
+ findoffset(key->Testament(), key->Index(), &start, &size);
+ entrySize = size; // support getEntrySize call
+
+ unsigned long newsize = ((size + 2) + strlen(prefix)) * FILTERPAD;
+ if (newsize > entrybufallocsize) {
+ if (entrybuf)
+ delete [] entrybuf;
+ entrybuf = new char [ newsize ];
+ entrybufallocsize = newsize;
+ }
+ tmpbuf = new char [ size + 10 ];
+
+ gettext(key->Testament(), start, size + 2, tmpbuf);
+ sprintf(entrybuf, "%s%s", prefix, tmpbuf);
+ preptext(entrybuf);
+
+ delete [] tmpbuf;
+
+ if (key != this->key)
+ delete key;
+
+ return entrybuf;
+}
diff --git a/src/modules/comments/hrefcom/jfbgen.cpp b/src/modules/comments/hrefcom/jfbgen.cpp
new file mode 100644
index 0000000..8b66a60
--- /dev/null
+++ b/src/modules/comments/hrefcom/jfbgen.cpp
@@ -0,0 +1,242 @@
+/*****************************************************************************
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef __GNUC__
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <fcntl.h>
+#include <versekey.h>
+
+#ifndef O_BINARY
+ #define O_BINARY 0
+#endif
+
+void writeidx(VerseKey &key1, VerseKey &key2, VerseKey &key3, long offset, short size);
+char findbreak(int fp, long *offset, int *num1, int *num2, int *rangemax, short *size);
+void openfiles();
+void checkparams(int argc, char **argv);
+void charsetconvert(char *data);
+
+
+VerseKey key1, key2, key3;
+int fp, vfp, cfp, bfp;
+long chapoffset;
+short chapsize;
+char testmnt;
+char startflag = 0;
+
+
+main(int argc, char **argv)
+{
+ long pos, offset;
+ int num1, num2, rangemax, curbook = 0, curchap = 0, curverse = 0;
+ char buf[127];
+ short size, tmp;
+ extern struct zonline online;
+
+ checkparams(argc, argv);
+
+ key1 = key2 = key3 = "Genesis 1:1";
+
+ openfiles();
+
+ num1 = key1.Chapter();
+ num2 = key1.Verse();
+
+ while(!findbreak(fp, &offset, &num1, &num2, &rangemax, &size)) {
+ if (!startflag) {
+ startflag = 1;
+ }
+ else {
+ if (num2 < key2.Verse()) { // new chapter
+ if (num1 <= key2.Chapter()) { // new book
+ key2.Verse(1);
+ key2.Chapter(1);
+ key2.Book(key2.Book()+1);
+ }
+ printf("Found Chapter Break: %d ('%s')\n", num1, (const char *)key2);
+ chapoffset = offset;
+ chapsize = size;
+// continue;
+ }
+ }
+ key2.Verse(1);
+ key2.Chapter(num1);
+ key2.Verse(num2);
+
+ key3 = key2;
+// key3 += (rangemax - key3.Verse());
+
+ writeidx(key1, key2, key3, offset, size);
+ }
+ close(vfp);
+ close(cfp);
+ close(bfp);
+ close(fp);
+}
+
+
+/**************************************************************************
+ * ENT: key1 - current location of index
+ * key2 - minimum keyval for which this offset is valid
+ * key3 - maximum keyval for which this offset is valid
+ */
+
+void writeidx(VerseKey &key1, VerseKey &key2, VerseKey &key3, long offset, short size)
+{
+ long pos;
+ short tmp;
+
+ if (key1.Verse() == 1) { // new chapter
+ if (key1.Chapter() == 1) { // new book
+ pos = lseek(cfp, 0, SEEK_CUR);
+ write(bfp, &pos, 4);
+ pos = lseek(vfp, 0, SEEK_CUR); /* Book intro (cps) */
+ write(cfp, &pos, 4);
+ write(vfp, &chapoffset, 4); /* Book intro (vss) set to same as chap for now(it should be chap 1 which usually contains the book into anyway)*/
+ write(vfp, &chapsize, 2);
+ }
+ pos = lseek(vfp, 0, SEEK_CUR);
+ write(cfp, &pos, 4);
+ write(vfp, &chapoffset, 4); /* Chapter intro */
+ write(vfp, &chapsize, 2);
+ }
+ if (key1 >= key2) {
+ write(vfp, &offset, 4);
+ write(vfp, &size, 2);
+ }
+ else {
+ pos = 0;
+ tmp = 0;
+ write(vfp, &pos, 4);
+ write(vfp, &tmp, 2);
+ }
+ key1++;
+}
+
+
+static VerseKey inckey = "Genesis 1:1";
+
+char findbreak(int fp, long *offset, int *num1, int *num2, int *rangemax, short *size)
+{
+ char buf[7];
+ char buf2[20];
+ char ch;
+ char loop;
+ long offset2;
+ int ch2, vs2, rm2;
+ bool flag;
+ long chapstart = 0;
+ static int olbvnum = 0;
+ char data[256];
+ char *bookabrev[66] = {"Ge", "Ex", "Le", "Nu", "De", "Jos", "Jud", "Ru",
+ "1Sa", "2Sa", "1Ki", "2Ki", "1Ch", "2Ch", "Ezr", "Ne", "Es",
+ "Job", "Ps", "Pr", "Ec", "So", "Isa", "Jer", "La", "Eze", "Da",
+ "Ho", "Joe", "Am", "Ob", "Jon", "Mic", "Na", "Heb", "Zep",
+ "Hag", "Zec", "Mal",
+ "Mt", "Mr", "Lu", "Joh", "Ac", "Ro", "1Co", "2Co", "Ga",
+ "Eph", "Php", "Col", "1Th", "2Th", "1Ti", "2Ti", "Tit", "Phm",
+ "Heb", "Jas", "1Pe", "2Pe", "1Jo", "2Jo", "3Jo", "Jude", "Re" };
+
+ if (++olbvnum <= 31102) {
+
+ if (olbvnum == 23146) { // "Matthew 1:1"
+ close(vfp);
+ close(cfp);
+ close(bfp);
+ close(fp);
+ key1 = key2 = key3 = inckey = "Matthew 1:1";
+ openfiles();
+ startflag = 0;
+ }
+
+
+ *offset = lseek(fp, 0, SEEK_CUR);
+
+ if ((olbvnum!=1) && (olbvnum != 23146))
+ inckey++;
+
+ *num1 = inckey.Chapter();
+ *num2 = inckey.Verse();
+
+ sprintf(data, "JFB%.2d.htm#%s%d_%d", inckey.Book() + ((inckey.Testament()>1)?39:0), bookabrev[inckey.Book() + ((inckey.Testament()>1)?39:0)-1], inckey.Chapter(), inckey.Verse());
+ write(fp, data, strlen(data));
+
+ *size = lseek(fp, 0, SEEK_CUR) - *offset;
+ write(fp, "\n", 1);
+ return 0;
+ }
+ return 1;
+}
+
+
+void openfiles()
+{
+ char buf[255];
+ char fname[5];
+ long pos;
+ short size;
+
+ testmnt = key1.Testament();
+
+ strcpy(fname, (testmnt==2) ? "nt" : "ot");
+ unlink(fname);
+ if ((fp = open(fname, O_CREAT|O_RDWR|O_BINARY)) == -1) {
+ fprintf(stderr, "Couldn't open file: %s\n", fname);
+ exit(1);
+ }
+
+ sprintf(buf, "%s.vss", fname);
+ unlink(buf);
+ if ((vfp = open(buf, O_CREAT|O_WRONLY|O_BINARY)) == -1) {
+ fprintf(stderr, "Couldn't open file: %s\n", buf);
+ exit(1);
+ }
+
+ sprintf(buf, "%s.cps", fname);
+ unlink(buf);
+ if ((cfp = open(buf, O_CREAT|O_WRONLY|O_BINARY)) == -1) {
+ fprintf(stderr, "Couldn't open file: %s\n", buf);
+ exit(1);
+ }
+
+ sprintf(buf, "%s.bks", fname);
+ unlink(buf);
+ if ((bfp = open(buf, O_CREAT|O_WRONLY|O_BINARY)) == -1) {
+ fprintf(stderr, "Couldn't open file: %s\n", buf);
+ exit(1);
+ }
+
+ pos = 0;
+ write(bfp, &pos, 4); /* Book offset for testament intros */
+ pos = 4;
+ write(cfp, &pos, 4); /* Chapter offset for testament intro */
+
+
+/* Right now just zero out intros until parsing correctly */
+ pos = 0;
+ size = 0;
+ write(vfp, &pos, 4); /* Module intro */
+ write(vfp, &size, 2);
+ write(vfp, &pos, 4); /* Testament intro */
+ write(vfp, &size, 2);
+
+}
+
+
+void checkparams(int argc, char **argv)
+{
+ if (argc !=1) {
+ fprintf(stderr, "usage: %s\n", argv[0]);
+ exit(1);
+ }
+}
diff --git a/src/modules/comments/rawcom/Makefile b/src/modules/comments/rawcom/Makefile
new file mode 100644
index 0000000..35d6648
--- /dev/null
+++ b/src/modules/comments/rawcom/Makefile
@@ -0,0 +1,5 @@
+
+root := ../../../..
+
+all:
+ make -C ${root}
diff --git a/src/modules/comments/rawcom/Makefile.am b/src/modules/comments/rawcom/Makefile.am
new file mode 100644
index 0000000..901cf6b
--- /dev/null
+++ b/src/modules/comments/rawcom/Makefile.am
@@ -0,0 +1,4 @@
+rawcomdir = $(top_srcdir)/src/modules/comments/rawcom
+
+libsword_la_SOURCES += $(rawcomdir)/rawcom.cpp
+
diff --git a/src/modules/comments/rawcom/mhcidx.cpp b/src/modules/comments/rawcom/mhcidx.cpp
new file mode 100644
index 0000000..df16f55
--- /dev/null
+++ b/src/modules/comments/rawcom/mhcidx.cpp
@@ -0,0 +1,292 @@
+/*****************************************************************************
+ *
+ * This code wreaks but works (at least for MHC). Good luck!
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef __GNUC__
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <fcntl.h>
+#include <versekey.h>
+
+
+void writeidx(VerseKey &key1, VerseKey &key2, VerseKey &key3, long offset, short size);
+char findbreak(int fp, long *offset, int *num1, int *num2, int *rangemax, short *size);
+void openfiles(char *fname);
+void checkparams(int argc, char **argv);
+
+
+VerseKey key1, key2, key3;
+int fp, vfp, cfp, bfp;
+long chapoffset;
+short chapsize;
+char testmnt;
+
+
+main(int argc, char **argv)
+{
+ long pos, offset;
+ int num1, num2, rangemax, curbook = 0, curchap = 0, curverse = 0;
+ char buf[127], startflag = 0;
+ short size, tmp;
+
+ checkparams(argc, argv);
+
+ openfiles(argv[1]);
+
+ testmnt = key1.Testament();
+ pos = 0;
+ write(bfp, &pos, 4); /* Book offset for testament intros */
+ pos = 4;
+ write(cfp, &pos, 4); /* Chapter offset for testament intro */
+
+
+/* Right now just zero out intros until parsing correctly */
+ pos = 0;
+ size = 0;
+ write(vfp, &pos, 4); /* Module intro */
+ write(vfp, &size, 2);
+ write(vfp, &pos, 4); /* Testament intro */
+ write(vfp, &size, 2);
+
+ while(!findbreak(fp, &offset, &num1, &num2, &rangemax, &size)) {
+ if (num2) {
+ key2.Verse(1);
+ key2.Chapter(num1);
+ key2.Verse(num2);
+ }
+ else {
+ key2.Verse(1);
+ if (!startflag) {
+ startflag = 1;
+ }
+ else {
+ if (num1 <= key2.Chapter()) { // new book
+ key2.Chapter(1);
+ key2.Book(key2.Book()+1);
+ }
+ }
+ key2.Chapter(num1);
+ printf("Found Chapter Break: %d ('%s')\n", num1, (const char *)key2);
+ chapoffset = offset;
+ chapsize = size;
+ continue;
+ }
+
+ key3 = key2;
+ key3 += (rangemax - key3.Verse());
+
+ writeidx(key1, key2, key3, offset, size);
+ }
+ close(vfp);
+ close(cfp);
+ close(bfp);
+ close(fp);
+}
+
+
+/**************************************************************************
+ * ENT: key1 - current location of index
+ * key2 - minimum keyval for which this offset is valid
+ * key3 - maximum keyval for which this offset is valid
+ */
+
+void writeidx(VerseKey &key1, VerseKey &key2, VerseKey &key3, long offset, short size)
+{
+ long pos;
+ short tmp;
+
+ for (; ((key1 <= key3) && (key1.Error() != KEYERR_OUTOFBOUNDS) && (key1.Testament() == testmnt)); key1+=1) {
+ if (key1.Verse() == 1) { // new chapter
+ if (key1.Chapter() == 1) { // new book
+ pos = lseek(cfp, 0, SEEK_CUR);
+ write(bfp, &pos, 4);
+ pos = lseek(vfp, 0, SEEK_CUR); /* Book intro (cps) */
+ write(cfp, &pos, 4);
+ write(vfp, &chapoffset, 4); /* Book intro (vss) set to same as chap for now(it should be chap 1 which usually contains the book into anyway)*/
+ write(vfp, &chapsize, 2);
+ }
+ pos = lseek(vfp, 0, SEEK_CUR);
+ write(cfp, &pos, 4);
+ write(vfp, &chapoffset, 4); /* Chapter intro */
+ write(vfp, &chapsize, 2);
+ }
+ if (key1 >= key2) {
+ write(vfp, &offset, 4);
+ write(vfp, &size, 2);
+ }
+ else {
+ pos = 0;
+ tmp = 0;
+ write(vfp, &pos, 4);
+ write(vfp, &tmp, 2);
+ }
+ }
+}
+
+
+char startentry(char *buf)
+{
+ char loop;
+
+ if (buf[0] != 10)
+ return 0;
+ if (buf[1] != '#')
+ return 0;
+ if (!isdigit(buf[2]))
+ return 0;
+ for (loop = 3; loop < 7; loop++) {
+ if (buf[loop] == ' ')
+ break;
+ if ((!isdigit(buf[loop])) && (buf[loop] != ',') && (buf[loop] != '-'))
+ return 0;
+ }
+ return 1;
+}
+
+
+char findbreak(int fp, long *offset, int *num1, int *num2, int *rangemax, short *size)
+{
+ char buf[7];
+ char buf2[20];
+ char ch;
+ char loop;
+ long offset2;
+ int ch2, vs2, rm2;
+
+ memset(buf, ' ', 7);
+
+ while (1) {
+ if (startentry(buf)) {
+ memset(buf, ' ', 2);
+ for (loop = 2; loop < 7; loop++) {
+ if ((buf[loop] == '-') || (buf[loop] == ',') || (buf[loop] == ' ')) {
+ buf[loop] = 0;
+ *num2 = atoi(buf);
+ break;
+ }
+ }
+ for (ch = loop + 1; ch < 7; ch++) {
+ if (buf[ch] == ' ') {
+ break;
+ }
+ }
+ buf[ch] = 0;
+ *rangemax = atoi(&buf[loop+1]);
+ if (!*rangemax)
+ *rangemax = *num2;
+ *offset = lseek(fp, 0, SEEK_CUR) - 5;
+ if (size) {
+ if (findbreak(fp, &offset2, &ch2, &vs2, &rm2, 0)) {
+ *size = (short) (lseek(fp, 0, SEEK_END) - (*offset));
+ }
+ else {
+ if (vs2) {
+ *size = (offset2 - (*offset)) - 3;
+ }
+ else {
+ sprintf(buf2, "$-$-$- XX:%d", ch2);
+ *size = (offset2 - (*offset)) - ((strlen(buf2) + 4));
+ }
+ }
+ lseek(fp, *offset, SEEK_SET);
+ }
+ return 0;
+ }
+
+ if (!strncmp(buf, "$-$-$-", 6)) {
+ memset(buf2, 0, 7);
+ loop = 0;
+ while ((read(fp, &buf2[loop], 1) == 1) && (loop < 7)) {
+ if ((buf2[loop] == 10) || (buf2[loop] == 13)) {
+ buf2[loop] = 0;
+ break;
+ }
+ loop++;
+ }
+ while (read(fp, &ch, 1) == 1) {
+ if (ch == '*')
+ break;
+ }
+
+ *offset = lseek(fp, 0, SEEK_CUR) - 1;
+ *num2 = 0;
+ for (loop = strlen(buf2) - 1; loop; loop--) {
+ if (buf2[loop] == ':')
+ break;
+ }
+ *num1 = atoi(&buf2[loop+1]);
+ printf("Chapter marker: %s\n", buf2);
+ if (size) {
+ if (findbreak(fp, &offset2, &ch2, &vs2, &rm2, 0)) {
+ *size = (short) (lseek(fp, 0, SEEK_END) - (*offset));
+ }
+ else {
+ if (vs2) {
+ *size = (offset2 - (*offset)) - 3;
+ }
+ else {
+ sprintf(buf2, "$-$-$- XX:%d", ch2);
+ *size = (offset2 - (*offset)) - ((strlen(buf2) + 4));
+ }
+ }
+ lseek(fp, *offset, SEEK_SET);
+ }
+ return 0;
+ }
+
+
+ memmove(buf, &buf[1], 6);
+ if (read(fp, &buf[6], 1) != 1)
+ return 1;
+ }
+}
+
+
+void openfiles(char *fname)
+{
+ char buf[255];
+
+ if ((fp = open(fname, O_RDONLY)) == -1) {
+ fprintf(stderr, "Couldn't open file: %s\n", fname);
+ exit(1);
+ }
+
+ sprintf(buf, "%s.vss", fname);
+ if ((vfp = open(buf, O_CREAT|O_WRONLY)) == -1) {
+ fprintf(stderr, "Couldn't open file: %s\n", buf);
+ exit(1);
+ }
+
+ sprintf(buf, "%s.cps", fname);
+ if ((cfp = open(buf, O_CREAT|O_WRONLY)) == -1) {
+ fprintf(stderr, "Couldn't open file: %s\n", buf);
+ exit(1);
+ }
+
+ sprintf(buf, "%s.bks", fname);
+ if ((bfp = open(buf, O_CREAT|O_WRONLY)) == -1) {
+ fprintf(stderr, "Couldn't open file: %s\n", buf);
+ exit(1);
+ }
+}
+
+
+void checkparams(int argc, char **argv)
+{
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s <file to process> [nt - for new testmt file]\n", argv[0]);
+ exit(1);
+ }
+ if (argc == 3)
+ key1 = key2 = key3 = "Matthew 1:1";
+ else key1 = key2 = key3 = "Genesis 1:1";
+}
diff --git a/src/modules/comments/rawcom/rawcom.cpp b/src/modules/comments/rawcom/rawcom.cpp
new file mode 100644
index 0000000..ca93c64
--- /dev/null
+++ b/src/modules/comments/rawcom/rawcom.cpp
@@ -0,0 +1,275 @@
+/******************************************************************************
+ * rawcom.cpp - code for class 'RawCom'- a module that reads raw commentary
+ * files: ot and nt using indexs ??.bks ??.cps ??.vss
+ */
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#ifndef __GNUC__
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <string.h>
+#include <utilfuns.h>
+#include <rawverse.h>
+#include <rawcom.h>
+
+
+ /******************************************************************************
+ * RawCom Constructor - Initializes data for instance of RawCom
+ *
+ * ENT: iname - Internal name for module
+ * idesc - Name to display to user for module
+ * idisp - Display object to use for displaying
+ */
+
+RawCom::RawCom(const char *ipath, const char *iname, const char *idesc, SWDisplay *idisp, SWTextEncoding encoding, SWTextDirection dir, SWTextMarkup markup, const char* ilang)
+ : RawVerse(ipath),
+ SWCom(iname, idesc, idisp, encoding, dir, markup, ilang){
+}
+
+
+/******************************************************************************
+ * RawCom Destructor - Cleans up instance of RawCom
+ */
+
+RawCom::~RawCom()
+{
+}
+
+
+/******************************************************************************
+ * RawCom::operator char * - Returns the correct verse when char * cast
+ * is requested
+ *
+ * RET: string buffer with verse
+ */
+
+char *RawCom::getRawEntry() {
+ long start = 0;
+ unsigned short size = 0;
+ VerseKey *key = 0;
+
+#ifndef _WIN32_WCE
+ try {
+#endif
+ key = SWDYNAMIC_CAST(VerseKey, this->key);
+#ifndef _WIN32_WCE
+ }
+ catch ( ... ) {}
+#endif
+ if (!key)
+ key = new VerseKey(this->key);
+
+
+ findoffset(key->Testament(), key->Index(), &start, &size);
+ entrySize = size; // support getEntrySize call
+
+ unsigned long newsize = (size + 2) * FILTERPAD;
+ if (newsize > entrybufallocsize) {
+ if (entrybuf)
+ delete [] entrybuf;
+ entrybuf = new char [ newsize ];
+ entrybufallocsize = newsize;
+ }
+ *entrybuf = 0;
+
+ gettext(key->Testament(), start, (size + 2), entrybuf);
+
+ rawFilter(entrybuf, size, key);
+
+ if (!isUnicode())
+ preptext(entrybuf);
+
+ if (key != this->key)
+ delete key;
+
+ return entrybuf;
+}
+
+
+/******************************************************************************
+ * RawCom::operator += - Increments module key a number of entries
+ *
+ * ENT: increment - Number of entries to jump forward
+ *
+ * RET: *this
+ */
+
+SWModule &RawCom::operator +=(int increment)
+{
+ long start;
+ unsigned short size;
+ VerseKey *tmpkey = 0;
+
+#ifndef _WIN32_WCE
+ try {
+#endif
+ tmpkey = SWDYNAMIC_CAST(VerseKey, key);
+#ifndef _WIN32_WCE
+ }
+ catch ( ... ) {}
+#endif
+ if (!tmpkey)
+ tmpkey = new VerseKey(key);
+
+ findoffset(tmpkey->Testament(), tmpkey->Index(), &start, &size);
+
+ SWKey lastgood = *tmpkey;
+ while (increment) {
+ long laststart = start;
+ unsigned short lastsize = size;
+ SWKey lasttry = *tmpkey;
+ (increment > 0) ? (*key)++ : (*key)--;
+ if (tmpkey != key)
+ delete tmpkey;
+ tmpkey = 0;
+#ifndef _WIN32_WCE
+ try {
+#endif
+ tmpkey = SWDYNAMIC_CAST(VerseKey, key);
+#ifndef _WIN32_WCE
+ }
+ catch ( ... ) {}
+#endif
+ if (!tmpkey)
+ tmpkey = new VerseKey(key);
+
+ if ((error = key->Error())) {
+ *key = lastgood;
+ break;
+ }
+ long index = tmpkey->Index();
+ findoffset(tmpkey->Testament(), index, &start, &size);
+ if ((((laststart != start) || (lastsize != size))||(!skipConsecutiveLinks)) && (start >= 0) && (size)) {
+ increment += (increment < 0) ? 1 : -1;
+ lastgood = *tmpkey;
+ }
+ }
+ error = (error) ? KEYERR_OUTOFBOUNDS : 0;
+
+ if (tmpkey != key)
+ delete tmpkey;
+
+ return *this;
+}
+
+SWModule &RawCom::setentry(const char *inbuf, long len) {
+ VerseKey *key = 0;
+ // see if we have a VerseKey * or decendant
+#ifndef _WIN32_WCE
+ try {
+#endif
+ key = SWDYNAMIC_CAST(VerseKey, this->key);
+#ifndef _WIN32_WCE
+ }
+ catch ( ... ) {}
+#endif
+ // if we don't have a VerseKey * decendant, create our own
+ if (!key)
+ key = new VerseKey(this->key);
+
+ settext(key->Testament(), key->Index(), inbuf, len);
+
+ if (this->key != key) // free our key if we created a VerseKey
+ delete key;
+
+ return *this;
+}
+
+SWModule &RawCom::operator <<(const char *inbuf) {
+ VerseKey *key = 0;
+ // see if we have a VerseKey * or decendant
+#ifndef _WIN32_WCE
+ try {
+#endif
+ key = SWDYNAMIC_CAST(VerseKey, this->key);
+#ifndef _WIN32_WCE
+ }
+ catch ( ... ) {}
+#endif
+ // if we don't have a VerseKey * decendant, create our own
+ if (!key)
+ key = new VerseKey(this->key);
+
+ settext(key->Testament(), key->Index(), inbuf);
+
+ if (this->key != key) // free our key if we created a VerseKey
+ delete key;
+
+ return *this;
+}
+
+
+SWModule &RawCom::operator <<(const SWKey *inkey) {
+ VerseKey *destkey = 0;
+ const VerseKey *srckey = 0;
+ // see if we have a VerseKey * or decendant
+#ifndef _WIN32_WCE
+ try {
+#endif
+ destkey = SWDYNAMIC_CAST(VerseKey, this->key);
+#ifndef _WIN32_WCE
+ }
+ catch ( ... ) {}
+#endif
+ // if we don't have a VerseKey * decendant, create our own
+ if (!destkey)
+ destkey = new VerseKey(this->key);
+
+ // see if we have a VerseKey * or decendant
+#ifndef _WIN32_WCE
+ try {
+#endif
+ srckey = SWDYNAMIC_CAST(VerseKey, inkey);
+#ifndef _WIN32_WCE
+ }
+ catch ( ... ) {}
+#endif
+ // if we don't have a VerseKey * decendant, create our own
+ if (!srckey)
+ srckey = new VerseKey(inkey);
+
+ linkentry(destkey->Testament(), destkey->Index(), srckey->Index());
+
+ if (this->key != destkey) // free our key if we created a VerseKey
+ delete destkey;
+
+ if (inkey != srckey) // free our key if we created a VerseKey
+ delete srckey;
+
+ return *this;
+}
+
+
+/******************************************************************************
+ * RawCom::deleteEntry - deletes this entry
+ *
+ * RET: *this
+ */
+
+void RawCom::deleteEntry() {
+
+ VerseKey *key = 0;
+
+#ifndef _WIN32_WCE
+ try {
+#endif
+ key = SWDYNAMIC_CAST(VerseKey, this->key);
+#ifndef _WIN32_WCE
+ }
+ catch ( ... ) {}
+#endif
+ if (!key)
+ key = new VerseKey(this->key);
+
+ settext(key->Testament(), key->Index(), "");
+
+ if (key != this->key)
+ delete key;
+}
diff --git a/src/modules/comments/rawcom/rtfidx.cpp b/src/modules/comments/rawcom/rtfidx.cpp
new file mode 100644
index 0000000..38b38bc
--- /dev/null
+++ b/src/modules/comments/rawcom/rtfidx.cpp
@@ -0,0 +1,292 @@
+/*****************************************************************************
+ *
+ * This code wreaks but works (at least for MHC). Good luck!
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef __GNUC__
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <fcntl.h>
+#include <versekey.h>
+
+
+void writeidx(VerseKey &key1, VerseKey &key2, VerseKey &key3, long offset, short size);
+char findbreak(int fp, long *offset, int *num1, int *num2, int *rangemax, short *size);
+void openfiles(char *fname);
+void checkparams(int argc, char **argv);
+
+
+VerseKey key1, key2, key3;
+int fp, vfp, cfp, bfp;
+long chapoffset;
+short chapsize;
+char testmnt;
+
+
+main(int argc, char **argv)
+{
+ long pos, offset;
+ int num1, num2, rangemax, curbook = 0, curchap = 0, curverse = 0;
+ char buf[127], startflag = 0;
+ short size, tmp;
+
+ checkparams(argc, argv);
+
+ openfiles(argv[1]);
+
+ testmnt = key1.Testament();
+ pos = 0;
+ write(bfp, &pos, 4); /* Book offset for testament intros */
+ pos = 4;
+ write(cfp, &pos, 4); /* Chapter offset for testament intro */
+
+
+/* Right now just zero out intros until parsing correctly */
+ pos = 0;
+ size = 0;
+ write(vfp, &pos, 4); /* Module intro */
+ write(vfp, &size, 2);
+ write(vfp, &pos, 4); /* Testament intro */
+ write(vfp, &size, 2);
+
+ while(!findbreak(fp, &offset, &num1, &num2, &rangemax, &size)) {
+ if (num2) {
+ key2.Verse(1);
+ key2.Chapter(num1);
+ key2.Verse(num2);
+ }
+ else {
+ key2.Verse(1);
+ if (!startflag) {
+ startflag = 1;
+ }
+ else {
+ if (num1 <= key2.Chapter()) { // new book
+ key2.Chapter(1);
+ key2.Book(key2.Book()+1);
+ }
+ }
+ key2.Chapter(num1);
+ printf("Found Chapter Break: %d ('%s')\n", num1, (char *)key2);
+ chapoffset = offset;
+ chapsize = size;
+ continue;
+ }
+
+ key3 = key2;
+ key3 += (rangemax - key3.Verse());
+
+ writeidx(key1, key2, key3, offset, size);
+ }
+ close(vfp);
+ close(cfp);
+ close(bfp);
+ close(fp);
+}
+
+
+/**************************************************************************
+ * ENT: key1 - current location of index
+ * key2 - minimum keyval for which this offset is valid
+ * key3 - maximum keyval for which this offset is valid
+ */
+
+void writeidx(VerseKey &key1, VerseKey &key2, VerseKey &key3, long offset, short size)
+{
+ long pos;
+ short tmp;
+
+ for (; ((key1 <= key3) && (key1.Error() != KEYERR_OUTOFBOUNDS) && (key1.Testament() == testmnt)); key1+=1) {
+ if (key1.Verse() == 1) { // new chapter
+ if (key1.Chapter() == 1) { // new book
+ pos = lseek(cfp, 0, SEEK_CUR);
+ write(bfp, &pos, 4);
+ pos = lseek(vfp, 0, SEEK_CUR); /* Book intro (cps) */
+ write(cfp, &pos, 4);
+ write(vfp, &chapoffset, 4); /* Book intro (vss) set to same as chap for now(it should be chap 1 which usually contains the book into anyway)*/
+ write(vfp, &chapsize, 2);
+ }
+ pos = lseek(vfp, 0, SEEK_CUR);
+ write(cfp, &pos, 4);
+ write(vfp, &chapoffset, 4); /* Chapter intro */
+ write(vfp, &chapsize, 2);
+ }
+ if (key1 >= key2) {
+ write(vfp, &offset, 4);
+ write(vfp, &size, 2);
+ }
+ else {
+ pos = 0;
+ tmp = 0;
+ write(vfp, &pos, 4);
+ write(vfp, &tmp, 2);
+ }
+ }
+}
+
+
+char startentry(char *buf)
+{
+ char loop;
+
+ if (buf[0] != 10)
+ return 0;
+ if (buf[1] != '#')
+ return 0;
+ if (!isdigit(buf[2]))
+ return 0;
+ for (loop = 3; loop < 7; loop++) {
+ if (buf[loop] == ' ')
+ break;
+ if ((!isdigit(buf[loop])) && (buf[loop] != ',') && (buf[loop] != '-'))
+ return 0;
+ }
+ return 1;
+}
+
+
+char findbreak(int fp, long *offset, int *num1, int *num2, int *rangemax, short *size)
+{
+ char buf[7];
+ char buf2[20];
+ char ch;
+ char loop;
+ long offset2;
+ int ch2, vs2, rm2;
+
+ memset(buf, ' ', 7);
+
+ while (1) {
+ if (startentry(buf)) {
+ memset(buf, ' ', 2);
+ for (loop = 2; loop < 7; loop++) {
+ if ((buf[loop] == '-') || (buf[loop] == ',') || (buf[loop] == ' ')) {
+ buf[loop] = 0;
+ *num2 = atoi(buf);
+ break;
+ }
+ }
+ for (ch = loop + 1; ch < 7; ch++) {
+ if (buf[ch] == ' ') {
+ break;
+ }
+ }
+ buf[ch] = 0;
+ *rangemax = atoi(&buf[loop+1]);
+ if (!*rangemax)
+ *rangemax = *num2;
+ *offset = lseek(fp, 0, SEEK_CUR) - 5;
+ if (size) {
+ if (findbreak(fp, &offset2, &ch2, &vs2, &rm2, 0)) {
+ *size = (short) (lseek(fp, 0, SEEK_END) - (*offset));
+ }
+ else {
+ if (vs2) {
+ *size = (offset2 - (*offset)) - 3;
+ }
+ else {
+ sprintf(buf2, "$-$-$- XX:%d", ch2);
+ *size = (offset2 - (*offset)) - ((strlen(buf2) + 4));
+ }
+ }
+ lseek(fp, *offset, SEEK_SET);
+ }
+ return 0;
+ }
+
+ if (!strncmp(buf, "$-$-$-", 6)) {
+ memset(buf2, 0, 7);
+ loop = 0;
+ while ((read(fp, &buf2[loop], 1) == 1) && (loop < 7)) {
+ if ((buf2[loop] == 10) || (buf2[loop] == 13)) {
+ buf2[loop] = 0;
+ break;
+ }
+ loop++;
+ }
+ while (read(fp, &ch, 1) == 1) {
+ if (ch == '*')
+ break;
+ }
+
+ *offset = lseek(fp, 0, SEEK_CUR) - 1;
+ *num2 = 0;
+ for (loop = strlen(buf2) - 1; loop; loop--) {
+ if (buf2[loop] == ':')
+ break;
+ }
+ *num1 = atoi(&buf2[loop+1]);
+ printf("Chapter marker: %s\n", buf2);
+ if (size) {
+ if (findbreak(fp, &offset2, &ch2, &vs2, &rm2, 0)) {
+ *size = (short) (lseek(fp, 0, SEEK_END) - (*offset));
+ }
+ else {
+ if (vs2) {
+ *size = (offset2 - (*offset)) - 3;
+ }
+ else {
+ sprintf(buf2, "$-$-$- XX:%d", ch2);
+ *size = (offset2 - (*offset)) - ((strlen(buf2) + 4));
+ }
+ }
+ lseek(fp, *offset, SEEK_SET);
+ }
+ return 0;
+ }
+
+
+ memmove(buf, &buf[1], 6);
+ if (read(fp, &buf[6], 1) != 1)
+ return 1;
+ }
+}
+
+
+void openfiles(char *fname)
+{
+ char buf[255];
+
+ if ((fp = open(fname, O_RDONLY)) == -1) {
+ fprintf(stderr, "Couldn't open file: %s\n", fname);
+ exit(1);
+ }
+
+ sprintf(buf, "%s.vss", fname);
+ if ((vfp = open(buf, O_CREAT|O_WRONLY)) == -1) {
+ fprintf(stderr, "Couldn't open file: %s\n", buf);
+ exit(1);
+ }
+
+ sprintf(buf, "%s.cps", fname);
+ if ((cfp = open(buf, O_CREAT|O_WRONLY)) == -1) {
+ fprintf(stderr, "Couldn't open file: %s\n", buf);
+ exit(1);
+ }
+
+ sprintf(buf, "%s.bks", fname);
+ if ((bfp = open(buf, O_CREAT|O_WRONLY)) == -1) {
+ fprintf(stderr, "Couldn't open file: %s\n", buf);
+ exit(1);
+ }
+}
+
+
+void checkparams(int argc, char **argv)
+{
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s <file to process> [nt - for new testmt file]\n", argv[0]);
+ exit(1);
+ }
+ if (argc == 3)
+ key1 = key2 = key3 = "Matthew 1:1";
+ else key1 = key2 = key3 = "Genesis 1:1";
+}
diff --git a/src/modules/comments/rawcom/rwpidx.cpp b/src/modules/comments/rawcom/rwpidx.cpp
new file mode 100644
index 0000000..afcbd81
--- /dev/null
+++ b/src/modules/comments/rawcom/rwpidx.cpp
@@ -0,0 +1,266 @@
+/*****************************************************************************
+ *
+ * This code wreaks but works (at least for RWP). Good luck!
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef __GNUC__
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <fcntl.h>
+#include <versekey.h>
+
+
+void writeidx(VerseKey &key1, VerseKey &key2, VerseKey &key3, long offset, short size);
+char findbreak(int fp, long *offset, int *num1, int *num2, int *rangemax, short *size);
+void openfiles(char *fname);
+void checkparams(int argc, char **argv);
+
+
+VerseKey key1, key2, key3;
+int fp, vfp, cfp, bfp;
+long chapoffset;
+short chapsize;
+char testmnt;
+
+
+main(int argc, char **argv)
+{
+ long pos, offset;
+ int num1 = 0, num2 = 0, rangemax, curbook = 0, curchap = 0, curverse = 0;
+ char buf[127], startflag = 0;
+ short size, tmp;
+
+ checkparams(argc, argv);
+
+ openfiles(argv[1]);
+
+ testmnt = key1.Testament();
+ pos = 0;
+ write(bfp, &pos, 4); /* Book offset for testament intros */
+ pos = 4;
+ write(cfp, &pos, 4); /* Chapter offset for testament intro */
+
+
+/* Right now just zero out intros until parsing correctly */
+ pos = 0;
+ size = 0;
+ write(vfp, &pos, 4); /* Module intro */
+ write(vfp, &size, 2);
+ write(vfp, &pos, 4); /* Testament intro */
+ write(vfp, &size, 2);
+
+ while(!findbreak(fp, &offset, &num1, &num2, &rangemax, &size)) {
+ if (num2) {
+ key2.Verse(1);
+ key2.Chapter(num1);
+ key2.Verse(num2);
+ }
+ else {
+ key2.Verse(1);
+ if (!startflag) {
+ startflag = 1;
+ }
+ else {
+ if (num1 <= key2.Chapter()) { // new book
+ key2.Chapter(1);
+ key2.Book(key2.Book()+1);
+ }
+ }
+ key2.Chapter(num1);
+ printf("Found Chapter Break: %d ('%s')\n", num1, (const char *)key2);
+ chapoffset = offset;
+ chapsize = size;
+ continue;
+ }
+
+ key3 = key2;
+ key3 += (rangemax - key3.Verse());
+
+ printf("Found verse Break: ('%s')\n", (const char *)key2);
+ writeidx(key1, key2, key3, offset, size);
+ }
+ close(vfp);
+ close(cfp);
+ close(bfp);
+ close(fp);
+}
+
+
+/**************************************************************************
+ * ENT: key1 - current location of index
+ * key2 - minimum keyval for which this offset is valid
+ * key3 - maximum keyval for which this offset is valid
+ */
+
+void writeidx(VerseKey &key1, VerseKey &key2, VerseKey &key3, long offset, short size)
+{
+ long pos;
+ short tmp;
+
+ for (; ((key1 <= key3) && (key1.Error() != KEYERR_OUTOFBOUNDS) && (key1.Testament() == testmnt)); key1+=1) {
+ if (key1.Verse() == 1) { // new chapter
+ if (key1.Chapter() == 1) { // new book
+ pos = lseek(cfp, 0, SEEK_CUR);
+ write(bfp, &pos, 4);
+ pos = lseek(vfp, 0, SEEK_CUR); /* Book intro (cps) */
+ write(cfp, &pos, 4);
+ write(vfp, &chapoffset, 4); /* Book intro (vss) set to same as chap for now(it should be chap 1 which usually contains the book into anyway)*/
+ write(vfp, &chapsize, 2);
+ }
+ pos = lseek(vfp, 0, SEEK_CUR);
+ write(cfp, &pos, 4);
+ write(vfp, &chapoffset, 4); /* Chapter intro */
+ write(vfp, &chapsize, 2);
+ }
+ if (key1 >= key2) {
+ write(vfp, &offset, 4);
+ write(vfp, &size, 2);
+ }
+ else {
+ pos = 0;
+ tmp = 0;
+ write(vfp, &pos, 4);
+ write(vfp, &tmp, 2);
+ }
+ }
+}
+
+
+char startentry(char *buf)
+{
+ char colon = 0;
+
+ if (buf[0] != 10)
+ return 0;
+ if (buf[1] != 10)
+ return 0;
+ if (!isdigit(buf[2]))
+ return 0;
+ if (!isdigit(buf[3])) {
+ if (buf[3]!= ':')
+ return 0;
+ else colon++;
+ }
+ if (!isdigit(buf[4])) {
+ if (buf[4]!= ':')
+ return 0;
+ else colon++;
+ }
+ if (colon != 1)
+ return 0;
+ return 1;
+}
+
+
+char findbreak(int fp, long *offset, int *num1, int *num2, int *rangemax, short *size)
+{
+ char buf[7];
+ char buf2[20];
+ char ch;
+ char loop;
+ long offset2;
+ int ch2, vs2, rm2;
+
+ memset(buf, ' ', 7);
+
+ while (1) {
+ if (startentry(buf)) {
+ buf[0] = ' ';
+ buf[1] = ' ';
+ sscanf(buf, "%d:%d", num1, num2);
+ *rangemax = *num2;
+ *offset = lseek(fp, 0, SEEK_CUR) - 5;
+ if (size) {
+ if (findbreak(fp, &offset2, &ch2, &vs2, &rm2, 0)) {
+ *size = (short) (lseek(fp, 0, SEEK_END) - (*offset));
+ }
+ else {
+ if (vs2) {
+ *size = (offset2 - (*offset)) - 2;
+ }
+ else {
+ *size = (offset2 - (*offset)) - 6;
+ }
+ }
+ lseek(fp, *offset, SEEK_SET);
+ }
+ return 0;
+ }
+
+ if (!strncmp(buf, "$-$-$-", 6)) {
+ *offset = lseek(fp, 0, SEEK_CUR) - 1;
+ *num2 = 0;
+ (*num1)++;
+ printf("Book marker: %s\n", buf2);
+ if (size) {
+ if (findbreak(fp, &offset2, &ch2, &vs2, &rm2, 0)) {
+ *size = (short) (lseek(fp, 0, SEEK_END) - (*offset));
+ }
+ else {
+ if (vs2) {
+ *size = (offset2 - (*offset)) - 2;
+ }
+ else {
+ *size = (offset2 - (*offset)) - 6;
+ }
+ }
+ lseek(fp, *offset, SEEK_SET);
+ }
+ return 0;
+ }
+
+
+ memmove(buf, &buf[1], 6);
+ if (read(fp, &buf[6], 1) != 1)
+ return 1;
+ }
+}
+
+
+void openfiles(char *fname)
+{
+ char buf[255];
+
+ if ((fp = open(fname, O_RDONLY)) == -1) {
+ fprintf(stderr, "Couldn't open file: %s\n", fname);
+ exit(1);
+ }
+
+ sprintf(buf, "%s.vss", fname);
+ if ((vfp = open(buf, O_CREAT|O_WRONLY)) == -1) {
+ fprintf(stderr, "Couldn't open file: %s\n", buf);
+ exit(1);
+ }
+
+ sprintf(buf, "%s.cps", fname);
+ if ((cfp = open(buf, O_CREAT|O_WRONLY)) == -1) {
+ fprintf(stderr, "Couldn't open file: %s\n", buf);
+ exit(1);
+ }
+
+ sprintf(buf, "%s.bks", fname);
+ if ((bfp = open(buf, O_CREAT|O_WRONLY)) == -1) {
+ fprintf(stderr, "Couldn't open file: %s\n", buf);
+ exit(1);
+ }
+}
+
+
+void checkparams(int argc, char **argv)
+{
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s <file to process> [nt - for new testmt file]\n", argv[0]);
+ exit(1);
+ }
+ if (argc == 3)
+ key1 = key2 = key3 = "Matthew 1:1";
+ else key1 = key2 = key3 = "Genesis 1:1";
+}
diff --git a/src/modules/comments/rawfiles/Makefile b/src/modules/comments/rawfiles/Makefile
new file mode 100644
index 0000000..35d6648
--- /dev/null
+++ b/src/modules/comments/rawfiles/Makefile
@@ -0,0 +1,5 @@
+
+root := ../../../..
+
+all:
+ make -C ${root}
diff --git a/src/modules/comments/rawfiles/Makefile.am b/src/modules/comments/rawfiles/Makefile.am
new file mode 100644
index 0000000..53aadbe
--- /dev/null
+++ b/src/modules/comments/rawfiles/Makefile.am
@@ -0,0 +1,3 @@
+rawfilesdir = $(top_srcdir)/src/modules/comments/rawfiles
+
+libsword_la_SOURCES += $(rawfilesdir)/rawfiles.cpp
diff --git a/src/modules/comments/rawfiles/rawfiles.cpp b/src/modules/comments/rawfiles/rawfiles.cpp
new file mode 100644
index 0000000..c8e9388
--- /dev/null
+++ b/src/modules/comments/rawfiles/rawfiles.cpp
@@ -0,0 +1,291 @@
+/******************************************************************************
+ * rawfiles.cpp - code for class 'RawFiles'- a module that produces HTML HREFs
+ * pointing to actual text desired. Uses standard
+ * files: ot and nt using indexs ??.bks ??.cps ??.vss
+ */
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#ifndef __GNUC__
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <string.h>
+#include <utilfuns.h>
+#include <rawverse.h>
+#include <rawfiles.h>
+#include <filemgr.h>
+
+#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.
+
+
+ /******************************************************************************
+ * RawFiles Constructor - Initializes data for instance of RawFiles
+ *
+ * ENT: iname - Internal name for module
+ * idesc - Name to display to user for module
+ * idisp - Display object to use for displaying
+ */
+
+RawFiles::RawFiles(const char *ipath, const char *iname, const char *idesc, SWDisplay *idisp, SWTextEncoding enc, SWTextDirection dir, SWTextMarkup mark, const char* ilang) : RawVerse(ipath, O_RDWR), SWCom(iname, idesc, idisp, enc, dir, mark, ilang)
+{
+}
+
+
+/******************************************************************************
+ * RawFiles Destructor - Cleans up instance of RawFiles
+ */
+
+RawFiles::~RawFiles()
+{
+}
+
+
+/******************************************************************************
+ * RawFiles::operator char * - Returns the correct verse when char * cast
+ * is requested
+ *
+ * RET: string buffer with verse
+ */
+
+char *RawFiles::getRawEntry() {
+ FileDesc *datafile;
+ long start = 0;
+ unsigned short size = 0;
+ char *tmpbuf;
+ VerseKey *key = 0;
+
+#ifndef _WIN32_WCE
+ try {
+#endif
+ key = SWDYNAMIC_CAST(VerseKey, this->key);
+#ifndef _WIN32_WCE
+ }
+ catch ( ... ) {}
+#endif
+ if (!key)
+ key = new VerseKey(this->key);
+
+ findoffset(key->Testament(), key->Index(), &start, &size);
+
+ if (entrybuf)
+ delete [] entrybuf;
+
+ if (size) {
+ tmpbuf = new char [ (size + 2) + strlen(path) + 5 ];
+ sprintf(tmpbuf,"%s/",path);
+ gettext(key->Testament(), start, (size + 2), tmpbuf+strlen(tmpbuf));
+ datafile = FileMgr::systemFileMgr.open(tmpbuf, O_RDONLY|O_BINARY);
+ delete [] tmpbuf;
+ if (datafile->getFd() > 0) {
+ size = lseek(datafile->getFd(), 0, SEEK_END);
+ entrybuf = new char [ size * FILTERPAD ];
+ memset(entrybuf, 0, size * FILTERPAD);
+ lseek(datafile->getFd(), 0, SEEK_SET);
+ read(datafile->getFd(), entrybuf, size);
+ preptext(entrybuf);
+ }
+ else {
+ entrybuf = new char [2];
+ entrybuf[0] = 0;
+ entrybuf[1] = 0;
+ }
+ FileMgr::systemFileMgr.close(datafile);
+ }
+ else {
+ entrybuf = new char [2];
+ entrybuf[0] = 0;
+ entrybuf[1] = 0;
+ }
+
+ if (key != this->key)
+ delete key;
+
+ return entrybuf;
+}
+
+
+/******************************************************************************
+ * RawFiles::operator << (char *)- Update the modules current key entry with
+ * provided text
+ *
+ * RET: *this
+ */
+
+SWModule &RawFiles::operator <<(const char *inbuf) {
+ FileDesc *datafile;
+ long start;
+ unsigned short size;
+ char *tmpbuf;
+ VerseKey *key = 0;
+
+#ifndef _WIN32_WCE
+ try {
+#endif
+ key = SWDYNAMIC_CAST(VerseKey, this->key);
+#ifndef _WIN32_WCE
+ }
+ catch ( ... ) {}
+#endif
+ if (!key)
+ key = new VerseKey(this->key);
+
+ findoffset(key->Testament(), key->Index(), &start, &size);
+
+ if (size) {
+ tmpbuf = new char [ (size + 2) + strlen(path) + 1 ];
+ sprintf(tmpbuf, "%s/", path);
+ gettext(key->Testament(), start, (size + 2), tmpbuf+strlen(tmpbuf));
+ }
+ else {
+ tmpbuf = new char [ 16 + strlen(path) + 1 ];
+ sprintf(tmpbuf, "%s/%s", path, getnextfilename());
+ settext(key->Testament(), key->Index(), tmpbuf+strlen(path)+1);
+ }
+ datafile = FileMgr::systemFileMgr.open(tmpbuf, O_CREAT|O_WRONLY|O_BINARY|O_TRUNC);
+ delete [] tmpbuf;
+ if (datafile->getFd() > 0) {
+ write(datafile->getFd(), inbuf, strlen(inbuf));
+ }
+ FileMgr::systemFileMgr.close(datafile);
+
+ if (key != this->key)
+ delete key;
+
+ return *this;
+}
+
+
+/******************************************************************************
+ * RawFiles::operator << (SWKey *)- Link the modules current key entry with
+ * another module entry
+ *
+ * RET: *this
+ */
+
+SWModule &RawFiles::operator <<(const SWKey *inkey) {
+
+ long start;
+ unsigned short size;
+ char *tmpbuf;
+ const VerseKey *key = 0;
+
+#ifndef _WIN32_WCE
+ try {
+#endif
+ key = SWDYNAMIC_CAST(VerseKey, inkey);
+#ifndef _WIN32_WCE
+ }
+ catch ( ... ) {}
+#endif
+ if (!key)
+ key = new VerseKey(this->key);
+
+ findoffset(key->Testament(), key->Index(), &start, &size);
+
+ if (size) {
+ tmpbuf = new char [ size + 2];
+ gettext(key->Testament(), start, size + 2, tmpbuf);
+
+ if (key != inkey)
+ delete key;
+ key = 0;
+
+#ifndef _WIN32_WCE
+ try {
+#endif
+ key = SWDYNAMIC_CAST(VerseKey, inkey);
+#ifndef _WIN32_WCE
+ }
+ catch ( ... ) {}
+#endif
+ if (!key)
+ key = new VerseKey(this->key);
+ settext(key->Testament(), key->Index(), tmpbuf);
+ }
+
+ if (key != inkey)
+ delete key;
+
+ return *this;
+}
+
+
+/******************************************************************************
+ * RawFiles::deleteEntry - deletes this entry
+ *
+ * RET: *this
+ */
+
+void RawFiles::deleteEntry() {
+
+ VerseKey *key = 0;
+
+#ifndef _WIN32_WCE
+ try {
+#endif
+ key = SWDYNAMIC_CAST(VerseKey, this->key);
+#ifndef _WIN32_WCE
+ }
+ catch ( ... ) {}
+#endif
+ if (!key)
+ key = new VerseKey(this->key);
+
+ settext(key->Testament(), key->Index(), "");
+
+ if (key != this->key)
+ delete key;
+}
+
+
+/******************************************************************************
+ * RawFiles::getnextfilename - generates a valid filename in which to store
+ * an entry
+ *
+ * RET: filename
+ */
+
+char *RawFiles::getnextfilename() {
+ static char incfile[255];
+ long number;
+ FileDesc *datafile;
+
+ sprintf(incfile, "%s/incfile", path);
+ datafile = FileMgr::systemFileMgr.open(incfile, O_RDONLY|O_BINARY);
+ if (read(datafile->getFd(), &number, 4) != 4)
+ number = 0;
+ number++;
+ FileMgr::systemFileMgr.close(datafile);
+
+ datafile = FileMgr::systemFileMgr.open(incfile, O_CREAT|O_WRONLY|O_BINARY|O_TRUNC);
+ write(datafile->getFd(), &number, 4);
+ FileMgr::systemFileMgr.close(datafile);
+ sprintf(incfile, "%.7ld", number-1);
+ return incfile;
+}
+
+
+char RawFiles::createModule (const char *path) {
+ char *incfile = new char [ strlen (path) + 16 ];
+ static long zero = 0;
+ FileDesc *datafile;
+
+ sprintf(incfile, "%s/incfile", path);
+ datafile = FileMgr::systemFileMgr.open(incfile, O_CREAT|O_WRONLY|O_BINARY|O_TRUNC);
+ delete [] incfile;
+ write(datafile->getFd(), &zero, 4);
+ FileMgr::systemFileMgr.close(datafile);
+
+ return RawVerse::createModule (path);
+}
+
+
+
diff --git a/src/modules/comments/rawfiles/rawfilesgen.cpp b/src/modules/comments/rawfiles/rawfilesgen.cpp
new file mode 100644
index 0000000..f60c9e2
--- /dev/null
+++ b/src/modules/comments/rawfiles/rawfilesgen.cpp
@@ -0,0 +1,236 @@
+/*****************************************************************************
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef __GNUC__
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <fcntl.h>
+#include <versekey.h>
+
+#ifndef O_BINARY
+ #define O_BINARY 0
+#endif
+
+void writeidx(VerseKey &key1, VerseKey &key2, VerseKey &key3, long offset, short size);
+char findbreak(int fp, long *offset, int *num1, int *num2, int *rangemax, short *size);
+void openfiles();
+void checkparams(int argc, char **argv);
+void charsetconvert(char *data);
+
+
+VerseKey key1, key2, key3;
+int fp, vfp, cfp, bfp;
+long chapoffset;
+short chapsize;
+char testmnt;
+char startflag = 0;
+
+
+main(int argc, char **argv)
+{
+ long pos, offset;
+ int num1, num2, rangemax, curbook = 0, curchap = 0, curverse = 0;
+ char buf[127];
+ short size, tmp;
+ extern struct zonline online;
+
+ checkparams(argc, argv);
+
+ key1 = key2 = key3 = "Genesis 1:1";
+
+ openfiles();
+
+ num1 = key1.Chapter();
+ num2 = key1.Verse();
+
+ while(!findbreak(fp, &offset, &num1, &num2, &rangemax, &size)) {
+ if (!startflag) {
+ startflag = 1;
+ }
+ else {
+ if (num2 < key2.Verse()) { // new chapter
+ if (num1 <= key2.Chapter()) { // new book
+ key2.Verse(1);
+ key2.Chapter(1);
+ key2.Book(key2.Book()+1);
+ }
+ printf("Created Empty Entry: %d ('%s')\n", num1, (const char *)key2);
+ chapoffset = offset;
+ chapsize = size;
+// continue;
+ }
+ }
+ key2.Verse(1);
+ key2.Chapter(num1);
+ key2.Verse(num2);
+
+ key3 = key2;
+// key3 += (rangemax - key3.Verse());
+
+ writeidx(key1, key2, key3, offset, size);
+ }
+ close(vfp);
+ close(cfp);
+ close(bfp);
+ close(fp);
+}
+
+
+/**************************************************************************
+ * ENT: key1 - current location of index
+ * key2 - minimum keyval for which this offset is valid
+ * key3 - maximum keyval for which this offset is valid
+ */
+
+void writeidx(VerseKey &key1, VerseKey &key2, VerseKey &key3, long offset, short size)
+{
+ long pos;
+ short tmp;
+
+ if (key1.Verse() == 1) { // new chapter
+ if (key1.Chapter() == 1) { // new book
+ pos = lseek(cfp, 0, SEEK_CUR);
+ write(bfp, &pos, 4);
+ pos = lseek(vfp, 0, SEEK_CUR); /* Book intro (cps) */
+ write(cfp, &pos, 4);
+ write(vfp, &chapoffset, 4); /* Book intro (vss) set to same as chap for now(it should be chap 1 which usually contains the book into anyway)*/
+ write(vfp, &chapsize, 2);
+ }
+ pos = lseek(vfp, 0, SEEK_CUR);
+ write(cfp, &pos, 4);
+ write(vfp, &chapoffset, 4); /* Chapter intro */
+ write(vfp, &chapsize, 2);
+ }
+ if (key1 >= key2) {
+ write(vfp, &offset, 4);
+ size = 0;
+ write(vfp, &size, 2);
+ }
+ else {
+ pos = 0;
+ tmp = 0;
+ write(vfp, &pos, 4);
+ write(vfp, &tmp, 2);
+ }
+ key1++;
+}
+
+
+static VerseKey inckey = "Genesis 1:1";
+
+char findbreak(int fp, long *offset, int *num1, int *num2, int *rangemax, short *size)
+{
+ char buf[7];
+ char buf2[20];
+ char ch;
+ char loop;
+ long offset2;
+ int ch2, vs2, rm2;
+ bool flag;
+ long chapstart = 0;
+ static int olbvnum = 0;
+ char data[16];
+
+ memset (data,0,16);
+
+ if (++olbvnum <= 31102) {
+
+ if (olbvnum == 23146) { // "Matthew 1:1"
+ close(vfp);
+ close(cfp);
+ close(bfp);
+ close(fp);
+ key1 = key2 = key3 = inckey = "Matthew 1:1";
+ openfiles();
+ startflag = 0;
+ }
+
+
+ *offset = lseek(fp, 0, SEEK_CUR);
+
+ if ((olbvnum!=1) && (olbvnum != 23146))
+ inckey++;
+
+ *num1 = inckey.Chapter();
+ *num2 = inckey.Verse();
+
+
+ write(fp, data, 16);
+
+ *size = lseek(fp, 0, SEEK_CUR) - *offset;
+ return 0;
+ }
+ return 1;
+}
+
+
+void openfiles()
+{
+ char buf[255];
+ char fname[5];
+ long pos;
+ short size;
+
+ testmnt = key1.Testament();
+
+ strcpy(fname, (testmnt==2) ? "nt" : "ot");
+ unlink(fname);
+ if ((fp = open(fname, O_CREAT|O_RDWR|O_BINARY)) == -1) {
+ fprintf(stderr, "Couldn't open file: %s\n", fname);
+ exit(1);
+ }
+
+ sprintf(buf, "%s.vss", fname);
+ unlink(buf);
+ if ((vfp = open(buf, O_CREAT|O_WRONLY|O_BINARY)) == -1) {
+ fprintf(stderr, "Couldn't open file: %s\n", buf);
+ exit(1);
+ }
+
+ sprintf(buf, "%s.cps", fname);
+ unlink(buf);
+ if ((cfp = open(buf, O_CREAT|O_WRONLY|O_BINARY)) == -1) {
+ fprintf(stderr, "Couldn't open file: %s\n", buf);
+ exit(1);
+ }
+
+ sprintf(buf, "%s.bks", fname);
+ unlink(buf);
+ if ((bfp = open(buf, O_CREAT|O_WRONLY|O_BINARY)) == -1) {
+ fprintf(stderr, "Couldn't open file: %s\n", buf);
+ exit(1);
+ }
+
+ pos = 0;
+ write(bfp, &pos, 4); /* Book offset for testament intros */
+ pos = 4;
+ write(cfp, &pos, 4); /* Chapter offset for testament intro */
+
+
+/* Right now just zero out intros until parsing correctly */
+ pos = 0;
+ size = 0;
+ write(vfp, &pos, 4); /* Module intro */
+ write(vfp, &size, 2);
+ write(vfp, &pos, 4); /* Testament intro */
+ write(vfp, &size, 2);
+
+}
+
+
+void checkparams(int argc, char **argv)
+{
+ if (argc !=1) {
+ fprintf(stderr, "usage: %s\n", argv[0]);
+ exit(1);
+ }
+}
diff --git a/src/modules/comments/swcom.cpp b/src/modules/comments/swcom.cpp
new file mode 100644
index 0000000..1feb0cf
--- /dev/null
+++ b/src/modules/comments/swcom.cpp
@@ -0,0 +1,30 @@
+/******************************************************************************
+ * swcom.cpp - code for base class 'SWCom'- The basis for all commentary
+ * modules
+ */
+
+#include <swcom.h>
+
+
+/******************************************************************************
+ * SWCom Constructor - Initializes data for instance of SWCom
+ *
+ * ENT: imodname - Internal name for module
+ * imoddesc - Name to display to user for module
+ * idisp - Display object to use for displaying
+ */
+
+SWCom::SWCom(const char *imodname, const char *imoddesc, SWDisplay *idisp, SWTextEncoding enc, SWTextDirection dir, SWTextMarkup mark, const char* ilang): SWModule(imodname, imoddesc, idisp, "Commentaries", enc, dir, mark, ilang)
+{
+ delete key;
+ key = CreateKey();
+}
+
+
+/******************************************************************************
+ * SWCom Destructor - Cleans up instance of SWCom
+ */
+
+SWCom::~SWCom()
+{
+}
diff --git a/src/modules/comments/zcom/Makefile b/src/modules/comments/zcom/Makefile
new file mode 100644
index 0000000..35d6648
--- /dev/null
+++ b/src/modules/comments/zcom/Makefile
@@ -0,0 +1,5 @@
+
+root := ../../../..
+
+all:
+ make -C ${root}
diff --git a/src/modules/comments/zcom/Makefile.am b/src/modules/comments/zcom/Makefile.am
new file mode 100644
index 0000000..ad1ef6a
--- /dev/null
+++ b/src/modules/comments/zcom/Makefile.am
@@ -0,0 +1,4 @@
+zcomdir = $(top_srcdir)/src/modules/comments/zcom
+
+libsword_la_SOURCES += $(zcomdir)/zcom.cpp
+
diff --git a/src/modules/comments/zcom/makeidx.c b/src/modules/comments/zcom/makeidx.c
new file mode 100644
index 0000000..311103e
--- /dev/null
+++ b/src/modules/comments/zcom/makeidx.c
@@ -0,0 +1,146 @@
+#include <stdio.h>
+#include <fcntl.h>
+
+
+char findbreak(int fp, int *offset, int *num1, int *num2, short *size);
+
+
+main(int argc, char **argv)
+{
+ int fp, vfp, cfp, bfp;
+ long pos;
+ short size, tmp;
+ int num1, num2, offset, curbook = 0, curchap = 0, curverse = 0;
+ char buf[127];
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s <file to process>\n", argv[0]);
+ exit(1);
+ }
+
+ if ((fp = open(argv[1], O_RDONLY)) == -1) {
+ fprintf(stderr, "Couldn't open file: %s\n", argv[1]);
+ exit(1);
+ }
+
+ sprintf(buf, "%s.vss", argv[1]);
+ if ((vfp = open(buf, O_CREAT|O_WRONLY)) == -1) {
+ fprintf(stderr, "Couldn't open file: %s\n", buf);
+ exit(1);
+ }
+
+ sprintf(buf, "%s.cps", argv[1]);
+ if ((cfp = open(buf, O_CREAT|O_WRONLY)) == -1) {
+ fprintf(stderr, "Couldn't open file: %s\n", buf);
+ exit(1);
+ }
+
+ sprintf(buf, "%s.bks", argv[1]);
+ if ((bfp = open(buf, O_CREAT|O_WRONLY)) == -1) {
+ fprintf(stderr, "Couldn't open file: %s\n", buf);
+ exit(1);
+ }
+
+ pos = 0;
+ write(bfp, &pos, 4); /* Book offset for testament intros */
+ pos = 4;
+ write(cfp, &pos, 4); /* Chapter offset for testament intro */
+
+
+/* Right now just zero out intros until parsing correctly */
+ pos = 0;
+ size = 0;
+ write(vfp, &pos, 4); /* Module intro */
+ write(vfp, &size, 2);
+ write(vfp, &pos, 4); /* Testament intro */
+ write(vfp, &size, 2);
+
+ while (!findbreak(fp, &offset, &num1, &num2, &size)) {
+
+ if (num2 == 1) { /* if we're at a new chapter */
+ if (num1 == 1) { /* if we're at a new book */
+ pos = lseek(cfp, 0, SEEK_CUR);
+ write(bfp, &pos, 4);
+ pos = lseek(vfp, 0, SEEK_CUR); /* Book intro (cps) */
+ write(cfp, &pos, 4);
+ pos = 0;
+ tmp = 0;
+ write(vfp, &pos, 4); /* Book intro (vss) */
+ write(vfp, &tmp, 2);
+ curbook++;
+ curchap = 0;
+ }
+ pos = lseek(vfp, 0, SEEK_CUR);
+ write(cfp, &pos, 4);
+ curverse = 1;
+ pos = 0;
+ tmp = 0;
+ write(vfp, &pos, 4); /* Chapter intro */
+ write(vfp, &tmp, 2);
+ curchap++;
+ }
+ else curverse++;
+
+ printf("%2d:%3d:%3d found at offset: %7d\n", curbook, num1, num2, offset);
+
+ if (num1 != curchap) {
+ fprintf(stderr, "Error: Found chaptures out of sequence\n", buf);
+ break;
+ }
+ if (num2 != curverse) {
+ fprintf(stderr, "Error: Found verses out of sequence\n", buf);
+ break;
+ }
+ write(vfp, &offset, 4);
+ write(vfp, &size, 2);
+ }
+
+ close(vfp);
+ close(cfp);
+ close(bfp);
+ close(fp);
+}
+
+
+char findbreak(int fp, int *offset, int *num1, int *num2, short *size)
+{
+ char buf[7];
+ char buf2[7];
+ char loop;
+ int offset2, ch2, vs2;
+
+ memset(buf, ' ', 7);
+
+ while (1) {
+ if (buf[3] == ':') {
+ memcpy(buf2, buf, 7);
+ for (loop = 0; loop < 7; loop++) {
+ if (!isdigit(buf2[loop]))
+ buf2[loop] = ' ';
+ }
+ buf2[3] = 0;
+ *num1 = atoi(buf2);
+ *num2 = atoi(&buf2[4]);
+ if (*num1 && *num2) {
+ *offset = lseek(fp, 0, SEEK_CUR);
+ sprintf(buf2, "%d", *num2);
+ *offset -= 2 - strlen(buf2);
+ if (size) {
+ if (findbreak(fp, &offset2, &ch2, &vs2, 0)) {
+ *size = (short) (lseek(fp, 0, SEEK_END) - (*offset));
+ }
+ else {
+ sprintf(buf2, "%d:%d", ch2, vs2);
+ *size = (offset2 - (*offset)) - (strlen(buf2) + 2);
+ }
+ lseek(fp, *offset, SEEK_SET);
+ }
+ return 0;
+ }
+ }
+ memmove(buf, &buf[1], 6);
+ if (read(fp, &buf[6], 1) != 1)
+ return 1;
+ }
+}
+
diff --git a/src/modules/comments/zcom/rawtxt2z.cpp b/src/modules/comments/zcom/rawtxt2z.cpp
new file mode 100644
index 0000000..f8c18d0
--- /dev/null
+++ b/src/modules/comments/zcom/rawtxt2z.cpp
@@ -0,0 +1,83 @@
+#include <ctype.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#ifndef __GNUC__
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <swcomprs.h>
+
+
+main(int argc, char **argv)
+{
+ SWCompress *zobj;
+ int ifd, ofd, ixfd, oxfd;
+ long offset, loffset, lzoffset;
+ short size, lsize, lzsize;
+ char *tmpbuf;
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s <datafilename>\n", argv[0]);
+ exit(1);
+ }
+
+ zobj = new SWCompress();
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+ tmpbuf = new char [ strlen(argv[1]) + 9 ];
+ ifd = open(argv[1], O_RDONLY|O_BINARY);
+ sprintf(tmpbuf, "%s.vss", argv[1]);
+ ixfd = open(tmpbuf, O_RDONLY|O_BINARY);
+ sprintf(tmpbuf, "%s.zzz", argv[1]);
+ ofd = open(tmpbuf, O_WRONLY|O_BINARY|O_CREAT);
+ sprintf(tmpbuf, "%s.zzz.vss", argv[1]);
+ oxfd = open(tmpbuf, O_WRONLY|O_BINARY|O_CREAT);
+
+ delete [] tmpbuf;
+
+ printf("\n");
+
+ while (1) {
+ if (read(ixfd, &offset, 4) != 4)
+ break;
+ if (read(ixfd, &size, 2) != 2)
+ break;
+
+ if ((offset == loffset) && (size == lsize)) {
+ printf("using previous offset,size\n", size);
+ write(oxfd, &lzoffset, 4);
+ write(oxfd, &lzsize, 2);
+ }
+ else {
+ printf("%d -> ", size);
+ lsize = size;
+ loffset = offset;
+
+ if (size) {
+ tmpbuf = (char *) calloc(size + 1, 1);
+ lseek(ifd, offset, SEEK_SET);
+ read(ifd, tmpbuf, size);
+ zobj->Buf(tmpbuf);
+ zobj->zBuf(&size);
+ free(tmpbuf);
+ }
+ offset = lseek(ofd, 0, SEEK_END);
+ write(oxfd, &offset, 4);
+ if (size)
+ write(ofd, zobj->zBuf(&size), size);
+ lzoffset = offset;
+ write(oxfd, &size, 2);
+ lzsize = size;
+ printf("%d \n", size);
+ }
+ }
+ delete zobj;
+}
diff --git a/src/modules/comments/zcom/zcom.cpp b/src/modules/comments/zcom/zcom.cpp
new file mode 100644
index 0000000..c53fd1e
--- /dev/null
+++ b/src/modules/comments/zcom/zcom.cpp
@@ -0,0 +1,290 @@
+/******************************************************************************
+ * rawcom.cpp - code for class 'zCom'- a module that reads raw commentary
+ * files: ot and nt using indexs ??.bks ??.cps ??.vss
+ */
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#ifndef __GNUC__
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <string.h>
+#include <utilfuns.h>
+#include <zverse.h>
+#include <zcom.h>
+
+
+/******************************************************************************
+ * zCom Constructor - Initializes data for instance of zCom
+ *
+ * ENT: ipath - path to data files
+ * iname - Internal name for module
+ * idesc - Name to display to user for module
+ * iblockType - verse, chapter, book, etc. of index chunks
+ * icomp - Compressor object
+ * idisp - Display object to use for displaying
+ */
+
+zCom::zCom(const char *ipath, const char *iname, const char *idesc, int iblockType, SWCompress *icomp, SWDisplay *idisp, SWTextEncoding enc, SWTextDirection dir, SWTextMarkup mark, const char* ilang) : zVerse(ipath, -1, iblockType, icomp), SWCom(iname, idesc, idisp, enc, dir, mark, ilang)/*, SWCompress()*/
+{
+ blockType = iblockType;
+ lastWriteKey = 0;
+}
+
+/******************************************************************************
+ * zCom Destructor - Cleans up instance of zCom
+ */
+
+zCom::~zCom() {
+ flushCache();
+
+ if (lastWriteKey)
+ delete lastWriteKey;
+}
+
+/******************************************************************************
+ * zCom::operator char * - Returns the correct verse when char * cast
+ * is requested
+ *
+ * RET: string buffer with verse
+ */
+char *zCom::getRawEntry() {
+ long start = 0;
+ unsigned short size = 0;
+ VerseKey *key = 0;
+
+#ifndef _WIN32_WCE
+ try {
+#endif
+ key = SWDYNAMIC_CAST(VerseKey, this->key);
+#ifndef _WIN32_WCE
+ }
+ catch ( ... ) {}
+#endif
+ // if we don't have a VerseKey * decendant, create our own
+ if (!key)
+ key = new VerseKey(this->key);
+
+ findoffset(key->Testament(), key->Index(), &start, &size);
+ entrySize = size; // support getEntrySize call
+
+ unsigned long newsize = (size + 2) * FILTERPAD;
+ if (newsize > entrybufallocsize) {
+ if (entrybuf)
+ delete [] entrybuf;
+ entrybuf = new char [ newsize ];
+ entrybufallocsize = newsize;
+ }
+ *entrybuf = 0;
+
+ swgettext(key->Testament(), start, (size + 2), entrybuf);
+
+ rawFilter(entrybuf, size, key);
+
+ if (!isUnicode())
+ preptext(entrybuf);
+
+ if (this->key != key) // free our key if we created a VerseKey
+ delete key;
+
+ return entrybuf;
+}
+
+
+bool zCom::sameBlock(VerseKey *k1, VerseKey *k2) {
+ if (k1->Testament() != k2->Testament())
+ return false;
+
+ switch (blockType) {
+ case VERSEBLOCKS:
+ if (k1->Verse() != k2->Verse())
+ return false;
+ case CHAPTERBLOCKS:
+ if (k1->Chapter() != k2->Chapter())
+ return false;
+ case BOOKBLOCKS:
+ if (k1->Book() != k2->Book())
+ return false;
+ }
+ return true;
+}
+
+SWModule &zCom::setentry(const char *inbuf, long len) {
+ VerseKey *key = 0;
+ // see if we have a VerseKey * or decendant
+#ifndef _WIN32_WCE
+ try {
+#endif
+ key = SWDYNAMIC_CAST(VerseKey, this->key);
+#ifndef _WIN32_WCE
+ }
+ catch ( ... ) {}
+#endif
+ // if we don't have a VerseKey * decendant, create our own
+ if (!key)
+ key = new VerseKey(this->key);
+
+
+ // see if we've jumped across blocks since last write
+ if (lastWriteKey) {
+ if (!sameBlock(lastWriteKey, key)) {
+ flushCache();
+ }
+ delete lastWriteKey;
+ }
+
+ settext(key->Testament(), key->Index(), inbuf, len);
+
+ lastWriteKey = (VerseKey *)key->clone(); // must delete
+
+ if (this->key != key) // free our key if we created a VerseKey
+ delete key;
+
+ return *this;
+}
+
+SWModule &zCom::operator <<(const char *inbuf) {
+ return setentry(inbuf, 0);
+}
+
+
+SWModule &zCom::operator <<(const SWKey *inkey) {
+ VerseKey *destkey = 0;
+ const VerseKey *srckey = 0;
+ // see if we have a VerseKey * or decendant
+#ifndef _WIN32_WCE
+ try {
+#endif
+ destkey = SWDYNAMIC_CAST(VerseKey, this->key);
+#ifndef _WIN32_WCE
+ }
+ catch ( ... ) {}
+#endif
+ // if we don't have a VerseKey * decendant, create our own
+ if (!destkey)
+ destkey = new VerseKey(this->key);
+
+ // see if we have a VerseKey * or decendant
+#ifndef _WIN32_WCE
+ try {
+#endif
+ srckey = (const VerseKey *) SWDYNAMIC_CAST(VerseKey, inkey);
+#ifndef _WIN32_WCE
+ }
+ catch ( ... ) {
+ }
+#endif
+ // if we don't have a VerseKey * decendant, create our own
+ if (!srckey)
+ srckey = new VerseKey(inkey);
+
+ linkentry(destkey->Testament(), destkey->Index(), srckey->Index());
+
+ if (this->key != destkey) // free our key if we created a VerseKey
+ delete destkey;
+
+ if (inkey != srckey) // free our key if we created a VerseKey
+ delete srckey;
+
+ return *this;
+}
+
+/******************************************************************************
+ * zCom::deleteEntry - deletes this entry
+ *
+ * RET: *this
+ */
+
+void zCom::deleteEntry() {
+
+ VerseKey *key = 0;
+
+#ifndef _WIN32_WCE
+ try {
+#endif
+ key = SWDYNAMIC_CAST(VerseKey, this->key);
+#ifndef _WIN32_WCE
+ }
+ catch ( ... ) {}
+#endif
+ if (!key)
+ key = new VerseKey(this->key);
+
+ settext(key->Testament(), key->Index(), "");
+
+ if (key != this->key)
+ delete key;
+}
+
+
+/******************************************************************************
+ * zCom::operator += - Increments module key a number of entries
+ *
+ * ENT: increment - Number of entries to jump forward
+ *
+ * RET: *this
+ */
+
+SWModule &zCom::operator +=(int increment) {
+ long start;
+ unsigned short size;
+ VerseKey *tmpkey = 0;
+
+#ifndef _WIN32_WCE
+ try {
+#endif
+ tmpkey = SWDYNAMIC_CAST(VerseKey, key);
+#ifndef _WIN32_WCE
+ }
+ catch ( ... ) {}
+#endif
+ if (!tmpkey)
+ tmpkey = new VerseKey(key);
+
+ findoffset(tmpkey->Testament(), tmpkey->Index(), &start, &size);
+
+ SWKey lastgood = *tmpkey;
+ while (increment) {
+ long laststart = start;
+ unsigned short lastsize = size;
+ SWKey lasttry = *tmpkey;
+ (increment > 0) ? (*key)++ : (*key)--;
+ if (tmpkey != key)
+ delete tmpkey;
+ tmpkey = 0;
+#ifndef _WIN32_WCE
+ try {
+#endif
+ tmpkey = SWDYNAMIC_CAST(VerseKey, key);
+#ifndef _WIN32_WCE
+ }
+ catch ( ... ) {}
+#endif
+ if (!tmpkey)
+ tmpkey = new VerseKey(key);
+
+ if ((error = key->Error())) {
+ *key = lastgood;
+ break;
+ }
+ long index = tmpkey->Index();
+ findoffset(tmpkey->Testament(), index, &start, &size);
+ if ((((laststart != start) || (lastsize != size))||(!skipConsecutiveLinks)) && (start >= 0) && (size)) {
+ increment += (increment < 0) ? 1 : -1;
+ lastgood = *tmpkey;
+ }
+ }
+ error = (error) ? KEYERR_OUTOFBOUNDS : 0;
+
+ if (tmpkey != key)
+ delete tmpkey;
+
+ return *this;
+}
+
diff --git a/src/modules/common/Makefile b/src/modules/common/Makefile
new file mode 100644
index 0000000..81f7721
--- /dev/null
+++ b/src/modules/common/Makefile
@@ -0,0 +1,4 @@
+root := ../../..
+
+all:
+ make -C ${root}
diff --git a/src/modules/common/Makefile.am b/src/modules/common/Makefile.am
new file mode 100644
index 0000000..ac235d8
--- /dev/null
+++ b/src/modules/common/Makefile.am
@@ -0,0 +1,22 @@
+commondir = $(top_srcdir)/src/modules/common
+
+libsword_la_SOURCES += $(commondir)/rawstr.cpp
+libsword_la_SOURCES += $(commondir)/rawstr4.cpp
+libsword_la_SOURCES += $(commondir)/swcomprs.cpp
+libsword_la_SOURCES += $(commondir)/lzsscomprs.cpp
+
+if ZLIB
+SWZLIB = $(commondir)/zipcomprs.cpp
+else
+SWZLIB =
+endif
+libsword_la_SOURCES += $(SWZLIB)
+libsword_la_SOURCES += $(commondir)/rawverse.cpp
+libsword_la_SOURCES += $(commondir)/swcipher.cpp
+libsword_la_SOURCES += $(commondir)/zverse.cpp
+libsword_la_SOURCES += $(commondir)/zstr.cpp
+libsword_la_SOURCES += $(commondir)/entriesblk.cpp
+
+DEFS += -DUNIX
+libsword_la_SOURCES += $(commondir)/sapphire.cpp
+
diff --git a/src/modules/common/compress.cpp b/src/modules/common/compress.cpp
new file mode 100644
index 0000000..5031adb
--- /dev/null
+++ b/src/modules/common/compress.cpp
@@ -0,0 +1,767 @@
+Compression Info, 10-11-95
+Jeff Wheeler
+
+Source of Algorithm
+-------------------
+
+The compression algorithms used here are based upon the algorithms developed and published by Haruhiko Okumura in a paper entitled "Data Compression Algorithms of LARC and LHarc." This paper discusses three compression algorithms, LSZZ, LZARI, and LZHUF. LZSS is described as the "first" of these, and is described as providing moderate compression with good speed. LZARI is described as an improved LZSS, a combination of the LZSS algorithm with adaptive arithmetic compression. It is described as being slower than LZSS but with better compression. LZHUF (the basis of the common LHA compression program) was included in the paper, however, a free usage license was not included.
+
+The following are copies of the statements included at the beginning of each source code listing that was supplied in the working paper.
+
+ LZSS, dated 4/6/89, marked as "Use, distribute and
+ modify this program freely."
+
+ LZARI, dated 4/7/89, marked as "Use, distribute and
+ modify this program freely."
+
+ LZHUF, dated 11/20/88, written by Haruyasu Yoshizaki,
+ translated by Haruhiko Okumura on 4/7/89. Not
+ expressly marked as redistributable or modifiable.
+
+Since both LZSS and LZARI are marked as "use, distribute and modify freely" we have felt at liberty basing our compression algorithm on either of these.
+
+Selection of Algorithm
+----------------------
+
+Working samples of three possible compression algorithms are supplied in Okumura's paper. Which should be used?
+
+LZSS is the fastest at decompression, but does not generated as small a compressed file as the other methods. The other two methods provided, perhaps, a 15% improvement in compression. Or, put another way, on a 100K file, LZSS might compress it to 50K while the others might approach 40-45K. For STEP purposes, it was decided that decoding speed was of more importance than tighter compression. For these reasons, the first compression algorithm implemented is the LZSS algorithm.
+
+About LZSS Encoding
+-------------------
+
+(adapted from Haruhiko Okumura's paper)
+
+This scheme was proposed by Ziv and Lempel [1]. A slightly modified version is described by Storer and Szymanski [2]. An implementation using a binary tree has been proposed by Bell [3].
+
+The algorithm is quite simple.
+1. Keep a ring buffer which initially contains all space characters.
+2. Read several letters from the file to the buffer.
+3. Search the buffer for the longest string that matches the letters just read, and send its length and position into the buffer.
+
+If the ring buffer is 4096 bytes, the position can be stored in 12 bits. If the length is represented in 4 bits, the <position, length> pair is two bytes long. If the longest match is no more than two characters, then just one character is sent without encoding. The process starts again with the next character. An extra bit is sent each time to tell the decoder whether the next item is a character of a <position, length> pair.
+
+[1] J. Ziv and A. Lempel, IEEE Transactions IT-23, 337-343 (1977).
+[2] J. A. Storer and T. G. Szymanski, J. ACM, 29, 928-951 (1982).
+[3] T.C. Gell, IEEE Transactions COM-34, 1176-1182 (1986).
+
+void InitTree( // no return value
+ void); // no parameters
+
+void InsertNode( // no return value
+ short int Pos); // position in the buffer
+
+void DeleteNode( // no return value
+ short int Node); // node to be removed
+
+void Encode( // no return value
+ void); // no parameters
+
+void Decode( // no return value
+ void); // no parameters
+
+// The following are constant sizes used by the compression algorithm.
+//
+// N - This is the size of the ring buffer. It is set
+// to 4K. It is important to note that a position
+// within the ring buffer requires 12 bits.
+//
+// F - This is the maximum length of a character sequence
+// that can be taken from the ring buffer. It is set
+// to 18. Note that a length must be 3 before it is
+// worthwhile to store a position/length pair, so the
+// length can be encoded in only 4 bits. Or, put yet
+// another way, it is not necessary to encode a length
+// of 0-18, it is necessary to encode a length of
+// 3-18, which requires 4 bits.
+//
+// THRESHOLD - It takes 2 bytes to store an offset and
+// a length. If a character sequence only
+// requires 1 or 2 characters to store
+// uncompressed, then it is better to store
+// it uncompressed than as an offset into
+// the ring buffer.
+//
+// Note that the 12 bits used to store the position and the 4 bits
+// used to store the length equal a total of 16 bits, or 2 bytes.
+
+#define N 4096
+#define F 18
+#define THRESHOLD 3
+#define NOT_USED N
+
+// m_ring_buffer is a text buffer. It contains "nodes" of
+// uncompressed text that can be indexed by position. That is,
+// a substring of the ring buffer can be indexed by a position
+// and a length. When decoding, the compressed text may contain
+// a position in the ring buffer and a count of the number of
+// bytes from the ring buffer that are to be moved into the
+// uncompressed buffer.
+//
+// This ring buffer is not maintained as part of the compressed
+// text. Instead, it is reconstructed dynamically. That is,
+// it starts out empty and gets built as the text is decompressed.
+//
+// The ring buffer contain N bytes, with an additional F - 1 bytes
+// to facilitate string comparison.
+
+unsigned char m_ring_buffer[N + F - 1];
+
+// m_match_position and m_match_length are set by InsertNode().
+//
+// These variables indicate the position in the ring buffer
+// and the number of characters at that position that match
+// a given string.
+
+short int m_match_position;
+short int m_match_length;
+
+// m_lson, m_rson, and m_dad are the Japanese way of referring to
+// a tree structure. The dad is the parent and it has a right and
+// left son (child).
+//
+// For i = 0 to N-1, m_rson[i] and m_lson[i] will be the right
+// and left children of node i.
+//
+// For i = 0 to N-1, m_dad[i] is the parent of node i.
+//
+// For i = 0 to 255, rson[N + i + 1] is the root of the tree for
+// strings that begin with the character i. Note that this requires
+// one byte characters.
+//
+// These nodes store values of 0...(N-1). Memory requirements
+// can be reduces by using 2-byte integers instead of full 4-byte
+// integers (for 32-bit applications). Therefore, these are
+// defined as "short ints."
+
+short int m_lson[N + 1];
+short int m_rson[N + 257];
+short int m_dad[N + 1];
+
+/*
+ -------------------------------------------------------------------------
+ cLZSS::InitTree
+
+ This function initializes the tree nodes to "empty" states.
+ -------------------------------------------------------------------------
+*/
+
+void cLZSS::InitTree( // no return value
+ void) // no parameters
+ throw() // exception list
+
+ {
+ int i;
+
+ // For i = 0 to N - 1, m_rson[i] and m_lson[i] will be the right
+ // and left children of node i. These nodes need not be
+ // initialized. However, for debugging purposes, it is nice to
+ // have them initialized. Since this is only used for compression
+ // (not decompression), I don't mind spending the time to do it.
+ //
+ // For the same range of i, m_dad[i] is the parent of node i.
+ // These are initialized to a known value that can represent
+ // a "not used" state.
+
+ for (i = 0; i < N; i++)
+ {
+ m_lson[i] = NOT_USED;
+ m_rson[i] = NOT_USED;
+ m_dad[i] = NOT_USED;
+ }
+
+ // For i = 0 to 255, m_rson[N + i + 1] is the root of the tree
+ // for strings that begin with the character i. This is why
+ // the right child array is larger than the left child array.
+ // These are also initialzied to a "not used" state.
+ //
+ // Note that there are 256 of these, one for each of the possible
+ // 256 characters.
+
+ for (i = N + 1; i <= (N + 256); i++)
+ {
+ m_rson[i] = NOT_USED;
+ }
+
+ // Done.
+ }
+
+/*
+ -------------------------------------------------------------------------
+ cLZSS::InsertNode
+
+ This function inserts a string from the ring buffer into one of
+ the trees. It loads the match position and length member variables
+ for the longest match.
+
+ The string to be inserted is identified by the parameter Pos,
+ A full F bytes are inserted. So, m_ring_buffer[Pos ... Pos+F-1]
+ are inserted.
+
+ If the matched length is exactly F, then an old node is removed
+ in favor of the new one (because the old one will be deleted
+ sooner).
+
+ Note that Pos plays a dual role. It is used as both a position
+ in the ring buffer and also as a tree node. m_ring_buffer[Pos]
+ defines a character that is used to identify a tree node.
+ -------------------------------------------------------------------------
+*/
+
+void cLZSS::InsertNode( // no return value
+ short int Pos) // position in the buffer
+ throw() // exception list
+
+ {
+ short int i;
+ short int p;
+ int cmp;
+ unsigned char * key;
+
+ ASSERT(Pos >= 0);
+ ASSERT(Pos < N);
+
+ cmp = 1;
+ key = &(m_ring_buffer[Pos]);
+
+ // The last 256 entries in m_rson contain the root nodes for
+ // strings that begin with a letter. Get an index for the
+ // first letter in this string.
+
+ p = (short int) (N + 1 + key[0]);
+
+ // Set the left and right tree nodes for this position to "not
+ // used."
+
+ m_lson[Pos] = NOT_USED;
+ m_rson[Pos] = NOT_USED;
+
+ // Haven't matched anything yet.
+
+ m_match_length = 0;
+
+ for ( ; ; )
+ {
+ if (cmp >= 0)
+ {
+ if (m_rson[p] != NOT_USED)
+ {
+ p = m_rson[p];
+ }
+ else
+ {
+ m_rson[p] = Pos;
+ m_dad[Pos] = p;
+ return;
+ }
+ }
+ else
+ {
+ if (m_lson[p] != NOT_USED)
+ {
+ p = m_lson[p];
+ }
+ else
+ {
+ m_lson[p] = Pos;
+ m_dad[Pos] = p;
+ return;
+ }
+ }
+
+ // Should we go to the right or the left to look for the
+ // next match?
+
+ for (i = 1; i < F; i++)
+ {
+ cmp = key[i] - m_ring_buffer[p + i];
+ if (cmp != 0)
+ break;
+ }
+
+ if (i > m_match_length)
+ {
+ m_match_position = p;
+ m_match_length = i;
+
+ if (i >= F)
+ break;
+ }
+ }
+
+ m_dad[Pos] = m_dad[p];
+ m_lson[Pos] = m_lson[p];
+ m_rson[Pos] = m_rson[p];
+
+ m_dad[ m_lson[p] ] = Pos;
+ m_dad[ m_rson[p] ] = Pos;
+
+ if (m_rson[ m_dad[p] ] == p)
+ {
+ m_rson[ m_dad[p] ] = Pos;
+ }
+ else
+ {
+ m_lson[ m_dad[p] ] = Pos;
+ }
+
+ // Remove "p"
+
+ m_dad[p] = NOT_USED;
+ }
+
+/*
+ -------------------------------------------------------------------------
+ cLZSS::DeleteNode
+
+ This function removes the node "Node" from the tree.
+ -------------------------------------------------------------------------
+*/
+
+void cLZSS::DeleteNode( // no return value
+ short int Node) // node to be removed
+ throw() // exception list
+
+ {
+ short int q;
+
+ ASSERT(Node >= 0);
+ ASSERT(Node < (N+1));
+
+ if (m_dad[Node] == NOT_USED)
+ {
+ // not in tree, nothing to do
+ return;
+ }
+
+ if (m_rson[Node] == NOT_USED)
+ {
+ q = m_lson[Node];
+ }
+ else if (m_lson[Node] == NOT_USED)
+ {
+ q = m_rson[Node];
+ }
+ else
+ {
+ q = m_lson[Node];
+ if (m_rson[q] != NOT_USED)
+ {
+ do
+ {
+ q = m_rson[q];
+ }
+ while (m_rson[q] != NOT_USED);
+
+ m_rson[ m_dad[q] ] = m_lson[q];
+ m_dad[ m_lson[q] ] = m_dad[q];
+ m_lson[q] = m_lson[Node];
+ m_dad[ m_lson[Node] ] = q;
+ }
+
+ m_rson[q] = m_rson[Node];
+ m_dad[ m_rson[Node] ] = q;
+ }
+
+ m_dad[q] = m_dad[Node];
+
+ if (m_rson[ m_dad[Node] ] == Node)
+ {
+ m_rson[ m_dad[Node] ] = q;
+ }
+ else
+ {
+ m_lson[ m_dad[Node] ] = q;
+ }
+
+ m_dad[Node] = NOT_USED;
+ }
+
+/*
+ -------------------------------------------------------------------------
+ cLZSS::Encode
+
+ This function "encodes" the input stream into the output stream.
+ The GetChars() and SendChars() functions are used to separate
+ this method from the actual i/o.
+ -------------------------------------------------------------------------
+*/
+
+void cLZSS::Encode( // no return value
+ void) // no parameters
+
+ {
+ short int i; // an iterator
+ short int r; // node number in the binary tree
+ short int s; // position in the ring buffer
+ unsigned short int len; // len of initial string
+ short int last_match_length; // length of last match
+ short int code_buf_pos; // position in the output buffer
+ unsigned char code_buf[17]; // the output buffer
+ unsigned char mask; // bit mask for byte 0 of out buf
+ unsigned char c; // character read from string
+
+ // Start with a clean tree.
+
+ InitTree();
+
+ // code_buf[0] works as eight flags. A "1" represents that the
+ // unit is an unencoded letter (1 byte), and a "0" represents
+ // that the next unit is a <position,length> pair (2 bytes).
+ //
+ // code_buf[1..16] stores eight units of code. Since the best
+ // we can do is store eight <position,length> pairs, at most 16
+ // bytes are needed to store this.
+ //
+ // This is why the maximum size of the code buffer is 17 bytes.
+
+ code_buf[0] = 0;
+ code_buf_pos = 1;
+
+ // Mask iterates over the 8 bits in the code buffer. The first
+ // character ends up being stored in the low bit.
+ //
+ // bit 8 7 6 5 4 3 2 1
+ // | |
+ // | first sequence in code buffer
+ // |
+ // last sequence in code buffer
+
+ mask = 1;
+
+ s = 0;
+ r = (short int) N - (short int) F;
+
+ // Initialize the ring buffer with spaces...
+
+ // Note that the last F bytes of the ring buffer are not filled.
+ // This is because those F bytes will be filled in immediately
+ // with bytes from the input stream.
+
+ memset(m_ring_buffer, ' ', N - F);
+
+ // Read F bytes into the last F bytes of the ring buffer.
+ //
+ // This function loads the buffer with X characters and returns
+ // the actual amount loaded.
+
+ len = GetChars(&(m_ring_buffer[r]), F);
+
+ // Make sure there is something to be compressed.
+
+ if (len == 0)
+ return;
+
+ // Insert the F strings, each of which begins with one or more
+ // 'space' characters. Note the order in which these strings
+ // are inserted. This way, degenerate trees will be less likely
+ // to occur.
+
+ for (i = 1; i <= F; i++)
+ {
+ InsertNode((short int) (r - i));
+ }
+
+ // Finally, insert the whole string just read. The
+ // member variables match_length and match_position are set.
+
+ InsertNode(r);
+
+ // Now that we're preloaded, continue till done.
+
+ do
+ {
+
+ // m_match_length may be spuriously long near the end of
+ // text.
+
+ if (m_match_length > len)
+ {
+ m_match_length = len;
+ }
+
+ // Is it cheaper to store this as a single character? If so,
+ // make it so.
+
+ if (m_match_length < THRESHOLD)
+ {
+ // Send one character. Remember that code_buf[0] is the
+ // set of flags for the next eight items.
+
+ m_match_length = 1;
+ code_buf[0] |= mask;
+ code_buf[code_buf_pos++] = m_ring_buffer[r];
+ }
+
+ // Otherwise, we do indeed have a string that can be stored
+ // compressed to save space.
+
+ else
+ {
+ // The next 16 bits need to contain the position (12 bits)
+ // and the length (4 bits).
+
+ code_buf[code_buf_pos++] = (unsigned char) m_match_position;
+ code_buf[code_buf_pos++] = (unsigned char) (
+ ((m_match_position >> 4) & 0xf0) |
+ (m_match_length - THRESHOLD) );
+ }
+
+ // Shift the mask one bit to the left so that it will be ready
+ // to store the new bit.
+
+ mask = (unsigned char) (mask << 1);
+
+ // If the mask is now 0, then we know that we have a full set
+ // of flags and items in the code buffer. These need to be
+ // output.
+
+ if (mask == 0)
+ {
+ // code_buf is the buffer of characters to be output.
+ // code_buf_pos is the number of characters it contains.
+
+ SendChars(code_buf, code_buf_pos);
+
+ // Reset for next buffer...
+
+ code_buf[0] = 0;
+ code_buf_pos = 1;
+ mask = 1;
+ }
+
+ last_match_length = m_match_length;
+
+ // Delete old strings and read new bytes...
+
+ for (i = 0; i < last_match_length; i++)
+ {
+
+ // Get next character...
+
+ if (GetChars(&c, 1) != 1)
+ break;
+
+ // Delete "old strings"
+
+ DeleteNode(s);
+
+ // Put this character into the ring buffer.
+ //
+ // The original comment here says "If the position is near
+ // the end of the buffer, extend the buffer to make
+ // string comparison easier."
+ //
+ // That's a little misleading, because the "end" of the
+ // buffer is really what we consider to be the "beginning"
+ // of the buffer, that is, positions 0 through F.
+ //
+ // The idea is that the front end of the buffer is duplicated
+ // into the back end so that when you're looking at characters
+ // at the back end of the buffer, you can index ahead (beyond
+ // the normal end of the buffer) and see the characters
+ // that are at the front end of the buffer wihtout having
+ // to adjust the index.
+ //
+ // That is...
+ //
+ // 1234xxxxxxxxxxxxxxxxxxxxxxxxxxxxx1234
+ // | | |
+ // position 0 end of buffer |
+ // |
+ // duplicate of front of buffer
+
+ m_ring_buffer[s] = c;
+
+ if (s < F - 1)
+ {
+ m_ring_buffer[s + N] = c;
+ }
+
+ // Increment the position, and wrap around when we're at
+ // the end. Note that this relies on N being a power of 2.
+
+ s = (short int) ( (s + 1) & (N - 1) );
+ r = (short int) ( (r + 1) & (N - 1) );
+
+ // Register the string that is found in
+ // m_ring_buffer[r..r+F-1].
+
+ InsertNode(r);
+ }
+
+ // If we didn't quit because we hit the last_match_length,
+ // then we must have quit because we ran out of characters
+ // to process.
+
+ while (i++ < last_match_length)
+ {
+ DeleteNode(s);
+
+ s = (short int) ( (s + 1) & (N - 1) );
+ r = (short int) ( (r + 1) & (N - 1) );
+
+ // Note that len hitting 0 is the key that causes the
+ // do...while() to terminate. This is the only place
+ // within the loop that len is modified.
+ //
+ // Its original value is F (or a number less than F for
+ // short strings).
+
+ if (--len)
+ {
+ InsertNode(r); /* buffer may not be empty. */
+ }
+ }
+
+ // End of do...while() loop. Continue processing until there
+ // are no more characters to be compressed. The variable
+ // "len" is used to signal this condition.
+ }
+ while (len > 0);
+
+ // There could still be something in the output buffer. Send it
+ // now.
+
+ if (code_buf_pos > 1)
+ {
+ // code_buf is the encoded string to send.
+ // code_buf_ptr is the number of characters.
+
+ SendChars(code_buf, code_buf_pos);
+ }
+
+ // Done!
+ }
+
+/*
+ -------------------------------------------------------------------------
+ cLZSS::Decode
+
+ This function "decodes" the input stream into the output stream.
+ The GetChars() and SendChars() functions are used to separate
+ this method from the actual i/o.
+ -------------------------------------------------------------------------
+*/
+
+void cLZSS::Decode( // no return value
+ void) // no parameters
+
+ {
+ int k;
+ int r; // node number
+ unsigned char c[F]; // an array of chars
+ unsigned char flags; // 8 bits of flags
+ int flag_count; // which flag we're on
+ short int pos; // position in the ring buffer
+ short int len; // number of chars in ring buffer
+
+ // Initialize the ring buffer with a common string.
+ //
+ // Note that the last F bytes of the ring buffer are not filled.
+
+ memset(m_ring_buffer, ' ', N - F);
+
+ r = N - F;
+
+ flags = (char) 0;
+ flag_count = 0;
+
+ for ( ; ; )
+ {
+
+ // If there are more bits of interest in this flag, then
+ // shift that next interesting bit into the 1's position.
+ //
+ // If this flag has been exhausted, the next byte must
+ // be a flag.
+
+ if (flag_count > 0)
+ {
+ flags = (unsigned char) (flags >> 1);
+ flag_count--;
+ }
+ else
+ {
+ // Next byte must be a flag.
+
+ if (GetChars(&flags, 1) != 1)
+ break;
+
+ // Set the flag counter. While at first it might appear
+ // that this should be an 8 since there are 8 bits in the
+ // flag, it should really be a 7 because the shift must
+ // be performed 7 times in order to see all 8 bits.
+
+ flag_count = 7;
+ }
+
+ // If the low order bit of the flag is now set, then we know
+ // that the next byte is a single, unencoded character.
+
+ if (flags & 1)
+ {
+ if (GetChars(c, 1) != 1)
+ break;
+
+ if (SendChars(c, 1) != 1)
+ break;
+
+ // Add to buffer, and increment to next spot. Wrap at end.
+
+ m_ring_buffer[r] = c[0];
+ r = (short int) ( (r + 1) & (N - 1) );
+ }
+
+ // Otherwise, we know that the next two bytes are a
+ // <position,length> pair. The position is in 12 bits and
+ // the length is in 4 bits.
+
+ else
+ {
+ // Original code:
+ // if ((i = getc(infile)) == EOF)
+ // break;
+ // if ((j = getc(infile)) == EOF)
+ // break;
+ // i |= ((j & 0xf0) << 4);
+ // j = (j & 0x0f) + THRESHOLD;
+ //
+ // I've modified this to only make one input call, and
+ // have changed the variable names to something more
+ // obvious.
+
+ if (GetChars(c, 2) != 2)
+ break;
+
+ // Convert these two characters into the position and
+ // length. Note that the length is always at least
+ // THRESHOLD, which is why we're able to get a length
+ // of 18 out of only 4 bits.
+
+ pos = (short int) ( c[0] | ((c[1] & 0xf0) << 4) );
+
+ len = (short int) ( (c[1] & 0x0f) + THRESHOLD );
+
+ // There are now "len" characters at position "pos" in
+ // the ring buffer that can be pulled out. Note that
+ // len is never more than F.
+
+ for (k = 0; k < len; k++)
+ {
+ c[k] = m_ring_buffer[(pos + k) & (N - 1)];
+
+ // Add to buffer, and increment to next spot. Wrap at end.
+
+ m_ring_buffer[r] = c[k];
+ r = (short int) ( (r + 1) & (N - 1) );
+ }
+
+ // Add the "len" characters to the output stream.
+
+ if (SendChars(c, len) != len)
+ break;
+ }
+ }
+ }
+
diff --git a/src/modules/common/entriesblk.cpp b/src/modules/common/entriesblk.cpp
new file mode 100644
index 0000000..d38cf53
--- /dev/null
+++ b/src/modules/common/entriesblk.cpp
@@ -0,0 +1,166 @@
+#include <entriesblk.h>
+#include <stdlib.h>
+#include <string.h>
+
+const int EntriesBlock::METAHEADERSIZE = 4;
+ // count(4);
+const int EntriesBlock::METAENTRYSIZE = 8;
+ // offset(4); size(4);
+
+EntriesBlock::EntriesBlock(const char *iBlock, unsigned long size) {
+ block = (char *)calloc(1, size);
+ memcpy(block, iBlock, size);
+}
+
+
+EntriesBlock::EntriesBlock() {
+ block = (char *)calloc(1, sizeof(__u32));
+}
+
+
+EntriesBlock::~EntriesBlock() {
+ free(block);
+}
+
+
+void EntriesBlock::setCount(int count) {
+ __u32 rawCount = archtosword32(count);
+ memcpy(block, &rawCount, sizeof(__u32));
+}
+
+
+int EntriesBlock::getCount() {
+ __u32 count = 0;
+ memcpy(&count, block, sizeof(__u32));
+ count = swordtoarch32(count);
+ return count;
+}
+
+
+void EntriesBlock::getMetaEntry(int index, unsigned long *offset, unsigned long *size) {
+ __u32 rawOffset = 0;
+ __u32 rawSize = 0;
+ *offset = 0;
+ *size = 0;
+ if (index >= getCount()) // assert index < count
+ return;
+
+ // first 4 bytes is count, each 6 bytes after is each meta entry
+ memcpy(&rawOffset, block + METAHEADERSIZE + (index * METAENTRYSIZE), sizeof(rawOffset));
+ memcpy(&rawSize, block + METAHEADERSIZE + (index * METAENTRYSIZE) + sizeof(rawOffset), sizeof(rawSize));
+
+ *offset = (unsigned long)swordtoarch32(rawOffset);
+ *size = (unsigned long)swordtoarch32(rawSize);
+}
+
+
+void EntriesBlock::setMetaEntry(int index, unsigned long offset, unsigned long size) {
+ __u32 rawOffset = archtosword32(offset);
+ __u32 rawSize = archtosword32(size);
+
+ if (index >= getCount()) // assert index < count
+ return;
+
+ // first 4 bytes is count, each 6 bytes after is each meta entry
+ memcpy(block + METAHEADERSIZE + (index * METAENTRYSIZE), &rawOffset, sizeof(rawOffset));
+ memcpy(block + METAHEADERSIZE + (index * METAENTRYSIZE) + sizeof(rawOffset), &rawSize, sizeof(rawSize));
+}
+
+
+const char *EntriesBlock::getRawData(unsigned long *retSize) {
+ unsigned long max = 4;
+ int loop;
+ unsigned long offset;
+ unsigned long size;
+ for (loop = 0; loop < getCount(); loop++) {
+ getMetaEntry(loop, &offset, &size);
+ max = ((offset + size) > max) ? (offset + size) : max;
+ }
+ *retSize = max;
+ return block;
+}
+
+
+int EntriesBlock::addEntry(const char *entry) {
+ unsigned long dataSize;
+ getRawData(&dataSize);
+ unsigned long len = strlen(entry);
+ unsigned long offset;
+ unsigned long size;
+ int count = getCount();
+ unsigned long dataStart = METAHEADERSIZE + (count * METAENTRYSIZE);
+ // new meta entry + new data size + 1 because null
+ block = (char *)realloc(block, dataSize + METAENTRYSIZE + len + 1);
+ // shift right to make room for new meta entry
+ memmove(block + dataStart + METAENTRYSIZE, block + dataStart, dataSize - dataStart);
+
+ for (int loop = 0; loop < count; loop++) {
+ getMetaEntry(loop, &offset, &size);
+ if (offset) { // if not a deleted entry
+ offset += METAENTRYSIZE;
+ setMetaEntry(loop, offset, size);
+ }
+ }
+
+ offset = dataSize; // original dataSize before realloc
+ size = len + 1;
+ // add our text to the end
+ memcpy(block + offset + METAENTRYSIZE, entry, size);
+ // increment count
+ setCount(count + 1);
+ // add our meta entry
+ setMetaEntry(count, offset + METAENTRYSIZE, size);
+ // return index of our new entry
+ return count;
+}
+
+
+const char *EntriesBlock::getEntry(int entryIndex) {
+ unsigned long offset;
+ unsigned long size;
+ static char *empty = "";
+
+ getMetaEntry(entryIndex, &offset, &size);
+ return (offset) ? block+offset : empty;
+}
+
+
+unsigned long EntriesBlock::getEntrySize(int entryIndex) {
+ unsigned long offset;
+ unsigned long size;
+
+ getMetaEntry(entryIndex, &offset, &size);
+ return (offset) ? size : 0;
+}
+
+
+void EntriesBlock::removeEntry(int entryIndex) {
+ unsigned long offset;
+ unsigned long size, size2;
+ unsigned long dataSize;
+ getRawData(&dataSize);
+ getMetaEntry(entryIndex, &offset, &size);
+ unsigned long len = size - 1;
+ int count = getCount();
+ unsigned long dataStart = METAHEADERSIZE + (count * METAENTRYSIZE);
+
+ if (!offset) // already deleted
+ return;
+
+ // shift left to retrieve space used for old entry
+ memmove(block + offset, block + offset + size, dataSize - (offset + size));
+
+ // fix offset for all entries after our entry that were shifted left
+ for (int loop = entryIndex + 1; loop < count; loop++) {
+ getMetaEntry(loop, &offset, &size2);
+ if (offset) { // if not a deleted entry
+ offset -= size;
+ setMetaEntry(loop, offset, size2);
+ }
+ }
+
+ // zero out our meta entry
+ setMetaEntry(entryIndex, 0L, 0);
+}
+
+
diff --git a/src/modules/common/lzsscomprs.cpp b/src/modules/common/lzsscomprs.cpp
new file mode 100644
index 0000000..3606fbc
--- /dev/null
+++ b/src/modules/common/lzsscomprs.cpp
@@ -0,0 +1,665 @@
+/******************************************************************************
+ * lzsscomprs.cpp - code for class 'LZSSCompress'- a driver class that
+ * provides LZSS compression
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <lzsscomprs.h>
+
+
+/******************************************************************************
+ * LZSSCompress Statics
+ */
+
+// m_ring_buffer is a text buffer. It contains "nodes" of
+// uncompressed text that can be indexed by position. That is,
+// a substring of the ring buffer can be indexed by a position
+// and a length. When decoding, the compressed text may contain
+// a position in the ring buffer and a count of the number of
+// bytes from the ring buffer that are to be moved into the
+// uncompressed buffer.
+//
+// This ring buffer is not maintained as part of the compressed
+// text. Instead, it is reconstructed dynamically. That is,
+// it starts out empty and gets built as the text is decompressed.
+//
+// The ring buffer contain N bytes, with an additional F - 1 bytes
+// to facilitate string comparison.
+
+unsigned char LZSSCompress::m_ring_buffer[N + F - 1];
+
+// m_match_position and m_match_length are set by InsertNode().
+//
+// These variables indicate the position in the ring buffer
+// and the number of characters at that position that match
+// a given string.
+
+short int LZSSCompress::m_match_position;
+short int LZSSCompress::m_match_length;
+
+// m_lson, m_rson, and m_dad are the Japanese way of referring to
+// a tree structure. The dad is the parent and it has a right and
+// left son (child).
+//
+// For i = 0 to N-1, m_rson[i] and m_lson[i] will be the right
+// and left children of node i.
+//
+// For i = 0 to N-1, m_dad[i] is the parent of node i.
+//
+// For i = 0 to 255, rson[N + i + 1] is the root of the tree for
+// strings that begin with the character i. Note that this requires
+// one byte characters.
+//
+// These nodes store values of 0...(N-1). Memory requirements
+// can be reduces by using 2-byte integers instead of full 4-byte
+// integers (for 32-bit applications). Therefore, these are
+// defined as "short ints."
+
+short int LZSSCompress::m_lson[N + 1];
+short int LZSSCompress::m_rson[N + 257];
+short int LZSSCompress::m_dad[N + 1];
+
+
+/******************************************************************************
+ * LZSSCompress Constructor - Initializes data for instance of LZSSCompress
+ *
+ */
+
+LZSSCompress::LZSSCompress() : SWCompress() {
+}
+
+
+/******************************************************************************
+ * LZSSCompress Destructor - Cleans up instance of LZSSCompress
+ */
+
+LZSSCompress::~LZSSCompress() {
+}
+
+
+/******************************************************************************
+ * LZSSCompress::InitTree - This function initializes the tree nodes to
+ * "empty" states.
+ */
+
+void LZSSCompress::InitTree(void) {
+ int i;
+
+ // For i = 0 to N - 1, m_rson[i] and m_lson[i] will be the right
+ // and left children of node i. These nodes need not be
+ // initialized. However, for debugging purposes, it is nice to
+ // have them initialized. Since this is only used for compression
+ // (not decompression), I don't mind spending the time to do it.
+ //
+ // For the same range of i, m_dad[i] is the parent of node i.
+ // These are initialized to a known value that can represent
+ // a "not used" state.
+
+ for (i = 0; i < N; i++) {
+ m_lson[i] = NOT_USED;
+ m_rson[i] = NOT_USED;
+ m_dad[i] = NOT_USED;
+ }
+
+ // For i = 0 to 255, m_rson[N + i + 1] is the root of the tree
+ // for strings that begin with the character i. This is why
+ // the right child array is larger than the left child array.
+ // These are also initialzied to a "not used" state.
+ //
+ // Note that there are 256 of these, one for each of the possible
+ // 256 characters.
+
+ for (i = N + 1; i <= (N + 256); i++) {
+ m_rson[i] = NOT_USED;
+ }
+}
+
+
+/******************************************************************************
+ * LZSSCompress::InsertNode - This function inserts a string from the ring
+ * buffer into one of the trees. It loads the
+ * match position and length member variables
+ * for the longest match.
+ *
+ * The string to be inserted is identified by
+ * the parameter Pos, A full F bytes are
+ * inserted. So,
+ * m_ring_buffer[Pos ... Pos+F-1]
+ * are inserted.
+ *
+ * If the matched length is exactly F, then an
+ * old node is removed in favor of the new one
+ * (because the old one will be deleted
+ * sooner).
+ *
+ * Note that Pos plays a dual role. It is
+ * used as both a position in the ring buffer
+ * and also as a tree node.
+ * m_ring_buffer[Pos] defines a character that
+ * is used to identify a tree node.
+ *
+ * ENT: pos - position in the buffer
+ */
+
+void LZSSCompress::InsertNode(short int Pos)
+{
+ short int i;
+ short int p;
+ int cmp;
+ unsigned char * key;
+
+/*
+ ASSERT(Pos >= 0);
+ ASSERT(Pos < N);
+*/
+
+ cmp = 1;
+ key = &(m_ring_buffer[Pos]);
+
+ // The last 256 entries in m_rson contain the root nodes for
+ // strings that begin with a letter. Get an index for the
+ // first letter in this string.
+
+ p = (short int) (N + 1 + key[0]);
+
+ // Set the left and right tree nodes for this position to "not
+ // used."
+
+ m_lson[Pos] = NOT_USED;
+ m_rson[Pos] = NOT_USED;
+
+ // Haven't matched anything yet.
+
+ m_match_length = 0;
+
+ for ( ; ; ) {
+ if (cmp >= 0) {
+ if (m_rson[p] != NOT_USED) {
+ p = m_rson[p];
+ }
+ else {
+ m_rson[p] = Pos;
+ m_dad[Pos] = p;
+ return;
+ }
+ }
+ else {
+ if (m_lson[p] != NOT_USED) {
+ p = m_lson[p];
+ }
+ else {
+ m_lson[p] = Pos;
+ m_dad[Pos] = p;
+ return;
+ }
+ }
+
+ // Should we go to the right or the left to look for the
+ // next match?
+
+ for (i = 1; i < F; i++) {
+ cmp = key[i] - m_ring_buffer[p + i];
+ if (cmp != 0)
+ break;
+ }
+
+ if (i > m_match_length) {
+ m_match_position = p;
+ m_match_length = i;
+
+ if (i >= F)
+ break;
+ }
+ }
+
+ m_dad[Pos] = m_dad[p];
+ m_lson[Pos] = m_lson[p];
+ m_rson[Pos] = m_rson[p];
+
+ m_dad[ m_lson[p] ] = Pos;
+ m_dad[ m_rson[p] ] = Pos;
+
+ if (m_rson[ m_dad[p] ] == p) {
+ m_rson[ m_dad[p] ] = Pos;
+ }
+ else {
+ m_lson[ m_dad[p] ] = Pos;
+ }
+
+ // Remove "p"
+
+ m_dad[p] = NOT_USED;
+}
+
+
+/******************************************************************************
+ * LZSSCompress::DeleteNode - This function removes the node "Node" from the
+ * tree.
+ *
+ * ENT: node - node to be removed
+ */
+
+void LZSSCompress::DeleteNode(short int Node)
+{
+ short int q;
+
+/*
+ ASSERT(Node >= 0);
+ ASSERT(Node < (N+1));
+*/
+
+ if (m_dad[Node] == NOT_USED) { // not in tree, nothing to do
+ return;
+ }
+
+ if (m_rson[Node] == NOT_USED) {
+ q = m_lson[Node];
+ }
+ else if (m_lson[Node] == NOT_USED) {
+ q = m_rson[Node];
+ }
+ else {
+ q = m_lson[Node];
+ if (m_rson[q] != NOT_USED) {
+ do {
+ q = m_rson[q];
+ } while (m_rson[q] != NOT_USED);
+
+ m_rson[ m_dad[q] ] = m_lson[q];
+ m_dad[ m_lson[q] ] = m_dad[q];
+ m_lson[q] = m_lson[Node];
+ m_dad[ m_lson[Node] ] = q;
+ }
+
+ m_rson[q] = m_rson[Node];
+ m_dad[ m_rson[Node] ] = q;
+ }
+
+ m_dad[q] = m_dad[Node];
+
+ if (m_rson[ m_dad[Node] ] == Node) {
+ m_rson[ m_dad[Node] ] = q;
+ }
+ else {
+ m_lson[ m_dad[Node] ] = q;
+ }
+
+ m_dad[Node] = NOT_USED;
+}
+
+
+/******************************************************************************
+ * LZSSCompress::Encode - This function "encodes" the input stream into the
+ * output stream.
+ * The GetChars() and SendChars() functions are
+ * used to separate this method from the actual
+ * i/o.
+ * NOTE: must set zlen for parent class to know length of
+ * compressed buffer.
+ */
+
+void LZSSCompress::Encode(void)
+{
+ short int i; // an iterator
+ short int r; // node number in the binary tree
+ short int s; // position in the ring buffer
+ unsigned short int len; // len of initial string
+ short int last_match_length; // length of last match
+ short int code_buf_pos; // position in the output buffer
+ unsigned char code_buf[17]; // the output buffer
+ unsigned char mask; // bit mask for byte 0 of out buf
+ unsigned char c; // character read from string
+
+ // Start with a clean tree.
+
+ InitTree();
+ direct = 0; // set direction needed by parent [Get|Send]Chars()
+
+ // code_buf[0] works as eight flags. A "1" represents that the
+ // unit is an unencoded letter (1 byte), and a "0" represents
+ // that the next unit is a <position,length> pair (2 bytes).
+ //
+ // code_buf[1..16] stores eight units of code. Since the best
+ // we can do is store eight <position,length> pairs, at most 16
+ // bytes are needed to store this.
+ //
+ // This is why the maximum size of the code buffer is 17 bytes.
+
+ code_buf[0] = 0;
+ code_buf_pos = 1;
+
+ // Mask iterates over the 8 bits in the code buffer. The first
+ // character ends up being stored in the low bit.
+ //
+ // bit 8 7 6 5 4 3 2 1
+ // | |
+ // | first sequence in code buffer
+ // |
+ // last sequence in code buffer
+
+ mask = 1;
+
+ s = 0;
+ r = (short int) N - (short int) F;
+
+ // Initialize the ring buffer with spaces...
+
+ // Note that the last F bytes of the ring buffer are not filled.
+ // This is because those F bytes will be filled in immediately
+ // with bytes from the input stream.
+
+ memset(m_ring_buffer, ' ', N - F);
+
+ // Read F bytes into the last F bytes of the ring buffer.
+ //
+ // This function loads the buffer with X characters and returns
+ // the actual amount loaded.
+
+ len = GetChars((char *) &(m_ring_buffer[r]), F);
+
+ // Make sure there is something to be compressed.
+
+ if (len == 0)
+ return;
+
+ // Insert the F strings, each of which begins with one or more
+ // 'space' characters. Note the order in which these strings
+ // are inserted. This way, degenerate trees will be less likely
+ // to occur.
+
+ for (i = 1; i <= F; i++) {
+ InsertNode((short int) (r - i));
+ }
+
+ // Finally, insert the whole string just read. The
+ // member variables match_length and match_position are set.
+
+ InsertNode(r);
+
+ // Now that we're preloaded, continue till done.
+
+ do {
+
+ // m_match_length may be spuriously long near the end of
+ // text.
+
+ if (m_match_length > len) {
+ m_match_length = len;
+ }
+
+ // Is it cheaper to store this as a single character? If so,
+ // make it so.
+
+ if (m_match_length < THRESHOLD) {
+ // Send one character. Remember that code_buf[0] is the
+ // set of flags for the next eight items.
+
+ m_match_length = 1;
+ code_buf[0] |= mask;
+ code_buf[code_buf_pos++] = m_ring_buffer[r];
+ }
+
+ // Otherwise, we do indeed have a string that can be stored
+ // compressed to save space.
+
+ else {
+ // The next 16 bits need to contain the position (12 bits)
+ // and the length (4 bits).
+
+ code_buf[code_buf_pos++] = (unsigned char) m_match_position;
+ code_buf[code_buf_pos++] = (unsigned char) (
+ ((m_match_position >> 4) & 0xf0) |
+ (m_match_length - THRESHOLD) );
+ }
+
+ // Shift the mask one bit to the left so that it will be ready
+ // to store the new bit.
+
+ mask = (unsigned char) (mask << 1);
+
+ // If the mask is now 0, then we know that we have a full set
+ // of flags and items in the code buffer. These need to be
+ // output.
+
+ if (!mask) {
+ // code_buf is the buffer of characters to be output.
+ // code_buf_pos is the number of characters it contains.
+
+ SendChars((char *) code_buf, code_buf_pos);
+
+ // Reset for next buffer...
+
+ code_buf[0] = 0;
+ code_buf_pos = 1;
+ mask = 1;
+ }
+
+ last_match_length = m_match_length;
+
+ // Delete old strings and read new bytes...
+
+ for (i = 0; i < last_match_length; i++) {
+ // Get next character...
+
+ if (GetChars((char *) &c, 1) != 1)
+ break;
+
+ // Delete "old strings"
+
+ DeleteNode(s);
+
+ // Put this character into the ring buffer.
+ //
+ // The original comment here says "If the position is near
+ // the end of the buffer, extend the buffer to make
+ // string comparison easier."
+ //
+ // That's a little misleading, because the "end" of the
+ // buffer is really what we consider to be the "beginning"
+ // of the buffer, that is, positions 0 through F.
+ //
+ // The idea is that the front end of the buffer is duplicated
+ // into the back end so that when you're looking at characters
+ // at the back end of the buffer, you can index ahead (beyond
+ // the normal end of the buffer) and see the characters
+ // that are at the front end of the buffer wihtout having
+ // to adjust the index.
+ //
+ // That is...
+ //
+ // 1234xxxxxxxxxxxxxxxxxxxxxxxxxxxxx1234
+ // | | |
+ // position 0 end of buffer |
+ // |
+ // duplicate of front of buffer
+
+ m_ring_buffer[s] = c;
+
+ if (s < F - 1) {
+ m_ring_buffer[s + N] = c;
+ }
+
+ // Increment the position, and wrap around when we're at
+ // the end. Note that this relies on N being a power of 2.
+
+ s = (short int) ( (s + 1) & (N - 1) );
+ r = (short int) ( (r + 1) & (N - 1) );
+
+ // Register the string that is found in
+ // m_ring_buffer[r..r+F-1].
+
+ InsertNode(r);
+ }
+
+ // If we didn't quit because we hit the last_match_length,
+ // then we must have quit because we ran out of characters
+ // to process.
+
+ while (i++ < last_match_length) {
+ DeleteNode(s);
+
+ s = (short int) ( (s + 1) & (N - 1) );
+ r = (short int) ( (r + 1) & (N - 1) );
+
+ // Note that len hitting 0 is the key that causes the
+ // do...while() to terminate. This is the only place
+ // within the loop that len is modified.
+ //
+ // Its original value is F (or a number less than F for
+ // short strings).
+
+ if (--len) {
+ InsertNode(r); /* buffer may not be empty. */
+ }
+ }
+
+ // End of do...while() loop. Continue processing until there
+ // are no more characters to be compressed. The variable
+ // "len" is used to signal this condition.
+ } while (len > 0);
+
+ // There could still be something in the output buffer. Send it
+ // now.
+
+ if (code_buf_pos > 1) {
+ // code_buf is the encoded string to send.
+ // code_buf_ptr is the number of characters.
+
+ SendChars((char *) code_buf, code_buf_pos);
+ }
+
+
+ // must set zlen for parent class to know length of compressed buffer
+ zlen = zpos;
+}
+
+
+/******************************************************************************
+ * LZSSCompress::Decode - This function "decodes" the input stream into the
+ * output stream.
+ * The GetChars() and SendChars() functions are
+ * used to separate this method from the actual
+ * i/o.
+ */
+
+void LZSSCompress::Decode(void)
+{
+ int k;
+ int r; // node number
+ unsigned char c[F]; // an array of chars
+ unsigned char flags; // 8 bits of flags
+ int flag_count; // which flag we're on
+ short int pos; // position in the ring buffer
+ short int len; // number of chars in ring buffer
+ unsigned long totalLen = 0;
+
+ direct = 1; // set direction needed by parent [Get|Send]Chars()
+
+ // Initialize the ring buffer with a common string.
+ //
+ // Note that the last F bytes of the ring buffer are not filled.
+
+ memset(m_ring_buffer, ' ', N - F);
+
+ r = N - F;
+
+ flags = (char) 0;
+ flag_count = 0;
+
+ for ( ; ; ) {
+
+ // If there are more bits of interest in this flag, then
+ // shift that next interesting bit into the 1's position.
+ //
+ // If this flag has been exhausted, the next byte must
+ // be a flag.
+
+ if (flag_count > 0) {
+ flags = (unsigned char) (flags >> 1);
+ flag_count--;
+ }
+ else {
+ // Next byte must be a flag.
+
+ if (GetChars((char *) &flags, 1) != 1)
+ break;
+
+ // Set the flag counter. While at first it might appear
+ // that this should be an 8 since there are 8 bits in the
+ // flag, it should really be a 7 because the shift must
+ // be performed 7 times in order to see all 8 bits.
+
+ flag_count = 7;
+ }
+
+ // If the low order bit of the flag is now set, then we know
+ // that the next byte is a single, unencoded character.
+
+ if (flags & 1) {
+ if (GetChars((char *) c, 1) != 1)
+ break;
+
+ if (SendChars((char *) c, 1) != 1) {
+ totalLen++;
+ break;
+ }
+
+ // Add to buffer, and increment to next spot. Wrap at end.
+
+ m_ring_buffer[r] = c[0];
+ r = (short int) ( (r + 1) & (N - 1) );
+ }
+
+ // Otherwise, we know that the next two bytes are a
+ // <position,length> pair. The position is in 12 bits and
+ // the length is in 4 bits.
+
+ else {
+ // Original code:
+ // if ((i = getc(infile)) == EOF)
+ // break;
+ // if ((j = getc(infile)) == EOF)
+ // break;
+ // i |= ((j & 0xf0) << 4);
+ // j = (j & 0x0f) + THRESHOLD;
+ //
+ // I've modified this to only make one input call, and
+ // have changed the variable names to something more
+ // obvious.
+
+ if (GetChars((char *) c, 2) != 2)
+ break;
+
+ // Convert these two characters into the position and
+ // length. Note that the length is always at least
+ // THRESHOLD, which is why we're able to get a length
+ // of 18 out of only 4 bits.
+
+ pos = (short int) ( c[0] | ((c[1] & 0xf0) << 4) );
+
+ len = (short int) ( (c[1] & 0x0f) + THRESHOLD );
+
+ // There are now "len" characters at position "pos" in
+ // the ring buffer that can be pulled out. Note that
+ // len is never more than F.
+
+ for (k = 0; k < len; k++) {
+ c[k] = m_ring_buffer[(pos + k) & (N - 1)];
+
+ // Add to buffer, and increment to next spot. Wrap at end.
+
+ m_ring_buffer[r] = c[k];
+ r = (short int) ( (r + 1) & (N - 1) );
+ }
+
+ // Add the "len" :characters to the output stream.
+
+ if (SendChars((char *) c, len) != (unsigned int)len) {
+ totalLen += len;
+ break;
+ }
+ }
+ }
+ slen = totalLen;
+}
diff --git a/src/modules/common/rawstr.cpp b/src/modules/common/rawstr.cpp
new file mode 100644
index 0000000..787946c
--- /dev/null
+++ b/src/modules/common/rawstr.cpp
@@ -0,0 +1,565 @@
+/******************************************************************************
+ * rawstr.cpp - code for class 'RawStr'- a module that reads raw text
+ * files: ot and nt using indexs ??.bks ??.cps ??.vss
+ * and provides lookup and parsing functions based on
+ * class StrKey
+ */
+
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#ifndef __GNUC__
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <utilfuns.h>
+#include <rawstr.h>
+#include <sysdata.h>
+/******************************************************************************
+ * RawStr Statics
+ */
+
+int RawStr::instance = 0;
+char RawStr::nl = '\n';
+
+
+/******************************************************************************
+ * RawStr Constructor - Initializes data for instance of RawStr
+ *
+ * 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/')
+ */
+
+RawStr::RawStr(const char *ipath, int fileMode)
+{
+ char buf[127];
+
+ lastoff = -1;
+ path = 0;
+ stdstr(&path, ipath);
+
+#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);
+
+ if (datfd < 0) {
+ sprintf(buf, "Error: %d", errno);
+ perror(buf);
+ }
+
+ instance++;
+}
+
+
+/******************************************************************************
+ * RawStr Destructor - Cleans up instance of RawStr
+ */
+
+RawStr::~RawStr()
+{
+ if (path)
+ delete [] path;
+
+ --instance;
+
+ FileMgr::systemFileMgr.close(idxfd);
+ FileMgr::systemFileMgr.close(datfd);
+}
+
+
+/******************************************************************************
+ * RawStr::getidxbufdat - Gets the index string at the given idx offset
+ * NOTE: buf is allocated and must be freed by
+ * calling function
+ *
+ * ENT: ioffset - offset in dat file to lookup
+ * buf - address of pointer to allocate for storage of string
+ */
+
+void RawStr::getidxbufdat(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 + 1) : (char *)malloc(size + 1);
+ if (size) {
+ lseek(datfd->getFd(), ioffset, SEEK_SET);
+ read(datfd->getFd(), *buf, size);
+ }
+ (*buf)[size] = 0;
+ for (size--; size > 0; size--)
+ (*buf)[size] = SW_toupper((*buf)[size]);
+ }
+ else {
+ *buf = (*buf) ? (char *)realloc(*buf, 1) : (char *)malloc(1);
+ **buf = 0;
+ }
+}
+
+
+/******************************************************************************
+ * RawStr::getidxbuf - Gets the index string at the given idx offset
+ * NOTE: buf is allocated 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 RawStr::getidxbuf(long ioffset, char **buf)
+{
+ char *trybuf, *targetbuf;
+ long offset;
+
+ if (idxfd > 0) {
+ lseek(idxfd->getFd(), ioffset, SEEK_SET);
+ read(idxfd->getFd(), &offset, 4);
+
+ offset = swordtoarch32(offset);
+
+ getidxbufdat(offset, buf);
+ for (trybuf = targetbuf = *buf; *trybuf; trybuf++, targetbuf++) {
+/*
+ if (*trybuf == '-') { // ignore '-' because alphabetized silly in file
+ targetbuf--;
+ continue;
+ }
+*/
+ *targetbuf = SW_toupper(*trybuf);
+ }
+ *targetbuf = 0;
+ trybuf = 0;
+ }
+}
+
+
+/******************************************************************************
+ * RawStr::findoffset - Finds the offset of the key string from the indexes
+ *
+ * ENT: key - key string to lookup
+ * start - 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 RawStr::findoffset(const char *ikey, long *start, unsigned short *size, long away, long *idxoff)
+{
+ char *trybuf, *targetbuf, *key, quitflag = 0;
+ signed char retval = 0;
+ long headoff, tailoff, tryoff = 0, maxoff = 0;
+
+ if (idxfd->getFd() >=0) {
+ tailoff = maxoff = lseek(idxfd->getFd(), 0, SEEK_END) - 6;
+ if (*ikey) {
+ headoff = 0;
+
+ key = new char [ strlen(ikey) + 1 ];
+ strcpy(key, ikey);
+
+ for (trybuf = targetbuf = key; *trybuf; trybuf++, targetbuf++) {
+ /*
+ if (*trybuf == '-') { // ignore '-' because alphabetized silly in file
+ targetbuf--;
+ continue;
+ }
+ */
+ *targetbuf = SW_toupper(*trybuf);
+ }
+ *targetbuf = 0;
+ trybuf = 0;
+
+ while (headoff < tailoff) {
+ tryoff = (lastoff == -1) ? headoff + ((((tailoff / 6) - (headoff / 6))) / 2) * 6 : lastoff;
+ lastoff = -1;
+ getidxbuf(tryoff, &trybuf);
+
+ if (!*trybuf && tryoff) { // In case of extra entry at end of idx (not first entry)
+ tryoff += (tryoff > (maxoff / 2))?-6:6;
+ retval = -1;
+ break;
+ }
+
+ if (!strcmp(key, trybuf))
+ break;
+
+ int diff = strcmp(key, trybuf);
+ if (diff < 0)
+ tailoff = (tryoff == headoff) ? headoff : tryoff;
+ else headoff = tryoff;
+ if (tailoff == headoff + 6) {
+ 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;
+ read(idxfd->getFd(), start, 4);
+ read(idxfd->getFd(), size, 2);
+ if (idxoff)
+ *idxoff = tryoff;
+
+ *start = swordtoarch32(*start);
+ *size = swordtoarch16(*size);
+
+ while (away) {
+ long laststart = *start;
+ unsigned short lastsize = *size;
+ long lasttry = tryoff;
+ tryoff += (away > 0) ? 6 : -6;
+
+ bool bad = false;
+ if (((tryoff + (away*6)) < -6) || (tryoff + (away*6) > (maxoff+6)))
+ 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, 4);
+ read(idxfd->getFd(), size, 2);
+ if (idxoff)
+ *idxoff = tryoff;
+
+ *start = swordtoarch32(*start);
+ *size = swordtoarch16(*size);
+
+ if (((laststart != *start) || (lastsize != *size)) && (*start >= 0) && (*size))
+ away += (away < 0) ? 1 : -1;
+ }
+
+ lastoff = tryoff;
+ }
+ else {
+ *start = 0;
+ *size = 0;
+ if (idxoff)
+ *idxoff = 0;
+ retval = -1;
+ }
+ return retval;
+}
+
+
+/******************************************************************************
+ * RawStr::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 RawStr::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;
+ }
+}
+
+
+/******************************************************************************
+ * RawStr::gettext - gets text at a given offset
+ *
+ * ENT:
+ * start - starting offset where the text is located in the file
+ * size - size of text entry
+ * buf - buffer to store text
+ *
+ */
+
+void RawStr::gettext(long istart, unsigned short isize, char *idxbuf, char *buf)
+{
+ char *ch;
+ char *idxbuflocal = 0;
+ getidxbufdat(istart, &idxbuflocal);
+ long start = istart;
+ unsigned short size = isize;
+
+ do {
+ memset(buf, 0, size);
+ lseek(datfd->getFd(), start, SEEK_SET);
+ read(datfd->getFd(), buf, (int)(size - 2));
+
+ for (ch = buf; *ch; ch++) { // skip over index string
+ if (*ch == 10) {
+ ch++;
+ break;
+ }
+ }
+ size -= (unsigned short)(ch-buf);
+ memmove(buf, ch, size);
+ buf[size] = 0;
+ buf[size+1] = 0;
+
+ // resolve link
+ if (!strncmp(buf, "@LINK", 5)) {
+ for (ch = buf; *ch; ch++) { // null before nl
+ if (*ch == 10) {
+ *ch = 0;
+ break;
+ }
+ }
+ findoffset(buf + 6, &start, &size);
+ // TODO: FIX! THIS IS WRONG!!! buf is not reallocated for the appropriate size!
+ }
+ else break;
+ }
+ while (true); // while we're resolving links
+
+ if (idxbuflocal) {
+ int localsize = strlen(idxbuflocal);
+ localsize = (localsize < (size - 1)) ? localsize : (size - 1);
+ strncpy(idxbuf, idxbuflocal, localsize);
+ idxbuf[localsize] = 0;
+ free(idxbuflocal);
+ }
+}
+
+
+/******************************************************************************
+ * RawLD::settext - Sets text for current offset
+ *
+ * ENT: key - key for this entry
+ * buf - buffer to store
+ * len - length of buffer (0 - null terminated)
+ */
+
+void RawStr::settext(const char *ikey, const char *buf, long len)
+{
+
+ long start, outstart;
+ long idxoff;
+ long endoff;
+ long shiftSize;
+ unsigned short size;
+ unsigned short outsize;
+ static const char nl[] = {13, 10};
+ char *tmpbuf = 0;
+ char *key = 0;
+ char *dbKey = 0;
+ char *idxBytes = 0;
+ char *outbuf = 0;
+ char *ch = 0;
+
+ findoffset(ikey, &start, &size, 0, &idxoff);
+ stdstr(&key, ikey);
+ for (ch = key; *ch; ch++)
+ *ch = SW_toupper(*ch);
+ ch = 0;
+
+ getidxbufdat(start, &dbKey);
+
+ if (strcmp(key, dbKey) < 0) {
+ }
+ else if (strcmp(key, dbKey) > 0) {
+ idxoff += 6;
+ } else if ((!strcmp(key, dbKey)) && (len || strlen(buf) /*we're not deleting*/)) { // got absolute entry
+ do {
+ tmpbuf = new char [ size + 2 ];
+ memset(tmpbuf, 0, size + 2);
+ lseek(datfd->getFd(), start, SEEK_SET);
+ read(datfd->getFd(), tmpbuf, (int)(size - 1));
+
+ for (ch = tmpbuf; *ch; ch++) { // skip over index string
+ if (*ch == 10) {
+ ch++;
+ break;
+ }
+ }
+ memmove(tmpbuf, ch, size - (unsigned short)(ch-tmpbuf));
+
+ // resolve link
+ if (!strncmp(tmpbuf, "@LINK", 5) && (len ? len : strlen(buf))) {
+ for (ch = tmpbuf; *ch; ch++) { // null before nl
+ if (*ch == 10) {
+ *ch = 0;
+ break;
+ }
+ }
+ findoffset(tmpbuf + 6, &start, &size, 0, &idxoff);
+ }
+ 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 ? len : strlen(buf)) + strlen(key) + 5 ];
+ sprintf(outbuf, "%s%c%c", key, 13, 10);
+ size = strlen(outbuf);
+ memcpy (outbuf + size, buf, len ? len : strlen(buf));
+ size = outsize = size + (len ? len : strlen(buf));
+
+ start = outstart = lseek(datfd->getFd(), 0, SEEK_END);
+
+ outstart = archtosword32(start);
+ outsize = archtosword16(size);
+
+ lseek(idxfd->getFd(), idxoff, SEEK_SET);
+ if (len ? len : strlen(buf)) {
+ lseek(datfd->getFd(), start, SEEK_SET);
+ write(datfd->getFd(), outbuf, (int)size);
+
+ // add a new line to make data file easier to read in an editor
+ write(datfd->getFd(), &nl, 2);
+
+ write(idxfd->getFd(), &outstart, 4);
+ write(idxfd->getFd(), &outsize, 2);
+ if (idxBytes) {
+ write(idxfd->getFd(), idxBytes, shiftSize);
+ delete [] idxBytes;
+ }
+ }
+ else { // delete entry
+ if (idxBytes) {
+ write(idxfd->getFd(), idxBytes+6, shiftSize-6);
+ lseek(idxfd->getFd(), -1, SEEK_CUR); // last valid byte
+ FileMgr::systemFileMgr.trunc(idxfd); // truncate index
+ delete [] idxBytes;
+ }
+ }
+
+ delete [] key;
+ delete [] outbuf;
+ free(dbKey);
+}
+
+
+/******************************************************************************
+ * RawLD::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 RawStr::linkentry(const char *destkey, const char *srckey) {
+ char *text = new char [ strlen(destkey) + 7 ];
+ sprintf(text, "@LINK %s", destkey);
+ settext(srckey, text);
+ delete [] text;
+}
+
+
+/******************************************************************************
+ * RawLD::CreateModule - Creates new module files
+ *
+ * ENT: path - directory to store module files
+ * RET: error status
+ */
+
+signed char RawStr::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);
+
+ delete [] path;
+
+ return 0;
+}
diff --git a/src/modules/common/rawstr4.cpp b/src/modules/common/rawstr4.cpp
new file mode 100644
index 0000000..d5926ff
--- /dev/null
+++ b/src/modules/common/rawstr4.cpp
@@ -0,0 +1,562 @@
+/******************************************************************************
+ * rawstr.cpp - code for class 'RawStr'- a module that reads raw text
+ * files: ot and nt using indexs ??.bks ??.cps ??.vss
+ * and provides lookup and parsing functions based on
+ * class StrKey
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#ifndef __GNUC__
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <utilfuns.h>
+#include <rawstr4.h>
+#include <sysdata.h>
+
+/******************************************************************************
+ * RawStr Statics
+ */
+
+int RawStr4::instance = 0;
+
+
+/******************************************************************************
+ * RawStr Constructor - Initializes data for instance of RawStr
+ *
+ * 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/')
+ */
+
+RawStr4::RawStr4(const char *ipath, int fileMode)
+{
+ char buf[127];
+
+ nl = '\n';
+ lastoff = -1;
+ path = 0;
+ stdstr(&path, ipath);
+
+#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);
+
+ if (datfd < 0) {
+ sprintf(buf, "Error: %d", errno);
+ perror(buf);
+ }
+
+ instance++;
+}
+
+
+/******************************************************************************
+ * RawStr Destructor - Cleans up instance of RawStr
+ */
+
+RawStr4::~RawStr4()
+{
+ if (path)
+ delete [] path;
+
+ --instance;
+
+ FileMgr::systemFileMgr.close(idxfd);
+ FileMgr::systemFileMgr.close(datfd);
+}
+
+
+/******************************************************************************
+ * RawStr4::getidxbufdat - Gets the index string at the given idx offset
+ * NOTE: buf is allocated and must be freed by
+ * calling function
+ *
+ * ENT: ioffset - offset in dat file to lookup
+ * buf - address of pointer to allocate for storage of string
+ */
+
+void RawStr4::getidxbufdat(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 + 1) : (char *)malloc(size + 1);
+ if (size) {
+ lseek(datfd->getFd(), ioffset, SEEK_SET);
+ read(datfd->getFd(), *buf, size);
+ }
+ (*buf)[size] = 0;
+ for (size--; size > 0; size--)
+ (*buf)[size] = SW_toupper((*buf)[size]);
+ }
+ else {
+ *buf = (*buf) ? (char *)realloc(*buf, 1) : (char *)malloc(1);
+ **buf = 0;
+ }
+}
+
+
+/******************************************************************************
+ * RawStr4::getidxbuf - Gets the index string at the given idx offset
+ * NOTE: buf is allocated 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 RawStr4::getidxbuf(long ioffset, char **buf)
+{
+ char *trybuf, *targetbuf;
+ long offset;
+
+ if (idxfd > 0) {
+ lseek(idxfd->getFd(), ioffset, SEEK_SET);
+ read(idxfd->getFd(), &offset, 4);
+
+ offset = swordtoarch32(offset);
+
+ getidxbufdat(offset, buf);
+ for (trybuf = targetbuf = *buf; *trybuf; trybuf++, targetbuf++) {
+/*
+ if (*trybuf == '-') { // ignore '-' because alphabetized silly in file
+ targetbuf--;
+ continue;
+ }
+*/
+ *targetbuf = SW_toupper(*trybuf);
+ }
+ *targetbuf = 0;
+ trybuf = 0;
+ }
+}
+
+
+/******************************************************************************
+ * RawStr4::findoffset - Finds the offset of the key string from the indexes
+ *
+ * ENT: key - key string to lookup
+ * start - 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 RawStr4::findoffset(const char *ikey, long *start, unsigned long *size, long away, long *idxoff)
+{
+ char *trybuf, *targetbuf, *key, quitflag = 0;
+ signed char retval = 0;
+ long headoff, tailoff, tryoff = 0, maxoff = 0;
+
+ if (idxfd->getFd() >=0) {
+ if (*ikey) {
+ headoff = 0;
+ tailoff = maxoff = lseek(idxfd->getFd(), 0, SEEK_END) - 8;
+
+ key = new char [ strlen(ikey) + 1 ];
+ strcpy(key, ikey);
+
+ for (trybuf = targetbuf = key; *trybuf; trybuf++, targetbuf++) {
+ /*
+ if (*trybuf == '-') { // ignore '-' because alphabetized silly in file
+ targetbuf--;
+ continue;
+ }
+ */
+ *targetbuf = SW_toupper(*trybuf);
+ }
+ *targetbuf = 0;
+ trybuf = 0;
+
+ while (headoff < tailoff) {
+ tryoff = (lastoff == -1) ? headoff + ((((tailoff / 8) - (headoff / 8))) / 2) * 8 : lastoff;
+ lastoff = -1;
+ getidxbuf(tryoff, &trybuf);
+
+ if (!*trybuf) { // In case of extra entry at end of idx
+ tryoff += (tryoff > (maxoff / 2))?-8:8;
+ retval = -1;
+ break;
+ }
+
+ if (!strcmp(key, trybuf))
+ break;
+
+ int diff = strcmp(key, trybuf);
+ if (diff < 0)
+ tailoff = (tryoff == headoff) ? headoff : tryoff;
+ else headoff = tryoff;
+ if (tailoff == headoff + 8) {
+ 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;
+ read(idxfd->getFd(), start, 4);
+ read(idxfd->getFd(), size, 4);
+ if (idxoff)
+ *idxoff = tryoff;
+
+ *start = swordtoarch32(*start);
+ *size = swordtoarch32(*size);
+
+ while (away) {
+ long laststart = *start;
+ unsigned long lastsize = *size;
+ long lasttry = tryoff;
+ tryoff += (away > 0) ? 8 : -8;
+
+ bool bad = false;
+ if (((tryoff + (away*8)) < -8) || (tryoff + (away*8) > (maxoff+8)))
+ 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, 4);
+ read(idxfd->getFd(), size, 4);
+ if (idxoff)
+ *idxoff = tryoff;
+
+ *start = swordtoarch32(*start);
+ *size = swordtoarch32(*size);
+
+ if (((laststart != *start) || (lastsize != *size)) && (*start >= 0) && (*size))
+ away += (away < 0) ? 1 : -1;
+ }
+
+ lastoff = tryoff;
+ }
+ else {
+ *start = 0;
+ *size = 0;
+ if (idxoff)
+ *idxoff = 0;
+ retval = -1;
+ }
+ return retval;
+}
+
+
+/******************************************************************************
+ * RawStr4::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 RawStr4::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;
+ }
+}
+
+
+/******************************************************************************
+ * RawStr4::gettext - gets text at a given offset
+ *
+ * ENT:
+ * start - starting offset where the text is located in the file
+ * size - size of text entry
+ * buf - buffer to store text
+ *
+ */
+
+void RawStr4::gettext(long istart, unsigned long isize, char *idxbuf, char *buf)
+{
+ char *ch;
+ char *idxbuflocal = 0;
+ getidxbufdat(istart, &idxbuflocal);
+ long start = istart;
+ unsigned long size = isize;
+
+ do {
+ memset(buf, 0, size);
+ lseek(datfd->getFd(), start, SEEK_SET);
+ read(datfd->getFd(), buf, (int)(size - 1));
+
+ 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;
+ }
+ }
+ findoffset(buf + 8, &start, &size);
+ }
+ else break;
+ }
+ while (true); // while we're resolving links
+
+ if (idxbuflocal) {
+ int localsize = strlen(idxbuflocal);
+ localsize = (localsize < (size - 1)) ? localsize : (size - 1);
+ strncpy(idxbuf, idxbuflocal, localsize);
+ idxbuf[localsize] = 0;
+ free(idxbuflocal);
+ }
+}
+
+
+/******************************************************************************
+ * RawLD::settext - Sets text for current offset
+ *
+ * ENT: key - key for this entry
+ * buf - buffer to store
+ * len - length of buffer (0 - null terminated)
+ */
+
+void RawStr4::settext(const char *ikey, const char *buf, long len)
+{
+
+ long start, outstart;
+ long idxoff;
+ long endoff;
+ long shiftSize;
+ unsigned long size;
+ unsigned long outsize;
+ static const char nl[] = {13, 10};
+ char *tmpbuf = 0;
+ char *key = 0;
+ char *dbKey = 0;
+ char *idxBytes = 0;
+ char *outbuf = 0;
+ char *ch = 0;
+
+ findoffset(ikey, &start, &size, 0, &idxoff);
+ stdstr(&key, ikey);
+ for (ch = key; *ch; ch++)
+ *ch = SW_toupper(*ch);
+ ch = 0;
+
+ getidxbufdat(start, &dbKey);
+
+ if (strcmp(key, dbKey) < 0) {
+ }
+ else if (strcmp(key, dbKey) > 0) {
+ idxoff += 8;
+ } else if ((!strcmp(key, dbKey)) && (len || strlen(buf) /*we're not deleting*/)) { // got absolute entry
+ do {
+ tmpbuf = new char [ size + 2 ];
+ memset(tmpbuf, 0, size + 2);
+ lseek(datfd->getFd(), start, SEEK_SET);
+ read(datfd->getFd(), tmpbuf, (int)(size - 1));
+
+ 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 ? len : strlen(buf))) {
+ for (ch = tmpbuf; *ch; ch++) { // null before nl
+ if (*ch == 10) {
+ *ch = 0;
+ break;
+ }
+ }
+ findoffset(tmpbuf + 8, &start, &size, 0, &idxoff);
+ }
+ 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 ? len : strlen(buf)) + strlen(key) + 5 ];
+ sprintf(outbuf, "%s%c%c", key, 13, 10);
+ size = strlen(outbuf);
+ memcpy (outbuf + size, buf, len ? len : strlen(buf));
+ size = outsize = size + (len ? len : strlen(buf));
+
+ start = outstart = lseek(datfd->getFd(), 0, SEEK_END);
+
+ outstart = archtosword32(start);
+ outsize = archtosword32(size);
+
+ lseek(idxfd->getFd(), idxoff, SEEK_SET);
+ if (len ? len : strlen(buf)) {
+ lseek(datfd->getFd(), start, SEEK_SET);
+ write(datfd->getFd(), outbuf, (long)size);
+
+ // add a new line to make data file easier to read in an editor
+ write(datfd->getFd(), &nl, 2);
+
+ write(idxfd->getFd(), &outstart, 4);
+ write(idxfd->getFd(), &outsize, 4);
+ if (idxBytes) {
+ write(idxfd->getFd(), idxBytes, shiftSize);
+ delete [] idxBytes;
+ }
+ }
+ else { // delete entry
+ if (idxBytes) {
+ write(idxfd->getFd(), idxBytes+8, shiftSize-8);
+ lseek(idxfd->getFd(), -1, SEEK_CUR); // last valid byte
+ FileMgr::systemFileMgr.trunc(idxfd); // truncate index
+ delete [] idxBytes;
+ }
+ }
+
+ delete [] key;
+ delete [] outbuf;
+ free(dbKey);
+}
+
+
+/******************************************************************************
+ * RawLD::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 RawStr4::linkentry(const char *destkey, const char *srckey) {
+ char *text = new char [ strlen(destkey) + 7 ];
+ sprintf(text, "@LINK %s", destkey);
+ settext(srckey, text);
+ delete [] text;
+}
+
+
+/******************************************************************************
+ * RawLD::CreateModule - Creates new module files
+ *
+ * ENT: path - directory to store module files
+ * RET: error status
+ */
+
+signed char RawStr4::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);
+
+ delete [] path;
+
+ return 0;
+}
diff --git a/src/modules/common/rawverse.cpp b/src/modules/common/rawverse.cpp
new file mode 100644
index 0000000..3374da5
--- /dev/null
+++ b/src/modules/common/rawverse.cpp
@@ -0,0 +1,345 @@
+/******************************************************************************
+ * rawverse.cpp - code for class 'RawVerse'- 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
+ */
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#ifndef __GNUC__
+#include <io.h>
+#include <sys/stat.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <string.h>
+#include <utilfuns.h>
+#include <rawverse.h>
+#include <versekey.h>
+#include <sysdata.h>
+
+#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.
+
+
+/******************************************************************************
+ * RawVerse Statics
+ */
+
+ int RawVerse::instance = 0;
+
+
+/******************************************************************************
+ * RawVerse Constructor - Initializes data for instance of RawVerse
+ *
+ * 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/')
+ */
+
+RawVerse::RawVerse(const char *ipath, int fileMode)
+{
+ char *buf;
+
+ nl = '\n';
+ path = 0;
+ stdstr(&path, ipath);
+ buf = new char [ strlen(path) + 80 ];
+ if ((path[strlen(path)-1] == '/') || (path[strlen(path)-1] == '\\'))
+ path[strlen(path)-1] = 0;
+
+ if (fileMode == -1) { // try read/write if possible
+ fileMode = O_RDWR;
+ }
+
+ sprintf(buf, "%s/ot.vss", path);
+ idxfp[0] = FileMgr::systemFileMgr.open(buf, fileMode|O_BINARY, true);
+
+ sprintf(buf, "%s/nt.vss", path);
+ idxfp[1] = FileMgr::systemFileMgr.open(buf, fileMode|O_BINARY, true);
+
+ sprintf(buf, "%s/ot", path);
+ textfp[0] = FileMgr::systemFileMgr.open(buf, fileMode|O_BINARY, true);
+
+ sprintf(buf, "%s/nt", path);
+ textfp[1] = FileMgr::systemFileMgr.open(buf, fileMode|O_BINARY, true);
+
+ delete [] buf;
+ instance++;
+}
+
+
+/******************************************************************************
+ * RawVerse Destructor - Cleans up instance of RawVerse
+ */
+
+RawVerse::~RawVerse()
+{
+ int loop1;
+
+ if (path)
+ delete [] path;
+
+ --instance;
+
+ for (loop1 = 0; loop1 < 2; loop1++) {
+ FileMgr::systemFileMgr.close(idxfp[loop1]);
+ FileMgr::systemFileMgr.close(textfp[loop1]);
+ }
+}
+
+
+/******************************************************************************
+ * RawVerse::findoffset - Finds the offset of the key verse from the indexes
+ *
+ * ENT: testmt - testament to find (0 - Bible/module introduction)
+ * idxoff - offset into .vss
+ * start - address to store the starting offset
+ * size - address to store the size of the entry
+ */
+
+void RawVerse::findoffset(char testmt, long idxoff, long *start, unsigned short *size) {
+ idxoff *= 6;
+ if (!testmt)
+ testmt = ((idxfp[1]) ? 1:2);
+
+ if (idxfp[testmt-1]->getFd() >= 0) {
+ lseek(idxfp[testmt-1]->getFd(), idxoff, SEEK_SET);
+ read(idxfp[testmt-1]->getFd(), start, 4);
+ long len = read(idxfp[testmt-1]->getFd(), size, 2); // read size
+
+ *start = swordtoarch32(*start);
+ *size = swordtoarch16(*size);
+
+ if (len < 2) {
+ *size = (unsigned short)((*start) ? (lseek(textfp[testmt-1]->getFd(), 0, SEEK_END) - (long)*start) : 0); // if for some reason we get an error reading size, make size to end of file
+ }
+ }
+ else {
+ *start = 0;
+ *size = 0;
+ }
+}
+
+
+/******************************************************************************
+ * RawVerse::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 RawVerse::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;
+ }
+}
+
+
+/******************************************************************************
+ * RawVerse::gettext - 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 + 2 (null)(null)
+ * buf - buffer to store text
+ *
+ */
+
+void RawVerse::gettext(char testmt, long start, unsigned short size, char *buf) {
+ memset(buf, 0, size+1);
+ if (size) {
+ if (textfp[testmt-1]->getFd() >= 0) {
+ lseek(textfp[testmt-1]->getFd(), start, SEEK_SET);
+ read(textfp[testmt-1]->getFd(), buf, (int)size - 2);
+ }
+ }
+}
+
+
+/******************************************************************************
+ * RawVerse::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 RawVerse::settext(char testmt, long idxoff, const char *buf, long len)
+{
+ long start, outstart;
+ unsigned short size;
+ unsigned short outsize;
+ static const char nl[] = {13, 10};
+
+ idxoff *= 6;
+ if (!testmt)
+ testmt = ((idxfp[1]) ? 1:2);
+
+ size = outsize = len ? len : strlen(buf);
+
+ start = outstart = lseek(textfp[testmt-1]->getFd(), 0, SEEK_END);
+ lseek(idxfp[testmt-1]->getFd(), idxoff, SEEK_SET);
+
+ if (size) {
+ lseek(textfp[testmt-1]->getFd(), start, SEEK_SET);
+ write(textfp[testmt-1]->getFd(), buf, (int)size);
+
+ // add a new line to make data file easier to read in an editor
+ write(textfp[testmt-1]->getFd(), &nl, 2);
+ }
+ else {
+ start = 0;
+ }
+
+ outstart = archtosword32(start);
+ outsize = archtosword16(size);
+
+ write(idxfp[testmt-1]->getFd(), &outstart, 4);
+ write(idxfp[testmt-1]->getFd(), &outsize, 2);
+
+
+}
+
+
+/******************************************************************************
+ * 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 RawVerse::linkentry(char testmt, long destidxoff, long srcidxoff) {
+ long start;
+ unsigned short size;
+
+ destidxoff *= 6;
+ srcidxoff *= 6;
+
+ if (!testmt)
+ testmt = ((idxfp[1]) ? 1:2);
+
+ // get source
+ lseek(idxfp[testmt-1]->getFd(), srcidxoff, SEEK_SET);
+ read(idxfp[testmt-1]->getFd(), &start, 4);
+ read(idxfp[testmt-1]->getFd(), &size, 2);
+
+ // write dest
+ lseek(idxfp[testmt-1]->getFd(), destidxoff, SEEK_SET);
+ write(idxfp[testmt-1]->getFd(), &start, 4);
+ write(idxfp[testmt-1]->getFd(), &size, 2);
+}
+
+
+/******************************************************************************
+ * RawVerse::CreateModule - Creates new module files
+ *
+ * ENT: path - directory to store module files
+ * RET: error status
+ */
+
+char RawVerse::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/ot", 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/nt", 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/ot.vss", path);
+ unlink(buf);
+ fd = FileMgr::systemFileMgr.open(buf, O_CREAT|O_WRONLY|O_BINARY, S_IREAD|S_IWRITE);
+ fd->getFd();
+
+ sprintf(buf, "%s/nt.vss", path);
+ unlink(buf);
+ fd2 = FileMgr::systemFileMgr.open(buf, O_CREAT|O_WRONLY|O_BINARY, S_IREAD|S_IWRITE);
+ fd2->getFd();
+
+ VerseKey vk;
+ vk.Headings(1);
+ long offset = 0;
+ short size = 0;
+ for (vk = TOP; !vk.Error(); vk++) {
+ write((vk.Testament() == 1) ? fd->getFd() : fd2->getFd(), &offset, 4);
+ write((vk.Testament() == 1) ? fd->getFd() : fd2->getFd(), &size, 2);
+ }
+
+ FileMgr::systemFileMgr.close(fd);
+ FileMgr::systemFileMgr.close(fd2);
+
+ delete [] path;
+/*
+ RawVerse rv(path);
+ VerseKey mykey("Rev 22:21");
+*/
+
+ return 0;
+}
diff --git a/src/modules/common/sapphire.cpp b/src/modules/common/sapphire.cpp
new file mode 100644
index 0000000..686bccb
--- /dev/null
+++ b/src/modules/common/sapphire.cpp
@@ -0,0 +1,228 @@
+/* sapphire.cpp -- the Saphire II stream cipher class.
+ Dedicated to the Public Domain the author and inventor:
+ (Michael Paul Johnson). This code comes with no warranty.
+ Use it at your own risk.
+ Ported from the Pascal implementation of the Sapphire Stream
+ Cipher 9 December 1994.
+ Added hash pre- and post-processing 27 December 1994.
+ Modified initialization to make index variables key dependent,
+ made the output function more resistant to cryptanalysis,
+ and renamed to Sapphire II 2 January 1995
+*/
+
+
+#ifdef WIN32
+#include <memory.h>
+#endif
+
+#ifdef UNIX
+#include <memory.h>
+#include <unistd.h>
+#else
+#ifndef _MSC_VER
+#include <mem.h>
+#endif
+#endif
+
+#ifdef _WIN32_WCE
+#include <string.h>
+#endif
+
+#include "sapphire.h"
+
+unsigned char sapphire::keyrand(int limit,
+ unsigned char *user_key,
+ unsigned char keysize,
+ unsigned char *rsum,
+ unsigned *keypos)
+ {
+ unsigned u, // Value from 0 to limit to return.
+ retry_limiter, // No infinite loops allowed.
+ mask; // Select just enough bits.
+
+ if (!limit) return 0; // Avoid divide by zero error.
+ retry_limiter = 0;
+ mask = 1; // Fill mask with enough bits to cover
+ while (mask < (unsigned)limit) // the desired range.
+ mask = (mask << 1) + 1;
+ do
+ {
+ *rsum = cards[*rsum] + user_key[(*keypos)++];
+ if (*keypos >= keysize)
+ {
+ *keypos = 0; // Recycle the user key.
+ *rsum += keysize; // key "aaaa" != key "aaaaaaaa"
+ }
+ u = mask & *rsum;
+ if (++retry_limiter > 11)
+ u %= limit; // Prevent very rare long loops.
+ }
+ while (u > (unsigned)limit);
+ return u;
+ }
+
+void sapphire::initialize(unsigned char *key, unsigned char keysize)
+ {
+ // Key size may be up to 256 bytes.
+ // Pass phrases may be used directly, with longer length
+ // compensating for the low entropy expected in such keys.
+ // Alternatively, shorter keys hashed from a pass phrase or
+ // generated randomly may be used. For random keys, lengths
+ // of from 4 to 16 bytes are recommended, depending on how
+ // secure you want this to be.
+
+ int i;
+ unsigned char toswap, swaptemp, rsum;
+ unsigned keypos;
+
+ // If we have been given no key, assume the default hash setup.
+
+ if (keysize < 1)
+ {
+ hash_init();
+ return;
+ }
+
+ // Start with cards all in order, one of each.
+
+ for (i=0;i<256;i++)
+ cards[i] = i;
+
+ // Swap the card at each position with some other card.
+
+ toswap = 0;
+ keypos = 0; // Start with first byte of user key.
+ rsum = 0;
+ for (i=255;i>=0;i--)
+ {
+ toswap = keyrand(i, key, keysize, &rsum, &keypos);
+ swaptemp = cards[i];
+ cards[i] = cards[toswap];
+ cards[toswap] = swaptemp;
+ }
+
+ // Initialize the indices and data dependencies.
+ // Indices are set to different values instead of all 0
+ // to reduce what is known about the state of the cards
+ // when the first byte is emitted.
+
+ rotor = cards[1];
+ ratchet = cards[3];
+ avalanche = cards[5];
+ last_plain = cards[7];
+ last_cipher = cards[rsum];
+
+ toswap = swaptemp = rsum = 0;
+ keypos = 0;
+ }
+
+void sapphire::hash_init(void)
+ {
+ // This function is used to initialize non-keyed hash
+ // computation.
+
+ int i, j;
+
+ // Initialize the indices and data dependencies.
+
+ rotor = 1;
+ ratchet = 3;
+ avalanche = 5;
+ last_plain = 7;
+ last_cipher = 11;
+
+ // Start with cards all in inverse order.
+
+ for (i=0, j=255;i<256;i++,j--)
+ cards[i] = (unsigned char) j;
+ }
+
+sapphire::sapphire(unsigned char *key, unsigned char keysize)
+ {
+ if (key && keysize)
+ initialize(key, keysize);
+ }
+
+void sapphire::burn(void)
+ {
+ // Destroy the key and state information in RAM.
+ memset(cards, 0, 256);
+ rotor = ratchet = avalanche = last_plain = last_cipher = 0;
+ }
+
+sapphire::~sapphire()
+ {
+ burn();
+ }
+
+unsigned char sapphire::encrypt(unsigned char b)
+ {
+#ifdef USBINARY
+ // Picture a single enigma rotor with 256 positions, rewired
+ // on the fly by card-shuffling.
+
+ // This cipher is a variant of one invented and written
+ // by Michael Paul Johnson in November, 1993.
+
+ unsigned char swaptemp;
+
+ // Shuffle the deck a little more.
+
+ ratchet += cards[rotor++];
+ swaptemp = cards[last_cipher];
+ cards[last_cipher] = cards[ratchet];
+ cards[ratchet] = cards[last_plain];
+ cards[last_plain] = cards[rotor];
+ cards[rotor] = swaptemp;
+ avalanche += cards[swaptemp];
+
+ // Output one byte from the state in such a way as to make it
+ // very hard to figure out which one you are looking at.
+
+ last_cipher = b^cards[(cards[ratchet] + cards[rotor]) & 0xFF] ^
+ cards[cards[(cards[last_plain] +
+ cards[last_cipher] +
+ cards[avalanche])&0xFF]];
+ last_plain = b;
+ return last_cipher;
+#else
+ return b;
+#endif
+ }
+
+unsigned char sapphire::decrypt(unsigned char b)
+ {
+ unsigned char swaptemp;
+
+ // Shuffle the deck a little more.
+
+ ratchet += cards[rotor++];
+ swaptemp = cards[last_cipher];
+ cards[last_cipher] = cards[ratchet];
+ cards[ratchet] = cards[last_plain];
+ cards[last_plain] = cards[rotor];
+ cards[rotor] = swaptemp;
+ avalanche += cards[swaptemp];
+
+ // Output one byte from the state in such a way as to make it
+ // very hard to figure out which one you are looking at.
+
+ last_plain = b^cards[(cards[ratchet] + cards[rotor]) & 0xFF] ^
+ cards[cards[(cards[last_plain] +
+ cards[last_cipher] +
+ cards[avalanche])&0xFF]];
+ last_cipher = b;
+ return last_plain;
+ }
+
+void sapphire::hash_final(unsigned char *hash, // Destination
+ unsigned char hashlength) // Size of hash.
+ {
+ int i;
+
+ for (i=255;i>=0;i--)
+ encrypt((unsigned char) i);
+ for (i=0;i<hashlength;i++)
+ hash[i] = encrypt(0);
+ }
+
diff --git a/src/modules/common/swcipher.cpp b/src/modules/common/swcipher.cpp
new file mode 100644
index 0000000..d221b8b
--- /dev/null
+++ b/src/modules/common/swcipher.cpp
@@ -0,0 +1,123 @@
+/******************************************************************************
+ * swcipher.cpp - code for class 'SWCipher'- a driver class that provides
+ * cipher utilities.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <swcipher.h>
+
+
+/******************************************************************************
+ * SWCipher Constructor - Initializes data for instance of SWCipher
+ *
+ */
+
+SWCipher::SWCipher(unsigned char *key) {
+ master.initialize(key, strlen((char *)key));
+ buf = 0;
+}
+
+
+/******************************************************************************
+ * SWCipher Destructor - Cleans up instance of SWCipher
+ */
+
+SWCipher::~SWCipher()
+{
+ if (buf)
+ free(buf);
+}
+
+
+char *SWCipher::Buf(const char *ibuf, unsigned int ilen)
+{
+ if (ibuf) {
+
+ if (buf)
+ free(buf);
+
+ if (!ilen) {
+ len = strlen(buf);
+ ilen = len + 1;
+ }
+ else len = ilen;
+
+ buf = (char *) malloc(ilen);
+ memcpy(buf, ibuf, ilen);
+ cipher = false;
+ }
+
+ Decode();
+
+ return buf;
+}
+
+
+char *SWCipher::cipherBuf(unsigned int *ilen, const char *ibuf)
+{
+ if (ibuf) {
+
+ if (buf)
+ free(buf);
+
+ buf = (char *) malloc(*ilen);
+ memcpy(buf, ibuf, *ilen);
+ len = *ilen;
+ cipher = true;
+ }
+
+ Encode();
+
+ *ilen = (short)len;
+ return buf;
+}
+
+
+/******************************************************************************
+ * SWCipher::Encode - This function "encodes" the input stream into the
+ * output stream.
+ * The GetChars() and SendChars() functions are
+ * used to separate this method from the actual
+ * i/o.
+ */
+
+void SWCipher::Encode(void)
+{
+ if (!cipher) {
+ work = master;
+ for (int i = 0; i < len; i++)
+ buf[i] = work.encrypt(buf[i]);
+ cipher = true;
+ }
+}
+
+
+/******************************************************************************
+ * SWCipher::Decode - This function "decodes" the input stream into the
+ * output stream.
+ * The GetChars() and SendChars() functions are
+ * used to separate this method from the actual
+ * i/o.
+ */
+
+void SWCipher::Decode(void)
+{
+ if (cipher) {
+ work = master;
+ for (int i = 0; i < len; i++)
+ buf[i] = work.decrypt(buf[i]);
+ cipher = false;
+ }
+}
+
+
+/******************************************************************************
+ * SWCipher::setCipherKey - setter for a new CipherKey
+ *
+ */
+
+void SWCipher::setCipherKey(const char *ikey) {
+ unsigned char *key = (unsigned char *)ikey;
+ master.initialize(key, strlen((char *)key));
+}
diff --git a/src/modules/common/swcomprs.cpp b/src/modules/common/swcomprs.cpp
new file mode 100644
index 0000000..4bd2e5e
--- /dev/null
+++ b/src/modules/common/swcomprs.cpp
@@ -0,0 +1,190 @@
+/******************************************************************************
+ * swcomprs.cpp - code for class 'SWCompress'- a driver class that provides
+ * compression utilities.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <swcomprs.h>
+
+
+/******************************************************************************
+ * SWCompress Constructor - Initializes data for instance of SWCompress
+ *
+ */
+
+SWCompress::SWCompress()
+{
+ buf = zbuf = 0;
+ Init();
+}
+
+
+/******************************************************************************
+ * SWCompress Destructor - Cleans up instance of SWCompress
+ */
+
+SWCompress::~SWCompress()
+{
+ if (zbuf)
+ free(zbuf);
+
+ if (buf)
+ free(buf);
+}
+
+
+void SWCompress::Init()
+{
+ if (buf)
+ free(buf);
+
+ if (zbuf)
+ free(zbuf);
+
+ buf = 0;
+ zbuf = 0;
+ direct = 0;
+ zlen = 0;
+ slen = 0;
+ zpos = 0;
+ pos = 0;
+}
+
+
+char *SWCompress::Buf(const char *ibuf, unsigned long *len) {
+ // setting an uncompressed buffer
+ if (ibuf) {
+ Init();
+ slen = (len) ? *len : strlen(ibuf);
+ buf = (char *) calloc(slen + 1, 1);
+ memcpy(buf, ibuf, slen);
+ }
+
+ // getting an uncompressed buffer
+ if (!buf) {
+ buf = (char *)calloc(1,1); // be sure we at least allocate an empty buf for return;
+ direct = 1;
+ Decode();
+// slen = strlen(buf);
+ if (len)
+ *len = slen;
+ }
+ return buf;
+}
+
+
+char *SWCompress::zBuf(unsigned long *len, char *ibuf)
+{
+ // setting a compressed buffer
+ if (ibuf) {
+ Init();
+ zbuf = (char *) malloc(*len);
+ memcpy(zbuf, ibuf, *len);
+ zlen = *len;
+ }
+
+ // getting a compressed buffer
+ if (!zbuf) {
+ direct = 0;
+ Encode();
+ }
+
+ *len = zlen;
+ return zbuf;
+}
+
+
+unsigned long SWCompress::GetChars(char *ibuf, unsigned long len)
+{
+ if (direct) {
+ len = (((zlen - zpos) > (unsigned)len) ? len : zlen - zpos);
+ if (len > 0) {
+ memmove(ibuf, &zbuf[zpos], len);
+ zpos += len;
+ }
+ }
+ else {
+// slen = strlen(buf);
+ len = (((slen - pos) > (unsigned)len) ? len : slen - pos);
+ if (len > 0) {
+ memmove(ibuf, &buf[pos], len);
+ pos += len;
+ }
+ }
+ return len;
+}
+
+
+unsigned long SWCompress::SendChars(char *ibuf, unsigned long len)
+{
+ if (direct) {
+ if (buf) {
+// slen = strlen(buf);
+ if ((pos + len) > (unsigned)slen) {
+ buf = (char *) realloc(buf, pos + len + 1024);
+ memset(&buf[pos], 0, len + 1024);
+ }
+ }
+ else buf = (char *)calloc(1, len + 1024);
+ memmove(&buf[pos], ibuf, len);
+ pos += len;
+ }
+ else {
+ if (zbuf) {
+ if ((zpos + len) > zlen) {
+ zbuf = (char *) realloc(zbuf, zpos + len + 1024);
+ zlen = zpos + len + 1024;
+ }
+ }
+ else {
+ zbuf = (char *)calloc(1, len + 1024);
+ zlen = len + 1024;
+ }
+ memmove(&zbuf[zpos], ibuf, len);
+ zpos += len;
+ }
+ return len;
+}
+
+
+/******************************************************************************
+ * SWCompress::Encode - This function "encodes" the input stream into the
+ * output stream.
+ * The GetChars() and SendChars() functions are
+ * used to separate this method from the actual
+ * i/o.
+ */
+
+void SWCompress::Encode(void)
+{
+ cycleStream();
+}
+
+
+/******************************************************************************
+ * SWCompress::Decode - This function "decodes" the input stream into the
+ * output stream.
+ * The GetChars() and SendChars() functions are
+ * used to separate this method from the actual
+ * i/o.
+ */
+
+void SWCompress::Decode(void)
+{
+ cycleStream();
+}
+
+
+void SWCompress::cycleStream() {
+ char buf[1024];
+ unsigned long len, totlen = 0;
+
+ do {
+ len = GetChars(buf, 1024);
+ if (len)
+ totlen += SendChars(buf, len);
+ } while (len == 1024);
+
+ zlen = slen = totlen;
+}
diff --git a/src/modules/common/swcomprs.doc b/src/modules/common/swcomprs.doc
new file mode 100644
index 0000000..b6817f2
--- /dev/null
+++ b/src/modules/common/swcomprs.doc
@@ -0,0 +1,802 @@
+The following is the original information send from Parson's Technologies via
+Craig Rairden.
+_______________________________________________________________________________
+Compression Info, 10-11-95
+Jeff Wheeler
+
+Source of Algorithm
+-------------------
+
+The compression algorithms used here are based upon the algorithms developed
+and published by Haruhiko Okumura in a paper entitled "Data Compression
+Algorithms of LARC and LHarc." This paper discusses three compression
+algorithms, LSZZ, LZARI, and LZHUF. LZSS is described as the "first" of
+these, and is described as providing moderate compression with good speed.
+LZARI is described as an improved LZSS, a combination of the LZSS algorithm
+with adaptive arithmetic compression. It is described as being slower than
+LZSS but with better compression. LZHUF (the basis of the common LHA
+compression program) was included in the paper, however, a free usage license
+was not included.
+
+The following are copies of the statements included at the beginning of each
+source code listing that was supplied in the working paper.
+
+ LZSS, dated 4/6/89, marked as "Use, distribute and
+ modify this program freely."
+
+ LZARI, dated 4/7/89, marked as "Use, distribute and
+ modify this program freely."
+
+ LZHUF, dated 11/20/88, written by Haruyasu Yoshizaki,
+ translated by Haruhiko Okumura on 4/7/89. Not
+ expressly marked as redistributable or modifiable.
+
+Since both LZSS and LZARI are marked as "use, distribute and modify freely" we
+have felt at liberty basing our compression algorithm on either of these.
+
+Selection of Algorithm
+----------------------
+
+Working samples of three possible compression algorithms are supplied in
+Okumura's paper. Which should be used?
+
+LZSS is the fastest at decompression, but does not generated as small a
+compressed file as the other methods. The other two methods provided, perhaps,
+a 15% improvement in compression. Or, put another way, on a 100K file, LZSS
+might compress it to 50K while the others might approach 40-45K. For STEP
+purposes, it was decided that decoding speed was of more importance than
+tighter compression. For these reasons, the first compression algorithm
+implemented is the LZSS algorithm.
+
+About LZSS Encoding
+-------------------
+
+(adapted from Haruhiko Okumura's paper)
+
+This scheme was proposed by Ziv and Lempel [1]. A slightly modified version
+is described by Storer and Szymanski [2]. An implementation using a binary
+tree has been proposed by Bell [3].
+
+The algorithm is quite simple.
+1. Keep a ring buffer which initially contains all space characters.
+2. Read several letters from the file to the buffer.
+3. Search the buffer for the longest string that matches the letters just
+ read, and send its length and position into the buffer.
+
+If the ring buffer is 4096 bytes, the position can be stored in 12 bits. If the
+length is represented in 4 bits, the <position, length> pair is two bytes
+long. If the longest match is no more than two characters, then just one
+character is sent without encoding. The process starts again with the next
+character. An extra bit is sent each time to tell the decoder whether the
+next item is a character of a <position, length> pair.
+
+[1] J. Ziv and A. Lempel, IEEE Transactions IT-23, 337-343 (1977).
+[2] J. A. Storer and T. G. Szymanski, J. ACM, 29, 928-951 (1982).
+[3] T.C. Gell, IEEE Transactions COM-34, 1176-1182 (1986).
+
+class SWCompress {
+public:
+void InitTree( // no return value
+ void); // no parameters
+
+void InsertNode( // no return value
+ short int Pos); // position in the buffer
+
+void DeleteNode( // no return value
+ short int Node); // node to be removed
+
+void Encode( // no return value
+ void); // no parameters
+
+void Decode( // no return value
+ void); // no parameters
+};
+
+// The following are constant sizes used by the compression algorithm.
+//
+// N - This is the size of the ring buffer. It is set
+// to 4K. It is important to note that a position
+// within the ring buffer requires 12 bits.
+//
+// F - This is the maximum length of a character sequence
+// that can be taken from the ring buffer. It is set
+// to 18. Note that a length must be 3 before it is
+// worthwhile to store a position/length pair, so the
+// length can be encoded in only 4 bits. Or, put yet
+// another way, it is not necessary to encode a length
+// of 0-18, it is necessary to encode a length of
+// 3-18, which requires 4 bits.
+//
+// THRESHOLD - It takes 2 bytes to store an offset and
+// a length. If a character sequence only
+// requires 1 or 2 characters to store
+// uncompressed, then it is better to store
+// it uncompressed than as an offset into
+// the ring buffer.
+//
+// Note that the 12 bits used to store the position and the 4 bits
+// used to store the length equal a total of 16 bits, or 2 bytes.
+
+#define N 4096
+#define F 18
+#define THRESHOLD 3
+#define NOT_USED N
+
+// m_ring_buffer is a text buffer. It contains "nodes" of
+// uncompressed text that can be indexed by position. That is,
+// a substring of the ring buffer can be indexed by a position
+// and a length. When decoding, the compressed text may contain
+// a position in the ring buffer and a count of the number of
+// bytes from the ring buffer that are to be moved into the
+// uncompressed buffer.
+//
+// This ring buffer is not maintained as part of the compressed
+// text. Instead, it is reconstructed dynamically. That is,
+// it starts out empty and gets built as the text is decompressed.
+//
+// The ring buffer contain N bytes, with an additional F - 1 bytes
+// to facilitate string comparison.
+
+unsigned char m_ring_buffer[N + F - 1];
+
+// m_match_position and m_match_length are set by InsertNode().
+//
+// These variables indicate the position in the ring buffer
+// and the number of characters at that position that match
+// a given string.
+
+short int m_match_position;
+short int m_match_length;
+
+// m_lson, m_rson, and m_dad are the Japanese way of referring to
+// a tree structure. The dad is the parent and it has a right and
+// left son (child).
+//
+// For i = 0 to N-1, m_rson[i] and m_lson[i] will be the right
+// and left children of node i.
+//
+// For i = 0 to N-1, m_dad[i] is the parent of node i.
+//
+// For i = 0 to 255, rson[N + i + 1] is the root of the tree for
+// strings that begin with the character i. Note that this requires
+// one byte characters.
+//
+// These nodes store values of 0...(N-1). Memory requirements
+// can be reduces by using 2-byte integers instead of full 4-byte
+// integers (for 32-bit applications). Therefore, these are
+// defined as "short ints."
+
+short int m_lson[N + 1];
+short int m_rson[N + 257];
+short int m_dad[N + 1];
+
+
+
+
+/*
+ -------------------------------------------------------------------------
+ cLZSS::InitTree
+
+ This function initializes the tree nodes to "empty" states.
+ -------------------------------------------------------------------------
+*/
+
+void cLZSS::InitTree( // no return value
+ void) // no parameters
+ throw() // exception list
+
+ {
+ int i;
+
+ // For i = 0 to N - 1, m_rson[i] and m_lson[i] will be the right
+ // and left children of node i. These nodes need not be
+ // initialized. However, for debugging purposes, it is nice to
+ // have them initialized. Since this is only used for compression
+ // (not decompression), I don't mind spending the time to do it.
+ //
+ // For the same range of i, m_dad[i] is the parent of node i.
+ // These are initialized to a known value that can represent
+ // a "not used" state.
+
+ for (i = 0; i < N; i++)
+ {
+ m_lson[i] = NOT_USED;
+ m_rson[i] = NOT_USED;
+ m_dad[i] = NOT_USED;
+ }
+
+ // For i = 0 to 255, m_rson[N + i + 1] is the root of the tree
+ // for strings that begin with the character i. This is why
+ // the right child array is larger than the left child array.
+ // These are also initialzied to a "not used" state.
+ //
+ // Note that there are 256 of these, one for each of the possible
+ // 256 characters.
+
+ for (i = N + 1; i <= (N + 256); i++)
+ {
+ m_rson[i] = NOT_USED;
+ }
+
+ // Done.
+ }
+
+/*
+ -------------------------------------------------------------------------
+ cLZSS::InsertNode
+
+ This function inserts a string from the ring buffer into one of
+ the trees. It loads the match position and length member variables
+ for the longest match.
+
+ The string to be inserted is identified by the parameter Pos,
+ A full F bytes are inserted. So, m_ring_buffer[Pos ... Pos+F-1]
+ are inserted.
+
+ If the matched length is exactly F, then an old node is removed
+ in favor of the new one (because the old one will be deleted
+ sooner).
+
+ Note that Pos plays a dual role. It is used as both a position
+ in the ring buffer and also as a tree node. m_ring_buffer[Pos]
+ defines a character that is used to identify a tree node.
+ -------------------------------------------------------------------------
+*/
+
+void cLZSS::InsertNode( // no return value
+ short int Pos) // position in the buffer
+ throw() // exception list
+
+ {
+ short int i;
+ short int p;
+ int cmp;
+ unsigned char * key;
+
+ ASSERT(Pos >= 0);
+ ASSERT(Pos < N);
+
+ cmp = 1;
+ key = &(m_ring_buffer[Pos]);
+
+ // The last 256 entries in m_rson contain the root nodes for
+ // strings that begin with a letter. Get an index for the
+ // first letter in this string.
+
+ p = (short int) (N + 1 + key[0]);
+
+ // Set the left and right tree nodes for this position to "not
+ // used."
+
+ m_lson[Pos] = NOT_USED;
+ m_rson[Pos] = NOT_USED;
+
+ // Haven't matched anything yet.
+
+ m_match_length = 0;
+
+ for ( ; ; )
+ {
+ if (cmp >= 0)
+ {
+ if (m_rson[p] != NOT_USED)
+ {
+ p = m_rson[p];
+ }
+ else
+ {
+ m_rson[p] = Pos;
+ m_dad[Pos] = p;
+ return;
+ }
+ }
+ else
+ {
+ if (m_lson[p] != NOT_USED)
+ {
+ p = m_lson[p];
+ }
+ else
+ {
+ m_lson[p] = Pos;
+ m_dad[Pos] = p;
+ return;
+ }
+ }
+
+ // Should we go to the right or the left to look for the
+ // next match?
+
+ for (i = 1; i < F; i++)
+ {
+ cmp = key[i] - m_ring_buffer[p + i];
+ if (cmp != 0)
+ break;
+ }
+
+ if (i > m_match_length)
+ {
+ m_match_position = p;
+ m_match_length = i;
+
+ if (i >= F)
+ break;
+ }
+ }
+
+ m_dad[Pos] = m_dad[p];
+ m_lson[Pos] = m_lson[p];
+ m_rson[Pos] = m_rson[p];
+
+ m_dad[ m_lson[p] ] = Pos;
+ m_dad[ m_rson[p] ] = Pos;
+
+ if (m_rson[ m_dad[p] ] == p)
+ {
+ m_rson[ m_dad[p] ] = Pos;
+ }
+ else
+ {
+ m_lson[ m_dad[p] ] = Pos;
+ }
+
+ // Remove "p"
+
+ m_dad[p] = NOT_USED;
+ }
+
+/*
+ -------------------------------------------------------------------------
+ cLZSS::DeleteNode
+
+ This function removes the node "Node" from the tree.
+ -------------------------------------------------------------------------
+*/
+
+void cLZSS::DeleteNode( // no return value
+ short int Node) // node to be removed
+ throw() // exception list
+
+ {
+ short int q;
+
+ ASSERT(Node >= 0);
+ ASSERT(Node < (N+1));
+
+ if (m_dad[Node] == NOT_USED)
+ {
+ // not in tree, nothing to do
+ return;
+ }
+
+ if (m_rson[Node] == NOT_USED)
+ {
+ q = m_lson[Node];
+ }
+ else if (m_lson[Node] == NOT_USED)
+ {
+ q = m_rson[Node];
+ }
+ else
+ {
+ q = m_lson[Node];
+ if (m_rson[q] != NOT_USED)
+ {
+ do
+ {
+ q = m_rson[q];
+ }
+ while (m_rson[q] != NOT_USED);
+
+ m_rson[ m_dad[q] ] = m_lson[q];
+ m_dad[ m_lson[q] ] = m_dad[q];
+ m_lson[q] = m_lson[Node];
+ m_dad[ m_lson[Node] ] = q;
+ }
+
+ m_rson[q] = m_rson[Node];
+ m_dad[ m_rson[Node] ] = q;
+ }
+
+ m_dad[q] = m_dad[Node];
+
+ if (m_rson[ m_dad[Node] ] == Node)
+ {
+ m_rson[ m_dad[Node] ] = q;
+ }
+ else
+ {
+ m_lson[ m_dad[Node] ] = q;
+ }
+
+ m_dad[Node] = NOT_USED;
+ }
+
+/*
+ -------------------------------------------------------------------------
+ cLZSS::Encode
+
+ This function "encodes" the input stream into the output stream.
+ The GetChars() and SendChars() functions are used to separate
+ this method from the actual i/o.
+ -------------------------------------------------------------------------
+*/
+
+void cLZSS::Encode( // no return value
+ void) // no parameters
+
+ {
+ short int i; // an iterator
+ short int r; // node number in the binary tree
+ short int s; // position in the ring buffer
+ unsigned short int len; // len of initial string
+ short int last_match_length; // length of last match
+ short int code_buf_pos; // position in the output buffer
+ unsigned char code_buf[17]; // the output buffer
+ unsigned char mask; // bit mask for byte 0 of out buf
+ unsigned char c; // character read from string
+
+ // Start with a clean tree.
+
+ InitTree();
+
+ // code_buf[0] works as eight flags. A "1" represents that the
+ // unit is an unencoded letter (1 byte), and a "0" represents
+ // that the next unit is a <position,length> pair (2 bytes).
+ //
+ // code_buf[1..16] stores eight units of code. Since the best
+ // we can do is store eight <position,length> pairs, at most 16
+ // bytes are needed to store this.
+ //
+ // This is why the maximum size of the code buffer is 17 bytes.
+
+ code_buf[0] = 0;
+ code_buf_pos = 1;
+
+ // Mask iterates over the 8 bits in the code buffer. The first
+ // character ends up being stored in the low bit.
+ //
+ // bit 8 7 6 5 4 3 2 1
+ // | |
+ // | first sequence in code buffer
+ // |
+ // last sequence in code buffer
+
+ mask = 1;
+
+ s = 0;
+ r = (short int) N - (short int) F;
+
+ // Initialize the ring buffer with spaces...
+
+ // Note that the last F bytes of the ring buffer are not filled.
+ // This is because those F bytes will be filled in immediately
+ // with bytes from the input stream.
+
+ memset(m_ring_buffer, ' ', N - F);
+
+ // Read F bytes into the last F bytes of the ring buffer.
+ //
+ // This function loads the buffer with X characters and returns
+ // the actual amount loaded.
+
+ len = GetChars(&(m_ring_buffer[r]), F);
+
+ // Make sure there is something to be compressed.
+
+ if (len == 0)
+ return;
+
+ // Insert the F strings, each of which begins with one or more
+ // 'space' characters. Note the order in which these strings
+ // are inserted. This way, degenerate trees will be less likely
+ // to occur.
+
+ for (i = 1; i <= F; i++)
+ {
+ InsertNode((short int) (r - i));
+ }
+
+ // Finally, insert the whole string just read. The
+ // member variables match_length and match_position are set.
+
+ InsertNode(r);
+
+ // Now that we're preloaded, continue till done.
+
+ do
+ {
+
+ // m_match_length may be spuriously long near the end of
+ // text.
+
+ if (m_match_length > len)
+ {
+ m_match_length = len;
+ }
+
+ // Is it cheaper to store this as a single character? If so,
+ // make it so.
+
+ if (m_match_length < THRESHOLD)
+ {
+ // Send one character. Remember that code_buf[0] is the
+ // set of flags for the next eight items.
+
+ m_match_length = 1;
+ code_buf[0] |= mask;
+ code_buf[code_buf_pos++] = m_ring_buffer[r];
+ }
+
+ // Otherwise, we do indeed have a string that can be stored
+ // compressed to save space.
+
+ else
+ {
+ // The next 16 bits need to contain the position (12 bits)
+ // and the length (4 bits).
+
+ code_buf[code_buf_pos++] = (unsigned char) m_match_position;
+ code_buf[code_buf_pos++] = (unsigned char) (
+ ((m_match_position >> 4) & 0xf0) |
+ (m_match_length - THRESHOLD) );
+ }
+
+ // Shift the mask one bit to the left so that it will be ready
+ // to store the new bit.
+
+ mask = (unsigned char) (mask << 1);
+
+ // If the mask is now 0, then we know that we have a full set
+ // of flags and items in the code buffer. These need to be
+ // output.
+
+ if (mask == 0)
+ {
+ // code_buf is the buffer of characters to be output.
+ // code_buf_pos is the number of characters it contains.
+
+ SendChars(code_buf, code_buf_pos);
+
+ // Reset for next buffer...
+
+ code_buf[0] = 0;
+ code_buf_pos = 1;
+ mask = 1;
+ }
+
+ last_match_length = m_match_length;
+
+ // Delete old strings and read new bytes...
+
+ for (i = 0; i < last_match_length; i++)
+ {
+
+ // Get next character...
+
+ if (GetChars(&c, 1) != 1)
+ break;
+
+ // Delete "old strings"
+
+ DeleteNode(s);
+
+ // Put this character into the ring buffer.
+ //
+ // The original comment here says "If the position is near
+ // the end of the buffer, extend the buffer to make
+ // string comparison easier."
+ //
+ // That's a little misleading, because the "end" of the
+ // buffer is really what we consider to be the "beginning"
+ // of the buffer, that is, positions 0 through F.
+ //
+ // The idea is that the front end of the buffer is duplicated
+ // into the back end so that when you're looking at characters
+ // at the back end of the buffer, you can index ahead (beyond
+ // the normal end of the buffer) and see the characters
+ // that are at the front end of the buffer wihtout having
+ // to adjust the index.
+ //
+ // That is...
+ //
+ // 1234xxxxxxxxxxxxxxxxxxxxxxxxxxxxx1234
+ // | | |
+ // position 0 end of buffer |
+ // |
+ // duplicate of front of buffer
+
+ m_ring_buffer[s] = c;
+
+ if (s < F - 1)
+ {
+ m_ring_buffer[s + N] = c;
+ }
+
+ // Increment the position, and wrap around when we're at
+ // the end. Note that this relies on N being a power of 2.
+
+ s = (short int) ( (s + 1) & (N - 1) );
+ r = (short int) ( (r + 1) & (N - 1) );
+
+ // Register the string that is found in
+ // m_ring_buffer[r..r+F-1].
+
+ InsertNode(r);
+ }
+
+ // If we didn't quit because we hit the last_match_length,
+ // then we must have quit because we ran out of characters
+ // to process.
+
+ while (i++ < last_match_length)
+ {
+ DeleteNode(s);
+
+ s = (short int) ( (s + 1) & (N - 1) );
+ r = (short int) ( (r + 1) & (N - 1) );
+
+ // Note that len hitting 0 is the key that causes the
+ // do...while() to terminate. This is the only place
+ // within the loop that len is modified.
+ //
+ // Its original value is F (or a number less than F for
+ // short strings).
+
+ if (--len)
+ {
+ InsertNode(r); /* buffer may not be empty. */
+ }
+ }
+
+ // End of do...while() loop. Continue processing until there
+ // are no more characters to be compressed. The variable
+ // "len" is used to signal this condition.
+ }
+ while (len > 0);
+
+ // There could still be something in the output buffer. Send it
+ // now.
+
+ if (code_buf_pos > 1)
+ {
+ // code_buf is the encoded string to send.
+ // code_buf_ptr is the number of characters.
+
+ SendChars(code_buf, code_buf_pos);
+ }
+
+ // Done!
+ }
+
+/*
+ -------------------------------------------------------------------------
+ cLZSS::Decode
+
+ This function "decodes" the input stream into the output stream.
+ The GetChars() and SendChars() functions are used to separate
+ this method from the actual i/o.
+ -------------------------------------------------------------------------
+*/
+
+void cLZSS::Decode( // no return value
+ void) // no parameters
+
+ {
+ int k;
+ int r; // node number
+ unsigned char c[F]; // an array of chars
+ unsigned char flags; // 8 bits of flags
+ int flag_count; // which flag we're on
+ short int pos; // position in the ring buffer
+ short int len; // number of chars in ring buffer
+
+ // Initialize the ring buffer with a common string.
+ //
+ // Note that the last F bytes of the ring buffer are not filled.
+
+ memset(m_ring_buffer, ' ', N - F);
+
+ r = N - F;
+
+ flags = (char) 0;
+ flag_count = 0;
+
+ for ( ; ; )
+ {
+
+ // If there are more bits of interest in this flag, then
+ // shift that next interesting bit into the 1's position.
+ //
+ // If this flag has been exhausted, the next byte must
+ // be a flag.
+
+ if (flag_count > 0)
+ {
+ flags = (unsigned char) (flags >> 1);
+ flag_count--;
+ }
+ else
+ {
+ // Next byte must be a flag.
+
+ if (GetChars(&flags, 1) != 1)
+ break;
+
+ // Set the flag counter. While at first it might appear
+ // that this should be an 8 since there are 8 bits in the
+ // flag, it should really be a 7 because the shift must
+ // be performed 7 times in order to see all 8 bits.
+
+ flag_count = 7;
+ }
+
+ // If the low order bit of the flag is now set, then we know
+ // that the next byte is a single, unencoded character.
+
+ if (flags & 1)
+ {
+ if (GetChars(c, 1) != 1)
+ break;
+
+ if (SendChars(c, 1) != 1)
+ break;
+
+ // Add to buffer, and increment to next spot. Wrap at end.
+
+ m_ring_buffer[r] = c[0];
+ r = (short int) ( (r + 1) & (N - 1) );
+ }
+
+ // Otherwise, we know that the next two bytes are a
+ // <position,length> pair. The position is in 12 bits and
+ // the length is in 4 bits.
+
+ else
+ {
+ // Original code:
+ // if ((i = getc(infile)) == EOF)
+ // break;
+ // if ((j = getc(infile)) == EOF)
+ // break;
+ // i |= ((j & 0xf0) << 4);
+ // j = (j & 0x0f) + THRESHOLD;
+ //
+ // I've modified this to only make one input call, and
+ // have changed the variable names to something more
+ // obvious.
+
+ if (GetChars(c, 2) != 2)
+ break;
+
+ // Convert these two characters into the position and
+ // length. Note that the length is always at least
+ // THRESHOLD, which is why we're able to get a length
+ // of 18 out of only 4 bits.
+
+ pos = (short int) ( c[0] | ((c[1] & 0xf0) << 4) );
+
+ len = (short int) ( (c[1] & 0x0f) + THRESHOLD );
+
+ // There are now "len" characters at position "pos" in
+ // the ring buffer that can be pulled out. Note that
+ // len is never more than F.
+
+ for (k = 0; k < len; k++)
+ {
+ c[k] = m_ring_buffer[(pos + k) & (N - 1)];
+
+ // Add to buffer, and increment to next spot. Wrap at end.
+
+ m_ring_buffer[r] = c[k];
+ r = (short int) ( (r + 1) & (N - 1) );
+ }
+
+ // Add the "len" characters to the output stream.
+
+ if (SendChars(c, len) != len)
+ break;
+ }
+ }
+ }
+
diff --git a/src/modules/common/zipcomprs.cpp b/src/modules/common/zipcomprs.cpp
new file mode 100644
index 0000000..01ba430
--- /dev/null
+++ b/src/modules/common/zipcomprs.cpp
@@ -0,0 +1,158 @@
+/******************************************************************************
+ * swcomprs.cpp - code for class 'ZipCompress'- a driver class that provides
+ * compression utilities. - using zlib
+ */
+
+#include <string.h>
+#include <string>
+#include <stdlib.h>
+#include <stdio.h>
+#include <zipcomprs.h>
+#include <zlib.h>
+
+/******************************************************************************
+ * ZipCompress Constructor - Initializes data for instance of ZipCompress
+ *
+ */
+
+ZipCompress::ZipCompress() : SWCompress()
+{
+// fprintf(stderr, "init compress\n");
+}
+
+
+/******************************************************************************
+ * ZipCompress Destructor - Cleans up instance of ZipCompress
+ */
+
+ZipCompress::~ZipCompress() {
+}
+
+
+/******************************************************************************
+ * ZipCompress::Encode - This function "encodes" the input stream into the
+ * output stream.
+ * The GetChars() and SendChars() functions are
+ * used to separate this method from the actual
+ * i/o.
+ * NOTE: must set zlen for parent class to know length of
+ * compressed buffer.
+ */
+
+void ZipCompress::Encode(void)
+{
+/*
+ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+ Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be at least 0.1% larger than
+ sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
+ compressed buffer.
+ This function can be used to compress a whole file at once if the
+ input file is mmap'ed.
+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer.
+*/
+ direct = 0; // set direction needed by parent [Get|Send]Chars()
+
+ // get buffer
+ char chunk[1024];
+ char *buf = (char *)calloc(1, 1024);
+ char *chunkbuf = buf;
+ unsigned long chunklen;
+ unsigned long len = 0;
+ while((chunklen = GetChars(chunk, 1023))) {
+ memcpy(chunkbuf, chunk, chunklen);
+ len += chunklen;
+ if (chunklen < 1023)
+ break;
+ else buf = (char *)realloc(buf, len + 1024);
+ chunkbuf = buf+len;
+ }
+
+
+ zlen = (long) (len*1.001)+15;
+ char *zbuf = new char[zlen+1];
+ if (len)
+ {
+ //printf("Doing compress\n");
+ if (compress((Bytef*)zbuf, &zlen, (const Bytef*)buf, len)!=Z_OK)
+ {
+ printf("ERROR in compression\n");
+ }
+ else {
+ SendChars(zbuf, zlen);
+ }
+ }
+ else
+ {
+ fprintf(stderr, "No buffer to compress\n");
+ }
+ delete [] zbuf;
+ free (buf);
+}
+
+
+/******************************************************************************
+ * ZipCompress::Decode - This function "decodes" the input stream into the
+ * output stream.
+ * The GetChars() and SendChars() functions are
+ * used to separate this method from the actual
+ * i/o.
+ */
+
+void ZipCompress::Decode(void)
+{
+/*
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+
+ // get buffer
+ char chunk[1024];
+ char *zbuf = (char *)calloc(1, 1024);
+ char *chunkbuf = zbuf;
+ int chunklen;
+ unsigned long zlen = 0;
+ while((chunklen = GetChars(chunk, 1023))) {
+ memcpy(chunkbuf, chunk, chunklen);
+ zlen += chunklen;
+ if (chunklen < 1023)
+ break;
+ else zbuf = (char *)realloc(zbuf, zlen + 1024);
+ chunkbuf = zbuf + zlen;
+ }
+
+ //printf("Decoding complength{%ld} uncomp{%ld}\n", zlen, blen);
+ if (zlen) {
+ unsigned long blen = zlen*20; // trust compression is less than 1000%
+ char *buf = new char[blen];
+ //printf("Doing decompress {%s}\n", zbuf);
+ if (uncompress((Bytef*)buf, &blen, (Bytef*)zbuf, zlen) != Z_OK) {
+ fprintf(stderr, "no room in outbuffer to during decompression. see zipcomp.cpp\n");
+ }
+ SendChars(buf, blen);
+ delete [] buf;
+ slen = blen;
+ }
+ else {
+ fprintf(stderr, "No buffer to decompress!\n");
+ }
+ //printf("Finished decoding\n");
+ free (zbuf);
+}
diff --git a/src/modules/common/zstr.cpp b/src/modules/common/zstr.cpp
new file mode 100644
index 0000000..fc02572
--- /dev/null
+++ b/src/modules/common/zstr.cpp
@@ -0,0 +1,705 @@
+/******************************************************************************
+ * zstr.cpp - code for class 'zStr'- a module that reads compressed text
+ * files and provides lookup and parsing functions based on
+ * class StrKey
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#ifndef __GNUC__
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <utilfuns.h>
+#include <zstr.h>
+#include <swcomprs.h>
+
+#include <sysdata.h>
+#include <entriesblk.h>
+
+/******************************************************************************
+ * 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 + 1) : (char *)malloc(size + 1);
+ if (size) {
+ lseek(datfd->getFd(), ioffset, SEEK_SET);
+ read(datfd->getFd(), *buf, size);
+ }
+ (*buf)[size] = 0;
+ for (size--; size > 0; size--)
+ (*buf)[size] = SW_toupper((*buf)[size]);
+ }
+ 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(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 + 1) : (char *)malloc(size + 1);
+ *idxbuf = (*idxbuf) ? (char *)realloc(*idxbuf, size + 1) : (char *)malloc(size + 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 + IDXENTRYSIZE, &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 + 1) : (char *)malloc(size + 1);
+
+ lseek(zdtfd->getFd(), start, SEEK_SET);
+ read(zdtfd->getFd(), *buf, size);
+
+ flushCache();
+
+ unsigned long len = size;
+ 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 + 1) : (char *)malloc(size + 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;
+
+ stdstr(&key, ikey);
+ toupperstr(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 || strlen(buf) /*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 ? len : strlen(buf))) {
+ 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 ? len : strlen(buf)) + strlen(key) + 5 ];
+ sprintf(outbuf, "%s%c%c", key, 13, 10);
+ size = strlen(outbuf);
+ if (len ? len : strlen(buf)) { // 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 ? len : strlen(buf));
+ size += (len ? len : strlen(buf));
+ }
+
+ start = lseek(datfd->getFd(), 0, SEEK_END);
+
+ outstart = archtosword32(start);
+ outsize = archtosword32(size);
+
+ lseek(idxfd->getFd(), idxoff, SEEK_SET);
+ if (len ? len : strlen(buf)) {
+ 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);
+
+ 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);
+ rawBuf = compressor->zBuf(&size);
+ write(zdtfd->getFd(), rawBuf, 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;
+}
diff --git a/src/modules/common/zverse.cpp b/src/modules/common/zverse.cpp
new file mode 100644
index 0000000..8d30797
--- /dev/null
+++ b/src/modules/common/zverse.cpp
@@ -0,0 +1,513 @@
+/******************************************************************************
+ * zverse.h - code for class 'zVerse'- 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
+ */
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#ifndef __GNUC__
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <string.h>
+#include <utilfuns.h>
+#include <versekey.h>
+#include <zverse.h>
+#include <sysdata.h>
+
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+
+/******************************************************************************
+ * zVerse Statics
+ */
+
+int zVerse::instance = 0;
+
+const char zVerse::uniqueIndexID[] = {'X', 'r', 'v', 'c', 'b'};
+
+/******************************************************************************
+ * zVerse Constructor - Initializes data for instance of zVerse
+ *
+ * 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 (O_RDONLY, etc.)
+ * blockType - verse, chapter, book, etc.
+ */
+
+zVerse::zVerse(const char *ipath, int fileMode, int blockType, SWCompress *icomp)
+{
+ char buf[127];
+
+ nl = '\n';
+ 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 = O_RDWR;
+ }
+
+ sprintf(buf, "%s/ot.%czs", path, uniqueIndexID[blockType]);
+ idxfp[0] = FileMgr::systemFileMgr.open(buf, fileMode|O_BINARY, true);
+
+ sprintf(buf, "%s/nt.%czs", path, uniqueIndexID[blockType]);
+ idxfp[1] = FileMgr::systemFileMgr.open(buf, fileMode|O_BINARY, true);
+
+ sprintf(buf, "%s/ot.%czz", path, uniqueIndexID[blockType]);
+ textfp[0] = FileMgr::systemFileMgr.open(buf, fileMode|O_BINARY, true);
+
+ sprintf(buf, "%s/nt.%czz", path, uniqueIndexID[blockType]);
+ textfp[1] = FileMgr::systemFileMgr.open(buf, fileMode|O_BINARY, true);
+
+ sprintf(buf, "%s/ot.%czv", path, uniqueIndexID[blockType]);
+ compfp[0] = FileMgr::systemFileMgr.open(buf, fileMode|O_BINARY, true);
+
+ sprintf(buf, "%s/nt.%czv", path, uniqueIndexID[blockType]);
+ compfp[1] = FileMgr::systemFileMgr.open(buf, fileMode|O_BINARY, true);
+
+ instance++;
+}
+
+
+/******************************************************************************
+ * zVerse Destructor - Cleans up instance of zVerse
+ */
+
+zVerse::~zVerse()
+{
+ int loop1;
+
+ if (cacheBuf) {
+ flushCache();
+ free(cacheBuf);
+ }
+
+ if (path)
+ delete [] path;
+
+ if (compressor)
+ delete compressor;
+
+ --instance;
+
+ for (loop1 = 0; loop1 < 2; loop1++) {
+ FileMgr::systemFileMgr.close(idxfp[loop1]);
+ FileMgr::systemFileMgr.close(textfp[loop1]);
+ FileMgr::systemFileMgr.close(compfp[loop1]);
+ }
+}
+
+
+/******************************************************************************
+ * zVerse::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 zVerse::findoffset(char testmt, long idxoff, long *start, unsigned short *size)
+{
+ // set start to offset in
+ // set size to
+ // set
+ unsigned long ulBuffNum=0; // buffer number
+ unsigned long ulVerseStart=0; // verse offset within buffer
+ unsigned short usVerseSize=0; // verse size
+ unsigned long ulCompOffset=0; // compressed buffer start
+ unsigned long ulCompSize=0; // buffer size compressed
+ unsigned long ulUnCompSize=0; // buffer size uncompressed
+ char *pcCompText=NULL; // compressed text
+
+ *start = *size = 0;
+ //printf ("Finding offset %ld\n", idxoff);
+ idxoff *= 10;
+ if (!testmt) {
+ testmt = ((idxfp[0]) ? 1:2);
+ }
+
+ // assert we have and valid file descriptor
+ if (compfp[testmt-1]->getFd() < 1)
+ return;
+
+ long newOffset = lseek(compfp[testmt-1]->getFd(), idxoff, SEEK_SET);
+ if (newOffset == idxoff) {
+ if (read(compfp[testmt-1]->getFd(), &ulBuffNum, 4) != 4) {
+ printf ("Error reading ulBuffNum\n");
+ return;
+ }
+ }
+ else return;
+
+ ulBuffNum = swordtoarch32(ulBuffNum);
+
+ if (read(compfp[testmt-1]->getFd(), &ulVerseStart, 4) < 2)
+ {
+ printf ("Error reading ulVerseStart\n");
+ return;
+ }
+ if (read(compfp[testmt-1]->getFd(), &usVerseSize, 2) < 2)
+ {
+ printf ("Error reading usVerseSize\n");
+ return;
+ }
+
+ *start = swordtoarch32(ulVerseStart);
+ *size = swordtoarch16(usVerseSize);
+
+ if (*size) {
+ if (((long) ulBuffNum == cacheBufIdx) && (testmt == cacheTestament) && (cacheBuf)) {
+ // have the text buffered
+ return;
+ }
+
+ //printf ("Got buffer number{%ld} versestart{%ld} versesize{%d}\n", ulBuffNum, ulVerseStart, usVerseSize);
+
+
+ if (lseek(idxfp[testmt-1]->getFd(), ulBuffNum*12, SEEK_SET)!=(long) ulBuffNum*12)
+ {
+ printf ("Error seeking compressed file index\n");
+ return;
+ }
+ if (read(idxfp[testmt-1]->getFd(), &ulCompOffset, 4)<4)
+ {
+ printf ("Error reading ulCompOffset\n");
+ return;
+ }
+ if (read(idxfp[testmt-1]->getFd(), &ulCompSize, 4)<4)
+ {
+ printf ("Error reading ulCompSize\n");
+ return;
+ }
+ if (read(idxfp[testmt-1]->getFd(), &ulUnCompSize, 4)<4)
+ {
+ printf ("Error reading ulUnCompSize\n");
+ return;
+ }
+
+ ulCompOffset = swordtoarch32(ulCompOffset);
+ ulCompSize = swordtoarch32(ulCompSize);
+ ulUnCompSize = swordtoarch32(ulUnCompSize);
+
+ if (lseek(textfp[testmt-1]->getFd(), ulCompOffset, SEEK_SET)!=(long)ulCompOffset)
+ {
+ printf ("Error: could not seek to right place in compressed text\n");
+ return;
+ }
+ pcCompText = new char[ulCompSize];
+
+ if (read(textfp[testmt-1]->getFd(), pcCompText, ulCompSize)<(long)ulCompSize)
+ {
+ printf ("Error reading compressed text\n");
+ return;
+ }
+ compressor->zBuf(&ulCompSize, pcCompText);
+
+ if (cacheBuf) {
+ flushCache();
+ free(cacheBuf);
+ }
+
+ unsigned long len = 0;
+ compressor->Buf(0, &len);
+ cacheBuf = (char *)calloc(len + 1, 1);
+ memcpy(cacheBuf, compressor->Buf(), len);
+
+ cacheTestament = testmt;
+ cacheBufIdx = ulBuffNum;
+ }
+}
+
+
+/******************************************************************************
+ * zVerse::swgettext - 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 zVerse::swgettext(char testmt, long start, unsigned short size, char *inbuf)
+{
+ memset(inbuf, 0, size);
+ if (size > 2) {
+ strncpy(inbuf, &(cacheBuf[start]), size-2);
+ }
+}
+
+
+/******************************************************************************
+ * zVerse::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 zVerse::settext(char testmt, long idxoff, const char *buf, long len)
+{
+ if ((!dirtyCache) || (cacheBufIdx < 0)) {
+ cacheBufIdx = lseek(idxfp[testmt-1]->getFd(), 0, SEEK_END) / 12;
+ cacheTestament = testmt;
+ if (cacheBuf)
+ free(cacheBuf);
+ cacheBuf = (char *)calloc(len ? len : strlen(buf)+1, 1);
+ }
+ else cacheBuf = (char *)((cacheBuf)?realloc(cacheBuf, strlen(cacheBuf)+(len ? len : strlen(buf)+1)):calloc((len ? len : strlen(buf)+1), 1));
+
+ dirtyCache = true;
+
+ unsigned long start, outstart;
+ unsigned long outBufIdx = cacheBufIdx;
+ unsigned short size;
+ unsigned short outsize;
+
+ idxoff *= 10;
+ size = outsize = len ? len : strlen(buf);
+
+ start = strlen(cacheBuf);
+
+ if (!size)
+ start = outBufIdx = 0;
+
+ outBufIdx = archtosword32(outBufIdx);
+ outstart = archtosword32(start);
+ outsize = archtosword16(size);
+
+ lseek(compfp[testmt-1]->getFd(), idxoff, SEEK_SET);
+ write(compfp[testmt-1]->getFd(), &outBufIdx, 4);
+ write(compfp[testmt-1]->getFd(), &outstart, 4);
+ write(compfp[testmt-1]->getFd(), &outsize, 2);
+ strcat(cacheBuf, buf);
+}
+
+
+void zVerse::flushCache() {
+ if (dirtyCache) {
+ unsigned long idxoff;
+ unsigned long start, outstart;
+ unsigned long size, outsize;
+ unsigned long zsize, outzsize;
+
+ idxoff = cacheBufIdx * 12;
+ size = outsize = zsize = outzsize = strlen(cacheBuf);
+ if (size) {
+// if (compressor) {
+// delete compressor;
+// compressor = new LZSSCompress();
+// }
+ compressor->Buf(cacheBuf);
+ compressor->zBuf(&zsize);
+ outzsize = zsize;
+
+ start = outstart = lseek(textfp[cacheTestament-1]->getFd(), 0, SEEK_END);
+
+ outstart = archtosword32(start);
+ outsize = archtosword32(size);
+ outzsize = archtosword32(zsize);
+
+ write(textfp[cacheTestament-1]->getFd(), compressor->zBuf(&zsize), zsize);
+
+ lseek(idxfp[cacheTestament-1]->getFd(), idxoff, SEEK_SET);
+ write(idxfp[cacheTestament-1]->getFd(), &outstart, 4);
+ write(idxfp[cacheTestament-1]->getFd(), &outzsize, 4);
+ write(idxfp[cacheTestament-1]->getFd(), &outsize, 4);
+ }
+ 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 zVerse::linkentry(char testmt, long destidxoff, long srcidxoff) {
+ long bufidx;
+ long start;
+ unsigned short size;
+
+ destidxoff *= 10;
+ srcidxoff *= 10;
+
+ if (!testmt)
+ testmt = ((idxfp[1]) ? 1:2);
+
+ // get source
+ lseek(compfp[testmt-1]->getFd(), srcidxoff, SEEK_SET);
+ read(compfp[testmt-1]->getFd(), &bufidx, 4);
+ read(compfp[testmt-1]->getFd(), &start, 4);
+ read(compfp[testmt-1]->getFd(), &size, 2);
+
+ // write dest
+ lseek(compfp[testmt-1]->getFd(), destidxoff, SEEK_SET);
+ write(compfp[testmt-1]->getFd(), &bufidx, 4);
+ write(compfp[testmt-1]->getFd(), &start, 4);
+ write(compfp[testmt-1]->getFd(), &size, 2);
+}
+
+
+/******************************************************************************
+ * RawVerse::CreateModule - Creates new module files
+ *
+ * ENT: path - directory to store module files
+ * RET: error status
+ */
+
+char zVerse::createModule(const char *ipath, int blockBound)
+{
+ 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/ot.%czs", path, uniqueIndexID[blockBound]);
+ 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/nt.%czs", path, uniqueIndexID[blockBound]);
+ 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/ot.%czz", path, uniqueIndexID[blockBound]);
+ 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/nt.%czz", path, uniqueIndexID[blockBound]);
+ unlink(buf);
+ fd2 = FileMgr::systemFileMgr.open(buf, O_CREAT|O_WRONLY|O_BINARY, S_IREAD|S_IWRITE);
+ fd2->getFd();
+ FileMgr::systemFileMgr.close(fd);
+
+ sprintf(buf, "%s/ot.%czv", path, uniqueIndexID[blockBound]);
+ unlink(buf);
+ fd = FileMgr::systemFileMgr.open(buf, O_CREAT|O_WRONLY|O_BINARY, S_IREAD|S_IWRITE);
+ fd->getFd();
+
+ sprintf(buf, "%s/nt.%czv", path, uniqueIndexID[blockBound]);
+ unlink(buf);
+ fd2 = FileMgr::systemFileMgr.open(buf, O_CREAT|O_WRONLY|O_BINARY, S_IREAD|S_IWRITE);
+ fd2->getFd();
+
+ VerseKey vk;
+ vk.Headings(1);
+ long offset = 0;
+ short size = 0;
+ for (vk = TOP; !vk.Error(); vk++) {
+ write((vk.Testament() == 1) ? fd->getFd() : fd2->getFd(), &offset, 4); //compBufIdxOffset
+ write((vk.Testament() == 1) ? fd->getFd() : fd2->getFd(), &offset, 4);
+ write((vk.Testament() == 1) ? fd->getFd() : fd2->getFd(), &size, 2);
+ }
+
+ FileMgr::systemFileMgr.close(fd);
+ FileMgr::systemFileMgr.close(fd2);
+
+ delete [] path;
+/*
+ RawVerse rv(path);
+ VerseKey mykey("Rev 22:21");
+*/
+
+ return 0;
+}
+
+
+/******************************************************************************
+ * zVerse::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 zVerse::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;
+
+ if (to > buf) {
+ for (to--; to > buf; to--) { // remove trailing excess
+ if ((*to == 10) || (*to == ' '))
+ *to = 0;
+ else break;
+ }
+ }
+}
diff --git a/src/modules/filters/Makefile b/src/modules/filters/Makefile
new file mode 100644
index 0000000..1a2d00d
--- /dev/null
+++ b/src/modules/filters/Makefile
@@ -0,0 +1,5 @@
+
+root := ../../..
+
+all:
+ make -C ${root}
diff --git a/src/modules/filters/Makefile.am b/src/modules/filters/Makefile.am
new file mode 100644
index 0000000..c58fb5f
--- /dev/null
+++ b/src/modules/filters/Makefile.am
@@ -0,0 +1,65 @@
+filtersdir = $(top_srcdir)/src/modules/filters
+
+libsword_la_SOURCES += $(filtersdir)/swbasicfilter.cpp
+
+libsword_la_SOURCES += $(filtersdir)/gbfhtml.cpp
+libsword_la_SOURCES += $(filtersdir)/gbfhtmlhref.cpp
+libsword_la_SOURCES += $(filtersdir)/gbfplain.cpp
+libsword_la_SOURCES += $(filtersdir)/gbfrtf.cpp
+libsword_la_SOURCES += $(filtersdir)/plainhtml.cpp
+libsword_la_SOURCES += $(filtersdir)/rwphtml.cpp
+libsword_la_SOURCES += $(filtersdir)/rwprtf.cpp
+libsword_la_SOURCES += $(filtersdir)/cipherfil.cpp
+libsword_la_SOURCES += $(filtersdir)/rtfhtml.cpp
+
+libsword_la_SOURCES += $(filtersdir)/gbfstrongs.cpp
+libsword_la_SOURCES += $(filtersdir)/gbffootnotes.cpp
+libsword_la_SOURCES += $(filtersdir)/gbfheadings.cpp
+libsword_la_SOURCES += $(filtersdir)/gbfmorph.cpp
+libsword_la_SOURCES += $(filtersdir)/plainfootnotes.cpp
+libsword_la_SOURCES += $(filtersdir)/thmlstrongs.cpp
+libsword_la_SOURCES += $(filtersdir)/thmlfootnotes.cpp
+libsword_la_SOURCES += $(filtersdir)/thmlheadings.cpp
+libsword_la_SOURCES += $(filtersdir)/thmlmorph.cpp
+libsword_la_SOURCES += $(filtersdir)/thmllemma.cpp
+libsword_la_SOURCES += $(filtersdir)/thmlscripref.cpp
+libsword_la_SOURCES += $(filtersdir)/thmlvariants.cpp
+
+libsword_la_SOURCES += $(filtersdir)/gbfthml.cpp
+libsword_la_SOURCES += $(filtersdir)/thmlgbf.cpp
+libsword_la_SOURCES += $(filtersdir)/thmlrtf.cpp
+libsword_la_SOURCES += $(filtersdir)/thmlhtml.cpp
+libsword_la_SOURCES += $(filtersdir)/thmlhtmlhref.cpp
+libsword_la_SOURCES += $(filtersdir)/thmlplain.cpp
+
+libsword_la_SOURCES += $(filtersdir)/unicodertf.cpp
+libsword_la_SOURCES += $(filtersdir)/latin1utf8.cpp
+libsword_la_SOURCES += $(filtersdir)/latin1utf16.cpp
+libsword_la_SOURCES += $(filtersdir)/utf8utf16.cpp
+libsword_la_SOURCES += $(filtersdir)/utf16utf8.cpp
+libsword_la_SOURCES += $(filtersdir)/scsuutf8.cpp
+libsword_la_SOURCES += $(filtersdir)/utf8html.cpp
+libsword_la_SOURCES += $(filtersdir)/utf8latin1.cpp
+
+libsword_la_SOURCES += $(filtersdir)/thmlolb.cpp
+
+libsword_la_SOURCES += $(filtersdir)/greeklexattribs.cpp
+
+if ICU
+ICUDEFS = -D_ICU_
+SWICUSRC = $(filtersdir)/utf8transliterator.cpp
+SWICUSRC += $(filtersdir)/utf8nfc.cpp
+SWICUSRC += $(filtersdir)/utf8nfkd.cpp
+SWICUSRC += $(filtersdir)/utf8arshaping.cpp
+SWICUSRC += $(filtersdir)/utf8bidireorder.cpp
+else
+SWICUSRC =
+ICUDEFS =
+endif
+libsword_la_SOURCES += $(SWICUSRC)
+DEFS += $(ICUDEFS)
+
+libsword_la_SOURCES += $(filtersdir)/utf8cantillation.cpp
+libsword_la_SOURCES += $(filtersdir)/utf8hebrewpoints.cpp
+libsword_la_SOURCES += $(filtersdir)/utf8greekaccents.cpp
+
diff --git a/src/modules/filters/cipherfil.cpp b/src/modules/filters/cipherfil.cpp
new file mode 100644
index 0000000..ad55396
--- /dev/null
+++ b/src/modules/filters/cipherfil.cpp
@@ -0,0 +1,38 @@
+/******************************************************************************
+ *
+ * cipherfil - SWFilter decendant to decipher a module
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <cipherfil.h>
+
+
+CipherFilter::CipherFilter(const char *key) {
+ cipher = new SWCipher((unsigned char *)key);
+}
+
+
+CipherFilter::~CipherFilter() {
+ delete cipher;
+}
+
+
+SWCipher *CipherFilter::getCipher() {
+ return cipher;
+}
+
+
+char CipherFilter::ProcessText(char *text, int maxlen, const SWKey *key, const SWModule *module) {
+ unsigned int len;
+// len = strlen(text);
+ len = maxlen;
+ if (len > 0) {
+ cipher->cipherBuf(&len, text);
+ strncpy(text, cipher->Buf(), (len < (unsigned int)maxlen) ? len : maxlen);
+ }
+ text[maxlen] = 0;
+ text[maxlen+1] = 0;
+ return 0;
+}
diff --git a/src/modules/filters/gbffootnotes.cpp b/src/modules/filters/gbffootnotes.cpp
new file mode 100644
index 0000000..c5b7b90
--- /dev/null
+++ b/src/modules/filters/gbffootnotes.cpp
@@ -0,0 +1,118 @@
+/******************************************************************************
+ *
+ * gbffootnotes - SWFilter decendant to hide or show footnotes
+ * in a GBF module.
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <gbffootnotes.h>
+#ifndef __GNUC__
+#else
+#include <unixstr.h>
+#endif
+
+
+const char GBFFootnotes::on[] = "On";
+const char GBFFootnotes::off[] = "Off";
+const char GBFFootnotes::optName[] = "Footnotes";
+const char GBFFootnotes::optTip[] = "Toggles Footnotes On and Off if they exist";
+
+
+GBFFootnotes::GBFFootnotes() {
+ option = false;
+ options.push_back(on);
+ options.push_back(off);
+}
+
+
+GBFFootnotes::~GBFFootnotes() {
+}
+
+void GBFFootnotes::setOptionValue(const char *ival)
+{
+ option = (!stricmp(ival, on));
+}
+
+const char *GBFFootnotes::getOptionValue()
+{
+ return (option) ? on:off;
+}
+
+char GBFFootnotes::ProcessText(char *text, int maxlen, const SWKey *key, const SWModule *module)
+{
+ if (!option) { // if we don't want footnotes
+ char *to, *from, token[4096]; // cheese. Fix.
+ int tokpos = 0;
+ bool intoken = false;
+ int len;
+ bool hide = false;
+
+ len = strlen(text) + 1; // shift string to right of buffer
+ if (len < maxlen) {
+ memmove(&text[maxlen - len], text, len);
+ from = &text[maxlen - len];
+ }
+ else from = text; // -------------------------------
+
+ for (to = text; *from; from++) {
+ if (*from == '<') {
+ intoken = true;
+ tokpos = 0;
+// memset(token, 0, 4096);
+ token[0] = 0;
+ token[1] = 0;
+ token[2] = 0;
+ continue;
+ }
+ if (*from == '>') { // process tokens
+ intoken = false;
+ switch (*token) {
+ case 'R': // Reference
+ switch(token[1]) {
+ case 'F': // Begin footnote
+ hide = true;
+ break;
+ case 'f': // end footnote
+ hide = false;
+ break;
+ }
+ continue; // skip token
+ case 'W':
+ if (token[1] == 'T') {
+ switch (token[2]) {
+ case 'P':
+ case 'S':
+ case 'A':
+ continue; // remove this token
+ default:
+ break;
+ }
+ }
+ }
+ // if not a footnote token, keep token in text
+ if (!hide) {
+ *to++ = '<';
+ for (char *tok = token; *tok; tok++)
+ *to++ = *tok;
+ *to++ = '>';
+ }
+ continue;
+ }
+ if (intoken) {
+ if (tokpos < 4090)
+ token[tokpos++] = *from;
+ token[tokpos+2] = 0; // +2 cuz we init token with 2 extra '0' because of switch statement
+ }
+ else {
+ if (!hide) {
+ *to++ = *from;
+ }
+ }
+ }
+ *to++ = 0;
+ *to = 0;
+ }
+ return 0;
+}
diff --git a/src/modules/filters/gbfheadings.cpp b/src/modules/filters/gbfheadings.cpp
new file mode 100644
index 0000000..590e2fa
--- /dev/null
+++ b/src/modules/filters/gbfheadings.cpp
@@ -0,0 +1,107 @@
+/******************************************************************************
+ *
+ * gbfheadings - SWFilter decendant to hide or show headings
+ * in a GBF module.
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <gbfheadings.h>
+#ifndef __GNUC__
+#else
+#include <unixstr.h>
+#endif
+
+
+const char GBFHeadings::on[] = "On";
+const char GBFHeadings::off[] = "Off";
+const char GBFHeadings::optName[] = "Headings";
+const char GBFHeadings::optTip[] = "Toggles Headings On and Off if they exist";
+
+
+GBFHeadings::GBFHeadings() {
+ option = false;
+ options.push_back(on);
+ options.push_back(off);
+}
+
+
+GBFHeadings::~GBFHeadings() {
+}
+
+void GBFHeadings::setOptionValue(const char *ival)
+{
+ option = (!stricmp(ival, on));
+}
+
+const char *GBFHeadings::getOptionValue()
+{
+ return (option) ? on:off;
+}
+
+char GBFHeadings::ProcessText(char *text, int maxlen, const SWKey *key, const SWModule *module)
+{
+ if (!option) { // if we don't want headings
+ char *to, *from, token[2048]; // cheese. Fix.
+ int tokpos = 0;
+ bool intoken = false;
+ int len;
+ bool hide = false;
+
+ len = strlen(text) + 1; // shift string to right of buffer
+ if (len < maxlen) {
+ memmove(&text[maxlen - len], text, len);
+ from = &text[maxlen - len];
+ }
+ else from = text; // -------------------------------
+
+ for (to = text; *from; from++) {
+ if (*from == '<') {
+ intoken = true;
+ tokpos = 0;
+// memset(token, 0, 2048);
+ token[0] = 0;
+ token[1] = 0;
+ token[2] = 0;
+ continue;
+ }
+ if (*from == '>') { // process tokens
+ intoken = false;
+ switch (*token) {
+ case 'T': // Reference
+ switch(token[1]) {
+ case 'S': // Begin heading
+ hide = true;
+ break;
+ case 's': // end heading
+ hide = false;
+ break;
+ }
+ continue; // skip token
+ }
+ // if not a heading token, keep token in text
+ if (!hide) {
+ *to++ = '<';
+ for (char *tok = token; *tok; tok++)
+ *to++ = *tok;
+ *to++ = '>';
+ }
+ continue;
+ }
+ if (intoken) {
+ if (tokpos < 2045)
+ token[tokpos++] = *from;
+ token[tokpos+2] = 0;
+ }
+ else {
+ if (!hide) {
+ *to++ = *from;
+ }
+ }
+ }
+ *to++ = 0;
+ *to = 0;
+ }
+ return 0;
+}
diff --git a/src/modules/filters/gbfhtml.cpp b/src/modules/filters/gbfhtml.cpp
new file mode 100644
index 0000000..73d445a
--- /dev/null
+++ b/src/modules/filters/gbfhtml.cpp
@@ -0,0 +1,536 @@
+/***************************************************************************
+ gbfhtml.cpp - description
+ -------------------
+ begin : Thu Jun 24 1999
+ copyright : (C) 1999 by Torsten Uhlmann
+ email : TUhlmann@gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <gbfhtml.h>
+
+
+GBFHTML::GBFHTML()
+{
+}
+
+
+char GBFHTML::ProcessText(char *text, int maxlen, const SWKey *key, const SWModule *module)
+{
+ char *to, *from, token[2048];
+ int tokpos = 0;
+ bool intoken = false;
+ bool hasFootnotePreTag = false;
+ bool isRightJustified = false;
+ bool isCentered = false;
+ int len;
+ const char *tok;
+
+ len = strlen(text) + 1; // shift string to right of buffer
+ if (len < maxlen) {
+ memmove(&text[maxlen - len], text, len);
+ from = &text[maxlen - len];
+ }
+ else
+ from = text; // -------------------------------
+
+ for (to = text; *from; from++)
+ {
+ if (*from == '\n') {
+ *from = ' ';
+ }
+ if (*from == '<') {
+ intoken = true;
+ tokpos = 0;
+ token[0] = 0;
+ token[1] = 0;
+ token[2] = 0;
+ continue;
+ }
+ if (*from == '>') {
+ intoken = false;
+ // process desired tokens
+ switch (*token) {
+ case 'W': // Strongs
+ switch(token[1])
+ {
+ case 'G': // Greek
+ case 'H': // Hebrew
+ case 'T': // Tense
+ *to++ = ' ';
+ *to++ = '<';
+ *to++ = 's';
+ *to++ = 'm';
+ *to++ = 'a';
+ *to++ = 'l';
+ *to++ = 'l';
+ *to++ = '>';
+ *to++ = '<';
+ *to++ = 'e';
+ *to++ = 'm';
+ *to++ = '>';
+ for (tok = token+2; *tok; tok++)
+ *to++ = *tok;
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'e';
+ *to++ = 'm';
+ *to++ = '>';
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 's';
+ *to++ = 'm';
+ *to++ = 'a';
+ *to++ = 'l';
+ *to++ = 'l';
+ *to++ = '>';
+ *to++ = ' ';
+ continue;
+ }
+ break;
+ case 'R':
+ switch(token[1])
+ {
+ case 'X':
+ *to++ = '<';
+ *to++ = 'a';
+ *to++ = ' ';
+ *to++ = 'h';
+ *to++ = 'r';
+ *to++ = 'e';
+ *to++ = 'f';
+ *to++ = '=';
+ *to++ = '\"';
+ for (tok = token + 3; *tok; tok++) {
+ if(*tok != '<' && *tok+1 != 'R' && *tok+2 != 'x') {
+ *to++ = *tok;
+ }
+ else {
+ break;
+ }
+ }
+ *to++ = '\"';
+ *to++ = '>';
+ continue;
+ case 'x':
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'a';
+ *to++ = '>';
+ continue;
+ case 'B': //word(s) explained in footnote
+ *to++ = '<';
+ *to++ = 'i';
+ *to++ = '>';
+ hasFootnotePreTag = true; //we have the RB tag
+ continue;
+ case 'F': // footnote begin
+ if (hasFootnotePreTag) {
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'i';
+ *to++ = '>';
+ *to++ = ' ';
+ }
+ *to++ = '<';
+ *to++ = 'f';
+ *to++ = 'o';
+ *to++ = 'n';
+ *to++ = 't';
+ *to++ = ' ';
+ *to++ = 'c';
+ *to++ = 'o';
+ *to++ = 'l';
+ *to++ = 'o';
+ *to++ = 'r';
+ *to++ = '=';
+ *to++ = '\"';
+ *to++ = '#';
+ *to++ = '8';
+ *to++ = '0';
+ *to++ = '0';
+ *to++ = '0';
+ *to++ = '0';
+ *to++ = '0';
+ *to++ = '\"';
+ *to++ = '>';
+
+ *to++ = ' ';
+ *to++ = '<';
+ *to++ = 's';
+ *to++ = 'm';
+ *to++ = 'a';
+ *to++ = 'l';
+ *to++ = 'l';
+ *to++ = '>';
+ *to++ = '(';
+
+ continue;
+ case 'f': // footnote end
+ *to++ = ')';
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 's';
+ *to++ = 'm';
+ *to++ = 'a';
+ *to++ = 'l';
+ *to++ = 'l';
+ *to++ = '>';
+ *to++ = ' ';
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'f';
+ *to++ = 'o';
+ *to++ = 'n';
+ *to++ = 't';
+ *to++ = '>';
+ hasFootnotePreTag = false;
+ continue;
+ }
+ break;
+
+ case 'F': // font tags
+ switch(token[1])
+ {
+ case 'I': // italic start
+ *to++ = '<';
+ *to++ = 'i';
+ *to++ = '>';
+ continue;
+ case 'i': // italic end
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'i';
+ *to++ = '>';
+ continue;
+ case 'B': // bold start
+ *to++ = '<';
+ *to++ = 'b';
+ *to++ = '>';
+ continue;
+ case 'b': // bold end
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'b';
+ *to++ = '>';
+ continue;
+ case 'R': // words of Jesus begin
+ *to++ = '<';
+ *to++ = 'f';
+ *to++ = 'o';
+ *to++ = 'n';
+ *to++ = 't';
+ *to++ = ' ';
+ *to++ = 'c';
+ *to++ = 'o';
+ *to++ = 'l';
+ *to++ = 'o';
+ *to++ = 'r';
+ *to++ = '=';
+ *to++ = '#';
+ *to++ = 'F';
+ *to++ = 'F';
+ *to++ = '0';
+ *to++ = '0';
+ *to++ = '0';
+ *to++ = '0';
+ *to++ = '>';
+ continue;
+ case 'r': // words of Jesus end
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'f';
+ *to++ = 'o';
+ *to++ = 'n';
+ *to++ = 't';
+ *to++ = '>';
+ continue;
+ case 'U': // Underline start
+ *to++ = '<';
+ *to++ = 'u';
+ *to++ = '>';
+ continue;
+ case 'u': // Underline end
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'u';
+ *to++ = '>';
+ continue;
+ case 'O': // Old Testament quote begin
+ *to++ = '<';
+ *to++ = 'c';
+ *to++ = 'i';
+ *to++ = 't';
+ *to++ = 'e';
+ *to++ = '>';
+ continue;
+ case 'o': // Old Testament quote end
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'c';
+ *to++ = 'i';
+ *to++ = 't';
+ *to++ = 'e';
+ *to++ = '>';
+ continue;
+ case 'S': // Superscript begin
+ *to++ = '<';
+ *to++ = 's';
+ *to++ = 'u';
+ *to++ = 'p';
+ *to++ = '>';
+ continue;
+ case 's': // Superscript end
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 's';
+ *to++ = 'u';
+ *to++ = 'p';
+ *to++ = '>';
+ continue;
+ case 'V': // Subscript begin
+ *to++ = '<';
+ *to++ = 's';
+ *to++ = 'u';
+ *to++ = 'b';
+ *to++ = '>';
+ continue;
+ case 'v': // Subscript end
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 's';
+ *to++ = 'u';
+ *to++ = 'b';
+ *to++ = '>';
+ continue;
+ case 'N':
+ *to++ = '<';
+ *to++ = 'f';
+ *to++ = 'o';
+ *to++ = 'n';
+ *to++ = 't';
+ *to++ = ' ';
+ *to++ = 'f';
+ *to++ = 'a';
+ *to++ = 'c';
+ *to++ = 'e';
+ *to++ = '=';
+ *to++ = '"';
+ for (tok = token + 2; *tok; tok++)
+ *to++ = *tok;
+ *to++ = '"';
+ *to++ = '>';
+ continue;
+ case 'n':
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'f';
+ *to++ = 'o';
+ *to++ = 'n';
+ *to++ = 't';
+ *to++ = '>';
+ continue;
+ }
+ break;
+ case 'C': // special character tags
+ switch(token[1])
+ {
+ case 'A': // ASCII value
+ *to++ = (char)atoi(&token[2]);
+ continue;
+ case 'G':
+ //*to++ = ' ';
+ continue;
+ case 'L': // line break
+ *to++ = '<';
+ *to++ = 'b';
+ *to++ = 'r';
+ *to++ = ' ';
+ *to++ = '/';
+ *to++ = '>';
+ *to++ = ' ';
+ continue;
+ case 'M': // new paragraph
+ *to++ = '<';
+ *to++ = 'b';
+ *to++ = 'r';
+ *to++ = ' ';
+ *to++ = '/';
+ *to++ = '>';
+ continue;
+ case 'T':
+ //*to++ = ' ';
+ continue;
+ }
+ break;
+ case 'J': //Justification
+ switch(token[1])
+ {
+ case 'R': //right
+ *to++ = '<';
+ *to++ = 'd';
+ *to++ = 'i';
+ *to++ = 'v';
+ *to++ = ' ';
+ *to++ = 'a';
+ *to++ = 'l';
+ *to++ = 'i';
+ *to++ = 'g';
+ *to++ = 'n';
+ *to++ = '=';
+ *to++ = '\"';
+ *to++ = 'r';
+ *to++ = 'i';
+ *to++ = 'g';
+ *to++ = 'h';
+ *to++ = 't';
+ *to++ = '\"';
+ *to++ = '>';
+ isRightJustified = true;
+ continue;
+
+ case 'C': //center
+ *to++ = '<';
+ *to++ = 'd';
+ *to++ = 'i';
+ *to++ = 'v';
+ *to++ = ' ';
+ *to++ = 'a';
+ *to++ = 'l';
+ *to++ = 'i';
+ *to++ = 'g';
+ *to++ = 'n';
+ *to++ = '=';
+ *to++ = '\"';
+ *to++ = 'c';
+ *to++ = 'e';
+ *to++ = 'n';
+ *to++ = 't';
+ *to++ = 'e';
+ *to++ = 'r';
+ *to++ = '\"';
+ *to++ = '>';
+ isCentered = true;
+ continue;
+
+ case 'L': //left, reset right and center
+ if (isCentered) {
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'c';
+ *to++ = 'e';
+ *to++ = 'n';
+ *to++ = 't';
+ *to++ = 'e';
+ *to++ = 'r';
+ *to++ = '>';
+ isCentered = false;
+ }
+ if (isRightJustified) {
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'd';
+ *to++ = 'i';
+ *to++ = 'v';
+ *to++ = '>';
+ isRightJustified = false;
+ }
+ continue;
+ }
+ break;
+ case 'T': // title formatting
+ switch(token[1])
+ {
+ case 'T': // Book title begin
+ *to++ = '<';
+ *to++ = 'b';
+ *to++ = 'i';
+ *to++ = 'g';
+ *to++ = '>';
+ continue;
+ case 't':
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'b';
+ *to++ = 'i';
+ *to++ = 'g';
+ *to++ = '>';
+ continue;/*
+ case 'S':
+ *to++ = '<';
+ *to++ = 'b';
+ *to++ = 'r';
+ *to++ = ' ';
+ *to++ = '/';
+ *to++ = '>';
+ *to++ = '<';
+ *to++ = 'b';
+ *to++ = 'i';
+ *to++ = 'g';
+ *to++ = '>';
+ continue;
+ case 's':
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'b';
+ *to++ = 'i';
+ *to++ = 'g';
+ *to++ = '>';
+ *to++ = '<';
+ *to++ = 'b';
+ *to++ = 'r';
+ *to++ = ' ';
+ *to++ = '/';
+ *to++ = '>';
+ continue;*/
+ }
+ break;
+
+ case 'P': // special formatting
+ switch(token[1])
+ {
+ case 'P': // Poetry begin
+ *to++ = '<';
+ *to++ = 'c';
+ *to++ = 'i';
+ *to++ = 't';
+ *to++ = 'e';
+ *to++ = '>';
+ continue;
+ case 'p':
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'c';
+ *to++ = 'i';
+ *to++ = 't';
+ *to++ = 'e';
+ *to++ = '>';
+ continue;
+ }
+ break;
+ }
+ continue;
+ }
+ if (intoken) {
+ if (tokpos < 2045) {
+ token[tokpos++] = *from;
+ token[tokpos+2] = 0;
+ }
+ }
+ else
+ *to++ = *from;
+ }
+ *to++ = 0;
+ *to = 0;
+ return 0;
+}
diff --git a/src/modules/filters/gbfhtmlhref.cpp b/src/modules/filters/gbfhtmlhref.cpp
new file mode 100644
index 0000000..30b27ba
--- /dev/null
+++ b/src/modules/filters/gbfhtmlhref.cpp
@@ -0,0 +1,148 @@
+/***************************************************************************
+ gbfhtmlhref.cpp - GBF to HTML filter with hrefs
+ for strongs and morph tags
+ -------------------
+ begin : 2001-09-03
+ copyright : 2001 by CrossWire Bible Society
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <gbfhtmlhref.h>
+
+GBFHTMLHREF::GBFHTMLHREF() {
+ setTokenStart("<");
+ setTokenEnd(">");
+
+ setTokenCaseSensitive(true);
+
+ addTokenSubstitute("Rf", ")</small></font>");
+ addTokenSubstitute("Rx", "</a>");
+ addTokenSubstitute("FI", "<i>"); // italics begin
+ addTokenSubstitute("Fi", "</i>");
+ addTokenSubstitute("FB", "<n>"); // bold begin
+ addTokenSubstitute("Fb", "</n>");
+ addTokenSubstitute("FR", "<font color=\"#FF0000\">"); // words of Jesus begin
+ addTokenSubstitute("Fr", "</font>");
+ addTokenSubstitute("FU", "<u>"); // underline begin
+ addTokenSubstitute("Fu", "</u>");
+ addTokenSubstitute("FO", "<cite>"); // Old Testament quote begin
+ addTokenSubstitute("Fo", "</cite>");
+ addTokenSubstitute("FS", "<sup>"); // Superscript begin// Subscript begin
+ addTokenSubstitute("Fs", "</sup>");
+ addTokenSubstitute("FV", "<sub>"); // Subscript begin
+ addTokenSubstitute("Fv", "</sub>");
+ addTokenSubstitute("TT", "<big>"); // Book title begin
+ addTokenSubstitute("Tt", "</big>");
+ addTokenSubstitute("PP", "<cite>"); // poetry begin
+ addTokenSubstitute("Pp", "</cite>");
+ addTokenSubstitute("Fn", "</font>"); // font end
+ addTokenSubstitute("CL", "<br />"); // new line
+ addTokenSubstitute("CM", "<!P><br />"); // paragraph <!P> is a non showing comment that can be changed in the front end to <P> if desired
+ addTokenSubstitute("CG", ""); // ???
+ addTokenSubstitute("CT", ""); // ???
+ addTokenSubstitute("JR", "<div align=\"right\">"); // right align begin
+ addTokenSubstitute("JC", "<div align=\"center\">"); // center align begin
+ addTokenSubstitute("JL", "</div>"); // align end
+
+}
+
+
+bool GBFHTMLHREF::handleToken(char **buf, const char *token, DualStringMap &userData) {
+ const char *tok;
+
+ if (!substituteToken(buf, token)) {
+ if (!strncmp(token, "WG", 2) || !strncmp(token, "WH", 2)) { // strong's numbers
+ pushString(buf, " <small><em>&lt;<a href=\"#");
+ for (tok = token+1; *tok; tok++)
+ //if(token[i] != '\"')
+ *(*buf)++ = *tok;
+ *(*buf)++ = '\"';
+ *(*buf)++ = '>';
+ for (tok = token + 2; *tok; tok++)
+ //if(token[i] != '\"')
+ *(*buf)++ = *tok;
+ pushString(buf, "</a>&gt;</em></small>");
+ }
+
+ else if (!strncmp(token, "WTG", 3) || !strncmp(token, "WTH", 3)) { // strong's numbers tense
+ pushString(buf, " <small><em>(<A HREF=\"#");
+ for (tok = token + 2; *tok; tok++)
+ if(*tok != '\"')
+ *(*buf)++ = *tok;
+ *(*buf)++ = '\"';
+ *(*buf)++ = '>';
+ for (tok = token + 3; *tok; tok++)
+ if(*tok != '\"')
+ *(*buf)++ = *tok;
+ pushString(buf, "</a>)</em></small>");
+ }
+
+ else if (!strncmp(token, "WT", 2) && strncmp(token, "WTH", 3) && strncmp(token, "WTG", 3)) { // morph tags
+ pushString(buf, " <small><em>(<a href=\"M");
+ for (tok = token + 2; *tok; tok++)
+ if(*tok != '\"')
+ *(*buf)++ = *tok;
+ *(*buf)++ = '\"';
+ *(*buf)++ = '>';
+ for (tok = token + 2; *tok; tok++)
+ if(*tok != '\"')
+ *(*buf)++ = *tok;
+ pushString(buf, "</a>)</em></small>");
+ }
+
+ else if (!strncmp(token, "RX", 2)) {
+ pushString(buf, "<a href=\"");
+ for (tok = token + 3; *tok; tok++) {
+ if(*tok != '<' && *tok+1 != 'R' && *tok+2 != 'x') {
+ *(*buf)++ = *tok;
+ }
+ else {
+ break;
+ }
+ }
+ *(*buf)++ = '\"';
+ *(*buf)++ = '>';
+ }
+
+ else if (!strncmp(token, "RB", 2)) {
+ pushString(buf, "<i>");
+ userData["hasFootnotePreTag"] = "true";
+ }
+
+ else if (!strncmp(token, "RF", 2)) {
+ if(userData["hasFootnotePreTag"] == "true") {
+ userData["hasFootnotePreTag"] = "false";
+ pushString(buf, "</i> ");
+ }
+ pushString(buf, "<font color=\"#800000\"><small> (");
+ }
+
+ else if (!strncmp(token, "FN", 2)) {
+ pushString(buf, "<font face=\"");
+ for (tok = token + 2; *tok; tok++)
+ if(*tok != '\"')
+ *(*buf)++ = *tok;
+ *(*buf)++ = '\"';
+ *(*buf)++ = '>';
+ }
+
+ else if (!strncmp(token, "CA", 2)) { // ASCII value
+ *(*buf)++ = (char)atoi(&token[2]);
+ }
+
+ else {
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/src/modules/filters/gbfmorph.cpp b/src/modules/filters/gbfmorph.cpp
new file mode 100644
index 0000000..f8d336e
--- /dev/null
+++ b/src/modules/filters/gbfmorph.cpp
@@ -0,0 +1,98 @@
+/******************************************************************************
+ *
+ * gbfmorph - SWFilter decendant to hide or show morph tags
+ * in a GBF module.
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <gbfmorph.h>
+#ifndef __GNUC__
+#else
+#include <unixstr.h>
+#endif
+
+
+const char GBFMorph::on[] = "On";
+const char GBFMorph::off[] = "Off";
+const char GBFMorph::optName[] = "Morphological Tags";
+const char GBFMorph::optTip[] = "Toggles Morphological Tags On and Off if they exist";
+
+
+GBFMorph::GBFMorph() {
+ option = false;
+ options.push_back(on);
+ options.push_back(off);
+}
+
+
+GBFMorph::~GBFMorph() {
+}
+
+void GBFMorph::setOptionValue(const char *ival)
+{
+ option = (!stricmp(ival, on));
+}
+
+const char *GBFMorph::getOptionValue()
+{
+ return (option) ? on:off;
+}
+
+char GBFMorph::ProcessText(char *text, int maxlen, const SWKey *key, const SWModule *module)
+{
+ if (!option) { // if we don't want morph tags
+ char *to, *from, token[2048]; // cheese. Fix.
+ int tokpos = 0;
+ bool intoken = false;
+ int len;
+ bool lastspace = false;
+
+ len = strlen(text) + 1; // shift string to right of buffer
+ if (len < maxlen) {
+ memmove(&text[maxlen - len], text, len);
+ from = &text[maxlen - len];
+ }
+ else from = text; // -------------------------------
+
+ for (to = text; *from; from++) {
+ if (*from == '<') {
+ intoken = true;
+ tokpos = 0;
+ token[0] = 0;
+ token[1] = 0;
+ token[2] = 0;
+ continue;
+ }
+ if (*from == '>') { // process tokens
+ intoken = false;
+ if (*token == 'W' && token[1] == 'T') { // Morph
+ if ((from[1] == ' ') || (from[1] == ',') || (from[1] == ';') || (from[1] == '.') || (from[1] == '?') || (from[1] == '!') || (from[1] == ')') || (from[1] == '\'') || (from[1] == '\"')) {
+ if (lastspace)
+ to--;
+ }
+ continue;
+ }
+ // if not a morph tag token, keep token in text
+ *to++ = '<';
+ for (char *tok = token; *tok; tok++)
+ *to++ = *tok;
+ *to++ = '>';
+ continue;
+ }
+ if (intoken) {
+ if (tokpos < 2045)
+ token[tokpos++] = *from;
+ token[tokpos+2] = 0;
+ }
+ else {
+ *to++ = *from;
+ lastspace = (*from == ' ');
+ }
+ }
+ *to++ = 0;
+ *to = 0;
+ }
+ return 0;
+}
diff --git a/src/modules/filters/gbfplain.cpp b/src/modules/filters/gbfplain.cpp
new file mode 100644
index 0000000..65766d3
--- /dev/null
+++ b/src/modules/filters/gbfplain.cpp
@@ -0,0 +1,106 @@
+/******************************************************************************
+ *
+ * gbfplain - SWFilter decendant to strip out all GBF tags or convert to
+ * ASCII rendered symbols.
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <gbfplain.h>
+
+
+GBFPlain::GBFPlain() {
+}
+
+
+char GBFPlain::ProcessText(char *text, int maxlen, const SWKey *key, const SWModule *module)
+{
+ char *to, *from, token[2048];
+ int tokpos = 0;
+ bool intoken = false;
+ int len;
+
+ len = strlen(text) + 1; // shift string to right of buffer
+ if (len < maxlen) {
+ memmove(&text[maxlen - len], text, len);
+ from = &text[maxlen - len];
+ }
+ else from = text; // -------------------------------
+
+ for (to = text; *from; from++) {
+ if (*from == '<') {
+ intoken = true;
+ tokpos = 0;
+ token[0] = 0;
+ token[1] = 0;
+ token[2] = 0;
+ continue;
+ }
+ if (*from == '>') {
+ intoken = false;
+ // process desired tokens
+ switch (*token) {
+ case 'W': // Strongs
+ switch(token[1]) {
+ case 'G': // Greek
+ case 'H': // Hebrew
+ case 'T': // Tense
+ *to++ = ' ';
+ *to++ = '<';
+ for (char *tok = token + 2; *tok; tok++)
+ *to++ = *tok;
+ *to++ = '>';
+ *to++ = ' ';
+ continue;
+ }
+ break;
+ case 'R':
+ switch(token[1]) {
+ case 'F': // footnote begin
+ *to++ = ' ';
+ *to++ = '[';
+ continue;
+ case 'f': // footnote end
+ *to++ = ']';
+ *to++ = ' ';
+ continue;
+ }
+ break;
+ case 'C':
+ switch(token[1]) {
+ case 'A': // ASCII value
+ *to++ = (char)atoi(&token[2]);
+ continue;
+ case 'G':
+ *to++ = '>';
+ continue;
+/* Bug in WEB
+ case 'L':
+ *to++ = '<';
+ continue;
+*/
+ case 'L': // Bug in WEB. Use above entry when fixed
+ case 'N': // new line
+ *to++ = '\n';
+ continue;
+ case 'M': // new paragraph
+ *to++ = '\n';
+ *to++ = '\n';
+ continue;
+ }
+ break;
+ }
+ continue;
+ }
+ if (intoken) {
+ if (tokpos < 2045)
+ token[tokpos++] = *from;
+ token[tokpos+2] = 0;
+ }
+ else *to++ = *from;
+ }
+ *to++ = 0;
+ *to = 0;
+ return 0;
+}
diff --git a/src/modules/filters/gbfrtf.cpp b/src/modules/filters/gbfrtf.cpp
new file mode 100644
index 0000000..5f7d064
--- /dev/null
+++ b/src/modules/filters/gbfrtf.cpp
@@ -0,0 +1,277 @@
+/******************************************************************************
+ *
+ * gbfrtf - SWFilter decendant to convert all GBF tags to RTF tags
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <gbfrtf.h>
+#include <ctype.h>
+
+GBFRTF::GBFRTF() {
+}
+
+
+char GBFRTF::ProcessText(char *text, int maxlen, const SWKey *key, const SWModule *module)
+{
+ unsigned char *to, *from;
+ char token[2048];
+ int tokpos = 0;
+ bool intoken = false;
+ int len;
+ const char *tok;
+
+ len = strlen(text) + 1; // shift string to right of buffer
+ if (len < maxlen) {
+ memmove(&text[maxlen - len], text, len);
+ from = (unsigned char *)&text[maxlen - len];
+ }
+ else from = (unsigned char *)text; // -------------------------------
+ for (to = (unsigned char *)text; *from; from++) {
+ if (*from == '<') {
+ intoken = true;
+ tokpos = 0;
+ token[0] = 0;
+ token[1] = 0;
+ token[2] = 0;
+ continue;
+ }
+ if (*from == '>') {
+ intoken = false;
+ // process desired tokens
+ switch (*token) {
+ case 'W': // Strongs
+ switch(token[1]) {
+ case 'G': // Greek
+ case 'H': // Hebrew
+ *to++ = '{';
+ *to++ = '\\';
+ *to++ = 'f';
+ *to++ = 's';
+ *to++ = '1';
+ *to++ = '7';
+ *to++ = ' ';
+ *to++ = '<';
+ for (tok = token + 2; *tok; tok++)
+ *to++ = *tok;
+ *to++ = '>';
+ *to++ = '}';
+ continue;
+
+ case 'T': // Tense
+ *to++ = '{';
+ *to++ = '\\';
+ *to++ = 'f';
+ *to++ = 's';
+ *to++ = '1';
+ *to++ = '7';
+ *to++ = ' ';
+ *to++ = '(';
+ bool separate = false;
+ for (tok = token + 2; *tok; tok++) {
+ if (separate) {
+ *to++ = ';';
+ *to++ = ' ';
+ separate = false;
+ }
+ switch (*tok) {
+ case 'G':
+ case 'H':
+ for (tok++; *tok; tok++) {
+ if (isdigit(*tok)) {
+ *to++ = *tok;
+ separate = true;
+ }
+ else {
+ tok--;
+ break;
+ }
+ }
+ break;
+ default:
+ for (; *tok; tok++) {
+ *to++ = *tok;
+ }
+ }
+ }
+ *to++ = ')';
+ *to++ = '}';
+ continue;
+ }
+ break;
+ case 'R':
+ switch(token[1]) {
+ case 'X':
+ *to++ = '#';
+ continue;
+ case 'x':
+ *to++ = '|';
+ continue;
+ case 'F': // footnote begin
+ *to++ = '{';
+ *to++ = '\\';
+ *to++ = 'i';
+ *to++ = '1';
+ *to++ = ' ';
+ *to++ = '\\';
+ *to++ = 'f';
+ *to++ = 's';
+ *to++ = '1';
+ *to++ = '7';
+ *to++ = ' ';
+ *to++ = '(';
+ continue;
+ case 'f': // footnote end
+ *to++ = ')';
+ *to++ = ' ';
+ *to++ = '}';
+ continue;
+ }
+ break;
+ case 'F': // font tags
+ switch(token[1]) {
+ case 'I': // italic start
+ *to++ = '\\';
+ *to++ = 'i';
+ *to++ = '1';
+ *to++ = ' ';
+ continue;
+ case 'i': // italic end
+ *to++ = '\\';
+ *to++ = 'i';
+ *to++ = '0';
+ *to++ = ' ';
+ continue;
+ case 'B': // bold start
+ *to++ = '\\';
+ *to++ = 'b';
+ *to++ = '1';
+ *to++ = ' ';
+ continue;
+ case 'b': // bold end
+ *to++ = '\\';
+ *to++ = 'b';
+ *to++ = '0';
+ *to++ = ' ';
+ continue;
+ case 'N':
+ *to++ = '{';
+ if (!strnicmp(token+2, "Symbol", 6)) {
+ *to++ = '\\';
+ *to++ = 'f';
+ *to++ = '7';
+ *to++ = ' ';
+ }
+ continue;
+ case 'n':
+ *to++ = '}';
+ continue;
+ case 'S':
+ *to++ = '{';
+ *to++ = '\\';
+ *to++ = 's';
+ *to++ = 'u';
+ *to++ = 'p';
+ *to++ = 'e';
+ *to++ = 'r';
+ *to++ = ' ';
+ continue;
+ case 's':
+ *to++ = '}';
+ continue;
+ case 'R':
+ *to++ = '{';
+ *to++ = '\\';
+ *to++ = 'c';
+ *to++ = 'f';
+ *to++ = '6';
+ *to++ = ' ';
+ continue;
+ case 'r':
+ *to++ = '}';
+ continue;
+ }
+ break;
+ case 'C': // special character tags
+ switch(token[1]) {
+ case 'A': // ASCII value
+ *to++ = (char)atoi(&token[2]);
+ continue;
+ case 'G':
+ *to++ = '>';
+ continue;
+ case 'L': // line break
+ *to++ = '\\';
+ *to++ = 'l';
+ *to++ = 'i';
+ *to++ = 'n';
+ *to++ = 'e';
+ *to++ = ' ';
+ continue;
+ case 'M': // new paragraph
+ *to++ = '\\';
+ *to++ = 'p';
+ *to++ = 'a';
+ *to++ = 'r';
+ *to++ = ' ';
+ continue;
+ case 'T':
+ *to++ = '<';
+ }
+ break;
+ case 'T': // title formatting
+ switch(token[1])
+ {
+ case 'T': // Book title begin
+ *to++ = '{';
+ *to++ = '\\';
+ *to++ = 'f';
+ *to++ = 's';
+ *to++ = '2';
+ *to++ = '2';
+ *to++ = ' ';
+ continue;
+ case 't':
+ *to++ = '}';
+ continue;
+ case 'S':
+ *to++ = '\\';
+ *to++ = 'p';
+ *to++ = 'a';
+ *to++ = 'r';
+ *to++ = ' ';
+ *to++ = '{';
+ *to++ = '\\';
+ *to++ = 'i';
+ *to++ = '1';
+ *to++ = '\\';
+ *to++ = 'b';
+ *to++ = '1';
+ *to++ = ' ';
+ continue;
+ case 's':
+ *to++ = '}';
+ *to++ = '\\';
+ *to++ = 'p';
+ *to++ = 'a';
+ *to++ = 'r';
+ *to++ = ' ';
+ continue;
+ }
+ break;
+
+ }
+ continue;
+ }
+ if (intoken) {
+ if (tokpos < 2045)
+ token[tokpos++] = *from;
+ token[tokpos+2] = 0;
+ }
+ else *to++ = *from;
+ }
+ *to++ = 0;
+ *to = 0;
+ return 0;
+}
diff --git a/src/modules/filters/gbfstrongs.cpp b/src/modules/filters/gbfstrongs.cpp
new file mode 100644
index 0000000..40fc958
--- /dev/null
+++ b/src/modules/filters/gbfstrongs.cpp
@@ -0,0 +1,98 @@
+/******************************************************************************
+ *
+ * gbfstrongs - SWFilter decendant to hide or show strongs number
+ * in a GBF module.
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <gbfstrongs.h>
+#ifndef __GNUC__
+#else
+#include <unixstr.h>
+#endif
+
+
+const char GBFStrongs::on[] = "On";
+const char GBFStrongs::off[] = "Off";
+const char GBFStrongs::optName[] = "Strong's Numbers";
+const char GBFStrongs::optTip[] = "Toggles Strong's Numbers On and Off if they exist";
+
+
+GBFStrongs::GBFStrongs() {
+ option = false;
+ options.push_back(on);
+ options.push_back(off);
+}
+
+
+GBFStrongs::~GBFStrongs() {
+}
+
+void GBFStrongs::setOptionValue(const char *ival)
+{
+ option = (!stricmp(ival, on));
+}
+
+const char *GBFStrongs::getOptionValue()
+{
+ return (option) ? on:off;
+}
+
+char GBFStrongs::ProcessText(char *text, int maxlen, const SWKey *key, const SWModule *module)
+{
+ if (!option) { // if we don't want strongs
+ char *to, *from, token[2048]; // cheese. Fix.
+ int tokpos = 0;
+ bool intoken = false;
+ int len;
+ bool lastspace = false;
+
+ len = strlen(text) + 1; // shift string to right of buffer
+ if (len < maxlen) {
+ memmove(&text[maxlen - len], text, len);
+ from = &text[maxlen - len];
+ }
+ else from = text; // -------------------------------
+
+ for (to = text; *from; from++) {
+ if (*from == '<') {
+ intoken = true;
+ tokpos = 0;
+ token[0] = 0;
+ token[1] = 0;
+ token[2] = 0;
+ continue;
+ }
+ if (*from == '>') { // process tokens
+ intoken = false;
+ if (*token == 'W' && (token[1] == 'G' || token[1] == 'H')) { // Strongs
+ if ((from[1] == ' ') || (from[1] == ',') || (from[1] == ';') || (from[1] == '.') || (from[1] == '?') || (from[1] == '!') || (from[1] == ')') || (from[1] == '\'') || (from[1] == '\"')) {
+ if (lastspace)
+ to--;
+ }
+ continue;
+ }
+ // if not a strongs token, keep token in text
+ *to++ = '<';
+ for (char *tok = token; *tok; tok++)
+ *to++ = *tok;
+ *to++ = '>';
+ continue;
+ }
+ if (intoken) {
+ if (tokpos < 2045)
+ token[tokpos++] = *from;
+ token[tokpos+2] = 0;
+ }
+ else {
+ *to++ = *from;
+ lastspace = (*from == ' ');
+ }
+ }
+ *to++ = 0;
+ *to = 0;
+ }
+ return 0;
+}
diff --git a/src/modules/filters/gbfthml.cpp b/src/modules/filters/gbfthml.cpp
new file mode 100644
index 0000000..ca03e71
--- /dev/null
+++ b/src/modules/filters/gbfthml.cpp
@@ -0,0 +1,463 @@
+/***************************************************************************
+ gbfthml.cpp - GBF to ThML filter
+ -------------------
+ begin : 1999-10-27
+ copyright : 2001 by CrossWire Bible Society
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <gbfthml.h>
+
+
+GBFThML::GBFThML()
+{
+}
+
+
+char GBFThML::ProcessText(char *text, int maxlen)
+{
+ char *to, *from, token[2048];
+ int tokpos = 0;
+ bool intoken = false;
+ int len;
+ const char *tok;
+
+ len = strlen(text) + 1; // shift string to right of buffer
+ if (len < maxlen) {
+ memmove(&text[maxlen - len], text, len);
+ from = &text[maxlen - len];
+ }
+ else from = text; // -------------------------------
+
+ for (to = text; *from; from++)
+ {
+ if (*from == '<') {
+ intoken = true;
+ tokpos = 0;
+ token[0] = 0;
+ token[1] = 0;
+ token[2] = 0;
+ continue;
+ }
+ if (*from == '>')
+ {
+ intoken = false;
+ // process desired tokens
+ switch (*token) {
+ case 'W': // Strongs
+ switch(token[1]) {
+ case 'G':
+ case 'H':
+ *to++ = '<';
+ *to++ = 's';
+ *to++ = 'y';
+ *to++ = 'n';
+ *to++ = 'c';
+ *to++ = ' ';
+ *to++ = 't';
+ *to++ = 'y';
+ *to++ = 'p';
+ *to++ = 'e';
+ *to++ = '=';
+ *to++ = '"';
+ *to++ = 'S';
+ *to++ = 't';
+ *to++ = 'r';
+ *to++ = 'o';
+ *to++ = 'n';
+ *to++ = 'g';
+ *to++ = 's';
+ *to++ = '"';
+ *to++ = ' ';
+ *to++ = 'v';
+ *to++ = 'a';
+ *to++ = 'l';
+ *to++ = 'u';
+ *to++ = 'e';
+ *to++ = '=';
+ *to++ = '"';
+ for (tok = token + 1; *tok; tok++)
+ *to++ = *tok;
+ *to++ = '"';
+ *to++ = ' ';
+ *to++ = '/';
+ *to++ = '>';
+ continue;
+
+ case 'T': // Tense
+ *to++ = '<';
+ *to++ = 's';
+ *to++ = 'y';
+ *to++ = 'n';
+ *to++ = 'c';
+ *to++ = ' ';
+ *to++ = 't';
+ *to++ = 'y';
+ *to++ = 'p';
+ *to++ = 'e';
+ *to++ = '=';
+ *to++ = '"';
+ *to++ = 'M';
+ *to++ = 'o';
+ *to++ = 'r';
+ *to++ = 'p';
+ *to++ = 'h';
+ *to++ = '"';
+ *to++ = ' ';
+ *to++ = 'v';
+ *to++ = 'a';
+ *to++ = 'l';
+ *to++ = 'u';
+ *to++ = 'e';
+ *to++ = '=';
+ *to++ = '"';
+ for (tok = token + 2; *tok; tok++)
+ *to++ = *tok;
+ *to++ = '"';
+ *to++ = ' ';
+ *to++ = '/';
+ *to++ = '>';
+ continue;
+ }
+ break;
+ case 'R':
+ switch(token[1])
+ {
+ case 'X':
+ *to++ = '<';
+ *to++ = 'a';
+ *to++ = ' ';
+ *to++ = 'h';
+ *to++ = 'r';
+ *to++ = 'e';
+ *to++ = 'f';
+ *to++ = '=';
+ *to++ = '\"';
+ for (tok = token + 3; *tok; tok++) {
+ if(*tok != '<' && *tok+1 != 'R' && *tok+2 != 'x') {
+ *to++ = *tok;
+ }
+ else {
+ break;
+ }
+ }
+ *to++ = '\"';
+ *to++ = '>';
+ continue;
+ case 'x':
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'a';
+ *to++ = '>';
+ continue;
+ case 'F': // footnote begin
+ *to++ = '<';
+ *to++ = 'n';
+ *to++ = 'o';
+ *to++ = 't';
+ *to++ = 'e';
+ *to++ = ' ';
+ *to++ = 'p';
+ *to++ = 'l';
+ *to++ = 'a';
+ *to++ = 'c';
+ *to++ = 'e';
+ *to++ = '=';
+ *to++ = '"';
+ *to++ = 'f';
+ *to++ = 'o';
+ *to++ = 'o';
+ *to++ = 't';
+ *to++ = '"';
+ *to++ = '>';
+ continue;
+ case 'f': // footnote end
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'n';
+ *to++ = 'o';
+ *to++ = 't';
+ *to++ = 'e';
+ *to++ = '>';
+ continue;
+ }
+ break;
+ case 'F': // font tags
+ switch(token[1])
+ {
+ case 'N':
+ *to++ = '<';
+ *to++ = 'f';
+ *to++ = 'o';
+ *to++ = 'n';
+ *to++ = 't';
+ *to++ = ' ';
+ *to++ = 'f';
+ *to++ = 'a';
+ *to++ = 'c';
+ *to++ = 'e';
+ *to++ = '=';
+ *to++ = '"';
+ for (tok = token + 2; *tok; tok++)
+ *to++ = *tok;
+ *to++ = '"';
+ *to++ = '>';
+ continue;
+ case 'n':
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'f';
+ *to++ = 'o';
+ *to++ = 'n';
+ *to++ = 't';
+ *to++ = '>';
+ continue;
+ case 'I': // italic start
+ *to++ = '<';
+ *to++ = 'i';
+ *to++ = '>';
+ continue;
+ case 'i': // italic end
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'i';
+ *to++ = '>';
+ continue;
+ case 'B': // bold start
+ *to++ = '<';
+ *to++ = 'b';
+ *to++ = '>';
+ continue;
+ case 'b': // bold end
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'b';
+ *to++ = '>';
+ continue;
+
+ case 'R': // words of Jesus begin
+ *to++ = '<';
+ *to++ = 'f';
+ *to++ = 'o';
+ *to++ = 'n';
+ *to++ = 't';
+ *to++ = ' ';
+ *to++ = 'c';
+ *to++ = 'o';
+ *to++ = 'l';
+ *to++ = 'o';
+ *to++ = 'r';
+ *to++ = '=';
+ *to++ = '\"';
+ *to++ = '#';
+ *to++ = 'f';
+ *to++ = 'f';
+ *to++ = '0';
+ *to++ = '0';
+ *to++ = '0';
+ *to++ = '0';
+ *to++ = '\"';
+ *to++ = '>';
+ continue;
+ case 'r': // words of Jesus end
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'f';
+ *to++ = 'o';
+ *to++ = 'n';
+ *to++ = 't';
+ *to++ = '>';
+ continue;
+ case 'U': // Underline start
+ *to++ = '<';
+ *to++ = 'u';
+ *to++ = '>';
+ continue;
+ case 'u': // Underline end
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'u';
+ *to++ = '>';
+ continue;
+ case 'O': // Old Testament quote begin
+ *to++ = '<';
+ *to++ = 'c';
+ *to++ = 'i';
+ *to++ = 't';
+ *to++ = 'e';
+ *to++ = '>';
+ continue;
+ case 'o': // Old Testament quote end
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'c';
+ *to++ = 'i';
+ *to++ = 't';
+ *to++ = 'e';
+ *to++ = '>';
+ continue;
+ case 'S': // Superscript begin
+ *to++ = '<';
+ *to++ = 's';
+ *to++ = 'u';
+ *to++ = 'p';
+ *to++ = '>';
+ continue;
+ case 's': // Superscript end
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 's';
+ *to++ = 'u';
+ *to++ = 'p';
+ *to++ = '>';
+ continue;
+ case 'V': // Subscript begin
+ *to++ = '<';
+ *to++ = 's';
+ *to++ = 'u';
+ *to++ = 'b';
+ *to++ = '>';
+ continue;
+ case 'v': // Subscript end
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 's';
+ *to++ = 'u';
+ *to++ = 'b';
+ *to++ = '>';
+ continue;
+ }
+ break;
+ case 'C': // special character tags
+ switch(token[1])
+ {
+ case 'A': // ASCII value
+ *to++ = (char)atoi(&token[2]);
+ continue;
+ case 'G':
+ //*to++ = ' ';
+ continue;
+ case 'L': // line break
+ *to++ = '<';
+ *to++ = 'b';
+ *to++ = 'r';
+ *to++ = ' ';
+ *to++ = '/';
+ *to++ = '>';
+ *to++ = ' ';
+ continue;
+ case 'M': // new paragraph
+ *to++ = '<';
+ *to++ = 'p';
+ *to++ = ' ';
+ *to++ = '/';
+ *to++ = '>';
+ continue;
+ case 'T':
+ //*to++ = ' ';
+ continue;
+ }
+ break;
+ case 'T': // title formatting
+ switch(token[1])
+ {
+ case 'T': // Book title begin
+ *to++ = '<';
+ *to++ = 'b';
+ *to++ = 'i';
+ *to++ = 'g';
+ *to++ = '>';
+ continue;
+ case 't':
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'b';
+ *to++ = 'i';
+ *to++ = 'g';
+ *to++ = '>';
+ continue;
+ case 'S':
+ *to++ = '<';
+ *to++ = 'd';
+ *to++ = 'i';
+ *to++ = 'v';
+ *to++ = ' ';
+ *to++ = 'c';
+ *to++ = 'l';
+ *to++ = 'a';
+ *to++ = 's';
+ *to++ = 's';
+ *to++ = '=';
+ *to++ = '\"';
+ *to++ = 's';
+ *to++ = 'e';
+ *to++ = 'c';
+ *to++ = 'h';
+ *to++ = 'e';
+ *to++ = 'a';
+ *to++ = 'd';
+ *to++ = '\"';
+ *to++ = '>';
+ continue;
+ case 's':
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'd';
+ *to++ = 'i';
+ *to++ = 'v';
+ *to++ = '>';
+ continue;
+ }
+ break;
+
+ case 'P': // special formatting
+ switch(token[1])
+ {
+ case 'P': // Poetry begin
+ *to++ = '<';
+ *to++ = 'v';
+ *to++ = 'e';
+ *to++ = 'r';
+ *to++ = 's';
+ *to++ = 'e';
+ *to++ = '>';
+ continue;
+ case 'p':
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'v';
+ *to++ = 'e';
+ *to++ = 'r';
+ *to++ = 's';
+ *to++ = 'e';
+ *to++ = '>';
+ continue;
+ }
+ break;
+ }
+ continue;
+ }
+ if (intoken) {
+ if (tokpos < 2045)
+ token[tokpos++] = *from;
+ token[tokpos+2] = 0;
+ }
+ else *to++ = *from;
+ }
+ *to++ = 0;
+ *to = 0;
+ return 0;
+}
+
+
+
diff --git a/src/modules/filters/greeklexattribs.cpp b/src/modules/filters/greeklexattribs.cpp
new file mode 100644
index 0000000..fb166df
--- /dev/null
+++ b/src/modules/filters/greeklexattribs.cpp
@@ -0,0 +1,58 @@
+/******************************************************************************
+ *
+ * greeklexattribs - SWFilter decendant to set entry attributes for greek
+ * lexicons
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <greeklexattribs.h>
+#include <swmodule.h>
+
+
+GreekLexAttribs::GreekLexAttribs() {
+}
+
+
+char GreekLexAttribs::ProcessText(char *text, int maxlen, const SWKey *key, const SWModule *module) {
+
+ if (module->isProcessEntryAttributes()) {
+ char *from;
+ bool inAV = false;
+ string phrase;
+ string freq;
+ char *currentPhrase = 0;
+
+
+ for (from = text; *from; from++) {
+ if (inAV) {
+ if (currentPhrase == 0) {
+ if (isalpha(*from))
+ currentPhrase = from;
+ }
+ else {
+ if ((!isalpha(*from)) && (*from != ' ')) {
+ phrase = "";
+ phrase.append(currentPhrase, (int)(from - currentPhrase)-1);
+ currentPhrase = from;
+ while (*from && isdigit(*from)) from++;
+ freq = "";
+ freq.append(currentPhrase, (int)(from - currentPhrase));
+ module->getEntryAttributes()["AVPhrase"][phrase]["Frequency"] = freq;
+ currentPhrase = 0;
+ }
+ }
+ if (*from == ';') inAV = false;
+
+ }
+ else if (!strncmp(from, "AV-", 3)) {
+ inAV = true;
+ from+=2;
+ }
+ }
+ }
+ return 0;
+}
+
+
diff --git a/src/modules/filters/latin1utf16.cpp b/src/modules/filters/latin1utf16.cpp
new file mode 100644
index 0000000..75ee998
--- /dev/null
+++ b/src/modules/filters/latin1utf16.cpp
@@ -0,0 +1,120 @@
+/******************************************************************************
+ *
+ * Latin1UTF16 - SWFilter decendant to convert a Latin-1 character to UTF-16
+ *
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <latin1utf16.h>
+
+Latin1UTF16::Latin1UTF16() {
+}
+
+
+char Latin1UTF16::ProcessText(char *text, int maxlen, const SWKey *key, const SWModule *module)
+{
+ unsigned char *from;
+ unsigned short *to;
+ int len;
+
+ len = strlen(text) + 1; // shift string to right of buffer
+ if (len < maxlen) {
+ memmove(&text[maxlen - len], text, len);
+ from = (unsigned char*)&text[maxlen - len];
+ }
+ else
+ from = (unsigned char*)text;
+ // -------------------------------
+
+ for (to = (unsigned short*)text; *from; from++) {
+ switch (*from) {
+ case 0x80: // ''
+ *to++ = 0x20AC;
+ break;
+ case 0x82: // ''
+ *to++ = 0x201A;
+ break;
+ case 0x83: // ''
+ *to++ = 0x0192;
+ break;
+ case 0x84: // ''
+ *to++ = 0x201E;
+ break;
+ case 0x85: // ''
+ *to++ = 0x2026;
+ break;
+ case 0x86: // ''
+ *to++ = 0x2020;
+ break;
+ case 0x87: // ''
+ *to++ = 0x2021;
+ break;
+ case 0x88: // ''
+ *to++ = 0x02C6;
+ break;
+ case 0x89: // ''
+ *to++ = 0x2030;
+ break;
+ case 0x8A: // ''
+ *to++ = 0x0160;
+ break;
+ case 0x8B: // ''
+ *to++ = 0x2039;
+ break;
+ case 0x8C: // ''
+ *to++ = 0x0152;
+ break;
+ case 0x8E: // ''
+ *to++ = 0x017D;
+ break;
+ case 0x91: // ''
+ *to++ = 0x2018;
+ break;
+ case 0x92: // ''
+ *to++ = 0x2019;
+ break;
+ case 0x93: // ''
+ *to++ = 0x201C;
+ break;
+ case 0x94: // ''
+ *to++ = 0x201D;
+ break;
+ case 0x95: // ''
+ *to++ = 0x2022;
+ break;
+ case 0x96: // ''
+ *to++ = 0x2013;
+ break;
+ case 0x97: // ''
+ *to++ = 0x2014;
+ break;
+ case 0x98: // ''
+ *to++ = 0x02DC;
+ break;
+ case 0x99: // ''
+ *to++ = 0x2122;
+ break;
+ case 0x9A: // ''
+ *to++ = 0x0161;
+ break;
+ case 0x9B: // ''
+ *to++ = 0x203A;
+ break;
+ case 0x9C: // ''
+ *to++ = 0x0153;
+ break;
+ case 0x9E: // ''
+ *to++ = 0x017E;
+ break;
+ case 0x9F: // ''
+ *to++ = 0x0178;
+ break;
+ default:
+ *to++ = (unsigned short)*from;
+ }
+ }
+ *to = 0;
+ return 0;
+}
diff --git a/src/modules/filters/latin1utf8.cpp b/src/modules/filters/latin1utf8.cpp
new file mode 100644
index 0000000..91af8dc
--- /dev/null
+++ b/src/modules/filters/latin1utf8.cpp
@@ -0,0 +1,179 @@
+/******************************************************************************
+ *
+ * Latin1UTF8 - SWFilter decendant to convert a Latin-1 character to UTF-8
+ *
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <latin1utf8.h>
+#include <swmodule.h>
+
+Latin1UTF8::Latin1UTF8() {
+}
+
+
+char Latin1UTF8::ProcessText(char *text, int maxlen, const SWKey *key, const SWModule *module)
+{
+ unsigned char *to, *from;
+ int len;
+
+ len = strlen(text) + 1;
+ if (len == maxlen + 1)
+ maxlen = (maxlen + 1) * FILTERPAD;
+ // shift string to right of buffer
+ if (len < maxlen) {
+ memmove(&text[maxlen - len], text, len);
+ from = (unsigned char*)&text[maxlen - len];
+ }
+ else
+ from = (unsigned char*)text; // -------------------------------
+
+
+
+ for (to = (unsigned char*)text; *from; from++) {
+ if (*from < 0x80) {
+ *to++ = *from;
+ }
+ else if (*from < 0xc0) {
+ switch(*from) {
+ case 0x80: // ''
+ *to++ = 0xe2; // ''
+ *to++ = 0x82; // ''
+ *to++ = 0xac; // ''
+ break;
+ case 0x82: // ''
+ *to++ = 0xe2; // ''
+ *to++ = 0x80; // ''
+ *to++ = 0x9a; // ''
+ break;
+ case 0x83: // ''
+ *to++ = 0xc6; // ''
+ *to++ = 0x92; // ''
+ break;
+ case 0x84: // ''
+ *to++ = 0xe2; // ''
+ *to++ = 0x80; // ''
+ *to++ = 0x9e; // ''
+ break;
+ case 0x85: // ''
+ *to++ = 0xe2; // ''
+ *to++ = 0x80; // ''
+ *to++ = 0xa6; // ''
+ break;
+ case 0x86: // ''
+ *to++ = 0xe2; // ''
+ *to++ = 0x80; // ''
+ *to++ = 0xa0; // ''
+ break;
+ case 0x87: // ''
+ *to++ = 0xe2; // ''
+ *to++ = 0x80; // ''
+ *to++ = 0xa1; // ''
+ break;
+ case 0x88: // ''
+ *to++ = 0xcb; // ''
+ *to++ = 0x86; // ''
+ break;
+ case 0x89: // ''
+ *to++ = 0xe2; // ''
+ *to++ = 0x80; // ''
+ *to++ = 0xb0; // ''
+ break;
+ case 0x8A: // ''
+ *to++ = 0xc5; // ''
+ *to++ = 0xa0; // ''
+ break;
+ case 0x8B: // ''
+ *to++ = 0xe2; // ''
+ *to++ = 0x80; // ''
+ *to++ = 0xb9; // ''
+ break;
+ case 0x8C: // ''
+ *to++ = 0xc5; // ''
+ *to++ = 0x92; // ''
+ break;
+ case 0x8E: // ''
+ *to++ = 0xc5; // ''
+ *to++ = 0xbd; // ''
+ break;
+ case 0x91: // ''
+ *to++ = 0xe2; // ''
+ *to++ = 0x80; // ''
+ *to++ = 0x98; // ''
+ break;
+ case 0x92: // ''
+ *to++ = 0xe2; // ''
+ *to++ = 0x80; // ''
+ *to++ = 0x99; // ''
+ break;
+ case 0x93: // ''
+ *to++ = 0xe2; // ''
+ *to++ = 0x80; // ''
+ *to++ = 0x9c; // ''
+ break;
+ case 0x94: // ''
+ *to++ = 0xe2; // ''
+ *to++ = 0x80; // ''
+ *to++ = 0x9d; // ''
+ break;
+ case 0x95: // ''
+ *to++ = 0xe2; // ''
+ *to++ = 0x80; // ''
+ *to++ = 0xa2; // ''
+ break;
+ case 0x96: // ''
+ *to++ = 0xe2; // ''
+ *to++ = 0x80; // ''
+ *to++ = 0x93; // ''
+ break;
+ case 0x97: // ''
+ *to++ = 0xe2; // ''
+ *to++ = 0x80; // ''
+ *to++ = 0x94; // ''
+ break;
+ case 0x98: // ''
+ *to++ = 0xcb; // ''
+ *to++ = 0x9c; // ''
+ break;
+ case 0x99: // ''
+ *to++ = 0xe2; // ''
+ *to++ = 0x84; // ''
+ *to++ = 0xa2; // ''
+ break;
+ case 0x9A: // ''
+ *to++ = 0xc5; // ''
+ *to++ = 0xa1; // ''
+ break;
+ case 0x9B: // ''
+ *to++ = 0xe2; // ''
+ *to++ = 0x80; // ''
+ *to++ = 0xba; // ''
+ break;
+ case 0x9C: // ''
+ *to++ = 0xc5; // ''
+ *to++ = 0x93; // ''
+ break;
+ case 0x9E: // ''
+ *to++ = 0xc5; // ''
+ *to++ = 0xbe; // ''
+ break;
+ case 0x9F: // ''
+ *to++ = 0xc5; // ''
+ *to++ = 0xb8; // ''
+ break;
+ default:
+ *to++ = 0xC2;
+ *to++ = *from;
+ }
+ }
+ else {
+ *to++ = 0xC3;
+ *to++ = (*from - 0x40);
+ }
+ }
+ *to++ = 0;
+ *to = 0;
+ return 0;
+}
diff --git a/src/modules/filters/plainfootnotes.cpp b/src/modules/filters/plainfootnotes.cpp
new file mode 100644
index 0000000..96fc4d8
--- /dev/null
+++ b/src/modules/filters/plainfootnotes.cpp
@@ -0,0 +1,102 @@
+/***************************************************************************
+ plainfootnotes.cpp - description
+ -------------------
+ begin : Wed Oct 13 1999
+ copyright : (C) 1999 by The team of BibleTime
+ email : info@bibletime.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <plainfootnotes.h>
+#include <swkey.h>
+
+#include <stdlib.h>
+#include <string.h>
+#ifndef __GNUC__
+#else
+#include <unixstr.h>
+#endif
+
+const char PLAINFootnotes::on[] = "On";
+const char PLAINFootnotes::off[] = "Off";
+const char PLAINFootnotes::optName[] = "Footnotes";
+const char PLAINFootnotes::optTip[] = "Toggles Footnotes On and Off In Bible Texts If They Exist";
+
+PLAINFootnotes::PLAINFootnotes(){
+ option = false;
+ options.push_back(on);
+ options.push_back(off);
+}
+
+PLAINFootnotes::~PLAINFootnotes(){
+}
+
+
+void PLAINFootnotes::setOptionValue(const char *ival)
+{
+ option = (!stricmp(ival, on));
+}
+
+const char *PLAINFootnotes::getOptionValue()
+{
+ return (option) ? on:off;
+}
+
+
+char PLAINFootnotes::ProcessText(char *text, int maxlen, const SWKey *key, const SWModule *module)
+{
+ char token[2048];
+ int tokpos = 0;
+ bool intoken = false;
+ bool lastspace = false;
+
+ if (!option) { // if we don't want footnotes
+ char *to, *from;
+ int len;
+ bool hide = false;
+
+ len = strlen(text) + 1; // shift string to right of buffer
+ if (len < maxlen)
+ {
+ memmove(&text[maxlen - len], text, len);
+ from = &text[maxlen - len];
+ }
+ else from = text; // -------------------------------
+
+ for (to = text; *from; from++) {
+ if (*from == '{') // Footnote start
+ {
+ hide = true;
+ continue;
+ }
+ if (*from == '}') // Footnote end
+ {
+ hide=false;
+ continue;
+ }
+ if (intoken) {
+ if (tokpos < 2045)
+ token[tokpos++] = *from;
+ token[tokpos+2] = 0;
+ }
+ else {
+ if (!hide) {
+ *to++ = *from;
+ lastspace = (*from == ' ');
+ }
+ }
+ }
+ *to++ = 0;
+ *to = 0;
+ }
+ return 0;
+}
+
diff --git a/src/modules/filters/plainhtml.cpp b/src/modules/filters/plainhtml.cpp
new file mode 100644
index 0000000..fefb029
--- /dev/null
+++ b/src/modules/filters/plainhtml.cpp
@@ -0,0 +1,134 @@
+/***************************************************************************
+ rwphtml.cpp - description
+ -------------------
+ begin : Thu Jun 24 1999
+ copyright : (C) 1999 by Torsten Uhlmann
+ email : TUhlmann@gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <plainhtml.h>
+
+
+PLAINHTML::PLAINHTML()
+{
+}
+
+
+char PLAINHTML::ProcessText(char *text, int maxlen, const SWKey *key, const SWModule *module)
+{
+ char *to, *from;
+ int len;
+ int count = 0;
+
+ len = strlen(text) + 1; // shift string to right of buffer
+ if (len < maxlen) {
+ memmove(&text[maxlen - len], text, len);
+ from = &text[maxlen - len];
+ }
+ else from = text; // -------------------------------
+ for (to = text; *from; from++)
+ {
+ if ((*from == '\n') && (from[1] == '\n')) // paragraph
+ {
+ *to++ = '<';
+ *to++ = 'P';
+ *to++ = '>';
+ from++;
+ continue;
+ } else {
+ if ((*from == '\n')) // && (from[1] != '\n')) // new line
+ {
+ *to++ = '<';
+ *to++ = 'B';
+ *to++ = 'R';
+ *to++ = '>';
+ continue;
+ }
+ }
+
+ if (*from == '{') {
+ *to++ = '<';
+ *to++ = 'F';
+ *to++ = 'O';
+ *to++ = 'N';
+ *to++ = 'T';
+ *to++ = ' ';
+ *to++ = 'C';
+ *to++ = 'O';
+ *to++ = 'L';
+ *to++ = 'O';
+ *to++ = 'R';
+ *to++ = '=';
+ *to++ = '#';
+ *to++ = '8';
+ *to++ = '0';
+ *to++ = '0';
+ *to++ = '0';
+ *to++ = '0';
+ *to++ = '0';
+ *to++ = '>';
+
+ *to++ = '<';
+ *to++ = 'S';
+ *to++ = 'M';
+ *to++ = 'A';
+ *to++ = 'L';
+ *to++ = 'L';
+ *to++ = '>';
+ *to++ = ' ';
+ *to++ = '(';
+ continue;
+ }
+
+ if (*from == '}')
+ {
+ *to++ = ')';
+ *to++ = ' ';
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'S';
+ *to++ = 'M';
+ *to++ = 'A';
+ *to++ = 'L';
+ *to++ = 'L';
+ *to++ = '>';
+
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'F';
+ *to++ = 'O';
+ *to++ = 'N';
+ *to++ = 'T';
+ *to++ = '>';
+ continue;
+ }
+
+ if ((*from == ' ') && (count > 5000))
+ {
+ *to++ = '<';
+ *to++ = 'W';
+ *to++ = 'B';
+ *to++ = 'R';
+ *to++ = '>';
+ count = 0;
+ continue;
+ }
+
+ *to++ = *from;
+ count++;
+ }
+ *to++ = 0;
+ *to = 0;
+ return 0;
+}
diff --git a/src/modules/filters/rtfhtml.cpp b/src/modules/filters/rtfhtml.cpp
new file mode 100644
index 0000000..f0b842b
--- /dev/null
+++ b/src/modules/filters/rtfhtml.cpp
@@ -0,0 +1,99 @@
+/***************************************************************************
+ rtfhtml.cpp - description
+ -------------------
+ begin : Wed Oct 13 1999
+ copyright : (C) 1999 by The team of BibleTime
+ email : info@bibletime.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <rtfhtml.h>
+
+
+RTFHTML::RTFHTML() {
+
+}
+
+
+char RTFHTML::ProcessText(char *text, int maxlen, const SWKey *key, const SWModule *module)
+{
+ char *to, *from;
+ int len;
+ bool center = false;
+
+ len = strlen(text) + 1; // shift string to right of buffer
+ if (len < maxlen) {
+ memmove(&text[maxlen - len], text, len);
+ from = &text[maxlen - len];
+ }
+ else from = text; // -------------------------------
+ for (to = text; *from; from++) {
+ if (*from == '\\') // a RTF command
+ {
+ if ((from[1] == 'p') && (from[2] == 'a') && (from[3] == 'r') && (from[4] == 'd'))
+ { // switch all modifier off
+ if (center)
+ {
+ *to++ = '<';
+ *to++ = '/';
+ *to++ = 'C';
+ *to++ = 'E';
+ *to++ = 'N';
+ *to++ = 'T';
+ *to++ = 'E';
+ *to++ = 'R';
+ *to++ = '>';
+ center = false;
+ }
+ from += 4;
+ continue;
+ }
+ if ((from[1] == 'p') && (from[2] == 'a') && (from[3] == 'r'))
+ {
+ *to++ = '<';
+ *to++ = 'P';
+ *to++ = '>';
+ *to++ = '\n';
+ from += 3;
+ continue;
+ }
+ if (from[1] == ' ')
+ {
+ from += 1;
+ continue;
+ }
+ if ((from[1] == 'q') && (from[2] == 'c')) // center on
+ {
+ if (!center)
+ {
+ *to++ = '<';
+ *to++ = 'C';
+ *to++ = 'E';
+ *to++ = 'N';
+ *to++ = 'T';
+ *to++ = 'E';
+ *to++ = 'R';
+ *to++ = '>';
+ center = true;
+ }
+ from += 2;
+ continue;
+ }
+ }
+
+ *to++ = *from;
+ }
+ *to++ = 0;
+ *to = 0;
+ return 0;
+}
diff --git a/src/modules/filters/rwphtml.cpp b/src/modules/filters/rwphtml.cpp
new file mode 100644
index 0000000..6f8ae4f
--- /dev/null
+++ b/src/modules/filters/rwphtml.cpp
@@ -0,0 +1,187 @@
+/***************************************************************************
+ rwphtml.cpp - description
+ -------------------
+ begin : Thu Jun 24 1999
+ copyright : (C) 1999 by Torsten Uhlmann
+ email : TUhlmann@gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <rwphtml.h>
+
+RWPHTML::RWPHTML()
+{
+}
+
+
+char RWPHTML::ProcessText(char *text, int maxlen, const SWKey *key, const SWModule *module)
+{
+ char *to, *from;
+ signed char greek_str[500];
+ bool inverse = false;
+ bool first_letter = false;
+ int len;
+
+ len = strlen(text) + 1; // shift string to right of buffer
+ if (len < maxlen) {
+ memmove(&text[maxlen - len], text, len);
+ from = &text[maxlen - len];
+ } else
+ from = text;
+ for (to = text; *from; from++) {
+ if (*from == '\\') {
+ ++from;
+ int i=0;
+ first_letter = true;
+ greek_str[0] = '\0';
+ while (*from != '\\') { /* get the greek word or phrase */
+ greek_str[i++] = *from;
+ greek_str[i + 1] = '\0';
+ from++;
+ } /* convert to symbol font as best we can */
+ strcpy(to,"<I> </I><FONT FACE=\"symbol\">");
+ to += strlen(to);
+ for (int j = 0; j < i; j++) {
+ if ((first_letter)
+ && (greek_str[j] == 'h')) {
+ if (greek_str[j + 1] == 'o') {
+ *to++ = 'o';
+ first_letter = false;
+ ++j;
+ continue;
+ } else if (greek_str[j + 1] == 'a') {
+ *to++ = 'a';
+ first_letter = false;
+ ++j;
+ continue;
+ } else if (greek_str[j + 1] == 'w') {
+ *to++ = 'w';
+ first_letter = false;
+ ++j;
+ continue;
+ } else if (greek_str[j + 1] == 'u') {
+ *to++ = 'u';
+ first_letter = false;
+ ++j;
+ continue;
+ } else if (greek_str[j + 1] ==
+ -109) {
+ *to++ = 'w';
+ first_letter = false;
+ ++j;
+ continue;
+ } else if (greek_str[j + 1] ==
+ -120) {
+ *to++ = 'h';
+ first_letter = false;
+ ++j;
+ continue;
+ } else if (greek_str[j + 1] == 'i') {
+ *to++ = 'i';
+ first_letter = false;
+ ++j;
+ continue;
+ }else if (greek_str[j + 1] == 'e') {
+ *to++ = 'e';
+ first_letter = false;
+ ++j;
+ continue;
+ }
+ first_letter = false;
+ }
+ if ((greek_str[j] == 't')
+ && (greek_str[j + 1] == 'h')) {
+ *to++ = 'q';
+ ++j;
+ continue;
+ }
+ if ((greek_str[j] == 'c')
+ && (greek_str[j + 1] == 'h')) {
+ *to++ = 'c';
+ ++j;
+ continue;
+ }
+ if ((greek_str[j] == 'p')
+ && (greek_str[j + 1] == 'h')) {
+ ++j;
+ *to++ = 'f';
+ continue;
+ }
+ if (greek_str[j] == -120) {
+ *to++ = 'h';
+ continue;
+ }
+ if (greek_str[j] == -125) {
+ *to++ = 'a';
+ continue;
+ }
+ if (greek_str[j] == -109) {
+ if(greek_str[j+1] == 'i') ++j;
+ *to++ = 'w';
+ continue;
+ }
+ if (greek_str[j] == ' ')
+ first_letter = true;
+ if (greek_str[j] == 's') {
+ if(isalpha(greek_str[j + 1])) *to++ = 's';
+ else if(!isprint(greek_str[j] )) *to++ = 's';
+ else *to++ = 'V';
+ continue;
+ }
+ if (greek_str[j] == '\'') {
+ continue;
+ }
+ *to++ = greek_str[j];
+ }
+ strcpy(to,"</FONT><I> </I>");
+ to += strlen(to);
+ continue;
+ }
+ if (*from == '#') { // verse markings (e.g. "#Mark 1:1|")
+ inverse = true;
+ strcpy(to,"<FONT COLOR=#0000FF>");
+ to += strlen(to);
+ continue;
+ }
+ if ((*from == '|') && (inverse)) {
+ inverse = false;
+ strcpy(to,"</FONT>");
+ to += strlen(to);
+ continue;
+ }
+ if (*from == '{') {
+ strcpy(to,"<BR><STRONG>");
+ to += strlen(to);
+ if ((from - &text[maxlen - len]) > 10) { // not the beginning of the entry
+ strcpy(to,"<P>");
+ to += strlen(to);
+ }
+ continue;
+ }
+ if (*from == '}') {
+ strcpy(to," </STRONG>");
+ to += strlen(to);
+ continue;
+ }
+ if ((*from == '\n') && (from[1] == '\n')) {
+ strcpy(to,"<P>");
+ to += strlen(to);
+ continue;
+ }
+ *to++ = *from;
+ }
+ *to++ = 0;
+ *to = 0;
+ return 0;
+}
diff --git a/src/modules/filters/rwprtf.cpp b/src/modules/filters/rwprtf.cpp
new file mode 100644
index 0000000..8f7b074
--- /dev/null
+++ b/src/modules/filters/rwprtf.cpp
@@ -0,0 +1,107 @@
+/******************************************************************************
+ *
+ * rwprtf - SWFilter decendant to convert all GBF tags to RTF tags
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <rwprtf.h>
+
+
+RWPRTF::RWPRTF() {
+
+}
+
+
+char RWPRTF::ProcessText(char *text, int maxlen, const SWKey *key, const SWModule *module)
+{
+ char *to, *from;
+ bool ingreek = false;
+ bool inverse = false;
+ int len;
+
+ len = strlen(text) + 1; // shift string to right of buffer
+ if (len < maxlen) {
+ memmove(&text[maxlen - len], text, len);
+ from = &text[maxlen - len];
+ }
+ else from = text; // -------------------------------
+ for (to = text; *from; from++) {
+ if (*from == '\\') {
+ if(!ingreek) {
+ ingreek = true;
+ *to++ = '[';
+ *to++ = '{';
+ *to++ = '\\';
+ *to++ = 'f';
+ *to++ = '8';
+ *to++ = ' ';
+ continue;
+ }
+ else {
+ ingreek = false;
+ *to++ = '}';
+ *to++ = ']';
+ continue;
+ }
+ }
+
+ if ((ingreek) && ((*from == 'h') || (*from == 'H')))
+ continue; // 'h's are mostly useless in RWP translitterations. The greek is more correct without them.
+
+ if (*from == '#') { // verse markings (e.g. "#Mark 1:1|")
+ inverse = true;
+ *to++ = '{';
+ *to++ = '\\';
+ *to++ = 'c';
+ *to++ = 'f';
+ *to++ = '2';
+ *to++ = ' ';
+ *to++ = '#';
+ continue;
+ }
+ if ((*from == '|') && (inverse)) {
+ inverse = false;
+ *to++ = '|';
+ *to++ = '}';
+ continue;
+ }
+
+ if (*from == '{') {
+ *to++ = '{';
+ *to++ = '\\';
+ *to++ = 'b';
+ *to++ = ' ';
+ if ((from - &text[maxlen - len]) > 10) { // not the beginning of the entry
+ *to++ = '\\';
+ *to++ = 'p';
+ *to++ = 'a';
+ *to++ = 'r';
+ *to++ = ' ';
+ }
+ continue;
+ }
+
+ if (*from == '}') {
+ // this is kinda neat... DO NOTHING
+ }
+ if ((*from == '\n') && (from[1] == '\n')) {
+ *to++ = '\\';
+ *to++ = 'p';
+ *to++ = 'a';
+ *to++ = 'r';
+ *to++ = '\\';
+ *to++ = 'p';
+ *to++ = 'a';
+ *to++ = 'r';
+ *to++ = ' ';
+ continue;
+ }
+
+ *to++ = *from;
+ }
+ *to++ = 0;
+ *to = 0;
+ return 0;
+}
diff --git a/src/modules/filters/scsuutf8.cpp b/src/modules/filters/scsuutf8.cpp
new file mode 100644
index 0000000..d0d5ceb
--- /dev/null
+++ b/src/modules/filters/scsuutf8.cpp
@@ -0,0 +1,220 @@
+/******************************************************************************
+ *
+ * SCSUUTF8 - SWFilter decendant to convert a SCSU character to UTF-8
+ *
+ */
+
+
+/* This class is based on:
+ * http://czyborra.com/scsu/scsu.c written by Roman Czyborra@dds.nl
+ * on Andrea's balcony in North Amsterdam on 1998-08-04
+ * Thanks to Richard Verhoeven <rcb5@win.tue.nl> for his suggestion
+ * to correct the haphazard "if" after UQU to "else if" on 1998-10-01
+ *
+ * This is a deflator to UTF-8 output for input compressed in SCSU,
+ * the (Reuters) Standard Compression Scheme for Unicode as described
+ * in http://www.unicode.org/unicode/reports/tr6.html
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <swmodule.h>
+
+#include <scsuutf8.h>
+
+SCSUUTF8::SCSUUTF8() {
+}
+
+
+unsigned char* SCSUUTF8::UTF8Output(unsigned long uchar, unsigned char* text)
+{
+ /* join UTF-16 surrogates without any pairing sanity checks */
+
+ static int d;
+
+ if (uchar >= 0xd800 && uchar <= 0xdbff) { d = uchar & 0x3f; return text; }
+ if (uchar >= 0xdc00 && uchar <= 0xdfff) { uchar = uchar + 0x2400 + d * 0x400; }
+
+ /* output one character as UTF-8 multibyte sequence */
+
+ if (uchar < 0x80) {
+ *text++ = c;
+ }
+ else if (uchar < 0x800) {
+ *text++ = 0xc0 | uchar >> 6;
+ *text++ = 0x80 | uchar & 0x3f;
+ }
+ else if (uchar < 0x10000) {
+ *text++ = 0xe0 | uchar >> 12;
+ *text++ = 0x80 | uchar >> 6 & 0x3f;
+ *text++ = 0x80 | uchar & 0x3f;
+ }
+ else if (uchar < 0x200000) {
+ *text++ = 0xf0 | uchar >> 18;
+ *text++ = 0x80 | uchar >> 12 & 0x3f;
+ *text++ = 0x80 | uchar >> 6 & 0x3f;
+ *text++ = 0x80 | uchar & 0x3f;
+ }
+
+ return text;
+}
+
+char SCSUUTF8::ProcessText(char *text, int len, const SWKey *key, const SWModule *module)
+{
+ unsigned char *to, *from;
+ unsigned long buflen = len * FILTERPAD;
+ char active = 0, mode = 0;
+
+ static unsigned short start[8] = {0x0000,0x0080,0x0100,0x0300,0x2000,0x2080,0x2100,0x3000};
+ static unsigned short slide[8] = {0x0080,0x00C0,0x0400,0x0600,0x0900,0x3040,0x30A0,0xFF00};
+ static unsigned short win[256] = {
+ 0x0000, 0x0080, 0x0100, 0x0180, 0x0200, 0x0280, 0x0300, 0x0380,
+ 0x0400, 0x0480, 0x0500, 0x0580, 0x0600, 0x0680, 0x0700, 0x0780,
+ 0x0800, 0x0880, 0x0900, 0x0980, 0x0A00, 0x0A80, 0x0B00, 0x0B80,
+ 0x0C00, 0x0C80, 0x0D00, 0x0D80, 0x0E00, 0x0E80, 0x0F00, 0x0F80,
+ 0x1000, 0x1080, 0x1100, 0x1180, 0x1200, 0x1280, 0x1300, 0x1380,
+ 0x1400, 0x1480, 0x1500, 0x1580, 0x1600, 0x1680, 0x1700, 0x1780,
+ 0x1800, 0x1880, 0x1900, 0x1980, 0x1A00, 0x1A80, 0x1B00, 0x1B80,
+ 0x1C00, 0x1C80, 0x1D00, 0x1D80, 0x1E00, 0x1E80, 0x1F00, 0x1F80,
+ 0x2000, 0x2080, 0x2100, 0x2180, 0x2200, 0x2280, 0x2300, 0x2380,
+ 0x2400, 0x2480, 0x2500, 0x2580, 0x2600, 0x2680, 0x2700, 0x2780,
+ 0x2800, 0x2880, 0x2900, 0x2980, 0x2A00, 0x2A80, 0x2B00, 0x2B80,
+ 0x2C00, 0x2C80, 0x2D00, 0x2D80, 0x2E00, 0x2E80, 0x2F00, 0x2F80,
+ 0x3000, 0x3080, 0x3100, 0x3180, 0x3200, 0x3280, 0x3300, 0x3800,
+ 0xE000, 0xE080, 0xE100, 0xE180, 0xE200, 0xE280, 0xE300, 0xE380,
+ 0xE400, 0xE480, 0xE500, 0xE580, 0xE600, 0xE680, 0xE700, 0xE780,
+ 0xE800, 0xE880, 0xE900, 0xE980, 0xEA00, 0xEA80, 0xEB00, 0xEB80,
+ 0xEC00, 0xEC80, 0xED00, 0xED80, 0xEE00, 0xEE80, 0xEF00, 0xEF80,
+ 0xF000, 0xF080, 0xF100, 0xF180, 0xF200, 0xF280, 0xF300, 0xF380,
+ 0xF400, 0xF480, 0xF500, 0xF580, 0xF600, 0xF680, 0xF700, 0xF780,
+ 0xF800, 0xF880, 0xF900, 0xF980, 0xFA00, 0xFA80, 0xFB00, 0xFB80,
+ 0xFC00, 0xFC80, 0xFD00, 0xFD80, 0xFE00, 0xFE80, 0xFF00, 0xFF80,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x00C0, 0x0250, 0x0370, 0x0530, 0x3040, 0x30A0, 0xFF60
+ };
+
+ if (!len)
+ return 0;
+
+ memmove(&text[buflen - len], text, len);
+ from = (unsigned char*)&text[buflen - len];
+ to = (unsigned char *)text;
+
+ // -------------------------------
+
+ for (int i = 0; i < len;) {
+
+
+ if (i >= len) break;
+ c = from[i++];
+
+ if (c >= 0x80)
+ {
+ to = UTF8Output (c - 0x80 + slide[active], to);
+ }
+ else if (c >= 0x20 && c <= 0x7F)
+ {
+ to = UTF8Output (c, to);
+ }
+ else if (c == 0x0 || c == 0x9 || c == 0xA || c == 0xC || c == 0xD)
+ {
+ to = UTF8Output (c, to);
+ }
+ else if (c >= 0x1 && c <= 0x8) /* SQn */
+ {
+ if (i >= len) break;
+ /* single quote */ d = from[i++];
+
+ to = UTF8Output (d < 0x80 ? d + start [c - 0x1] :
+ d - 0x80 + slide [c - 0x1], to);
+ }
+ else if (c >= 0x10 && c <= 0x17) /* SCn */
+ {
+ /* change window */ active = c - 0x10;
+ }
+ else if (c >= 0x18 && c <= 0x1F) /* SDn */
+ {
+ /* define window */ active = c - 0x18;
+ if (i >= len) break;
+ slide [active] = win [from[i++]];
+ }
+ else if (c == 0xB) /* SDX */
+ {
+ if (i >= len) break;
+ c = from[i++];
+
+ if (i >= len) break;
+ d = from[i++];
+
+ slide [active = c>>5] = 0x10000 + (((c & 0x1F) << 8 | d) << 7);
+ }
+ else if (c == 0xE) /* SQU */
+ {
+ if (i >= len) break;
+ /* SQU */ c = from[i++];
+
+ if (i >= len) break;
+ to = UTF8Output (c << 8 | from[i++], to);
+ }
+ else if (c == 0xF) /* SCU */
+ {
+ /* change to Unicode mode */ mode = 1;
+
+ while (mode)
+ {
+ if (i >= len) break;
+ c = from[i++];
+
+ if (c <= 0xDF || c >= 0xF3)
+ {
+ if (i >= len) break;
+ to = UTF8Output (c << 8 | from[i++], to);
+ }
+ else if (c == 0xF0) /* UQU */
+ {
+ if (i >= len) break;
+ c = from[i++];
+
+ if (i >= len) break;
+ to = UTF8Output (c << 8 | from[i++], to);
+ }
+ else if (c >= 0xE0 && c <= 0xE7) /* UCn */
+ {
+ active = c - 0xE0; mode = 0;
+ }
+ else if (c >= 0xE8 && c <= 0xEF) /* UDn */
+ {
+ if (i >= len) break;
+ slide [active=c-0xE8] = win [from[i++]]; mode = 0;
+ }
+ else if (c == 0xF1) /* UDX */
+ {
+ if (i >= len) break;
+ c = from[i++];
+
+ if (i >= len) break;
+ d = from[i++];
+
+ slide [active = c>>5] =
+ 0x10000 + (((c & 0x1F) << 8 | d) << 7); mode = 0;
+ }
+ }
+ }
+
+
+ }
+
+ *to++ = 0;
+ *to = 0;
+ return 0;
+}
+
diff --git a/src/modules/filters/swbasicfilter.cpp b/src/modules/filters/swbasicfilter.cpp
new file mode 100644
index 0000000..2865085
--- /dev/null
+++ b/src/modules/filters/swbasicfilter.cpp
@@ -0,0 +1,299 @@
+/******************************************************************************
+ * swbasicfilter.h - definition of class SWBasicFilter. An SWFilter
+ * impl that provides some basic methods that
+ * many filters will need and can use as a starting
+ * point.
+ *
+ * $Id: swbasicfilter.cpp,v 1.17 2002/03/11 19:01:28 scribe Exp $
+ *
+ * Copyright 2001 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 <stdlib.h>
+#include <string.h>
+#include <swbasicfilter.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+SWBasicFilter::SWBasicFilter() {
+ tokenStart = 0;
+ tokenEnd = 0;
+ escStart = 0;
+ escEnd = 0;
+
+ setTokenStart("<");
+ setTokenEnd(">");
+ setEscapeStart("&");
+ setEscapeEnd(";");
+
+ escStringCaseSensitive = false;
+ tokenCaseSensitive = false;
+ passThruUnknownToken = false;
+ passThruUnknownEsc = false;
+}
+
+
+void SWBasicFilter::setPassThruUnknownToken(bool val) {
+ passThruUnknownToken = val;
+}
+
+
+void SWBasicFilter::setPassThruUnknownEscapeString(bool val) {
+ passThruUnknownEsc = val;
+}
+
+
+void SWBasicFilter::setTokenCaseSensitive(bool val) {
+ tokenCaseSensitive = val;
+}
+
+
+void SWBasicFilter::setEscapeStringCaseSensitive(bool val) {
+ escStringCaseSensitive = val;
+}
+
+
+SWBasicFilter::~SWBasicFilter() {
+ if (tokenStart)
+ delete [] tokenStart;
+
+ if (tokenEnd)
+ delete [] tokenEnd;
+
+ if (escStart)
+ delete [] escStart;
+
+ if (escEnd)
+ delete [] escEnd;
+}
+
+
+void SWBasicFilter::addTokenSubstitute(const char *findString, const char *replaceString) {
+ char *buf = 0;
+
+ if (!tokenCaseSensitive) {
+ stdstr(&buf, findString);
+ toupperstr(buf);
+ tokenSubMap.insert(DualStringMap::value_type(buf, replaceString));
+ delete [] buf;
+ }
+ else tokenSubMap.insert(DualStringMap::value_type(findString, replaceString));
+}
+
+
+void SWBasicFilter::addEscapeStringSubstitute(const char *findString, const char *replaceString) {
+ char *buf = 0;
+
+ if (!escStringCaseSensitive) {
+ stdstr(&buf, findString);
+ toupperstr(buf);
+ escSubMap.insert(DualStringMap::value_type(buf, replaceString));
+ delete [] buf;
+ }
+ else escSubMap.insert(DualStringMap::value_type(findString, replaceString));
+}
+
+
+void SWBasicFilter::pushString(char **buf, const char *format, ...) {
+ va_list argptr;
+
+ va_start(argptr, format);
+ *buf += vsprintf(*buf, format, argptr);
+ va_end(argptr);
+
+// *buf += strlen(*buf);
+}
+
+
+bool SWBasicFilter::substituteToken(char **buf, const char *token) {
+ DualStringMap::iterator it;
+
+ if (!tokenCaseSensitive) {
+ char *tmp = 0;
+ stdstr(&tmp, token);
+ toupperstr(tmp);
+ it = tokenSubMap.find(tmp);
+ delete [] tmp;
+ } else
+ it = tokenSubMap.find(token);
+
+ if (it != tokenSubMap.end()) {
+ pushString(buf, it->second.c_str());
+ return true;
+ }
+ return false;
+}
+
+
+bool SWBasicFilter::substituteEscapeString(char **buf, const char *escString) {
+ DualStringMap::iterator it;
+
+ if (!escStringCaseSensitive) {
+ char *tmp = 0;
+ stdstr(&tmp, escString);
+ toupperstr(tmp);
+ it = escSubMap.find(tmp);
+ delete [] tmp;
+ } else
+ it = escSubMap.find(escString);
+
+ if (it != escSubMap.end()) {
+ pushString(buf, it->second.c_str());
+ return true;
+ }
+ return false;
+}
+
+
+bool SWBasicFilter::handleToken(char **buf, const char *token, DualStringMap &userData) {
+ return substituteToken(buf, token);
+}
+
+
+bool SWBasicFilter::handleEscapeString(char **buf, const char *escString, DualStringMap &userData) {
+ return substituteEscapeString(buf, escString);
+}
+
+
+void SWBasicFilter::setEscapeStart(const char *escStart) {
+ stdstr(&(this->escStart), escStart);
+}
+
+
+void SWBasicFilter::setEscapeEnd(const char *escEnd) {
+ stdstr(&(this->escEnd), escEnd);
+}
+
+
+void SWBasicFilter::setTokenStart(const char *tokenStart) {
+ stdstr(&(this->tokenStart), tokenStart);
+}
+
+
+void SWBasicFilter::setTokenEnd(const char *tokenEnd) {
+ stdstr(&(this->tokenEnd), tokenEnd);
+}
+
+
+char SWBasicFilter::ProcessText(char *text, int maxlen, const SWKey *key, const SWModule *module) {
+ this->key = key;
+ this->module = module;
+ char *to, *from, token[4096];
+ int tokpos = 0;
+ bool intoken = false;
+ int len;
+ bool inEsc = false;
+ char escStartLen = strlen(escStart);
+ char escEndLen = strlen(escEnd);
+ char escStartPos = 0, escEndPos = 0;
+ char tokenStartLen = strlen(tokenStart);
+ char tokenEndLen = strlen(tokenEnd);
+ char tokenStartPos = 0, tokenEndPos = 0;
+ DualStringMap userData;
+ string lastTextNode;
+
+ bool suspendTextPassThru = false;
+ userData["suspendTextPassThru"] = "false";
+
+ len = strlen(text) + 1; // shift string to right of buffer
+ if (len < maxlen) {
+ memmove(&text[maxlen - len], text, len);
+ from = &text[maxlen - len];
+ }
+ else from = text; // -------------------------------
+
+
+ for (to = text; *from; from++) {
+ if (*from == tokenStart[tokenStartPos]) {
+ if (tokenStartPos == (tokenStartLen - 1)) {
+ intoken = true;
+ tokpos = 0;
+ token[0] = 0;
+ token[1] = 0;
+ token[2] = 0;
+ inEsc = false;
+ }
+ else tokenStartPos++;
+ continue;
+ }
+
+ if (*from == escStart[escStartPos]) {
+ if (escStartPos == (escStartLen - 1)) {
+ intoken = true;
+ tokpos = 0;
+ token[0] = 0;
+ token[1] = 0;
+ token[2] = 0;
+ inEsc = true;
+ }
+ else escStartPos++;
+ continue;
+ }
+
+ if (inEsc) {
+ if (*from == escEnd[escEndPos]) {
+ if (escEndPos == (escEndLen - 1)) {
+ intoken = false;
+ userData["lastTextNode"] = lastTextNode;
+ if ((!handleEscapeString(&to, token, userData)) && (passThruUnknownEsc)) {
+ pushString(&to, escStart);
+ pushString(&to, token);
+ pushString(&to, escEnd);
+ }
+ escEndPos = escStartPos = tokenEndPos = tokenStartPos = 0;
+ lastTextNode = "";
+ suspendTextPassThru = (!userData["suspendTextPassThru"].compare("true"));
+ continue;
+ }
+ }
+ }
+
+ if (!inEsc) {
+ if (*from == tokenEnd[tokenEndPos]) {
+ if (tokenEndPos == (tokenEndLen - 1)) {
+ intoken = false;
+ userData["lastTextNode"] = lastTextNode;
+ if ((!handleToken(&to, token, userData)) && (passThruUnknownToken)) {
+ pushString(&to, tokenStart);
+ pushString(&to, token);
+ pushString(&to, tokenEnd);
+ }
+ escEndPos = escStartPos = tokenEndPos = tokenStartPos = 0;
+ lastTextNode = "";
+ suspendTextPassThru = (!userData["suspendTextPassThru"].compare("true"));
+ continue;
+ }
+ }
+ }
+
+ if (intoken) {
+ if (tokpos < 4090)
+ token[tokpos++] = *from;
+ token[tokpos+2] = 0;
+ }
+ else {
+ if (!suspendTextPassThru)
+ *to++ = *from;
+ lastTextNode += *from;
+ }
+ }
+ *to++ = 0;
+ *to = 0;
+ return 0;
+}
+
+
+
diff --git a/src/modules/filters/thmlfootnotes.cpp b/src/modules/filters/thmlfootnotes.cpp
new file mode 100644
index 0000000..d9b1f0e
--- /dev/null
+++ b/src/modules/filters/thmlfootnotes.cpp
@@ -0,0 +1,103 @@
+/******************************************************************************
+ *
+ * thmlfootnotes - SWFilter decendant to hide or show footnotes
+ * in a ThML module.
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <thmlfootnotes.h>
+#ifndef __GNUC__
+#else
+#include <unixstr.h>
+#endif
+
+
+const char ThMLFootnotes::on[] = "On";
+const char ThMLFootnotes::off[] = "Off";
+const char ThMLFootnotes::optName[] = "Footnotes";
+const char ThMLFootnotes::optTip[] = "Toggles Footnotes On and Off if they exist";
+
+
+ThMLFootnotes::ThMLFootnotes() {
+ option = false;
+ options.push_back(on);
+ options.push_back(off);
+}
+
+
+ThMLFootnotes::~ThMLFootnotes() {
+}
+
+void ThMLFootnotes::setOptionValue(const char *ival)
+{
+ option = (!stricmp(ival, on));
+}
+
+const char *ThMLFootnotes::getOptionValue()
+{
+ return (option) ? on:off;
+}
+
+char ThMLFootnotes::ProcessText(char *text, int maxlen, const SWKey *key, const SWModule *module)
+{
+ if (!option) { // if we don't want footnotes
+ char *to, *from, token[2048]; // cheese. Fix.
+ int tokpos = 0;
+ bool intoken = false;
+ int len;
+ bool hide = false;
+
+ len = strlen(text) + 1; // shift string to right of buffer
+ if (len < maxlen) {
+ memmove(&text[maxlen - len], text, len);
+ from = &text[maxlen - len];
+ }
+ else from = text; // -------------------------------
+
+ for (to = text; *from; from++) {
+ if (*from == '<') {
+ intoken = true;
+ tokpos = 0;
+ token[0] = 0;
+ token[1] = 0;
+ token[2] = 0;
+ continue;
+ }
+ if (*from == '>') { // process tokens
+ intoken = false;
+ if (!strncmp(token, "note", 4)) {
+ hide = true;
+ continue;
+ }
+ else if (!strncmp(token, "/note", 5)) {
+ hide = false;
+ continue;
+ }
+
+ // if not a footnote token, keep token in text
+ if (!hide) {
+ *to++ = '<';
+ for (char *tok = token; *tok; tok++)
+ *to++ = *tok;
+ *to++ = '>';
+ }
+ continue;
+ }
+ if (intoken) {
+ if (tokpos < 2045)
+ token[tokpos++] = *from;
+ token[tokpos+2] = 0;
+ }
+ else {
+ if (!hide) {
+ *to++ = *from;
+ }
+ }
+ }
+ *to++ = 0;
+ *to = 0;
+ }
+ return 0;
+}
diff --git a/src/modules/filters/thmlgbf.cpp b/src/modules/filters/thmlgbf.cpp
new file mode 100644
index 0000000..66d9a20
--- /dev/null
+++ b/src/modules/filters/thmlgbf.cpp
@@ -0,0 +1,330 @@
+/***************************************************************************
+ thmlgbf.cpp - ThML to GBF filter
+ -------------------
+ begin : 1999-10-28
+ copyright : 2001 by CrossWire Bible Society
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <thmlgbf.h>
+
+
+ThMLGBF::ThMLGBF()
+{
+}
+
+
+char ThMLGBF::ProcessText(char *text, int maxlen)
+{
+ char *to, *from, token[2048];
+ int tokpos = 0;
+ bool intoken = false;
+ int len;
+ bool ampersand = false;
+ bool sechead = false;
+ bool title = false;
+
+ len = strlen(text) + 1; // shift string to right of buffer
+ if (len < maxlen) {
+ memmove(&text[maxlen - len], text, len);
+ from = &text[maxlen - len];
+ }
+ else from = text; // -------------------------------
+ for (to = text; *from; from++) {
+ if (*from == '<') {
+ intoken = true;
+ tokpos = 0;
+ token[0] = 0;
+ token[1] = 0;
+ token[2] = 0;
+ ampersand = false;
+ continue;
+ }
+ else if (*from == '&') {
+ intoken = true;
+ tokpos = 0;
+ memset(token, 0, 2048);
+ ampersand = true;
+ continue;
+ }
+ if (*from == ';' && ampersand) {
+ intoken = false;
+
+ if (!strncmp("nbsp", token, 4)) *to++ = ' ';
+ else if (!strncmp("quot", token, 4)) *to++ = '"';
+ else if (!strncmp("amp", token, 3)) *to++ = '&';
+ else if (!strncmp("lt", token, 2)) *to++ = '<';
+ else if (!strncmp("gt", token, 2)) *to++ = '>';
+ else if (!strncmp("brvbar", token, 6)) *to++ = '|';
+ else if (!strncmp("sect", token, 4)) *to++ = '';
+ else if (!strncmp("copy", token, 4)) *to++ = '';
+ else if (!strncmp("laquo", token, 5)) *to++ = '';
+ else if (!strncmp("reg", token, 3)) *to++ = '';
+ else if (!strncmp("acute", token, 5)) *to++ = '';
+ else if (!strncmp("para", token, 4)) *to++ = '';
+ else if (!strncmp("raquo", token, 5)) *to++ = '';
+
+ else if (!strncmp("Aacute", token, 6)) *to++ = '';
+ else if (!strncmp("Agrave", token, 6)) *to++ = '';
+ else if (!strncmp("Acirc", token, 5)) *to++ = '';
+ else if (!strncmp("Auml", token, 4)) *to++ = '';
+ else if (!strncmp("Atilde", token, 6)) *to++ = '';
+ else if (!strncmp("Aring", token, 5)) *to++ = '';
+ else if (!strncmp("aacute", token, 6)) *to++ = '';
+ else if (!strncmp("agrave", token, 6)) *to++ = '';
+ else if (!strncmp("acirc", token, 5)) *to++ = '';
+ else if (!strncmp("auml", token, 4)) *to++ = '';
+ else if (!strncmp("atilde", token, 6)) *to++ = '';
+ else if (!strncmp("aring", token, 5)) *to++ = '';
+ else if (!strncmp("Eacute", token, 6)) *to++ = '';
+ else if (!strncmp("Egrave", token, 6)) *to++ = '';
+ else if (!strncmp("Ecirc", token, 5)) *to++ = '';
+ else if (!strncmp("Euml", token, 4)) *to++ = '';
+ else if (!strncmp("eacute", token, 6)) *to++ = '';
+ else if (!strncmp("egrave", token, 6)) *to++ = '';
+ else if (!strncmp("ecirc", token, 5)) *to++ = '';
+ else if (!strncmp("euml", token, 4)) *to++ = '';
+ else if (!strncmp("Iacute", token, 6)) *to++ = '';
+ else if (!strncmp("Igrave", token, 6)) *to++ = '';
+ else if (!strncmp("Icirc", token, 5)) *to++ = '';
+ else if (!strncmp("Iuml", token, 4)) *to++ = '';
+ else if (!strncmp("iacute", token, 6)) *to++ = '';
+ else if (!strncmp("igrave", token, 6)) *to++ = '';
+ else if (!strncmp("icirc", token, 5)) *to++ = '';
+ else if (!strncmp("iuml", token, 4)) *to++ = '';
+ else if (!strncmp("Oacute", token, 6)) *to++ = '';
+ else if (!strncmp("Ograve", token, 6)) *to++ = '';
+ else if (!strncmp("Ocirc", token, 5)) *to++ = '';
+ else if (!strncmp("Ouml", token, 4)) *to++ = '';
+ else if (!strncmp("Otilde", token, 6)) *to++ = '';
+ else if (!strncmp("oacute", token, 6)) *to++ = '';
+ else if (!strncmp("ograve", token, 6)) *to++ = '';
+ else if (!strncmp("ocirc", token, 5)) *to++ = '';
+ else if (!strncmp("ouml", token, 4)) *to++ = '';
+ else if (!strncmp("otilde", token, 6)) *to++ = '';
+ else if (!strncmp("Uacute", token, 6)) *to++ = '';
+ else if (!strncmp("Ugrave", token, 6)) *to++ = '';
+ else if (!strncmp("Ucirc", token, 5)) *to++ = '';
+ else if (!strncmp("Uuml", token, 4)) *to++ = '';
+ else if (!strncmp("uacute", token, 6)) *to++ = '';
+ else if (!strncmp("ugrave", token, 6)) *to++ = '';
+ else if (!strncmp("ucirc", token, 5)) *to++ = '';
+ else if (!strncmp("uuml", token, 4)) *to++ = '';
+ else if (!strncmp("Yacute", token, 6)) *to++ = '';
+ else if (!strncmp("yacute", token, 6)) *to++ = '';
+ else if (!strncmp("yuml", token, 4)) *to++ = '';
+
+ else if (!strncmp("deg", token, 3)) *to++ = '';
+ else if (!strncmp("plusmn", token, 6)) *to++ = '';
+ else if (!strncmp("sup2", token, 4)) *to++ = '';
+ else if (!strncmp("sup3", token, 4)) *to++ = '';
+ else if (!strncmp("sup1", token, 4)) *to++ = '';
+ else if (!strncmp("nbsp", token, 4)) *to++ = '';
+ else if (!strncmp("pound", token, 5)) *to++ = '';
+ else if (!strncmp("cent", token, 4)) *to++ = '';
+ else if (!strncmp("frac14", token, 6)) *to++ = '';
+ else if (!strncmp("frac12", token, 6)) *to++ = '';
+ else if (!strncmp("frac34", token, 6)) *to++ = '';
+ else if (!strncmp("iquest", token, 6)) *to++ = '';
+ else if (!strncmp("iexcl", token, 5)) *to++ = '';
+ else if (!strncmp("ETH", token, 3)) *to++ = '';
+ else if (!strncmp("eth", token, 3)) *to++ = '';
+ else if (!strncmp("THORN", token, 5)) *to++ = '';
+ else if (!strncmp("thorn", token, 5)) *to++ = '';
+ else if (!strncmp("AElig", token, 5)) *to++ = '';
+ else if (!strncmp("aelig", token, 5)) *to++ = '';
+ else if (!strncmp("Oslash", token, 6)) *to++ = '';
+ else if (!strncmp("curren", token, 6)) *to++ = '';
+ else if (!strncmp("Ccedil", token, 6)) *to++ = '';
+ else if (!strncmp("ccedil", token, 6)) *to++ = '';
+ else if (!strncmp("szlig", token, 5)) *to++ = '';
+ else if (!strncmp("Ntilde", token, 6)) *to++ = '';
+ else if (!strncmp("ntilde", token, 6)) *to++ = '';
+ else if (!strncmp("yen", token, 3)) *to++ = '';
+ else if (!strncmp("not", token, 3)) *to++ = '';
+ else if (!strncmp("ordf", token, 4)) *to++ = '';
+ else if (!strncmp("uml", token, 3)) *to++ = '';
+ else if (!strncmp("shy", token, 3)) *to++ = '';
+ else if (!strncmp("macr", token, 4)) *to++ = '';
+ continue;
+
+ }
+ else if (*from == '>' && !ampersand) {
+ intoken = false;
+ // process desired tokens
+ if (!strncmp(token, "sync type=\"Strongs\" value=\"", 27)) {
+ *to++ = '<';
+ *to++ = 'W';
+ for (unsigned int i = 27; token[i] != '\"'; i++)
+ *to++ = token[i];
+ *to++ = '>';
+ continue;
+ }
+ if (!strncmp(token, "sync type=\"morph\" value=\"", 25)) {
+ *to++ = '<';
+ *to++ = 'W';
+ *to++ = 'T';
+ for (unsigned int i = 25; token[i] != '\"'; i++)
+ *to++ = token[i];
+ *to++ = '>';
+ continue;
+ }
+ else if (!strncmp(token, "scripRef", 8)) {
+ *to++ = '<';
+ *to++ = 'R';
+ *to++ = 'X';
+ *to++ = '>';
+ continue;
+ }
+ else if (!strncmp(token, "/scripRef", 9)) {
+ *to++ = '<';
+ *to++ = 'R';
+ *to++ = 'x';
+ *to++ = '>';
+ continue;
+ }
+ else if (!strncmp(token, "note", 4)) {
+ *to++ = '<';
+ *to++ = 'R';
+ *to++ = 'F';
+ *to++ = '>';
+ continue;
+ }
+ else if (!strncmp(token, "/note", 5)) {
+ *to++ = '<';
+ *to++ = 'R';
+ *to++ = 'f';
+ *to++ = '>';
+ continue;
+ }
+ else if (!strncmp(token, "sup", 3)) {
+ *to++ = '<';
+ *to++ = 'F';
+ *to++ = 'S';
+ *to++ = '>';
+ }
+ else if (!strncmp(token, "/sup", 4)) {
+ *to++ = '<';
+ *to++ = 'F';
+ *to++ = 's';
+ *to++ = '>';
+ }
+ else if (!strnicmp(token, "font color=#ff0000", 18)) {
+ *to++ = '<';
+ *to++ = 'F';
+ *to++ = 'R';
+ *to++ = '>';
+ continue;
+ }
+ else if (!strnicmp(token, "/font", 5)) {
+ *to++ = '<';
+ *to++ = 'F';
+ *to++ = 'r';
+ *to++ = '>';
+ continue;
+ }
+ else if (!strncmp(token, "div class=\"sechead\"", 19)) {
+ *to++ = '<';
+ *to++ = 'T';
+ *to++ = 'S';
+ *to++ = '>';
+ sechead = true;
+ continue;
+ }
+ else if (sechead && !strncmp(token, "/div", 19)) {
+ *to++ = '<';
+ *to++ = 'T';
+ *to++ = 's';
+ *to++ = '>';
+ sechead = false;
+ continue;
+ }
+ else if (!strncmp(token, "div class=\"title\"", 19)) {
+ *to++ = '<';
+ *to++ = 'T';
+ *to++ = 'T';
+ *to++ = '>';
+ title = true;
+ continue;
+ }
+ else if (title && !strncmp(token, "/div", 19)) {
+ *to++ = '<';
+ *to++ = 'T';
+ *to++ = 't';
+ *to++ = '>';
+ title = false;
+ continue;
+ }
+ else if (!strnicmp(token, "br", 2)) {
+ *to++ = '<';
+ *to++ = 'C';
+ *to++ = 'L';
+ *to++ = '>';
+ continue;
+ }
+ else switch(*token) {
+ case 'I': // font tags
+ case 'i':
+ *to++ = '<';
+ *to++ = 'F';
+ *to++ = 'I';
+ *to++ = '>';
+ continue;
+ case 'B': // bold start
+ case 'b':
+ *to++ = '<';
+ *to++ = 'F';
+ *to++ = 'B';
+ *to++ = '>';
+ continue;
+ case '/':
+ switch(token[1]) {
+ case 'P':
+ case 'p':
+ *to++ = '<';
+ *to++ = 'C';
+ *to++ = 'M';
+ *to++ = '>';
+ continue;
+ case 'I':
+ case 'i': // italic end
+ *to++ = '<';
+ *to++ = 'F';
+ *to++ = 'i';
+ *to++ = '>';
+ continue;
+ case 'B': // bold start
+ case 'b':
+ *to++ = '<';
+ *to++ = 'F';
+ *to++ = 'b';
+ *to++ = '>';
+ continue;
+ }
+ }
+ continue;
+ }
+ if (intoken) {
+ if (tokpos < 2045)
+ token[tokpos++] = *from;
+ token[tokpos+2] = 0;
+ }
+ else *to++ = *from;
+ }
+ *to++ = 0;
+ *to = 0;
+ return 0;
+}
+
+
+
diff --git a/src/modules/filters/thmlheadings.cpp b/src/modules/filters/thmlheadings.cpp
new file mode 100644
index 0000000..00b8a23
--- /dev/null
+++ b/src/modules/filters/thmlheadings.cpp
@@ -0,0 +1,107 @@
+/******************************************************************************
+ *
+ * thmlheadings - SWFilter decendant to hide or show headings
+ * in a ThML module.
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <thmlheadings.h>
+#ifndef __GNUC__
+#else
+#include <unixstr.h>
+#endif
+
+
+const char ThMLHeadings::on[] = "On";
+const char ThMLHeadings::off[] = "Off";
+const char ThMLHeadings::optName[] = "Headings";
+const char ThMLHeadings::optTip[] = "Toggles Headings On and Off if they exist";
+
+
+ThMLHeadings::ThMLHeadings() {
+ option = false;
+ options.push_back(on);
+ options.push_back(off);
+}
+
+
+ThMLHeadings::~ThMLHeadings() {
+}
+
+void ThMLHeadings::setOptionValue(const char *ival)
+{
+ option = (!stricmp(ival, on));
+}
+
+const char *ThMLHeadings::getOptionValue()
+{
+ return (option) ? on:off;
+}
+
+char ThMLHeadings::ProcessText(char *text, int maxlen, const SWKey *key, const SWModule *module)
+{
+ if (!option) { // if we don't want headings
+ char *to, *from, token[2048]; // cheese. Fix.
+ int tokpos = 0;
+ bool intoken = false;
+ int len;
+ bool hide = false;
+
+ len = strlen(text) + 1; // shift string to right of buffer
+ if (len < maxlen) {
+ memmove(&text[maxlen - len], text, len);
+ from = &text[maxlen - len];
+ }
+ else from = text; // -------------------------------
+
+ for (to = text; *from; from++) {
+ if (*from == '<') {
+ intoken = true;
+ tokpos = 0;
+ token[0] = 0;
+ token[1] = 0;
+ token[2] = 0;
+ continue;
+ }
+ if (*from == '>') { // process tokens
+ intoken = false;
+ if (!strnicmp(token, "div class=\"sechead\"", 19)) {
+ hide = true;
+ continue;
+ }
+ if (!strnicmp(token, "div class=\"title\"", 17)) {
+ hide = true;
+ continue;
+ }
+ else if (hide && !strnicmp(token, "/div", 4)) {
+ hide = false;
+ continue;
+ }
+
+ // if not a heading token, keep token in text
+ if (!hide) {
+ *to++ = '<';
+ for (char *tok = token; *tok; tok++)
+ *to++ = *tok;
+ *to++ = '>';
+ }
+ continue;
+ }
+ if (intoken) {
+ if (tokpos < 2045)
+ token[tokpos++] = *from;
+ token[tokpos+2] = 0;
+ }
+ else {
+ if (!hide) {
+ *to++ = *from;
+ }
+ }
+ }
+ *to++ = 0;
+ *to = 0;
+ }
+ return 0;
+}
diff --git a/src/modules/filters/thmlhtml.cpp b/src/modules/filters/thmlhtml.cpp
new file mode 100644
index 0000000..9cb8679
--- /dev/null
+++ b/src/modules/filters/thmlhtml.cpp
@@ -0,0 +1,211 @@
+/***************************************************************************
+ thmlhtml.cpp - ThML to HTML filter
+ -------------------
+ begin : 1999-10-27
+ copyright : 2001 by CrossWire Bible Society
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <thmlhtml.h>
+#include <swmodule.h>
+
+
+ThMLHTML::ThMLHTML() {
+ setTokenStart("<");
+ setTokenEnd(">");
+/*
+ setEscapeStart("&");
+ setEscapeEnd(";");
+
+ setEscapeStringCaseSensitive(true);
+
+ addEscapeStringSubstitute("nbsp", " ");
+ addEscapeStringSubstitute("quot", "\"");
+ addEscapeStringSubstitute("amp", "&");
+ addEscapeStringSubstitute("lt", "<");
+ addEscapeStringSubstitute("gt", ">");
+ addEscapeStringSubstitute("brvbar", "|");
+ addEscapeStringSubstitute("sect", "");
+ addEscapeStringSubstitute("copy", "");
+ addEscapeStringSubstitute("laquo", "");
+ addEscapeStringSubstitute("reg", "");
+ addEscapeStringSubstitute("acute", "");
+ addEscapeStringSubstitute("para", "");
+ addEscapeStringSubstitute("raquo", "");
+
+ addEscapeStringSubstitute("Aacute", "");
+ addEscapeStringSubstitute("Agrave", "");
+ addEscapeStringSubstitute("Acirc", "");
+ addEscapeStringSubstitute("Auml", "");
+ addEscapeStringSubstitute("Atilde", "");
+ addEscapeStringSubstitute("Aring", "");
+ addEscapeStringSubstitute("aacute", "");
+ addEscapeStringSubstitute("agrave", "");
+ addEscapeStringSubstitute("acirc", "");
+ addEscapeStringSubstitute("auml", "");
+ addEscapeStringSubstitute("atilde", "");
+ addEscapeStringSubstitute("aring", "");
+ addEscapeStringSubstitute("Eacute", "");
+ addEscapeStringSubstitute("Egrave", "");
+ addEscapeStringSubstitute("Ecirc", "");
+ addEscapeStringSubstitute("Euml", "");
+ addEscapeStringSubstitute("eacute", "");
+ addEscapeStringSubstitute("egrave", "");
+ addEscapeStringSubstitute("ecirc", "");
+ addEscapeStringSubstitute("euml", "");
+ addEscapeStringSubstitute("Iacute", "");
+ addEscapeStringSubstitute("Igrave", "");
+ addEscapeStringSubstitute("Icirc", "");
+ addEscapeStringSubstitute("Iuml", "");
+ addEscapeStringSubstitute("iacute", "");
+ addEscapeStringSubstitute("igrave", "");
+ addEscapeStringSubstitute("icirc", "");
+ addEscapeStringSubstitute("iuml", "");
+ addEscapeStringSubstitute("Oacute", "");
+ addEscapeStringSubstitute("Ograve", "");
+ addEscapeStringSubstitute("Ocirc", "");
+ addEscapeStringSubstitute("Ouml", "");
+ addEscapeStringSubstitute("Otilde", "");
+ addEscapeStringSubstitute("oacute", "");
+ addEscapeStringSubstitute("ograve", "");
+ addEscapeStringSubstitute("ocirc", "");
+ addEscapeStringSubstitute("ouml", "");
+ addEscapeStringSubstitute("otilde", "");
+ addEscapeStringSubstitute("Uacute", "");
+ addEscapeStringSubstitute("Ugrave", "");
+ addEscapeStringSubstitute("Ucirc", "");
+ addEscapeStringSubstitute("Uuml", "");
+ addEscapeStringSubstitute("uacute", "");
+ addEscapeStringSubstitute("ugrave", "");
+ addEscapeStringSubstitute("ucirc", "");
+ addEscapeStringSubstitute("uuml", "");
+ addEscapeStringSubstitute("Yacute", "");
+ addEscapeStringSubstitute("yacute", "");
+ addEscapeStringSubstitute("yuml", "");
+
+ addEscapeStringSubstitute("deg", "");
+ addEscapeStringSubstitute("plusmn", "");
+ addEscapeStringSubstitute("sup2", "");
+ addEscapeStringSubstitute("sup3", "");
+ addEscapeStringSubstitute("sup1", "");
+ addEscapeStringSubstitute("nbsp", "");
+ addEscapeStringSubstitute("pound", "");
+ addEscapeStringSubstitute("cent", "");
+ addEscapeStringSubstitute("frac14", "");
+ addEscapeStringSubstitute("frac12", "");
+ addEscapeStringSubstitute("frac34", "");
+ addEscapeStringSubstitute("iquest", "");
+ addEscapeStringSubstitute("iexcl", "");
+ addEscapeStringSubstitute("ETH", "");
+ addEscapeStringSubstitute("eth", "");
+ addEscapeStringSubstitute("THORN", "");
+ addEscapeStringSubstitute("thorn", "");
+ addEscapeStringSubstitute("AElig", "");
+ addEscapeStringSubstitute("aelig", "");
+ addEscapeStringSubstitute("Oslash", "");
+ addEscapeStringSubstitute("curren", "");
+ addEscapeStringSubstitute("Ccedil", "");
+ addEscapeStringSubstitute("ccedil", "");
+ addEscapeStringSubstitute("szlig", "");
+ addEscapeStringSubstitute("Ntilde", "");
+ addEscapeStringSubstitute("ntilde", "");
+ addEscapeStringSubstitute("yen", "");
+ addEscapeStringSubstitute("not", "");
+ addEscapeStringSubstitute("ordf", "");
+ addEscapeStringSubstitute("uml", "");
+ addEscapeStringSubstitute("shy", "");
+ addEscapeStringSubstitute("macr", "");
+*/
+ setTokenCaseSensitive(true);
+
+ addTokenSubstitute("/scripRef", " </a>");
+ addTokenSubstitute("note", " <font color=\"#800000\"><small>(");
+ addTokenSubstitute("/note", ")</small></font> ");
+}
+
+
+bool ThMLHTML::handleToken(char **buf, const char *token, DualStringMap &userData) {
+ if (!substituteToken(buf, token)) {
+ // manually process if it wasn't a simple substitution
+ if (!strncmp(token, "sync type=\"Strongs\" value=\"", 27)) {
+ if (token[27] == 'H' || token[27] == 'G' || token[27] == 'A') {
+ pushString(buf, "<small><em>");
+ for (const char *tok = token + 5; *tok; tok++)
+ if(*tok != '\"')
+ *(*buf)++ = *tok;
+ pushString(buf, "</em></small>");
+ }
+ else if (token[27] == 'T') {
+ pushString(buf, "<small><i>");
+ for (unsigned int i = 29; token[i] != '\"'; i++)
+ *(*buf)++ = token[i];
+ pushString(buf, "</i></small>");
+ }
+ }
+ else if (!strncmp(token, "sync type=\"morph\" value=\"", 25)) {
+ pushString(buf, "<small><em>");
+ for (unsigned int i = 25; token[i] != '\"'; i++)
+ *(*buf)++ = token[i];
+ pushString(buf, "</em></small>");
+ }
+ else if (!strncmp(token, "sync type=\"lemma\" value=\"", 25)) {
+ pushString(buf, "<small><em>(");
+ for (unsigned int i = 25; token[i] != '\"'; i++)
+ *(*buf)++ = token[i];
+ pushString(buf, ")</em></small>");
+ }
+ else if (!strncmp(token, "scripRef", 8)) {
+ pushString(buf, "<a href=\"");
+ for (const char *tok = token + 9; *tok; tok++)
+ if(*tok != '\"')
+ *(*buf)++ = *tok;
+ *(*buf)++ = '\"';
+ *(*buf)++ = '>';
+ }
+ else if (!strncmp(token, "img ", 4)) {
+ const char *src = strstr(token, "src");
+ if (!src) // assert we have a src attribute
+ return false;
+
+ *(*buf)++ = '<';
+ for (const char *c = token; *c; c++) {
+ if (c == src) {
+ for (;((*c) && (*c != '"')); c++)
+ *(*buf)++ = *c;
+
+ if (!*c) { c--; continue; }
+
+ *(*buf)++ = '"';
+ if (*(c+1) == '/') {
+ pushString(buf, "file:");
+ pushString(buf, module->getConfigEntry("AbsoluteDataPath"));
+ if (*((*buf)-1) == '/')
+ c++; // skip '/'
+ }
+ continue;
+ }
+ *(*buf)++ = *c;
+ }
+ *(*buf)++ = '>';
+ }
+ else if(!strncmp(token, "note", 4)) {
+ pushString(buf, " <font color=\"#800000\"><small>(");
+ }
+
+ else {
+ return false; // we still didn't handle token
+ }
+ }
+ return true;
+}
+
diff --git a/src/modules/filters/thmlhtmlhref.cpp b/src/modules/filters/thmlhtmlhref.cpp
new file mode 100644
index 0000000..ce7e3fd
--- /dev/null
+++ b/src/modules/filters/thmlhtmlhref.cpp
@@ -0,0 +1,269 @@
+/***************************************************************************
+ thmlhtmlhref.cpp - ThML to HTML filter with hrefs
+ -------------------
+ begin : 2001-09-03
+ copyright : 2001 by CrossWire Bible Society
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <thmlhtmlhref.h>
+#include <swmodule.h>
+
+
+ThMLHTMLHREF::ThMLHTMLHREF() {
+ setTokenStart("<");
+ setTokenEnd(">");
+/*
+ setEscapeStart("&");
+ setEscapeEnd(";");
+
+ setEscapeStringCaseSensitive(true);
+
+ addEscapeStringSubstitute("nbsp", " ");
+ addEscapeStringSubstitute("quot", "\"");
+ addEscapeStringSubstitute("amp", "&");
+ addEscapeStringSubstitute("lt", "<");
+ addEscapeStringSubstitute("gt", ">");
+ addEscapeStringSubstitute("brvbar", "|");
+ addEscapeStringSubstitute("sect", "");
+ addEscapeStringSubstitute("copy", "");
+ addEscapeStringSubstitute("laquo", "");
+ addEscapeStringSubstitute("reg", "");
+ addEscapeStringSubstitute("acute", "");
+ addEscapeStringSubstitute("para", "");
+ addEscapeStringSubstitute("raquo", "");
+
+ addEscapeStringSubstitute("Aacute", "");
+ addEscapeStringSubstitute("Agrave", "");
+ addEscapeStringSubstitute("Acirc", "");
+ addEscapeStringSubstitute("Auml", "");
+ addEscapeStringSubstitute("Atilde", "");
+ addEscapeStringSubstitute("Aring", "");
+ addEscapeStringSubstitute("aacute", "");
+ addEscapeStringSubstitute("agrave", "");
+ addEscapeStringSubstitute("acirc", "");
+ addEscapeStringSubstitute("auml", "");
+ addEscapeStringSubstitute("atilde", "");
+ addEscapeStringSubstitute("aring", "");
+ addEscapeStringSubstitute("Eacute", "");
+ addEscapeStringSubstitute("Egrave", "");
+ addEscapeStringSubstitute("Ecirc", "");
+ addEscapeStringSubstitute("Euml", "");
+ addEscapeStringSubstitute("eacute", "");
+ addEscapeStringSubstitute("egrave", "");
+ addEscapeStringSubstitute("ecirc", "");
+ addEscapeStringSubstitute("euml", "");
+ addEscapeStringSubstitute("Iacute", "");
+ addEscapeStringSubstitute("Igrave", "");
+ addEscapeStringSubstitute("Icirc", "");
+ addEscapeStringSubstitute("Iuml", "");
+ addEscapeStringSubstitute("iacute", "");
+ addEscapeStringSubstitute("igrave", "");
+ addEscapeStringSubstitute("icirc", "");
+ addEscapeStringSubstitute("iuml", "");
+ addEscapeStringSubstitute("Oacute", "");
+ addEscapeStringSubstitute("Ograve", "");
+ addEscapeStringSubstitute("Ocirc", "");
+ addEscapeStringSubstitute("Ouml", "");
+ addEscapeStringSubstitute("Otilde", "");
+ addEscapeStringSubstitute("oacute", "");
+ addEscapeStringSubstitute("ograve", "");
+ addEscapeStringSubstitute("ocirc", "");
+ addEscapeStringSubstitute("ouml", "");
+ addEscapeStringSubstitute("otilde", "");
+ addEscapeStringSubstitute("Uacute", "");
+ addEscapeStringSubstitute("Ugrave", "");
+ addEscapeStringSubstitute("Ucirc", "");
+ addEscapeStringSubstitute("Uuml", "");
+ addEscapeStringSubstitute("uacute", "");
+ addEscapeStringSubstitute("ugrave", "");
+ addEscapeStringSubstitute("ucirc", "");
+ addEscapeStringSubstitute("uuml", "");
+ addEscapeStringSubstitute("Yacute", "");
+ addEscapeStringSubstitute("yacute", "");
+ addEscapeStringSubstitute("yuml", "");
+
+ addEscapeStringSubstitute("deg", "");
+ addEscapeStringSubstitute("plusmn", "");
+ addEscapeStringSubstitute("sup2", "");
+ addEscapeStringSubstitute("sup3", "");
+ addEscapeStringSubstitute("sup1", "");
+ addEscapeStringSubstitute("nbsp", "");
+ addEscapeStringSubstitute("pound", "");
+ addEscapeStringSubstitute("cent", "");
+ addEscapeStringSubstitute("frac14", "");
+ addEscapeStringSubstitute("frac12", "");
+ addEscapeStringSubstitute("frac34", "");
+ addEscapeStringSubstitute("iquest", "");
+ addEscapeStringSubstitute("iexcl", "");
+ addEscapeStringSubstitute("ETH", "");
+ addEscapeStringSubstitute("eth", "");
+ addEscapeStringSubstitute("THORN", "");
+ addEscapeStringSubstitute("thorn", "");
+ addEscapeStringSubstitute("AElig", "");
+ addEscapeStringSubstitute("aelig", "");
+ addEscapeStringSubstitute("Oslash", "");
+ addEscapeStringSubstitute("curren", "");
+ addEscapeStringSubstitute("Ccedil", "");
+ addEscapeStringSubstitute("ccedil", "");
+ addEscapeStringSubstitute("szlig", "");
+ addEscapeStringSubstitute("Ntilde", "");
+ addEscapeStringSubstitute("ntilde", "");
+ addEscapeStringSubstitute("yen", "");
+ addEscapeStringSubstitute("not", "");
+ addEscapeStringSubstitute("ordf", "");
+ addEscapeStringSubstitute("uml", "");
+ addEscapeStringSubstitute("shy", "");
+ addEscapeStringSubstitute("macr", "");
+*/
+ setTokenCaseSensitive(true);
+
+ addTokenSubstitute("note", " <font color=\"#800000\"><small>(");
+ addTokenSubstitute("/note", ")</small></font> ");
+ addTokenSubstitute("/scripture", "</i> ");
+}
+
+
+bool ThMLHTMLHREF::handleToken(char **buf, const char *token, DualStringMap &userData) {
+ const char *tok;
+ if (!substituteToken(buf, token)) {
+ // manually process if it wasn't a simple substitution
+ if (!strncmp(token, "sync ", 5)) {
+ pushString(buf, "<a href=\"");
+ for (tok = token + 5; *(tok+1); tok++)
+ if(*tok != '\"')
+ *(*buf)++ = *tok;
+ *(*buf)++ = '\"';
+ *(*buf)++ = '>';
+
+ //scan for value and add it to the buffer
+ for (tok = token + 5; *tok; tok++) {
+ if (!strncmp(tok, "value=\"", 7)) {
+ tok += 7;
+ for (;*tok != '\"'; tok++)
+ *(*buf)++ = *tok;
+ break;
+ }
+ }
+ pushString(buf, "</a>");
+ }
+
+ else if (!strncmp(token, "scripture ", 10)) {
+ userData["inscriptRef"] = "true";
+ pushString(buf, "<i>");
+ }
+
+ else if (!strncmp(token, "scripRef p", 10) || !strncmp(token, "scripRef v", 10)) {
+ userData["inscriptRef"] = "true";
+ pushString(buf, "<a href=\"");
+ for (const char *tok = token + 9; *(tok+1); tok++)
+ if(*tok != '\"')
+ *(*buf)++ = *tok;
+ *(*buf)++ = '\"';
+ *(*buf)++ = '>';
+ }
+
+ // we're starting a scripRef like "<scripRef>John 3:16</scripRef>"
+ else if (!strcmp(token, "scripRef")) {
+ userData["inscriptRef"] = "false";
+ // let's stop text from going to output
+ userData["suspendTextPassThru"] = "true";
+ }
+
+ // we've ended a scripRef
+ else if (!strcmp(token, "/scripRef")) {
+ if (userData["inscriptRef"] == "true") { // like "<scripRef passage="John 3:16">John 3:16</scripRef>"
+ userData["inscriptRef"] = "false";
+ pushString(buf, "</a>");
+ }
+
+ else { // like "<scripRef>John 3:16</scripRef>"
+ pushString(buf, "<a href=\"passage=");
+ //char *strbuf = (char *)userData["lastTextNode"].c_str();
+ pushString(buf, userData["lastTextNode"].c_str());
+ *(*buf)++ = '\"';
+ *(*buf)++ = '>';
+ pushString(buf, userData["lastTextNode"].c_str());
+ // let's let text resume to output again
+ userData["suspendTextPassThru"] = "false";
+ pushString(buf, "</a>");
+ }
+ }
+
+ else if (!strncmp(token, "div class=\"sechead\"", 19)) {