Passwordfile library 5.0.11
C++ library to read/write passwords from/to encrypted files
Loading...
Searching...
No Matches
entry.cpp
Go to the documentation of this file.
1#include "./entry.h"
3
4#include <c++utilities/conversion/stringbuilder.h>
5#include <c++utilities/io/binaryreader.h>
6#include <c++utilities/io/binarywriter.h>
7
8#include <algorithm>
9#include <sstream>
10
11using namespace std;
12using namespace CppUtilities;
13
14namespace Io {
15
32Entry::Entry(const string &label, NodeEntry *parent)
33 : m_parent(nullptr)
34 , m_index(-1)
35{
38}
39
45Entry::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 return;
68 }
69 string newLabel(label());
70 for (unsigned int index = 2;; ++index) {
71 bool needsNewLabel = false;
72 for (Entry *const sibling : m_parent->children()) {
73 if (sibling == this || newLabel != sibling->label()) {
74 continue;
75 }
76 needsNewLabel = true;
77 newLabel = argsToString(label(), ' ', index);
78 break;
79 }
80 if (!needsNewLabel) {
81 break;
82 }
83 }
84 m_label.swap(newLabel);
85}
86
99void Entry::setParent(NodeEntry *parent, int index)
100{
101 // skip if \a parent already assigned and the index doesn't change, too
102 if (m_parent == parent && !(m_index != index && index >= 0)) {
103 return;
104 }
105
106 // detach the current parent
107 if (m_parent) {
108 m_parent->m_children.erase(m_parent->m_children.begin() + m_index);
109 for (auto i = m_parent->m_children.begin() + m_index; i < m_parent->m_children.end(); ++i) {
110 (*i)->m_index -= 1;
111 }
112 }
113
114 // attach the new parent
115 if (parent) {
116 if (index < 0 || static_cast<size_t>(index) >= parent->m_children.size()) {
117 m_index = static_cast<int>(parent->m_children.size());
118 parent->m_children.push_back(this);
119 } else {
120 for (auto i = parent->m_children.insert(parent->m_children.begin() + index, this) + 1; i != parent->m_children.end(); ++i) {
121 (*i)->m_index += 1;
122 }
123 m_index = index;
124 }
125 } else {
126 m_index = -1;
127 }
128
129 // actually assign the parent
130 m_parent = parent;
131
132 // ensure the label is still unique within the new parent
134}
135
139bool Entry::isIndirectChildOf(const NodeEntry *entry) const
140{
141 if (!parent()) {
142 return false;
143 }
144 if (parent() == entry) {
145 return true;
146 } else {
147 return parent()->isIndirectChildOf(entry);
148 }
149}
150
154std::list<string> Entry::path() const
155{
156 list<string> res;
157 path(res);
158 return res;
159}
160
164void Entry::path(std::list<string> &res) const
165{
166 if (m_parent) {
167 m_parent->path(res);
168 }
169 res.push_back(label());
170}
171
176Entry *Entry::parse(istream &stream)
177{
178 const auto version = static_cast<std::uint8_t>(stream.peek());
179 if (denotesNodeEntry(version)) {
180 return new NodeEntry(stream);
181 } else {
182 return new AccountEntry(stream);
183 }
184}
185
212 : Entry()
213 , m_expandedByDefault(true)
214{
215}
216
220NodeEntry::NodeEntry(const string &label, NodeEntry *parent)
221 : Entry(label, parent)
222 , m_expandedByDefault(true)
223{
224}
225
229NodeEntry::NodeEntry(istream &stream)
230 : m_expandedByDefault(true)
231{
232 BinaryReader reader(&stream);
233 const std::uint8_t version = reader.readByte();
234 if (!denotesNodeEntry(version)) {
235 throw ParsingException("Node entry expected.");
236 }
237 if (version != 0x0 && version != 0x1) {
238 throw ParsingException("Entry version not supported.");
239 }
240 setLabel(reader.readLengthPrefixedString());
241 // read extended header for version 0x1
242 if (version == 0x1) {
243 std::uint16_t extendedHeaderSize = reader.readUInt16BE();
244 if (extendedHeaderSize >= 1) {
245 std::uint8_t flags = reader.readByte();
246 m_expandedByDefault = flags & 0x80;
247 extendedHeaderSize -= 1;
248 }
249 m_extendedData = reader.readString(extendedHeaderSize);
250 }
251 const std::uint32_t childCount = reader.readUInt32BE();
252 for (std::uint32_t i = 0; i != childCount; ++i) {
253 Entry::parse(stream)->setParent(this);
254 }
255}
256
263 : Entry(other)
264{
265 for (Entry *const otherChild : other.m_children) {
266 Entry *clonedChild = otherChild->clone();
267 clonedChild->m_parent = this;
268 clonedChild->m_index = static_cast<int>(m_children.size());
269 m_children.push_back(clonedChild);
270 }
271}
272
277{
278 for (Entry *const child : m_children) {
279 child->m_parent = nullptr;
280 delete child;
281 }
282}
283
290void NodeEntry::deleteChildren(int begin, int end)
291{
292 const auto endIterator = m_children.begin() + end;
293
294 // delete the children
295 for (auto iterator = m_children.cbegin() + begin; iterator != endIterator; ++iterator) {
296 (*iterator)->m_parent = nullptr;
297 delete *iterator;
298 }
299
300 // remove the children from the list
301 m_children.erase(m_children.begin() + begin, endIterator);
302
303 // adjust indices of subsequent children
304 const int diff = end - begin;
305 for (auto iterator = m_children.begin() + begin, end2 = m_children.end(); iterator != end2; ++iterator) {
306 (*iterator)->m_index -= diff;
307 }
308}
309
317void NodeEntry::replaceChild(size_t at, Entry *newChild)
318{
319 if (at >= m_children.size()) {
320 return;
321 }
322
323 // detach the old child
324 m_children[at]->m_parent = nullptr;
325 m_children[at]->m_index = -1;
326
327 // detach new child from its previous parent
328 if (auto *newChildOldParent = newChild->m_parent) {
329 newChildOldParent->m_children.erase(newChildOldParent->m_children.begin() + newChild->m_index);
330 for (auto i = newChildOldParent->m_children.begin() + newChild->m_index; i < newChildOldParent->m_children.end(); ++i) {
331 (*i)->m_index -= 1;
332 }
333 }
334
335 // do the actual assignment
336 newChild->m_parent = this;
337 newChild->m_index = static_cast<int>(at);
338 m_children[at] = newChild;
339}
340
350Entry *NodeEntry::entryByPath(list<string> &path, bool includeThis, const EntryType *creationType)
351{
352 if (path.empty()) {
353 return nullptr;
354 }
355
356 // check for current instance
357 if (includeThis) {
358 if (path.front() == label()) {
359 path.pop_front();
360 } else {
361 return nullptr;
362 }
363 }
364 if (path.empty()) {
365 return this;
366 }
367
368 for (Entry *const child : m_children) {
369 if (path.front() != child->label()) {
370 continue;
371 }
372 path.pop_front();
373 if (path.empty()) {
374 return child;
375 } else if (child->type() == EntryType::Node) {
376 return static_cast<NodeEntry *>(child)->entryByPath(path, false, creationType);
377 } else {
378 return nullptr; // can not resolve path since an account entry can not have children
379 }
380 }
381
382 // create a new entry
383 if (!creationType || path.size() != 1) {
384 return nullptr;
385 }
386 switch (*creationType) {
388 return new AccountEntry(path.front(), this);
389 case EntryType::Node:
390 return new NodeEntry(path.front(), this);
391 }
392 return nullptr;
393}
394
395void NodeEntry::make(ostream &stream) const
396{
397 BinaryWriter writer(&stream);
398 writer.writeByte(isExpandedByDefault() && m_extendedData.empty() ? 0x0 : 0x1); // version
399 writer.writeLengthPrefixedString(label());
400 if (!isExpandedByDefault() || !m_extendedData.empty()) {
401 writer.writeUInt16BE(static_cast<std::uint16_t>(1 + m_extendedData.size())); // extended header is 1 byte long
402 std::uint8_t flags = 0x00;
403 if (isExpandedByDefault()) {
404 flags |= 0x80;
405 }
406 writer.writeByte(flags);
407 writer.writeString(m_extendedData);
408 }
409 writer.writeUInt32BE(static_cast<std::uint32_t>(m_children.size()));
410 for (const Entry *const child : m_children) {
411 child->make(stream);
412 }
413}
414
416{
417 return new NodeEntry(*this);
418}
419
424{
425 ++stats.nodeCount;
426 for (const auto *children : children()) {
427 children->accumulateStatistics(stats);
428 }
429}
430
439
443AccountEntry::AccountEntry(const string &label, NodeEntry *parent)
444 : Entry(label, parent)
445{
446}
447
452{
453 BinaryReader reader(&stream);
454 std::uint8_t version = reader.readByte();
455 if (denotesNodeEntry(version)) {
456 throw ParsingException("Account entry expected.");
457 }
458 version ^= 0x80; // set first bit to zero
459 if (version != 0x0 && version != 0x1) {
460 throw ParsingException("Entry version not supported.");
461 }
462 setLabel(reader.readLengthPrefixedString());
463 // read extended header for version 0x1
464 if (version == 0x1) {
465 const std::uint16_t extendedHeaderSize = reader.readUInt16BE();
466 // currently there's nothing to read here
467 m_extendedData = reader.readString(extendedHeaderSize);
468 }
469 const std::uint32_t fieldCount = reader.readUInt32BE();
470 for (std::uint32_t i = 0; i != fieldCount; ++i) {
471 m_fields.push_back(Field(this, stream));
472 }
473}
474
481 : Entry(other)
482{
483 m_fields = other.m_fields;
484}
485
492
493void AccountEntry::make(ostream &stream) const
494{
495 BinaryWriter writer(&stream);
496 writer.writeByte(0x80 | (m_extendedData.empty() ? 0x0 : 0x1)); // version
497 writer.writeLengthPrefixedString(label());
498 if (!m_extendedData.empty()) {
499 writer.writeUInt16BE(static_cast<std::uint16_t>(m_extendedData.size()));
500 writer.writeString(m_extendedData);
501 }
502 writer.writeUInt32BE(static_cast<std::uint32_t>(m_fields.size()));
503 for (const Field &field : m_fields) {
504 field.make(stream);
505 }
506}
507
509{
510 return new AccountEntry(*this);
511}
512
517{
518 stats.accountCount += 1;
519 stats.fieldCount += fields().size();
520}
521} // namespace Io
The exception that is thrown when a parsing error occurs.
Definition entry.h:170
~AccountEntry() override
Destroys the entry.
Definition entry.cpp:489
const std::vector< Field > & fields() const
Definition entry.h:194
void accumulateStatistics(EntryStatistics &stats) const override
Accumulates the statistics for this account entry and its fields.
Definition entry.cpp:516
AccountEntry * clone() const override
Clones the entry.
Definition entry.cpp:508
void make(std::ostream &stream) const override
Serializes the entry to the specified stream.
Definition entry.cpp:493
Instances of the Entry class form a hierarchic data structure used to store account information.
Definition entry.h:30
int index() const
Returns the index of the entry within its parent.
Definition entry.h:98
static Entry * parse(std::istream &stream)
Parses an entry from the specified stream.
Definition entry.cpp:176
Entry(const std::string &label=std::string(), NodeEntry *parent=nullptr)
Constructs a new entry with the specified label and parent.
Definition entry.cpp:32
void makeLabelUnique()
Internally called to make the entry's label unique within the parent.
Definition entry.cpp:64
friend class NodeEntry
Definition entry.h:31
bool isIndirectChildOf(const NodeEntry *entry) const
Returns an indication whether the instance is an indirect child of the specified entry.
Definition entry.cpp:139
void setParent(NodeEntry *parent, int index=-1)
Sets the parent for the entry.
Definition entry.cpp:99
NodeEntry * parent() const
Returns the parent entry.
Definition entry.h:90
static bool denotesNodeEntry(std::uint8_t version)
Definition entry.h:160
void setLabel(const std::string &label)
Sets the label.
Definition entry.h:80
std::string m_extendedData
Definition entry.h:64
const std::string & label() const
Returns the label.
Definition entry.h:70
virtual Entry * clone() const =0
Clones the entry.
std::list< std::string > path() const
Returns the path of the entry.
Definition entry.cpp:154
virtual ~Entry()
Destroys the entry.
Definition entry.cpp:55
The Field class holds field information which consists of a name and a value and is able to serialize...
Definition field.h:15
The NodeEntry class acts as parent for other entries.
Definition entry.h:114
Entry * entryByPath(std::list< std::string > &path, bool includeThis=true, const EntryType *creationType=nullptr)
Returns an entry specified by the provided path.
Definition entry.cpp:350
void replaceChild(std::size_t at, Entry *newChild)
Replaces the child at the specified index with the specified newChild.
Definition entry.cpp:317
bool isExpandedByDefault() const
Definition entry.h:150
void accumulateStatistics(EntryStatistics &stats) const override
Accumulates the statistics for this node entry and its children.
Definition entry.cpp:423
NodeEntry * clone() const override
Clones the entry.
Definition entry.cpp:415
~NodeEntry() override
Destroys the entry.
Definition entry.cpp:276
NodeEntry()
Constructs a new node entry.
Definition entry.cpp:211
void deleteChildren(int begin, int end)
Deletes children from the node entry.
Definition entry.cpp:290
const std::vector< Entry * > & children() const
Definition entry.h:145
void make(std::ostream &stream) const override
Serializes the entry to the specified stream.
Definition entry.cpp:395
The exception that is thrown when a parsing error occurs.
Contains all IO related classes.
EntryType
Specifies the entry type.
Definition entry.h:17
std::size_t accountCount
Definition entry.h:24
std::size_t nodeCount
Definition entry.h:23
std::size_t fieldCount
Definition entry.h:25