The SWORD Project  1.9.0.svnversion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
versificationmgr.cpp
Go to the documentation of this file.
1 /******************************************************************************
2  *
3  * versificationmgr.cpp - implementation of class VersificationMgr used
4  * for managing versification systems
5  *
6  * $Id: versificationmgr.cpp 3822 2020-11-03 18:54:47Z scribe $
7  *
8  * Copyright 2008-2013 CrossWire Bible Society (http://www.crosswire.org)
9  * CrossWire Bible Society
10  * P. O. Box 2528
11  * Tempe, AZ 85280-2528
12  *
13  * This program is free software; you can redistribute it and/or modify it
14  * under the terms of the GNU General Public License as published by the
15  * Free Software Foundation version 2.
16  *
17  * This program is distributed in the hope that it will be useful, but
18  * WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20  * General Public License for more details.
21  *
22  */
23 
24 #include <versificationmgr.h>
25 #include <vector>
26 #include <map>
27 #include <treekey.h>
28 #include <canon.h> // KJV internal versification system
29 #include <swlog.h>
30 #include <algorithm>
31 
32 #include <canon_null.h> // null v11n system
33 
34 #include <canon_leningrad.h> // Leningrad Codex (WLC) v11n system
35 #include <canon_mt.h> // Masoretic Text (MT) v11n system
36 #include <canon_kjva.h> // KJV + Apocrypha v11n system
37 #include <canon_nrsv.h> // NRSV v11n system
38 #include <canon_nrsva.h> // NRSV + Apocrypha v11n system
39 #include <canon_synodal.h> // Russian Synodal v11n system
40 #include <canon_synodalprot.h> // Russian Synodal v11n system
41 #include <canon_vulg.h> // Vulgate v11n system
42 #include <canon_german.h> // German v11n system
43 #include <canon_luther.h> // Luther v11n system
44 #include <canon_catholic.h> // Catholic v11n system (10 chapter Esther)
45 #include <canon_catholic2.h> // Catholic2 v11n system (16 chapter Esther)
46 #include <canon_lxx.h> // General LXX v11n system (includes GNT, as used in Orthodox Bibles)
47 #include <canon_orthodox.h> // Orthodox v11n system as used in Orthodox Bibles
48 #include <canon_segond.h> // French v11n system as used by Segond Bibles and its derivatives
49 #include <canon_calvin.h> // French v11n system
50 #include <canon_darbyfr.h> // French v11n system based on John Darby's French translation
51 
52 using std::vector;
53 using std::map;
54 using std::distance;
55 using std::lower_bound;
56 
57 
59 
60 
82  }
84 }
85 
86 
88 public:
90  vector<Book> books;
91  map<SWBuf, int> osisLookup;
105  typedef vector<const unsigned char*> mappingRule;
106  vector<mappingRule> mappings;
107  vector<const char*> mappingsExtraBooks;
108 
110  }
112  books = other.books;
113  osisLookup = other.osisLookup;
114  }
116  books = other.books;
117  osisLookup = other.osisLookup;
118  return *this;
119  }
120 };
121 
122 
124 friend struct BookOffsetLess;
125 public:
127  vector<int> verseMax;
128  vector<long> offsetPrecomputed;
129 
131  verseMax.clear();
132  }
134  verseMax.clear();
135  verseMax = other.verseMax;
137  }
139  verseMax.clear();
140  int s = (int)other.verseMax.size();
141  if (s) verseMax = other.verseMax;
143  return *this;
144  }
145 };
146 
147 
149  bool operator() (const VersificationMgr::Book &o1, const VersificationMgr::Book &o2) const { return o1.p->offsetPrecomputed[0] < o2.p->offsetPrecomputed[0]; }
150  bool operator() (const long &o1, const VersificationMgr::Book &o2) const { return o1 < o2.p->offsetPrecomputed[0]; }
151  bool operator() (const VersificationMgr::Book &o1, const long &o2) const { return o1.p->offsetPrecomputed[0] < o2; }
152  bool operator() (const long &o1, const long &o2) const { return o1 < o2; }
153 };
154 
155 
157  p = new Private();
158 }
159 
160 
162  p = new Private();
163  BMAX[0] = 0;
164  BMAX[1] = 0;
165  ntStartOffset = 0;
166 }
167 
168 
170  init();
171  name = other.name;
172  BMAX[0] = other.BMAX[0];
173  BMAX[1] = other.BMAX[1];
174  (*p) = *(other.p);
175  ntStartOffset = other.ntStartOffset;
176 }
177 
178 
180  name = other.name;
181  BMAX[0] = other.BMAX[0];
182  BMAX[1] = other.BMAX[1];
183  (*p) = *(other.p);
184  ntStartOffset = other.ntStartOffset;
185  return *this;
186 }
187 
188 
190  delete p;
191 }
192 
193 
195  return (number < (signed int)p->books.size()) ? &(p->books[number]) : 0;
196 }
197 
198 
199 int VersificationMgr::System::getBookNumberByOSISName(const char *bookName) const {
200  map<SWBuf, int>::const_iterator it = p->osisLookup.find(bookName);
201  return (it != p->osisLookup.end()) ? it->second : -1;
202 }
203 
204 
205 void VersificationMgr::System::loadFromSBook(const sbook *ot, const sbook *nt, int *chMax, const unsigned char *mappings) {
206  int chap = 0;
207  int book = 0;
208  long offset = 0; // module heading
209  offset++; // testament heading
210  while (ot->chapmax) {
211  p->books.push_back(Book(ot->name, ot->osis, ot->prefAbbrev, ot->chapmax));
212  offset++; // book heading
213  Book &b = p->books[p->books.size()-1];
214  p->osisLookup[b.getOSISName()] = (int)p->books.size();
215  for (int i = 0; i < ot->chapmax; i++) {
216  b.p->verseMax.push_back(chMax[chap]);
217  offset++; // chapter heading
218  b.p->offsetPrecomputed.push_back(offset);
219  offset += chMax[chap++];
220  }
221  ot++;
222  book++;
223  }
224  BMAX[0] = book;
225  book = 0;
226  ntStartOffset = offset;
227  offset++; // testament heading
228  while (nt->chapmax) {
229  p->books.push_back(Book(nt->name, nt->osis, nt->prefAbbrev, nt->chapmax));
230  offset++; // book heading
231  Book &b = p->books[p->books.size()-1];
232  p->osisLookup[b.getOSISName()] = (int)p->books.size();
233  for (int i = 0; i < nt->chapmax; i++) {
234  b.p->verseMax.push_back(chMax[chap]);
235  offset++; // chapter heading
236  b.p->offsetPrecomputed.push_back(offset);
237  offset += chMax[chap++];
238  }
239  nt++;
240  book++;
241  }
242  BMAX[1] = book;
243 
244  // TODO: build offset speed array
245 
246  // parse mappings
247  if (mappings != NULL) {
248  const unsigned char *m=mappings;
249  for (; *m != 0; m += strlen((const char*)m)+1) {
250  p->mappingsExtraBooks.push_back((const char*)m);
251  }
252  p->mappings.resize(p->books.size()+p->mappingsExtraBooks.size());
253 
254  for (++m; *m != 0; m += 7) {
255  p->mappings[m[0]-1].push_back(m);
256  if (*m > p->books.size()) {
257  p->mappings[m[7]-1].push_back(m);
258  m += 1;
259  }
260  }
261  }
262 }
263 
264 
266  longName = other.longName;
267  osisName = other.osisName;
268  prefAbbrev = other.prefAbbrev;
269  chapMax = other.chapMax;
270  init();
271  (*p) = *(other.p);
272 }
273 
274 
276  longName = other.longName;
277  osisName = other.osisName;
278  prefAbbrev = other.prefAbbrev;
279  chapMax = other.chapMax;
280  init();
281  (*p) = *(other.p);
282  return *this;
283 }
284 
285 
287  delete p;
288 }
289 
290 
291 int VersificationMgr::Book::getVerseMax(int chapter) const {
292  chapter--;
293  return (p && (chapter < (signed int)p->verseMax.size()) && (chapter > -1)) ? p->verseMax[chapter] : -1;
294 }
295 
296 
298  return (int)(p ? p->books.size() : 0);
299 }
300 
301 
302 long VersificationMgr::System::getOffsetFromVerse(int book, int chapter, int verse) const {
303  long offset = -1;
304  chapter--;
305 
306  const Book *b = getBook(book);
307 
308  if (!b) return -1; // assert we have a valid book
309  if ((chapter > -1) && (chapter >= (signed int)b->p->offsetPrecomputed.size())) return -1; // assert we have a valid chapter
310 
311  offset = b->p->offsetPrecomputed[(chapter > -1)?chapter:0];
312  if (chapter < 0) offset--;
313 
314 /* old code
315  *
316  offset = offsets[testament-1][0][book];
317  offset = offsets[testament-1][1][(int)offset + chapter];
318  if (!(offset|verse)) // if we have a testament but nothing else.
319  offset = 1;
320 
321 */
322 
323  return (offset + verse);
324 }
325 
326 
327 char VersificationMgr::System::getVerseFromOffset(long offset, int *book, int *chapter, int *verse) const {
328 
329  if (offset < 1) { // just handle the module heading corner case up front (and error case)
330  (*book) = -1;
331  (*chapter) = 0;
332  (*verse) = 0;
333  return offset; // < 0 = error
334  }
335 
336  // binary search for book
337  vector<Book>::iterator b = lower_bound(p->books.begin(), p->books.end(), offset, BookOffsetLess());
338  if (b == p->books.end()) b--;
339  (*book) = distance(p->books.begin(), b)+1;
340  if (offset < (*(b->p->offsetPrecomputed.begin()))-((((!(*book)) || (*book)==BMAX[0]+1))?2:1)) { // -1 for chapter headings
341  (*book)--;
342  if (b != p->books.begin()) {
343  b--;
344  }
345  }
346  vector<long>::iterator c = lower_bound(b->p->offsetPrecomputed.begin(), b->p->offsetPrecomputed.end(), offset);
347 
348  // if we're a book heading, we are lessthan chapter precomputes, but greater book. This catches corner case.
349  if (c == b->p->offsetPrecomputed.end()) {
350  c--;
351  }
352  if ((offset < *c) && (c == b->p->offsetPrecomputed.begin())) {
353  (*chapter) = (offset - *c)+1; // should be 0 or -1 (for testament heading)
354  (*verse) = 0;
355  }
356  else {
357  if (offset < *c) c--;
358  (*chapter) = distance(b->p->offsetPrecomputed.begin(), c)+1;
359  (*verse) = (offset - *c);
360  }
361  return ((*chapter > 0) && (*verse > b->getVerseMax(*chapter))) ? KEYERR_OUTOFBOUNDS : 0;
362 }
363 
364 
365 /***************************************************
366  * VersificationMgr
367  */
368 
370 public:
372  }
374  systems = other.systems;
375  }
377  systems = other.systems;
378  return *this;
379  }
380  map<SWBuf, System> systems;
381 };
382 // ---------------- statics -----------------
384 
386 public:
390 
391 
393  p = new Private();
394 }
395 
396 
398  delete p;
399 }
400 
401 
404  delete systemVersificationMgr;
405  systemVersificationMgr = newVersificationMgr;
406 }
407 
408 
410  map<SWBuf, System>::const_iterator it = p->systems.find(name);
411  return (it != p->systems.end()) ? &(it->second) : 0;
412 }
413 
414 
415 void VersificationMgr::registerVersificationSystem(const char *name, const sbook *ot, const sbook *nt, int *chMax, const unsigned char *mappings) {
416  p->systems[name] = name;
417  System &s = p->systems[name];
418  s.loadFromSBook(ot, nt, chMax, mappings);
419 }
420 
421 
422 void VersificationMgr::registerVersificationSystem(const char *name, const TreeKey *tk) {
423 }
424 
425 
427  StringList retVal;
428  for (map<SWBuf, System>::const_iterator it = p->systems.begin(); it != p->systems.end(); it++) {
429  retVal.push_back(it->first);
430  }
431  return retVal;
432 }
433 
434 void VersificationMgr::System::translateVerse(const System *dstSys, const char **book, int *chapter, int *verse, int *verse_end) const {
435 //dbg_mapping SWLOGD("translate verse from %s to %s: %s.%i.%i-%i\n",getName(), dstSys->getName(), *book, *chapter, *verse, *verse_end);
436 
437  if (!strcmp(getName(),"KJVA") || !strcmp(getName(),"KJV")) {
438  if (!strcmp(dstSys->getName(),"KJVA") || !strcmp(dstSys->getName(),"KJV"))
439  return;
440  // reversed mapping
441  //dbg_mapping SWLOGD("Perform reversed mapping.\n");
442  int b = dstSys->getBookNumberByOSISName(*book)-1;
443 
444  //dbg_mapping SWLOGD("\tgetBookNumberByOSISName %i %s.\n", b, *book);
445 
446  if (b < 0) {
447  //dbg_mapping SWLOGD("\tmappingsExtraBooks.size() %i.\n", dstSys->p->mappingsExtraBooks.size());
448  for (int i=0; i<(int)dstSys->p->mappingsExtraBooks.size(); ++i) {
449  //dbg_mapping SWLOGD("\t%s %s.\n", *book, dstSys->p->mappingsExtraBooks[i]);
450  if (!strcmp(*book, dstSys->p->mappingsExtraBooks[i])) {
451  b = (int)p->books.size()+i-2;
452  break;
453  }
454  }
455  }
456 
457  //dbg_mapping SWLOGD("\tb %i.\n", b);
458 
459  if (b >= (int)dstSys->p->mappings.size() || b < 0) {
460  //dbg_mapping SWLOGD("no modification");
461  return;
462  }
463 
464  const unsigned char *a = NULL;
465 
466  // reversed mapping should use forward search for item
467  for (unsigned int i=0; i<dstSys->p->mappings[b].size(); ++i) {
468  const unsigned char *m = dstSys->p->mappings[b][i];
469 
470  if (m[0] != b+1) continue; // filter inter-book rules
471 
472  if (m[4] == *chapter && m[5] <= *verse) {
473  //dbg_mapping SWLOGD("found mapping %i %i %i %i %i %i\n",m[1],m[2],m[3],m[4],m[5],m[6]);
474  if (m[5] == *verse || (m[6] >= *verse && m[5] <= *verse)) {
475  // inside of any mapping range
476  *chapter = m[1];
477  *verse = m[2];
478  *verse_end = m[3];
479  if (*m >= dstSys->p->books.size()) {
480  SWLog::getSystemLog()->logWarning("map to extra books, possible bug source\n");
481  *book = dstSys->getBook(m[7]-1)->getOSISName();
482  }
483  return;
484  }
485  // destination mapping can have duplicate items, use the last (by using <=)
486  if (a == NULL || (a[5]>a[6]?a[5]:a[6]) <= (m[5]>m[6]?m[5]:m[6]))
487  a = m;
488  }
489  }
490  if (a != NULL) {
491  //dbg_mapping SWLOGD("set appropriate: %i %i %i %i %i %i\n",a[1],a[2],a[3],a[4],a[5],a[6]);
492  (*chapter) = a[1];
493  // shift verse
494  const int d = (a[3]>a[2]?a[3]:a[2])-(a[6]>a[5]?a[6]:a[5]);
495  if (*verse < *verse_end)
496  *verse_end += d;
497  else
498  *verse_end = (*verse) + d;
499  *verse += d;
500  if (*a > dstSys->p->books.size()) {
501  //dbg_mapping SWLOGD("appropriate: %i %i %i %i %i %i %i %i\n",a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7]);
502  //dbg_mapping SWLOGD("book: %s\n", dstSys->getBook(a[7]-1)->getOSISName());
503  *book = dstSys->getBook(a[7]-1)->getOSISName();
504  }
505  return;
506  }
507  //dbg_mapping SWLOGD("There is no mapping.\n");
508  }
509  else if (strcmp(dstSys->getName(),"KJVA") && strcmp(dstSys->getName(),"KJV")) {
511  const int src_verse = *verse;
512 
513  translateVerse(kjva, book, chapter, verse, verse_end);
514 
515  int interm_verse = *verse, interm_range = *verse_end, interm_chapter = *chapter;
516  const char *interm_book = *book;
517 
518  kjva->translateVerse(dstSys, book, chapter, verse, verse_end);
519 
520  // contraction->expansion fix
521  if (verse < verse_end && !(interm_verse < interm_range)) {
522  kjva->translateVerse(this, &interm_book, &interm_chapter, &interm_verse, &interm_range);
523  if (interm_verse < interm_range) {
524  *verse += src_verse - interm_verse;
525  if (*verse > *verse_end)
526  *verse = *verse_end;
527  else
528  *verse_end = *verse;
529  }
530  }
531  }
532  else {
533  //dbg_mapping SWLOGD("Perform forward mapping.\n");
534  const int b = getBookNumberByOSISName(*book)-1;
535  if (b >= (int)p->mappings.size())
536  return;
537  // forward mapping should use reversed search for item
538  for (int i = (int)p->mappings[b].size()-1; i>=0; --i) {
539  const unsigned char *m = p->mappings[b][i];
540  if (m[1] < *chapter) {
541  SWLog::getSystemLog()->logWarning("There is no mapping for this chapter.\n");
542  return;
543  }
544  if (m[1] == *chapter && m[2] <= *verse) {
545  //dbg_mapping SWLOGD("found mapping %i %i %i %i %i %i\n",m[1],m[2],m[3],m[4],m[5],m[6]);
546  if (m[2] == *verse || (m[3] >= *verse && m[2] <= *verse)) {
547  *chapter = m[4];
548  *verse = m[5];
549  *verse_end = m[6];
550  }
551  else {
552  *chapter = m[4];
553  // shift verse
554  const int d = (m[6]>m[5]?m[6]:m[5])-(m[3]>m[2]?m[3]:m[2]);
555  if (*verse < *verse_end)
556  *verse_end += d;
557  else
558  *verse_end = (*verse) + d;
559  *verse += d;
560  }
561  if (*m > p->books.size())
562  *book = p->mappingsExtraBooks[m[0]-p->books.size()-1];
563  return;
564  }
565  }
566  //dbg_mapping SWLOGD("No mapping.\n");
567  }
568 }
569 
571 
SWORD_NAMESPACE_START int vm_nrsv[]
Definition: canon_nrsv.h:43
int vm_synodal[]
#define SWORD_NAMESPACE_START
Definition: defs.h:39
SWORD_NAMESPACE_START struct sbook otbooks_german[]
Definition: canon_german.h:35
SWORD_NAMESPACE_START struct sbook otbooks_luther[]
Definition: canon_luther.h:35
Book & operator=(const Book &other)
unsigned char mappings_synodal[]
long getOffsetFromVerse(int book, int chapter, int verse) const
static SWLog * getSystemLog()
Definition: swlog.cpp:53
SWORD_NAMESPACE_START struct sbook otbooks_lxx[]
Definition: canon_lxx.h:48
unsigned char mappings_nrsv[]
Definition: canon_nrsv.h:267
Private(const VersificationMgr::Private &other)
SWORD_NAMESPACE_START int vm_segond[]
Definition: canon_segond.h:50
SWORD_NAMESPACE_START struct sbook otbooks_kjva[]
Definition: canon_kjva.h:35
class __staticsystemVersificationMgr _staticsystemVersificationMgr
Private(const VersificationMgr::System::Private &other)
SWORD_NAMESPACE_START struct sbook otbooks_catholic2[]
int vm_german[]
Definition: canon_german.h:82
unsigned char mappings_segond[]
Definition: canon_segond.h:275
void loadFromSBook(const sbook *ot, const sbook *nt, int *chMax, const unsigned char *mappings=NULL)
unsigned char mappings_calvin[]
Definition: canon_calvin.h:292
SWORD_NAMESPACE_START struct sbook otbooks[]
Definition: canon.h:35
struct sbook ntbooks[]
Definition: canon.h:77
struct sbook ntbooks_synodal[]
Definition: canon_synodal.h:97
const char * osis
char getVerseFromOffset(long offset, int *book, int *chapter, int *verse) const
const Book * getBook(int number) const
int vm_mt[]
Definition: canon_mt.h:84
System & operator=(const System &other)
return NULL
Definition: regex.c:7953
void registerVersificationSystem(const char *name, const sbook *ot, const sbook *nt, int *chMax, const unsigned char *mappings=NULL)
SWORD_NAMESPACE_START struct sbook otbooks_nrsva[]
Definition: canon_nrsva.h:34
struct sbook ntbooks_luther[]
Definition: canon_luther.h:88
int vm_leningrad[]
std::list< SWBuf > StringList
Definition: swmodule.cpp:91
map< SWBuf, System > systems
SWORD_NAMESPACE_START struct sbook otbooks_vulg[]
Definition: canon_vulg.h:39
unsigned char chapmax
int vm_vulg[]
Definition: canon_vulg.h:129
SWORD_NAMESPACE_START struct sbook otbooks_orthodox[]
SWORD_NAMESPACE_START struct sbook otbooks_leningrad[]
VersificationMgr::System::Private & operator=(const VersificationMgr::System::Private &other)
vector< const unsigned char * > mappingRule
void translateVerse(const System *dstSys, const char **book, int *chapter, int *verse, int *verse_end) const
SWORD_NAMESPACE_START int vm_calvin[]
Definition: canon_calvin.h:67
int getBookNumberByOSISName(const char *bookName) const
const StringList getVersificationSystems() const
int vm_luther[]
Definition: canon_luther.h:123
#define KEYERR_OUTOFBOUNDS
Definition: swkey.h:35
const char * getOSISName() const
const char * getName() const
static void setSystemVersificationMgr(VersificationMgr *newVersificationMgr)
const char * name
int vm_lxx[]
Definition: canon_lxx.h:114
const char * prefAbbrev
SWORD_NAMESPACE_START struct sbook otbooks_mt[]
Definition: canon_mt.h:35
void logWarning(const char *fmt,...) const
Definition: swlog.cpp:74
int vm_nrsva[]
Definition: canon_nrsva.h:100
struct sbook ntbooks_vulg[]
Definition: canon_vulg.h:89
SWORD_NAMESPACE_START struct sbook otbooks_synodalProt[]
int vm_catholic2[]
int vm[]
Definition: canon.h:112
SWORD_NAMESPACE_START int vm_darbyfr[]
Definition: canon_darbyfr.h:49
static VersificationMgr * systemVersificationMgr
int getVerseMax(int chapter) const
int vm_synodalProt[]
vector< const char * > mappingsExtraBooks
SWORD_NAMESPACE_START struct sbook otbooks_synodal[]
Definition: canon_synodal.h:42
unsigned char mappings_vulg[]
Definition: canon_vulg.h:389
#define SWORD_NAMESPACE_END
Definition: defs.h:40
bool operator()(const VersificationMgr::Book &o1, const VersificationMgr::Book &o2) const
int vm_kjva[]
Definition: canon_kjva.h:98
VersificationMgr::Book::Private & operator=(const VersificationMgr::Book::Private &other)
Private(const VersificationMgr::Book::Private &other)
static VersificationMgr * getSystemVersificationMgr()
int vm_orthodox[]
const System * getVersificationSystem(const char *name) const
struct sbook ntbooks_null[]
Definition: canon_null.h:40
int vm_catholic[]
unsigned char mappings_darbyfr[]
SWORD_NAMESPACE_START struct sbook otbooks_catholic[]