Passwordfile library  3.1.4
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 <algorithm>
8 #include <sstream>
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 }
51 
56 {
57  setParent(nullptr);
58 }
59 
65 {
66  if (m_parent) {
67  int index = 1;
68  string currentLabel(label());
69  checkLabel:
70  for (Entry *sibling : m_parent->children()) {
71  if (sibling != this && currentLabel == sibling->label()) {
72  stringstream newLabel(currentLabel);
73  newLabel.seekp(0, ios_base::end);
74  if (newLabel.tellp()) {
75  newLabel << ' ';
76  }
77  newLabel << ++index;
78  currentLabel = newLabel.str();
79  goto checkLabel;
80  }
81  }
82  m_label = currentLabel;
83  }
84 }
85 
93 {
94  if (m_parent != parent || (m_index != index && index >= 0)) {
95  if (m_parent) {
96  m_parent->m_children.erase(m_parent->m_children.begin() + m_index);
97  for (auto i = m_parent->m_children.begin() + m_index; i < m_parent->m_children.end(); ++i) {
98  (*i)->m_index -= 1;
99  }
100  }
101  if (parent) {
102  if (index < 0 || static_cast<size_t>(index) >= parent->m_children.size()) {
103  m_index = parent->m_children.size();
104  parent->m_children.push_back(this);
105  } else {
106  for (auto i = parent->m_children.insert(parent->m_children.begin() + index, this) + 1; 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 }
200 
205  : Entry(label, parent)
206  , m_expandedByDefault(true)
207 {
208 }
209 
213 NodeEntry::NodeEntry(istream &stream)
214  : m_expandedByDefault(true)
215 {
216  BinaryReader reader(&stream);
217  byte version = reader.readByte();
218  if (denotesNodeEntry(version)) {
219  if (version == 0x0 || version == 0x1) {
220  setLabel(reader.readLengthPrefixedString());
221  if (version == 0x1) { // version 0x1 has an extended header
222  uint16 extendedHeaderSize = reader.readUInt16BE();
223  if (extendedHeaderSize >= 1) {
224  byte flags = reader.readByte();
225  m_expandedByDefault = flags & 0x80;
226  extendedHeaderSize -= 1;
227  }
228  m_extendedData = reader.readString(extendedHeaderSize);
229  }
230  uint32 childCount = reader.readUInt32BE();
231  for (uint32 i = 0; i < childCount; ++i) {
232  Entry::parse(stream)->setParent(this);
233  }
234  } else {
235  throw ParsingException("Entry version not supported.");
236  }
237  } else {
238  throw ParsingException("Node entry expected.");
239  }
240 }
241 
248  : Entry(other)
249 {
250  for (Entry *otherChild : other.m_children) {
251  Entry *clonedChild = otherChild->clone();
252  clonedChild->m_parent = this;
253  clonedChild->m_index = m_children.size();
254  m_children.push_back(clonedChild);
255  }
256 }
257 
262 {
263  for (Entry *child : m_children) {
264  child->m_parent = nullptr;
265  delete child;
266  }
267 }
268 
274 void NodeEntry::deleteChildren(int begin, int end)
275 {
276  auto iterator = m_children.cbegin() + begin;
277  auto endIterator = m_children.begin() + end;
278  for (; iterator < endIterator; ++iterator) {
279  (*iterator)->m_parent = nullptr;
280  delete *iterator;
281  }
282  m_children.erase(m_children.begin() + begin, endIterator);
283 }
284 
288 void NodeEntry::replaceChild(size_t at, Entry *newChild)
289 {
290  if (at < m_children.size()) {
291  m_children.at(at)->m_parent = nullptr;
292  m_children[at] = newChild;
293  }
294 }
295 
305 Entry *NodeEntry::entryByPath(list<string> &path, bool includeThis, EntryType *creationType)
306 {
307  if (path.size()) {
308  if (includeThis) {
309  if (path.front() == label()) {
310  path.pop_front();
311  } else {
312  return nullptr;
313  }
314  }
315  if (path.size()) {
316  for (Entry *child : m_children) {
317  if (path.front() == child->label()) {
318  path.pop_front();
319  if (path.empty()) {
320  return child;
321  } else if (child->type() == EntryType::Node) {
322  return static_cast<NodeEntry *>(child)->entryByPath(path, false, creationType);
323  } else {
324  return nullptr; // can not resolve path since an account entry can not have children
325  }
326  }
327  }
328  if (creationType) {
329  if (path.size() == 1) {
330  switch (*creationType) {
331  case EntryType::Account:
332  return new AccountEntry(path.front(), this);
333  case EntryType::Node:
334  return new NodeEntry(path.front(), this);
335  }
336  } else {
337  return nullptr;
338  }
339  }
340  } else {
341  return this;
342  }
343  }
344  return nullptr;
345 }
346 
347 void NodeEntry::make(ostream &stream) const
348 {
349  BinaryWriter writer(&stream);
350  writer.writeByte(isExpandedByDefault() && m_extendedData.empty() ? 0x0 : 0x1); // version
351  writer.writeLengthPrefixedString(label());
352  if (!isExpandedByDefault() || !m_extendedData.empty()) {
353  writer.writeUInt16BE(1 + m_extendedData.size()); // extended header is 1 byte long
354  byte flags = 0x00;
355  if (isExpandedByDefault()) {
356  flags |= 0x80;
357  }
358  writer.writeByte(flags);
359  writer.writeString(m_extendedData);
360  }
361  writer.writeUInt32BE(m_children.size());
362  for (const Entry *child : m_children) {
363  child->make(stream);
364  }
365 }
366 
368 {
369  return new NodeEntry(*this);
370 }
371 
378 {
379 }
380 
385  : Entry(label, parent)
386 {
387 }
388 
393 {
394  BinaryReader reader(&stream);
395  byte version = reader.readByte();
396  if (!denotesNodeEntry(version)) {
397  version ^= 0x80; // set bit 0 to false
398  if (version == 0x0 || version == 0x1) {
399  setLabel(reader.readLengthPrefixedString());
400  if (version == 0x1) { // version 0x1 has an extended header
401  uint16 extendedHeaderSize = reader.readUInt16BE();
402  // currently there's nothing to read here
403  m_extendedData = reader.readString(extendedHeaderSize);
404  }
405  uint32 fieldCount = reader.readUInt32BE();
406  for (uint32 i = 0; i < fieldCount; ++i) {
407  m_fields.push_back(Field(this, stream));
408  }
409  } else {
410  throw ParsingException("Entry version not supported.");
411  }
412  } else {
413  throw ParsingException("Account entry expected.");
414  }
415 }
416 
423  : Entry(other)
424 {
425  m_fields = other.m_fields;
426 }
427 
432 {
433 }
434 
435 void AccountEntry::make(ostream &stream) const
436 {
437  BinaryWriter writer(&stream);
438  writer.writeByte(0x80 | (m_extendedData.empty() ? 0x0 : 0x1)); // version
439  writer.writeLengthPrefixedString(label());
440  if (!m_extendedData.empty()) {
441  writer.writeUInt16BE(m_extendedData.size());
442  writer.writeString(m_extendedData);
443  }
444  writer.writeUInt32BE(m_fields.size());
445  for (const Field &field : m_fields) {
446  field.make(stream);
447  }
448 }
449 
451 {
452  return new AccountEntry(*this);
453 }
454 }
~NodeEntry()
Destroys the entry.
Definition: entry.cpp:261
NodeEntry * parent() const
Returns the parent entry.
Definition: entry.h:82
The NodeEntry class acts as parent for other entries.
Definition: entry.h:95
virtual void make(std::ostream &stream) const
Serializes the entry to the specified stream.
Definition: entry.cpp:347
const std::string & label() const
Returns the label.
Definition: entry.h:62
void setLabel(const std::string &label)
Sets the label.
Definition: entry.h:72
~AccountEntry()
Destroys the entry.
Definition: entry.cpp:431
bool isIndirectChildOf(NodeEntry *entry) const
Returns an indication whether the instance is an indirect child of the specified entry.
Definition: entry.cpp:122
NodeEntry()
Constructs a new node entry.
Definition: entry.cpp:195
STL namespace.
virtual Entry * clone() const =0
Clones the entry.
bool isExpandedByDefault() const
Definition: entry.h:130
friend class NodeEntry
Definition: entry.h:26
Contains all IO related classes.
int index() const
Returns the index of the entry within its parent.
Definition: entry.h:90
Entry * entryByPath(std::list< std::string > &path, bool includeThis=true, EntryType *creationType=nullptr)
Returns an entry specified by the provided path.
Definition: entry.cpp:305
virtual NodeEntry * clone() const
Clones the entry.
Definition: entry.cpp:367
std::list< std::string > path() const
Returns the path of the entry.
Definition: entry.cpp:138
std::string m_extendedData
Definition: entry.h:56
The Field class holds field information which consists of a name and a value and is able to serialize...
Definition: field.h:15
The exception that is thrown when a parsing error occurs.
Definition: entry.h:145
Entry(const std::string &label=std::string(), NodeEntry *parent=nullptr)
Constructs a new entry with the specified label and parent.
Definition: entry.cpp:32
virtual void make(std::ostream &stream) const
Serializes the entry to the specified stream.
Definition: entry.cpp:435
static Entry * parse(std::istream &stream)
Parses an entry from the specified stream.
Definition: entry.cpp:160
virtual AccountEntry * clone() const
Clones the entry.
Definition: entry.cpp:450
virtual ~Entry()
Destroys the entry.
Definition: entry.cpp:55
static bool denotesNodeEntry(byte version)
Definition: entry.h:140
const std::vector< Entry * > & children() const
Definition: entry.h:125
void makeLabelUnique()
Internally called to make the label unique.
Definition: entry.cpp:64
void replaceChild(size_t at, Entry *newChild)
Replaces the child at the specified index with the specified newChild.
Definition: entry.cpp:288
void setParent(NodeEntry *parent, int index=-1)
Sets the parent for the entry.
Definition: entry.cpp:92
void deleteChildren(int begin, int end)
Deletes children from the node entry.
Definition: entry.cpp:274
EntryType
Specifies the entry type.
Definition: entry.h:18
The exception that is thrown when a parsing error occurs.
Instances of the Entry class form a hierarchic data strucutre used to store account information...
Definition: entry.h:25