The SWORD Project  1.9.0.svnversion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
treekeyidx.cpp
Go to the documentation of this file.
1 /******************************************************************************
2  *
3  * treekeyidx.cpp -
4  *
5  * $Id: treekeyidx.cpp 3822 2020-11-03 18:54:47Z scribe $
6  *
7  * Copyright 2002-2013 CrossWire Bible Society (http://www.crosswire.org)
8  * CrossWire Bible Society
9  * P. O. Box 2528
10  * Tempe, AZ 85280-2528
11  *
12  * This program is free software; you can redistribute it and/or modify it
13  * under the terms of the GNU General Public License as published by the
14  * Free Software Foundation version 2.
15  *
16  * This program is distributed in the hope that it will be useful, but
17  * WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * General Public License for more details.
20  *
21  */
22 
23 
24 #include <treekeyidx.h>
25 #include <fcntl.h>
26 #include <stdio.h>
27 #include <errno.h>
28 
29 #include <swlog.h>
30 #include <utilstr.h>
31 #include <filemgr.h>
32 #include <swbuf.h>
33 
35 
36 
37 static const char *classes[] = {"TreeKeyIdx", "TreeKey", "SWKey", "SWObject", 0};
38 static const SWClass classdef(classes);
39 
40 
41 TreeKeyIdx::TreeKeyIdx(const TreeKeyIdx &ikey) : currentNode() {
42  init();
43  path = 0;
44  idxfd = 0;
45  datfd = 0;
46  copyFrom(ikey);
47 }
48 
49 TreeKeyIdx::TreeKeyIdx(const char *idxPath, int fileMode) : currentNode() {
50  SWBuf buf;
51 
52  init();
53  path = 0;
54  stdstr(&path, idxPath);
55 
56  if (fileMode == -1) { // try read/write if possible
57  fileMode = FileMgr::RDWR;
58  }
59 
60  buf.setFormatted("%s.idx", path);
61  idxfd = FileMgr::getSystemFileMgr()->open(buf, fileMode, true);
62  buf.setFormatted("%s.dat", path);
63  datfd = FileMgr::getSystemFileMgr()->open(buf, fileMode, true);
64 
65  if (!datfd || datfd->getFd() < 0) {
66 // couldn't find datafile but this might be fine if we're
67 // merely instantiating a remote InstallMgr SWMgr
68 SWLOGD("Couldn't open file: %s. errno: %d", buf.c_str(), errno);
69  error = errno;
70  }
71  else {
72  root();
73  }
74 }
75 
76 
78  myClass = &classdef;
79 }
80 
81 
83  if (path)
84  delete [] path;
85 
88 }
89 
90 
91 const char *TreeKeyIdx::getLocalName() {
92  unsnappedKeyText = "";
93  return currentNode.name;
94 }
95 
96 
97 const char *TreeKeyIdx::getUserData(int *size) const {
98  unsnappedKeyText = "";
99  if (size)
100  *size = (int)currentNode.dsize;
101  return currentNode.userData;
102 }
103 
104 
105 void TreeKeyIdx::setUserData(const char *userData, int size) {
106  // this makes sure any unsnapped path exists
107  assureKeyPath();
108  if (currentNode.userData)
109  delete currentNode.userData;
110 
111  if (!size)
112  size = (int)strlen(userData) + 1;
113 
114  currentNode.userData = new char [ size ];
115  memcpy(currentNode.userData, userData, size);
117 }
118 
119 const char *TreeKeyIdx::setLocalName(const char *newName) {
120  unsnappedKeyText = "";
121  stdstr(&(currentNode.name), newName);
122  return currentNode.name;
123 }
124 
125 
128 }
129 
130 
133  positionChanged();
134 }
135 
137  TreeNode iterator;
138  iterator.parent = currentNode.parent;
139  int level = 0;
140  while (iterator.parent > -1) {
141  level++;
142  getTreeNodeFromIdxOffset(iterator.parent, &iterator);
143  }
144  return level;
145 }
146 
147 
149  if (currentNode.parent > -1) {
151  positionChanged();
152  return true;
153  }
154  return false;
155 }
156 
157 
159  if (currentNode.firstChild > -1) {
161  positionChanged();
162  return true;
163  }
164  return false;
165 }
166 
167 
169  if (currentNode.next > -1) {
171  positionChanged();
172  return true;
173  }
174  return false;
175 }
176 
177 
179  TreeNode iterator;
180  SW_s32 target = currentNode.offset;
181  if (currentNode.parent > -1) {
183  getTreeNodeFromIdxOffset(iterator.firstChild, &iterator);
184  if (iterator.offset != target) {
185  while ((iterator.next != target) && (iterator.next > -1))
186  getTreeNodeFromIdxOffset(iterator.next, &iterator);
187  if (iterator.next > -1) {
189  positionChanged();
190  return true;
191  }
192  }
193  }
194  return false;
195 }
196 
197 
199  return (currentNode.firstChild > -1);
200 }
201 
202 
204  TreeNode lastSib;
205  if (currentNode.offset) {
207  while (lastSib.next > -1) {
208  getTreeNodeFromIdxOffset(lastSib.next, &lastSib);
209  }
210  SW_u32 idxOffset = (SW_u32)idxfd->seek(0, SEEK_END);
211  lastSib.next = idxOffset;
212  saveTreeNodeOffsets(&lastSib);
214  currentNode.clear();
215  currentNode.offset = idxOffset;
217  positionChanged();
218  }
219 }
220 
221 
223  if (firstChild()) {
224  append();
225  }
226  else {
227  SW_u32 idxOffset = (SW_u32)idxfd->seek(0, SEEK_END);
228  currentNode.firstChild = idxOffset;
231  currentNode.clear();
232  currentNode.offset = idxOffset;
234  }
235  positionChanged();
236 }
237 
238 
240 }
241 
242 
244  TreeNode node;
245  bool done = false;
246  if (currentNode.offset) {
248  if (node.parent > -1) {
250  getTreeNodeFromIdxOffset(node.parent, &parent);
251  if (parent.firstChild == node.offset) {
252  parent.firstChild = node.next;
253  saveTreeNodeOffsets(&parent);
255  done = true;
256  }
257  }
258  if (!done) {
259  TreeNode iterator;
260  SW_s32 target = currentNode.offset;
261  if (currentNode.parent > -1) {
263  getTreeNodeFromIdxOffset(iterator.firstChild, &iterator);
264  if (iterator.offset != target) {
265  while ((iterator.next != target) && (iterator.next > -1)) {
266  getTreeNodeFromIdxOffset(iterator.next, &iterator);
267  }
268  if (iterator.next > -1) {
269  TreeNode prev;
270  getTreeNodeFromIdxOffset(iterator.offset, &prev);
271  prev.next = node.next;
272  saveTreeNodeOffsets(&prev);
274  }
275  }
276  }
277  }
278  positionChanged();
279  }
280 }
281 
282 
283 /******************************************************************************
284  * TreeKeyIdx::Create - Creates new key idx/dat files
285  *
286  * ENT: path - directory to store module files
287  * RET: error status
288  */
289 
290 signed char TreeKeyIdx::create(const char *ipath) {
291  char *path = 0;
292  char *buf = new char [ strlen (ipath) + 20 ];
293  FileDesc *fd, *fd2;
294 
295  stdstr(&path, ipath);
296 
297  if ((path[strlen(path)-1] == '/') || (path[strlen(path)-1] == '\\'))
298  path[strlen(path)-1] = 0;
299 
300  sprintf(buf, "%s.dat", path);
301  FileMgr::removeFile(buf);
303  fd->getFd();
305 
306  sprintf(buf, "%s.idx", path);
307  FileMgr::removeFile(buf);
309  fd2->getFd();
311  TreeKeyIdx newTree(path);
313  stdstr(&(root.name), "");
314  newTree.saveTreeNode(&root);
315 
316  delete [] path;
317 
318  return 0;
319 }
320 
321 
322 /******************************************************************************
323  * zStr::getidxbufdat - Gets the index string at the given dat offset
324  * NOTE: buf is calloc'd, or if not null, realloc'd and must
325  * be free'd by calling function
326  *
327  * ENT: ioffset - offset in dat file to lookup
328  * node - address of pointer to allocate for storage of string
329  */
330 
331 void TreeKeyIdx::getTreeNodeFromDatOffset(long ioffset, TreeNode *node) const {
332  unsnappedKeyText = "";
333  char ch;
334  SW_s32 tmp;
335  SW_u16 tmp2;
336 
337  if (datfd && datfd->getFd() >= 0) {
338 
339  datfd->seek(ioffset, SEEK_SET);
340 
341  datfd->read(&tmp, 4);
342  node->parent = swordtoarch32(tmp);
343 
344  datfd->read(&tmp, 4);
345  node->next = swordtoarch32(tmp);
346 
347  datfd->read(&tmp, 4);
348  node->firstChild = swordtoarch32(tmp);
349 
350  SWBuf name;
351  do {
352  datfd->read(&ch, 1);
353  name += ch;
354  } while (ch);
355 
356  stdstr(&(node->name), name.c_str());
357 
358  datfd->read(&tmp2, 2);
359  node->dsize = swordtoarch16(tmp2);
360 
361  if (node->dsize) {
362  if (node->userData)
363  delete [] node->userData;
364  node->userData = new char [node->dsize];
365  datfd->read(node->userData, node->dsize);
366  }
367  }
368 }
369 
370 
371 /******************************************************************************
372  * zStr::getidxbuf - Gets the index string at the given idx offset
373  * NOTE: buf is calloc'd, or if not null, realloc'd
374  * and must be freed by calling function
375  *
376  * ENT: ioffset - offset in idx file to lookup
377  * buf - address of pointer to allocate for storage of string
378  */
379 
380 char TreeKeyIdx::getTreeNodeFromIdxOffset(long ioffset, TreeNode *node) const {
381  unsnappedKeyText = "";
382  SW_u32 offset;
383  char error = KEYERR_OUTOFBOUNDS;
384 
385  if (ioffset < 0) {
386  ioffset = 0;
387  error = 77; // out of bounds but still position to 0;
388  }
389 
390  node->offset = (SW_s32)ioffset;
391  if (idxfd && idxfd->getFd() >= 0) {
392  idxfd->seek(ioffset, SEEK_SET);
393  if (idxfd->read(&offset, 4) == 4) {
394  offset = swordtoarch32(offset);
395  error = (error == 77) ? KEYERR_OUTOFBOUNDS : 0;
396  getTreeNodeFromDatOffset(offset, node);
397  }
398  else {
399  idxfd->seek(-4, SEEK_END);
400  if (idxfd->read(&offset, 4) == 4) {
401  offset = swordtoarch32(offset);
402  getTreeNodeFromDatOffset(offset, node);
403  }
404  }
405  }
406  return error;
407 }
408 
409 
410 unsigned long TreeKeyIdx::getOffset() const {
411  unsnappedKeyText = "";
412  return currentNode.offset;
413 }
414 
415 void TreeKeyIdx::setOffset(unsigned long offset) {
417  positionChanged();
418 }
419 
420 
422  unsnappedKeyText = "";
423  long datOffset = 0;
424  SW_s32 tmp;
425 
426  if (idxfd && idxfd->getFd() >= 0) {
427  idxfd->seek(node->offset, SEEK_SET);
428  if (idxfd->read(&tmp, 4) != 4) {
429  datOffset = datfd->seek(0, SEEK_END);
430  tmp = (SW_s32)archtosword32(datOffset);
431  idxfd->write(&tmp, 4);
432  }
433  else {
434  datOffset = swordtoarch32(tmp);
435  datfd->seek(datOffset, SEEK_SET);
436  }
437 
438  tmp = (SW_s32)archtosword32(node->parent);
439  datfd->write(&tmp, 4);
440 
441  tmp = (SW_s32)archtosword32(node->next);
442  datfd->write(&tmp, 4);
443 
444  tmp = (SW_s32)archtosword32(node->firstChild);
445  datfd->write(&tmp, 4);
446  }
447 }
448 
449 
450 void TreeKeyIdx::copyFrom(const TreeKeyIdx &ikey) {
451  unsnappedKeyText = "";
452 
453  SWKey::copyFrom(ikey);
454 
461 
462  if (currentNode.userData)
463  delete [] currentNode.userData;
464  if (currentNode.dsize) {
465  currentNode.userData = new char [ currentNode.dsize ];
467  }
468  else currentNode.userData = 0;
469 
470  bool newFiles = true;
471 
472  if (path && ikey.path)
473  newFiles = strcmp(path, ikey.path);
474 
475  if (newFiles) {
476  stdstr(&path, ikey.path);
477 
478  if (idxfd) {
481  }
482  idxfd = FileMgr::getSystemFileMgr()->open(ikey.idxfd->path, ikey.idxfd->mode, ikey.idxfd->perms);
483  datfd = FileMgr::getSystemFileMgr()->open(ikey.datfd->path, ikey.datfd->mode, ikey.datfd->perms);
484  }
485  positionChanged();
486 }
487 
488 
490  long datOffset = 0;
491  SW_s32 tmp;
492  if (idxfd && idxfd->getFd() >= 0) {
493 
494  idxfd->seek(node->offset, SEEK_SET);
495  datOffset = datfd->seek(0, SEEK_END);
496  tmp = (SW_s32)archtosword32(datOffset);
497  idxfd->write(&tmp, 4);
498 
499  saveTreeNodeOffsets(node);
500 
501  datfd->write(node->name, strlen(node->name));
502  char null = 0;
503  datfd->write(&null, 1);
504 
505  SW_u16 tmp2 = archtosword16(node->dsize);
506  datfd->write(&tmp2, 2);
507 
508  if (node->dsize) {
509  datfd->write(node->userData, node->dsize);
510  }
511  }
512 }
513 
514 
515 void TreeKeyIdx::setText(const char *ikey) {
516  char *buf = 0;
517  stdstr(&buf, ikey);
518  SWBuf leaf = strtok(buf, "/");
519  leaf.trim();
520  root();
521  while ((leaf.size()) && (!popError())) {
522  bool ok, inChild = false;
524  for (ok = firstChild(); ok; ok = nextSibling()) {
525  inChild = true;
526  if (leaf == getLocalName()) {
527  error = 0;
528  break;
529  }
530  }
531  leaf = strtok(0, "/");
532  leaf.trim();
533  if (!ok) {
534  if (inChild) { // if we didn't find a matching child node, default to first child
535  parent();
536  firstChild();
537  }
539  }
540  }
541  if (leaf.size())
543  delete [] buf;
544  unsnappedKeyText = ikey;
545  positionChanged();
546 }
547 
548 
549 
550 void TreeKeyIdx::copyFrom(const SWKey &ikey) {
551  unsnappedKeyText = ikey;
552  SWKey::copyFrom(ikey);
553  positionChanged();
554 }
555 
557  switch (p) {
558  case POS_TOP:
559  root();
560  break;
561  case POS_BOTTOM:
563  break;
564  }
565  positionChanged();
566  popError(); // clear error from normalize
567 }
568 
569 
570 int TreeKeyIdx::_compare (const TreeKeyIdx & ikey) {
571  return (int)(getOffset() - ikey.getOffset());
572 }
573 
574 
575 int TreeKeyIdx::compare(const SWKey &ikey) {
576  const TreeKeyIdx *treeKey = SWDYNAMIC_CAST(const TreeKeyIdx, (&ikey));
577  if (treeKey)
578  return _compare(*treeKey);
579  return SWKey::compare(ikey);
580 }
581 
582 
583 void TreeKeyIdx::decrement(int steps) {
585  positionChanged();
586 }
587 
588 void TreeKeyIdx::increment(int steps) {
590  if (error) {
591  SWLog::getSystemLog(); // strange fix for android // ->logError("error: %d", error);
592  }
593  positionChanged();
594 
595 /*
596  // assert positive
597  if (steps < 0) {
598  decrement(steps * -1);
599  return;
600  }
601 
602  while (steps > 0) {
603  if (!firstChild()) {
604  if (!nextSibbling() {
605  error = KEYERR_OUTOFBOUNDS;
606  return;
607  }
608  }
609  steps--;
610  }
611 */
612 }
613 
614 
615 const char *TreeKeyIdx::getText() const {
617  static SWBuf fullPath;
618  fullPath = currentNode.name;
619  parent.parent = currentNode.parent;
620  while (parent.parent > -1) {
621  getTreeNodeFromIdxOffset(parent.parent, &parent);
622  fullPath = ((SWBuf)parent.name) + (SWBuf) "/" + fullPath;
623  }
624  // we've snapped; clear our unsnapped text holder
625  unsnappedKeyText = "";
626  return fullPath.c_str();
627 }
628 
629 
631 
632  name = 0;
633  stdstr(&name, "");
634  userData = 0;
635 
636  clear();
637 }
638 
639 
641  offset = 0;
642  parent = -1;
643  next = -1;
644  firstChild = -1;
645  dsize = 0;
646 
647  if (name)
648  delete [] name;
649  name = 0;
650  stdstr(&name, "");
651 
652  if (userData)
653  delete [] userData;
654  userData = 0;
655 }
656 
657 
658 
660  if (name)
661  delete [] name;
662 
663  if (userData)
664  delete [] userData;
665 }
666 
667 
669 {
670  return new TreeKeyIdx(*this);
671 }
672 
#define SWORD_NAMESPACE_START
Definition: defs.h:39
long seek(long offset, int whence)
Definition: filemgr.cpp:143
FileDesc * open(const char *path, int mode, bool tryDowngrade)
Definition: filemgr.cpp:175
Definition: swbuf.h:47
virtual const char * getUserData(int *size=0) const
Definition: treekeyidx.cpp:97
virtual void root()
Definition: treekeyidx.cpp:131
virtual const char * getLocalName()
Definition: treekeyidx.cpp:91
virtual void copyFrom(const TreeKeyIdx &ikey)
Definition: treekeyidx.cpp:450
#define archtosword32(x)
Definition: sysdata.h:97
virtual void decrement(int steps=1)
Definition: treekeyidx.cpp:583
static SWLog * getSystemLog()
Definition: swlog.cpp:53
int perms
Definition: filemgr.h:251
virtual void assureKeyPath(const char *keyPath=0)
Definition: treekey.cpp:41
const SWClass * myClass
Definition: swobject.h:55
#define SEEK_END
Definition: zconf.h:246
static unsigned int RDWR
Definition: filemgr.h:76
virtual int compare(const SWKey &ikey)
Definition: treekeyidx.cpp:575
signed int SW_s32
Definition: sysdata.h:40
int mode
Definition: filemgr.h:248
SWBuf unsnappedKeyText
Definition: treekey.h:47
FileDesc * idxfd
Definition: treekeyidx.h:58
virtual int _compare(const TreeKeyIdx &ikey)
Definition: treekeyidx.cpp:570
virtual void setUserData(const char *userData, int size=0)
Definition: treekeyidx.cpp:105
virtual ~TreeKeyIdx()
Definition: treekeyidx.cpp:82
virtual void insertBefore()
Definition: treekeyidx.cpp:239
virtual SWKey * clone() const
Definition: treekeyidx.cpp:668
int getFd()
Definition: filemgr.h:231
char * path
Definition: filemgr.h:245
static signed char create(const char *path)
Definition: treekeyidx.cpp:290
virtual bool previousSibling()
Definition: treekeyidx.cpp:178
virtual bool nextSibling()
Definition: treekeyidx.cpp:168
long write(const void *buf, long count)
Definition: filemgr.cpp:153
void getTreeNodeFromDatOffset(long ioffset, TreeNode *buf) const
Definition: treekeyidx.cpp:331
SWORD_NAMESPACE_START char * stdstr(char **ipstr, const char *istr, unsigned int memPadFactor=1)
Definition: utilstr.h:44
char * path
Definition: treekeyidx.h:56
void close(FileDesc *file)
Definition: filemgr.cpp:196
void init()
Definition: treekeyidx.cpp:77
virtual const char * getText() const
Definition: treekeyidx.cpp:615
const char * c_str() const
Definition: swbuf.h:158
static int removeFile(const char *fName)
Definition: filemgr.cpp:517
#define POS_TOP
Definition: swkey.h:65
virtual int compare(const SWKey &ikey)
Definition: swkey.cpp:218
SWBuf & trim()
Definition: swbuf.h:443
virtual void copyFrom(const SWKey &ikey)
Definition: swkey.cpp:173
#define swordtoarch32(x)
Definition: sysdata.h:94
virtual bool parent()
Definition: treekeyidx.cpp:148
unsigned short SW_u16
Definition: sysdata.h:38
FileDesc * datfd
Definition: treekeyidx.h:59
void setOffset(unsigned long offset)
Definition: treekeyidx.cpp:415
char getTreeNodeFromIdxOffset(long ioffset, TreeNode *node) const
Definition: treekeyidx.cpp:380
#define SWDYNAMIC_CAST(className, object)
Definition: defs.h:47
virtual bool hasChildren()
Definition: treekeyidx.cpp:198
#define KEYERR_OUTOFBOUNDS
Definition: swkey.h:35
unsigned long size() const
Definition: swbuf.h:185
virtual int getLevel()
Definition: treekeyidx.cpp:136
virtual char popError()
Definition: swkey.cpp:147
virtual void append()
Definition: treekeyidx.cpp:203
#define POS_BOTTOM
Definition: swkey.h:66
#define SEEK_SET
Definition: zconf.h:244
int size
Definition: regex.c:5043
virtual void increment(int steps=1)
Definition: treekeyidx.cpp:588
class TreeKeyIdx::TreeNode currentNode
static unsigned int CREAT
Definition: filemgr.h:72
virtual void setPosition(SW_POSITION p)
Definition: treekeyidx.cpp:556
void positionChanged()
Definition: treekey.h:51
void saveTreeNode(TreeNode *node)
Definition: treekeyidx.cpp:489
virtual void remove()
Definition: treekeyidx.cpp:243
#define swordtoarch16(x)
Definition: sysdata.h:93
unsigned int SW_u32
Definition: sysdata.h:41
virtual const char * setLocalName(const char *)
Definition: treekeyidx.cpp:119
TreeKeyIdx(const TreeKeyIdx &ikey)
Definition: treekeyidx.cpp:41
char error
Definition: swkey.h:106
static unsigned int IWRITE
Definition: filemgr.h:79
static unsigned int WRONLY
Definition: filemgr.h:77
long read(void *buf, long count)
Definition: filemgr.cpp:148
static SWORD_NAMESPACE_START const char * classes[]
Definition: treekeyidx.cpp:37
SW_u64 userData
Definition: swkey.h:115
static unsigned int IREAD
Definition: filemgr.h:78
#define SWORD_NAMESPACE_END
Definition: defs.h:40
unsigned long getOffset() const
Definition: treekeyidx.cpp:410
#define SWLOGD(...)
Definition: defs.h:187
SWBuf & setFormatted(const char *format,...)
Definition: swbuf.cpp:50
Definition: swkey.h:77
virtual SWKEY_OPERATORS void setText(const char *ikey)
Definition: treekeyidx.cpp:515
void saveTreeNodeOffsets(TreeNode *node)
Definition: treekeyidx.cpp:421
#define archtosword16(x)
Definition: sysdata.h:96
virtual bool firstChild()
Definition: treekeyidx.cpp:158
virtual void appendChild()
Definition: treekeyidx.cpp:222
static const SWClass classdef(classes)
virtual void save()
Definition: treekeyidx.cpp:126
static FileMgr * getSystemFileMgr()
Definition: filemgr.cpp:101