Passwordfile library 5.0.13
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
8using namespace std;
9using namespace CppUtilities;
10
11namespace Io {
12
17
25
30 : m_parent(nullptr)
31 , m_index(-1)
32{
35}
36
42Entry::Entry(const Entry &other)
43 : m_label(other.m_label)
44 , m_parent(nullptr)
45 , m_index(-1)
46{
47}
48
53{
54 setParent(nullptr);
55}
56
62{
63 if (!m_parent) {
64 return;
65 }
66 string newLabel(label());
67 for (unsigned int index = 2;; ++index) {
68 bool needsNewLabel = false;
69 for (Entry *const sibling : m_parent->children()) {
70 if (sibling == this || newLabel != sibling->label()) {
71 continue;
72 }
73 needsNewLabel = true;
74 newLabel = argsToString(label(), ' ', index);
75 break;
76 }
77 if (!needsNewLabel) {
78 break;
79 }
80 }
81 m_label.swap(newLabel);
82}
83
97{
98 // skip if \a parent already assigned and the index doesn't change, too
99 if (m_parent == parent && !(m_index != index && index >= 0)) {
100 return;
101 }
102
103 // detach the current parent
104 if (m_parent) {
105 m_parent->m_children.erase(m_parent->m_children.begin() + m_index);
106 for (auto i = m_parent->m_children.begin() + m_index; i < m_parent->m_children.end(); ++i) {
107 (*i)->m_index -= 1;
108 }
109 }
110
111 // attach the new parent
112 if (parent) {
113 if (index < 0 || static_cast<size_t>(index) >= parent->m_children.size()) {
114 m_index = static_cast<int>(parent->m_children.size());
115 parent->m_children.push_back(this);
116 } else {
117 for (auto i = parent->m_children.insert(parent->m_children.begin() + index, this) + 1; i != parent->m_children.end(); ++i) {
118 (*i)->m_index += 1;
119 }
120 m_index = index;
121 }
122 } else {
123 m_index = -1;
124 }
125
126 // actually assign the parent
127 m_parent = parent;
128
129 // ensure the label is still unique within the new parent
131}
132
136bool Entry::isIndirectChildOf(const NodeEntry *entry) const
137{
138 if (!parent()) {
139 return false;
140 }
141 if (parent() == entry) {
142 return true;
143 } else {
144 return parent()->isIndirectChildOf(entry);
145 }
146}
147
151std::list<string> Entry::path() const
152{
153 list<string> res;
154 path(res);
155 return res;
156}
157
161void Entry::path(std::list<string> &res) const
162{
163 if (m_parent) {
164 m_parent->path(res);
165 }
166 res.push_back(label());
167}
168
173Entry *Entry::parse(istream &stream)
174{
175 const auto version = static_cast<std::uint8_t>(stream.peek());
176 if (denotesNodeEntry(version)) {
177 return new NodeEntry(stream);
178 } else {
179 return new AccountEntry(stream);
180 }
181}
182
187
192
199
204
209 : Entry()
210 , m_expandedByDefault(true)
211{
212}
213
218 : Entry(label, parent)
219 , m_expandedByDefault(true)
220{
221}
222
226NodeEntry::NodeEntry(istream &stream)
227 : m_expandedByDefault(true)
228{
229 BinaryReader reader(&stream);
230 const std::uint8_t version = reader.readByte();
231 if (!denotesNodeEntry(version)) {
232 throw ParsingException("Node entry expected.");
233 }
234 if (version != 0x0 && version != 0x1) {
235 throw ParsingException("Entry version not supported.");
236 }
237 setLabel(reader.readLengthPrefixedString());
238 // read extended header for version 0x1
239 if (version == 0x1) {
240 std::uint16_t extendedHeaderSize = reader.readUInt16BE();
241 if (extendedHeaderSize >= 1) {
242 std::uint8_t flags = reader.readByte();
243 m_expandedByDefault = flags & 0x80;
244 extendedHeaderSize -= 1;
245 }
246 m_extendedData = reader.readString(extendedHeaderSize);
247 }
248 const std::uint32_t childCount = reader.readUInt32BE();
249 for (std::uint32_t i = 0; i != childCount; ++i) {
250 Entry::parse(stream)->setParent(this);
251 }
252}
253
260 : Entry(other)
261{
262 for (Entry *const otherChild : other.m_children) {
263 Entry *clonedChild = otherChild->clone();
264 clonedChild->m_parent = this;
265 clonedChild->m_index = static_cast<int>(m_children.size());
266 m_children.push_back(clonedChild);
267 }
268}
269
274{
275 for (Entry *const child : m_children) {
276 child->m_parent = nullptr;
277 delete child;
278 }
279}
280
287void NodeEntry::deleteChildren(int begin, int end)
288{
289 const auto endIterator = m_children.begin() + end;
290
291 // delete the children
292 for (auto iterator = m_children.cbegin() + begin; iterator != endIterator; ++iterator) {
293 (*iterator)->m_parent = nullptr;
294 delete *iterator;
295 }
296
297 // remove the children from the list
298 m_children.erase(m_children.begin() + begin, endIterator);
299
300 // adjust indices of subsequent children
301 const int diff = end - begin;
302 for (auto iterator = m_children.begin() + begin, end2 = m_children.end(); iterator != end2; ++iterator) {
303 (*iterator)->m_index -= diff;
304 }
305}
306
314void NodeEntry::replaceChild(size_t at, Entry *newChild)
315{
316 if (at >= m_children.size()) {
317 return;
318 }
319
320 // detach the old child
321 m_children[at]->m_parent = nullptr;
322 m_children[at]->m_index = -1;
323
324 // detach new child from its previous parent
325 if (auto *newChildOldParent = newChild->m_parent) {
326 newChildOldParent->m_children.erase(newChildOldParent->m_children.begin() + newChild->m_index);
327 for (auto i = newChildOldParent->m_children.begin() + newChild->m_index; i < newChildOldParent->m_children.end(); ++i) {
328 (*i)->m_index -= 1;
329 }
330 }
331
332 // do the actual assignment
333 newChild->m_parent = this;
334 newChild->m_index = static_cast<int>(at);
335 m_children[at] = newChild;
336}
337
347Entry *NodeEntry::entryByPath(list<string> &path, bool includeThis, const EntryType *creationType)
348{
349 if (path.empty()) {
350 return nullptr;
351 }
352
353 // check for current instance
354 if (includeThis) {
355 if (path.front() == label()) {
356 path.pop_front();
357 } else {
358 return nullptr;
359 }
360 }
361 if (path.empty()) {
362 return this;
363 }
364
365 for (Entry *const child : m_children) {
366 if (path.front() != child->label()) {
367 continue;
368 }
369 path.pop_front();
370 if (path.empty()) {
371 return child;
372 } else if (child->type() == EntryType::Node) {
373 return static_cast<NodeEntry *>(child)->entryByPath(path, false, creationType);
374 } else {
375 return nullptr; // can not resolve path since an account entry can not have children
376 }
377 }
378
379 // create a new entry
380 if (!creationType || path.size() != 1) {
381 return nullptr;
382 }
383 switch (*creationType) {
385 return new AccountEntry(path.front(), this);
386 case EntryType::Node:
387 return new NodeEntry(path.front(), this);
388 }
389 return nullptr;
390}
391
392void NodeEntry::make(ostream &stream) const
393{
394 BinaryWriter writer(&stream);
395 writer.writeByte(isExpandedByDefault() && m_extendedData.empty() ? 0x0 : 0x1); // version
396 writer.writeLengthPrefixedString(label());
397 if (!isExpandedByDefault() || !m_extendedData.empty()) {
398 writer.writeUInt16BE(static_cast<std::uint16_t>(1 + m_extendedData.size())); // extended header is 1 byte long
399 std::uint8_t flags = 0x00;
400 if (isExpandedByDefault()) {
401 flags |= 0x80;
402 }
403 writer.writeByte(flags);
404 writer.writeString(m_extendedData);
405 }
406 writer.writeUInt32BE(static_cast<std::uint32_t>(m_children.size()));
407 for (const Entry *const child : m_children) {
408 child->make(stream);
409 }
410}
411
413{
414 return new NodeEntry(*this);
415}
416
421{
422 ++stats.nodeCount;
423 for (const auto *children : children()) {
424 children->accumulateStatistics(stats);
425 }
426}
427
432
436
444
449{
450 BinaryReader reader(&stream);
451 std::uint8_t version = reader.readByte();
452 if (denotesNodeEntry(version)) {
453 throw ParsingException("Account entry expected.");
454 }
455 version ^= 0x80; // set first bit to zero
456 if (version != 0x0 && version != 0x1) {
457 throw ParsingException("Entry version not supported.");
458 }
459 setLabel(reader.readLengthPrefixedString());
460 // read extended header for version 0x1
461 if (version == 0x1) {
462 const std::uint16_t extendedHeaderSize = reader.readUInt16BE();
463 // currently there's nothing to read here
464 m_extendedData = reader.readString(extendedHeaderSize);
465 }
466 const std::uint32_t fieldCount = reader.readUInt32BE();
467 for (std::uint32_t i = 0; i != fieldCount; ++i) {
468 m_fields.push_back(Field(this, stream));
469 }
470}
471
478 : Entry(other)
479{
480 m_fields = other.m_fields;
481}
482
489
490void AccountEntry::make(ostream &stream) const
491{
492 BinaryWriter writer(&stream);
493 writer.writeByte(0x80 | (m_extendedData.empty() ? 0x0 : 0x1)); // version
494 writer.writeLengthPrefixedString(label());
495 if (!m_extendedData.empty()) {
496 writer.writeUInt16BE(static_cast<std::uint16_t>(m_extendedData.size()));
497 writer.writeString(m_extendedData);
498 }
499 writer.writeUInt32BE(static_cast<std::uint32_t>(m_fields.size()));
500 for (const Field &field : m_fields) {
501 field.make(stream);
502 }
503}
504
506{
507 return new AccountEntry(*this);
508}
509
514{
515 stats.accountCount += 1;
516 stats.fieldCount += fields().size();
517}
518} // namespace Io
The exception that is thrown when a parsing error occurs.
Definition entry.h:170
~AccountEntry() override
Destroys the entry.
Definition entry.cpp:486
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:513
AccountEntry * clone() const override
Clones the entry.
Definition entry.cpp:505
void make(std::ostream &stream) const override
Serializes the entry to the specified stream.
Definition entry.cpp:490
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:173
Entry(const std::string &label=std::string(), NodeEntry *parent=nullptr)
Constructs a new entry with the specified label and parent.
Definition entry.cpp:29
void makeLabelUnique()
Internally called to make the entry's label unique within the parent.
Definition entry.cpp:61
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:136
void setParent(NodeEntry *parent, int index=-1)
Sets the parent for the entry.
Definition entry.cpp:96
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
std::list< std::string > path() const
Returns the path of the entry.
Definition entry.cpp:151
virtual ~Entry()
Destroys the entry.
Definition entry.cpp:52
The Field class holds field information which consists of a name and a value and is able to serialize...
Definition field.h:15
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:347
void replaceChild(std::size_t at, Entry *newChild)
Replaces the child at the specified index with the specified newChild.
Definition entry.cpp:314
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:420
NodeEntry * clone() const override
Clones the entry.
Definition entry.cpp:412
friend class Entry
Definition entry.h:115
~NodeEntry() override
Destroys the entry.
Definition entry.cpp:273
NodeEntry()
Constructs a new node entry.
Definition entry.cpp:208
void deleteChildren(int begin, int end)
Deletes children from the node entry.
Definition entry.cpp:287
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:392
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