summaryrefslogtreecommitdiff
path: root/src/mgr/versemgr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mgr/versemgr.cpp')
-rw-r--r--src/mgr/versemgr.cpp369
1 files changed, 369 insertions, 0 deletions
diff --git a/src/mgr/versemgr.cpp b/src/mgr/versemgr.cpp
new file mode 100644
index 0000000..0673746
--- /dev/null
+++ b/src/mgr/versemgr.cpp
@@ -0,0 +1,369 @@
+/******************************************************************************
+ * versemgr.cpp - implementation of class VerseMgr used for managing
+ * versification systems
+ *
+ * $Id: versemgr.cpp 2108 2007-10-13 20:35:02Z scribe $
+ *
+ * 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 <versemgr.h>
+#include <vector>
+#include <map>
+#include <treekey.h>
+#include <canon.h> // KJV internal versification system
+#include <swlog.h>
+#include <algorithm>
+
+#include <canon_null.h> // null v11n system
+
+#include <canon_leningrad.h> // Leningrad Codex (WLC) v11n system
+#include <canon_mt.h> // Masoretic Text (MT) v11n system
+#include <canon_kjva.h> // KJV + Apocrypha v11n system
+#include <canon_nrsv.h> // NRSV v11n system
+#include <canon_nrsva.h> // NRSVA + Apocrypha v11n system
+
+using std::vector;
+using std::map;
+using std::distance;
+using std::lower_bound;
+
+SWORD_NAMESPACE_START
+
+
+VerseMgr *VerseMgr::getSystemVerseMgr() {
+ if (!systemVerseMgr) {
+ systemVerseMgr = new VerseMgr();
+ systemVerseMgr->registerVersificationSystem("KJV", otbooks, ntbooks, vm);
+ systemVerseMgr->registerVersificationSystem("Leningrad", otbooks_leningrad, ntbooks_null, vm_leningrad);
+ systemVerseMgr->registerVersificationSystem("MT", otbooks_mt, ntbooks_null, vm_mt);
+ systemVerseMgr->registerVersificationSystem("KJVA", otbooks_kjva, ntbooks, vm_kjva);
+ systemVerseMgr->registerVersificationSystem("NRSV", otbooks, ntbooks, vm_nrsv);
+ systemVerseMgr->registerVersificationSystem("NRSVA", otbooks_nrsva, ntbooks, vm_nrsva);
+ }
+ return systemVerseMgr;
+}
+
+
+class VerseMgr::System::Private {
+public:
+ /** Array[chapmax] of maximum verses in chapters */
+ vector<Book> books;
+ map<SWBuf, int> osisLookup;
+
+ Private() {
+ }
+ Private(const VerseMgr::System::Private &other) {
+ books = other.books;
+ osisLookup = other.osisLookup;
+ }
+ VerseMgr::System::Private &operator =(const VerseMgr::System::Private &other) {
+ books = other.books;
+ osisLookup = other.osisLookup;
+ return *this;
+ }
+};
+
+
+class VerseMgr::Book::Private {
+friend struct BookOffsetLess;
+public:
+ /** Array[chapmax] of maximum verses in chapters */
+ vector<int> verseMax;
+ vector<long> offsetPrecomputed;
+
+ Private() {
+ verseMax.clear();
+ }
+ Private(const VerseMgr::Book::Private &other) {
+ verseMax.clear();
+ verseMax = other.verseMax;
+ offsetPrecomputed = other.offsetPrecomputed;
+ }
+ VerseMgr::Book::Private &operator =(const VerseMgr::Book::Private &other) {
+ verseMax.clear();
+ verseMax = other.verseMax;
+ offsetPrecomputed = other.offsetPrecomputed;
+ return *this;
+ }
+};
+
+struct BookOffsetLess {
+ bool operator() (const VerseMgr::Book &o1, const VerseMgr::Book &o2) const { return o1.p->offsetPrecomputed[0] < o2.p->offsetPrecomputed[0]; }
+ bool operator() (const long &o1, const VerseMgr::Book &o2) const { return o1 < o2.p->offsetPrecomputed[0]; }
+ bool operator() (const VerseMgr::Book &o1, const long &o2) const { return o1.p->offsetPrecomputed[0] < o2; }
+ bool operator() (const long &o1, const long &o2) const { return o1 < o2; }
+};
+
+void VerseMgr::Book::init() {
+ p = new Private();
+}
+
+void VerseMgr::System::init() {
+ p = new Private();
+ BMAX[0] = 0;
+ BMAX[1] = 0;
+ ntStartOffset = 0;
+}
+
+
+VerseMgr::System::System(const System &other) {
+ init();
+ name = other.name;
+ BMAX[0] = other.BMAX[0];
+ BMAX[1] = other.BMAX[1];
+ (*p) = *(other.p);
+ ntStartOffset = other.ntStartOffset;
+}
+
+VerseMgr::System &VerseMgr::System::operator =(const System &other) {
+ name = other.name;
+ BMAX[0] = other.BMAX[0];
+ BMAX[1] = other.BMAX[1];
+ (*p) = *(other.p);
+ ntStartOffset = other.ntStartOffset;
+ return *this;
+}
+
+
+VerseMgr::System::~System() {
+ delete p;
+}
+
+const VerseMgr::Book *VerseMgr::System::getBook(int number) const {
+ return (number < (signed int)p->books.size()) ? &(p->books[number]) : 0;
+}
+
+
+int VerseMgr::System::getBookNumberByOSISName(const char *bookName) const {
+ map<SWBuf, int>::const_iterator it = p->osisLookup.find(bookName);
+ return (it != p->osisLookup.end()) ? it->second : -1;
+}
+
+
+void VerseMgr::System::loadFromSBook(const sbook *ot, const sbook *nt, int *chMax) {
+ int chap = 0;
+ int book = 0;
+ long offset = 0; // module heading
+ offset++; // testament heading
+ while (ot->chapmax) {
+ p->books.push_back(Book(ot->name, ot->osis, ot->prefAbbrev, ot->chapmax));
+ offset++; // book heading
+ Book &b = p->books[p->books.size()-1];
+ p->osisLookup[b.getOSISName()] = p->books.size();
+ for (int i = 0; i < ot->chapmax; i++) {
+ b.p->verseMax.push_back(chMax[chap]);
+ offset++; // chapter heading
+ b.p->offsetPrecomputed.push_back(offset);
+ offset += chMax[chap++];
+ }
+ ot++;
+ book++;
+ }
+ BMAX[0] = book;
+ book = 0;
+ ntStartOffset = offset;
+ offset++; // testament heading
+ while (nt->chapmax) {
+ p->books.push_back(Book(nt->name, nt->osis, nt->prefAbbrev, nt->chapmax));
+ offset++; // book heading
+ Book &b = p->books[p->books.size()-1];
+ p->osisLookup[b.getOSISName()] = p->books.size();
+ for (int i = 0; i < nt->chapmax; i++) {
+ b.p->verseMax.push_back(chMax[chap]);
+ offset++; // chapter heading
+ b.p->offsetPrecomputed.push_back(offset);
+ offset += chMax[chap++];
+ }
+ nt++;
+ book++;
+ }
+ BMAX[1] = book;
+
+ // TODO: build offset speed array
+}
+
+
+VerseMgr::Book::Book(const Book &other) {
+ longName = other.longName;
+ osisName = other.osisName;
+ prefAbbrev = other.prefAbbrev;
+ chapMax = other.chapMax;
+ init();
+ (*p) = *(other.p);
+}
+
+VerseMgr::Book& VerseMgr::Book::operator =(const Book &other) {
+ longName = other.longName;
+ osisName = other.osisName;
+ prefAbbrev = other.prefAbbrev;
+ chapMax = other.chapMax;
+ init();
+ (*p) = *(other.p);
+ return *this;
+}
+
+
+VerseMgr::Book::~Book() {
+ delete p;
+}
+
+
+int VerseMgr::Book::getVerseMax(int chapter) const {
+ chapter--;
+ return (p && (chapter < (signed int)p->verseMax.size()) && (chapter > -1)) ? p->verseMax[chapter] : -1;
+}
+
+
+int VerseMgr::System::getBookCount() const {
+ return (p ? p->books.size() : 0);
+}
+
+
+long VerseMgr::System::getOffsetFromVerse(int book, int chapter, int verse) const {
+ long offset = -1;
+ chapter--;
+
+ const Book *b = getBook(book);
+
+ if (!b) return -1; // assert we have a valid book
+ if ((chapter > -1) && (chapter >= (signed int)b->p->offsetPrecomputed.size())) return -1; // assert we have a valid chapter
+
+ offset = b->p->offsetPrecomputed[(chapter > -1)?chapter:0];
+ if (chapter < 0) offset--;
+
+/* old code
+ *
+ 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);
+}
+
+
+char VerseMgr::System::getVerseFromOffset(long offset, int *book, int *chapter, int *verse) const {
+
+ if (offset < 1) { // just handle the module heading corner case up front (and error case)
+ (*book) = -1;
+ (*chapter) = 0;
+ (*verse) = 0;
+ return offset; // < 0 = error
+ }
+
+ // binary search for book
+ vector<Book>::iterator b = lower_bound(p->books.begin(), p->books.end(), offset, BookOffsetLess());
+ if (b == p->books.end()) b--;
+ (*book) = distance(p->books.begin(), b)+1;
+ if (offset < (*(b->p->offsetPrecomputed.begin()))-((((!(*book)) || (*book)==BMAX[0]+1))?2:1)) { // -1 for chapter headings
+ (*book)--;
+ if (b != p->books.begin()) {
+ b--;
+ }
+ }
+ vector<long>::iterator c = lower_bound(b->p->offsetPrecomputed.begin(), b->p->offsetPrecomputed.end(), offset);
+
+ // if we're a book heading, we are lessthan chapter precomputes, but greater book. This catches corner case.
+ if (c == b->p->offsetPrecomputed.end()) {
+ c--;
+ }
+ if ((offset < *c) && (c == b->p->offsetPrecomputed.begin())) {
+ (*chapter) = (offset - *c)+1; // should be 0 or -1 (for testament heading)
+ (*verse) = 0;
+ }
+ else {
+ if (offset < *c) c--;
+ (*chapter) = distance(b->p->offsetPrecomputed.begin(), c)+1;
+ (*verse) = (offset - *c);
+ }
+ return ((*chapter > 0) && (*verse > b->getVerseMax(*chapter))) ? KEYERR_OUTOFBOUNDS : 0;
+}
+
+
+/***************************************************
+ * VerseMgr
+ */
+
+class VerseMgr::Private {
+public:
+ Private() {
+ }
+ Private(const VerseMgr::Private &other) {
+ systems = other.systems;
+ }
+ VerseMgr::Private &operator =(const VerseMgr::Private &other) {
+ systems = other.systems;
+ return *this;
+ }
+ map<SWBuf, System> systems;
+};
+// ---------------- statics -----------------
+VerseMgr *VerseMgr::systemVerseMgr = 0;
+
+class __staticsystemVerseMgr {
+public:
+ __staticsystemVerseMgr() { }
+ ~__staticsystemVerseMgr() { delete VerseMgr::systemVerseMgr; }
+} _staticsystemVerseMgr;
+
+
+void VerseMgr::init() {
+ p = new Private();
+}
+
+
+VerseMgr::~VerseMgr() {
+ delete p;
+}
+
+
+void VerseMgr::setSystemVerseMgr(VerseMgr *newVerseMgr) {
+ if (systemVerseMgr)
+ delete systemVerseMgr;
+ systemVerseMgr = newVerseMgr;
+}
+
+
+const VerseMgr::System *VerseMgr::getVersificationSystem(const char *name) const {
+ map<SWBuf, System>::const_iterator it = p->systems.find(name);
+ return (it != p->systems.end()) ? &(it->second) : 0;
+}
+
+
+void VerseMgr::registerVersificationSystem(const char *name, const sbook *ot, const sbook *nt, int *chMax) {
+ p->systems[name] = name;
+ System &s = p->systems[name];
+ s.loadFromSBook(ot, nt, chMax);
+}
+
+
+void VerseMgr::registerVersificationSystem(const char *name, const TreeKey *tk) {
+}
+
+
+const StringList VerseMgr::getVersificationSystems() const {
+ StringList retVal;
+ for (map<SWBuf, System>::const_iterator it = p->systems.begin(); it != p->systems.end(); it++) {
+ retVal.push_back(it->first);
+ }
+ return retVal;
+}
+
+
+SWORD_NAMESPACE_END