diff --git a/io/entry.cpp b/io/entry.cpp index 387bc42..503aede 100644 --- a/io/entry.cpp +++ b/io/entry.cpp @@ -223,7 +223,7 @@ NodeEntry::NodeEntry(istream &stream) : m_expandedByDefault = flags & 0x80; extendedHeaderSize -= 1; } - stream.seekg(extendedHeaderSize, ios_base::cur); + m_extendedData = reader.readString(extendedHeaderSize); } uint32 childCount = reader.readUInt32BE(); for(uint32 i = 0; i < childCount; ++i) { @@ -345,11 +345,16 @@ Entry *NodeEntry::entryByPath(list &path, bool includeThis, EntryType *c void NodeEntry::make(ostream &stream) const { BinaryWriter writer(&stream); - writer.writeByte(isExpandedByDefault() ? 0x0 : 0x1); // version + writer.writeByte(isExpandedByDefault() && m_extendedData.empty() ? 0x0 : 0x1); // version writer.writeLengthPrefixedString(label()); - if(!isExpandedByDefault()) { - writer.writeUInt16BE(1); // extended header is 1 byte long - writer.writeByte(0x00); // all flags cleared + if(!isExpandedByDefault() || !m_extendedData.empty()) { + writer.writeUInt16BE(1 + m_extendedData.size()); // extended header is 1 byte long + byte flags = 0x00; + if(isExpandedByDefault()) { + flags |= 0x80; + } + writer.writeByte(flags); + writer.writeString(m_extendedData); } writer.writeUInt32BE(m_children.size()); for(const Entry *child : m_children) { @@ -391,7 +396,7 @@ AccountEntry::AccountEntry(istream &stream) if(version == 0x1) { // version 0x1 has an extended header uint16 extendedHeaderSize = reader.readUInt16BE(); // currently there's nothing to read here - stream.seekg(extendedHeaderSize, ios_base::cur); + m_extendedData = reader.readString(extendedHeaderSize); } uint32 fieldCount = reader.readUInt32BE(); for(uint32 i = 0; i < fieldCount; ++i) { @@ -425,8 +430,12 @@ AccountEntry::~AccountEntry() void AccountEntry::make(ostream &stream) const { BinaryWriter writer(&stream); - writer.writeByte(0x80 | 0x0); // version + writer.writeByte(0x80 | (m_extendedData.empty() ? 0x0 : 0x1)); // version writer.writeLengthPrefixedString(label()); + if(!m_extendedData.empty()) { + writer.writeUInt16BE(m_extendedData.size()); + writer.writeString(m_extendedData); + } writer.writeUInt32BE(m_fields.size()); for(const Field &field : m_fields) { field.make(stream); diff --git a/io/entry.h b/io/entry.h index 45531a8..c585dbf 100644 --- a/io/entry.h +++ b/io/entry.h @@ -53,6 +53,10 @@ private: std::string m_label; NodeEntry *m_parent; int m_index; + +protected: + std::string m_extendedData; + }; /*! @@ -110,6 +114,7 @@ public: void setExpandedByDefault(bool expandedByDefault); virtual void make(std::ostream &stream) const; virtual NodeEntry *clone() const; + private: std::vector m_children; bool m_expandedByDefault; diff --git a/io/field.cpp b/io/field.cpp index e21d249..00c5fdb 100644 --- a/io/field.cpp +++ b/io/field.cpp @@ -48,7 +48,7 @@ Field::Field(AccountEntry *tiedAccount, istream &stream) if(version == 0x1) { // version 0x1 has an extended header uint16 extendedHeaderSize = reader.readUInt16BE(); // currently there's nothing to read here - stream.seekg(extendedHeaderSize, ios_base::cur); + m_extendedData = reader.readString(extendedHeaderSize); } m_tiedAccount = tiedAccount; } else { @@ -62,10 +62,14 @@ Field::Field(AccountEntry *tiedAccount, istream &stream) void Field::make(ostream &stream) const { BinaryWriter writer(&stream); - writer.writeByte(0x0); // version + writer.writeByte(m_extendedData.empty() ? 0x0 : 0x1); // version writer.writeLengthPrefixedString(m_name); writer.writeLengthPrefixedString(m_value); writer.writeByte(static_cast(m_type)); + if(!m_extendedData.empty()) { + writer.writeUInt16BE(m_extendedData.size()); + writer.writeString(m_extendedData); + } } } diff --git a/io/field.h b/io/field.h index 19b70a6..3dd138c 100644 --- a/io/field.h +++ b/io/field.h @@ -38,6 +38,10 @@ private: std::string m_value; FieldType m_type; AccountEntry *m_tiedAccount; + +protected: + std::string m_extendedData; + }; /*! diff --git a/io/passwordfile.cpp b/io/passwordfile.cpp index b584561..ad68e16 100644 --- a/io/passwordfile.cpp +++ b/io/passwordfile.cpp @@ -135,8 +135,9 @@ void PasswordFile::load() } // check version and flags (used in version 0x3 only) uint32 version = m_freader.readUInt32LE(); - if(version != 0x0U && version != 0x1U && version != 0x2U && version != 0x3U) + if(version != 0x0U && version != 0x1U && version != 0x2U && version != 0x3U && version != 0x4U) { throw ParsingException("Version is unknown."); + } bool decrypterUsed; bool ivUsed; bool compressionUsed; @@ -150,6 +151,13 @@ void PasswordFile::load() ivUsed = version == 0x2U; compressionUsed = false; } + // skip extended header + // the extended header might be used in further versions to + // add additional information without breaking compatibility + if(version == 0x4U) { + uint16 extendedHeaderSize = m_freader.readUInt16BE(); + m_extendedHeader = m_freader.readString(extendedHeaderSize); + } // get length fstream::pos_type headerSize = m_file.tellg(); m_file.seekg(0, ios_base::end); @@ -250,8 +258,7 @@ void PasswordFile::save(bool useEncryption, bool useCompression) m_file.open(m_path, ios_base::in | ios_base::out | ios_base::trunc | ios_base::binary); // write header m_fwriter.writeUInt32LE(0x7770616DU); // write magic number - //m_fwriter.writeUInt32(useEncryption ? 2U : 0U); // write version (old versions) - m_fwriter.writeUInt32LE(0x3U); // write version + m_fwriter.writeUInt32LE(m_extendedHeader.empty() ? 0x3U : 0x4U); // write version, extended header requires version 4 byte flags = 0x00; if(useEncryption) { flags |= 0x80 | 0x40; @@ -260,6 +267,11 @@ void PasswordFile::save(bool useEncryption, bool useCompression) flags |= 0x20; } m_fwriter.writeByte(flags); + // write extened header + if(!m_extendedHeader.empty()) { + m_fwriter.writeUInt16BE(m_extendedHeader.size()); + m_fwriter.writeString(m_extendedHeader); + } // serialize root entry and descendants stringstream buffstr(stringstream::in | stringstream::out | stringstream::binary); buffstr.exceptions(ios_base::failbit | ios_base::badbit); diff --git a/io/passwordfile.h b/io/passwordfile.h index 36307db..32eb61e 100644 --- a/io/passwordfile.h +++ b/io/passwordfile.h @@ -46,6 +46,7 @@ private: std::string m_path; char m_password[32]; std::unique_ptr m_rootEntry; + std::string m_extendedHeader; std::fstream m_file; IoUtilities::BinaryReader m_freader; IoUtilities::BinaryWriter m_fwriter;