- added global extended header (introducing global file format version

4)
- unknown extended headers will not be just ignored anymore, they will
be read and written again when saving the file
This commit is contained in:
Martchus 2015-06-07 00:14:00 +02:00
parent a6a089d765
commit b860d01b1e
6 changed files with 47 additions and 12 deletions

View File

@ -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<string> &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);

View File

@ -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<Entry *> m_children;
bool m_expandedByDefault;

View File

@ -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<byte>(m_type));
if(!m_extendedData.empty()) {
writer.writeUInt16BE(m_extendedData.size());
writer.writeString(m_extendedData);
}
}
}

View File

@ -38,6 +38,10 @@ private:
std::string m_value;
FieldType m_type;
AccountEntry *m_tiedAccount;
protected:
std::string m_extendedData;
};
/*!

View File

@ -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);

View File

@ -46,6 +46,7 @@ private:
std::string m_path;
char m_password[32];
std::unique_ptr<NodeEntry> m_rootEntry;
std::string m_extendedHeader;
std::fstream m_file;
IoUtilities::BinaryReader m_freader;
IoUtilities::BinaryWriter m_fwriter;