Passwordfile library  3.1.2
C++ library to read/write passwords from/to encrypted files
entry.cpp
Go to the documentation of this file.
1 #include "./entry.h"
2 #include "./parsingexception.h"
3 
4 #include <c++utilities/io/binaryreader.h>
5 #include <c++utilities/io/binarywriter.h>
6 
7 #include <sstream>
8 #include <algorithm>
9 
10 using namespace std;
11 using namespace IoUtilities;
12 using namespace ConversionUtilities;
13 
14 namespace Io {
15 
32 Entry::Entry(const string &label, NodeEntry *parent) :
33  m_parent(nullptr),
34  m_index(-1)
35 {
36  setParent(parent);
37  setLabel(label);
38 }
39 
45 Entry::Entry(const Entry &other) :
46  m_label(other.m_label),
47  m_parent(nullptr),
48  m_index(-1)
49 {}
50 
55 {
56  setParent(nullptr);
57 }
58 
64 {
65  if(m_parent) {
66  int index = 1;
67  string currentLabel(label());
68  checkLabel:
69  for(Entry *sibling : m_parent->children()) {
70  if(sibling != this && currentLabel == sibling->label()) {
71  stringstream newLabel(currentLabel);
72  newLabel.seekp(0, ios_base::end);
73  if(newLabel.tellp()) {
74  newLabel << ' ';
75  }
76  newLabel << ++index;
77  currentLabel = newLabel.str();
78  goto checkLabel;
79  }
80  }
81  m_label = currentLabel;
82  }
83 }
84 
92 {
93  if(m_parent != parent || (m_index != index && index >= 0)) {
94  if(m_parent) {
95  m_parent->m_children.erase(m_parent->m_children.begin() + m_index);
96  for(auto i = m_parent->m_children.begin() + m_index; i < m_parent->m_children.end(); ++i) {
97  (*i)->m_index -= 1;
98  }
99  }
100  if(parent) {
101  if(index < 0 || static_cast<size_t>(index) >= parent->m_children.size()) {
102  m_index = parent->m_children.size();
103  parent->m_children.push_back(this);
104  } else {
105  for(auto i = parent->m_children.insert(parent->m_children.begin() + index, this) + 1;
106  i != parent->m_children.end(); ++i) {
107  (*i)->m_index += 1;
108  }
109  m_index = index;
110  }
111  } else {
112  m_index = -1;
113  }
114  m_parent = parent;
115  makeLabelUnique();
116  }
117 }
118 
123 {
124  if(parent()) {
125  if(parent() == entry) {
126  return true;
127  } else {
128  return parent()->isIndirectChildOf(entry);
129  }
130  } else {
131  return false;
132  }
133 }
134 
138 std::list<string> Entry::path() const
139 {
140  list<string> res;
141  path(res);
142  return res;
143 }
144 
148 void Entry::path(std::list<string> &res) const
149 {
150  if(m_parent) {
151  m_parent->path(res);
152  }
153  res.push_back(label());
154 }
155 
160 Entry *Entry::parse(istream &stream)
161 {
162  byte version = stream.peek();
163  if(denotesNodeEntry(version)) {
164  return new NodeEntry(stream);
165  } else {
166  return new AccountEntry(stream);
167  }
168 }
169 
196  Entry(),
197  m_expandedByDefault(true)
198 {}
199 
204  Entry(label, parent),
205  m_expandedByDefault(true)
206 {}
207 
211 NodeEntry::NodeEntry(istream &stream) :
212  m_expandedByDefault(true)
213 {
214  BinaryReader reader(&stream);
215  byte version = reader.readByte();
216  if(denotesNodeEntry(version)) {
217  if(version == 0x0 || version == 0x1) {
218  setLabel(reader.readLengthPrefixedString());
219  if(version == 0x1) { // version 0x1 has an extended header
220  uint16 extendedHeaderSize = reader.readUInt16BE();
221  if(extendedHeaderSize >= 1) {
222  byte flags = reader.readByte();
223  m_expandedByDefault = flags & 0x80;
224  extendedHeaderSize -= 1;
225  }
226  m_extendedData = reader.readString(extendedHeaderSize);
227  }
228  uint32 childCount = reader.readUInt32BE();
229  for(uint32 i = 0; i < childCount; ++i) {
230  Entry::parse(stream)->setParent(this);
231  }
232  } else {
233  throw ParsingException("Entry version not supported.");
234  }
235  } else {
236  throw ParsingException("Node entry expected.");
237  }
238 }
239 
246  Entry(other)
247 {
248  for(Entry *otherChild : other.m_children) {
249  Entry *clonedChild = otherChild->clone();
250  clonedChild->m_parent = this;
251  clonedChild->m_index = m_children.size();
252  m_children.push_back(clonedChild);
253  }
254 }
255 
260 {
261  for(Entry *child : m_children) {
262  child->m_parent = nullptr;
263  delete child;
264  }
265 }
266 
272 void NodeEntry::deleteChildren(int begin, int end)
273 {
274  auto iterator = m_children.cbegin() + begin;
275  auto endIterator = m_children.begin() + end;
276  for(; iterator < endIterator; ++iterator) {
277  (*iterator)->m_parent = nullptr;
278  delete *iterator;
279  }
280  m_children.erase(m_children.begin() + begin, endIterator);
281 }
282 
286 void NodeEntry::replaceChild(size_t at, Entry *newChild)
287 {
288  if(at < m_children.size()) {
289  m_children.at(at)->m_parent = nullptr;
290  m_children[at] = newChild;
291  }
292 }
293 
303 Entry *NodeEntry::entryByPath(list<string> &path, bool includeThis, EntryType *creationType)
304 {
305  if(path.size()) {
306  if(includeThis) {
307  if(path.front() == label()) {
308  path.pop_front();
309  } else {
310  return nullptr;
311  }
312  }
313  if(path.size()) {
314  for(Entry *child : m_children) {
315  if(path.front() == child->label()) {
316  path.pop_front();
317  if(path.empty()) {
318  return child;
319  } else if(child->type() == EntryType::Node) {
320  return static_cast<NodeEntry *>(child)->entryByPath(path, false, creationType);
321  } else {
322  return nullptr; // can not resolve path since an account entry can not have children
323  }
324  }
325  }
326  if(creationType) {
327  if(path.size() == 1) {
328  switch(*creationType) {
329  case EntryType::Account:
330  return new AccountEntry(path.front(), this);
331  case EntryType::Node:
332  return new NodeEntry(path.front(), this);
333  }
334  } else {
335  return nullptr;
336  }
337  }
338  } else {
339  return this;
340  }
341  }
342  return nullptr;
343 }
344 
345 void NodeEntry::make(ostream &stream) const
346 {
347  BinaryWriter writer(&stream);
348  writer.writeByte(isExpandedByDefault() && m_extendedData.empty() ? 0x0 : 0x1); // version
349  writer.writeLengthPrefixedString(label());
350  if(!isExpandedByDefault() || !m_extendedData.empty()) {
351  writer.writeUInt16BE(1 + m_extendedData.size()); // extended header is 1 byte long
352  byte flags = 0x00;
353  if(isExpandedByDefault()) {
354  flags |= 0x80;
355  }
356  writer.writeByte(flags);
357  writer.writeString(m_extendedData);
358  }
359  writer.writeUInt32BE(m_children.size());
360  for(const Entry *child : m_children) {
361  child->make(stream);
362  }
363 }
364 
366 {
367  return new NodeEntry(*this);
368 }
369 
376 {}
377 
382  Entry(label, parent)
383 {}
384 
389 {
390  BinaryReader reader(&stream);
391  byte version = reader.readByte();
392  if(!denotesNodeEntry(version)) {
393  version ^= 0x80; // set bit 0 to false
394  if(version == 0x0 || version == 0x1) {
395  setLabel(reader.readLengthPrefixedString());
396  if(version == 0x1) { // version 0x1 has an extended header
397  uint16 extendedHeaderSize = reader.readUInt16BE();
398  // currently there's nothing to read here
399  m_extendedData = reader.readString(extendedHeaderSize);
400  }
401  uint32 fieldCount = reader.readUInt32BE();
402  for(uint32 i = 0; i < fieldCount; ++i) {
403  m_fields.push_back(Field(this, stream));
404  }
405  } else {
406  throw ParsingException("Entry version not supported.");
407  }
408  } else {
409  throw ParsingException("Account entry expected.");
410  }
411 }
412 
419  Entry(other)
420 {
421  m_fields = other.m_fields;
422 }
423 
428 {}
429 
430 void AccountEntry::make(ostream &stream) const
431 {
432  BinaryWriter writer(&stream);
433  writer.writeByte(0x80 | (m_extendedData.empty() ? 0x0 : 0x1)); // version
434  writer.writeLengthPrefixedString(label());
435  if(!m_extendedData.empty()) {
436  writer.writeUInt16BE(m_extendedData.size());
437  writer.writeString(m_extendedData);
438  }
439  writer.writeUInt32BE(m_fields.size());
440  for(const Field &field : m_fields) {
441  field.make(stream);
442  }
443 }
444 
446 {
447  return new AccountEntry(*this);
448 }
449 
450 }
virtual AccountEntry * clone() const
Clones the entry.
Definition: entry.cpp:445
~NodeEntry()
Destroys the entry.
Definition: entry.cpp:259
The NodeEntry class acts as parent for other entries.
Definition: entry.h:97
bool isIndirectChildOf(NodeEntry *entry) const
Returns an indication whether the instance is an indirect child of the specified entry.
Definition: entry.cpp:122
void setLabel(const std::string &label)
Sets the label.
Definition: entry.h:74
~AccountEntry()
Destroys the entry.
Definition: entry.cpp:427
NodeEntry()
Constructs a new node entry.
Definition: entry.cpp:195
STL namespace.
virtual void make(std::ostream &stream) const
Serializes the entry to the specified stream.
Definition: entry.cpp:430
virtual Entry * clone() const =0
Clones the entry.
friend class NodeEntry
Definition: entry.h:28
Contains all IO related classes.
const std::vector< Entry * > & children() const
Definition: entry.h:127
Entry * entryByPath(std::list< std::string > &path, bool includeThis=true, EntryType *creationType=nullptr)
Returns an entry specified by the provided path.
Definition: entry.cpp:303
std::string m_extendedData
Definition: entry.h:57
The Field class holds field information which consists of a name and a value and is able to serialize...
Definition: field.h:19
The exception that is thrown when a parsing error occurs.
Definition: entry.h:147
Entry(const std::string &label=std::string(), NodeEntry *parent=nullptr)
Constructs a new entry with the specified label and parent.
Definition: entry.cpp:32
static Entry * parse(std::istream &stream)
Parses an entry from the specified stream.
Definition: entry.cpp:160
virtual void make(std::ostream &stream) const
Serializes the entry to the specified stream.
Definition: entry.cpp:345
virtual ~Entry()
Destroys the entry.
Definition: entry.cpp:54
static bool denotesNodeEntry(byte version)
Definition: entry.h:142
void makeLabelUnique()
Internally called to make the label unique.
Definition: entry.cpp:63
const std::string & label() const
Returns the label.
Definition: entry.h:64
void replaceChild(size_t at, Entry *newChild)
Replaces the child at the specified index with the specified newChild.
Definition: entry.cpp:286
void setParent(NodeEntry *parent, int index=-1)
Sets the parent for the entry.
Definition: entry.cpp:91
virtual NodeEntry * clone() const
Clones the entry.
Definition: entry.cpp:365
std::list< std::string > path() const
Returns the path of the entry.
Definition: entry.cpp:138
bool isExpandedByDefault() const
Definition: entry.h:132
void deleteChildren(int begin, int end)
Deletes children from the node entry.
Definition: entry.cpp:272
EntryType
Specifies the entry type.
Definition: entry.h:18
The exception that is thrown when a parsing error occurs.
NodeEntry * parent() const
Returns the parent entry.
Definition: entry.h:84
int index() const
Returns the index of the entry within its parent.
Definition: entry.h:92
Instances of the Entry class form a hierarchic data strucutre used to store account information...
Definition: entry.h:26