diff --git a/src/KeePassLib2Android/PwDatabase.cs b/src/KeePassLib2Android/PwDatabase.cs index 925ab468..425c65ec 100644 --- a/src/KeePassLib2Android/PwDatabase.cs +++ b/src/KeePassLib2Android/PwDatabase.cs @@ -588,7 +588,7 @@ namespace KeePassLib kdbx.DetachBinaries = m_strDetachBins; Stream s = IOConnection.OpenRead(ioSource); - kdbx.Load(s, KdbxFormat.Default, slLogger); + kdbx.Load(s, KdbpFile.GetFormatToUse(ioSource), slLogger); s.Close(); m_pbHashOfLastIO = kdbx.HashOfFileOnDisk; @@ -623,7 +623,7 @@ namespace KeePassLib Stream s = ft.OpenWrite(); KdbxFile kdb = new KdbxFile(this); - kdb.Save(s, null, KdbxFormat.Default, slLogger); + kdb.Save(s, null, KdbpFile.GetFormatToUse(m_ioSource), slLogger); ft.CommitWrite(); diff --git a/src/KeePassLib2Android/Serialization/KdbxFile.Read.cs b/src/KeePassLib2Android/Serialization/KdbxFile.Read.cs index 4eff0c4a..236fe138 100644 --- a/src/KeePassLib2Android/Serialization/KdbxFile.Read.cs +++ b/src/KeePassLib2Android/Serialization/KdbxFile.Read.cs @@ -82,7 +82,7 @@ namespace KeePassLib.Serialization BinaryReaderEx brDecrypted = null; Stream readerStream = null; - if(kdbFormat == KdbxFormat.Default) + if(kdbFormat == KdbxFormat.Default || kdbFormat == KdbxFormat.ProtocolBuffers) { br = new BinaryReaderEx(hashedStream, encNoBom, KLRes.FileCorrupted); ReadHeader(br); @@ -127,34 +127,21 @@ namespace KeePassLib.Serialization } else m_randomStream = null; // No random stream for plain-text files - // Test: read to memory var stopWatch = Stopwatch.StartNew(); - var memStream = new MemoryStream((int)hashedStream.Length); - CopyStream(readerStream, memStream); - readerStream.Close(); - readerStream = memStream; - System.Diagnostics.Debug.WriteLine(String.Format("Copy input stream: {0}ms", stopWatch.ElapsedMilliseconds)); - var isXml = memStream.ReadByte() == '<'; - memStream.Seek(0, SeekOrigin.Begin); - - if (isXml) + if (kdbFormat == KdbxFormat.ProtocolBuffers) { - stopWatch.Restart(); - - ReadXmlStreamed(readerStream, hashedStream); - System.Diagnostics.Debug.WriteLine(String.Format("ReadXmlStreamed: {0}ms", stopWatch.ElapsedMilliseconds)); - - } - else - { - stopWatch.Restart(); - KdbpFile.ReadDocument(m_pwDatabase, readerStream, m_pbProtectedStreamKey, m_pbHashOfHeader); System.Diagnostics.Debug.WriteLine(String.Format("KdbpFile.ReadDocument: {0}ms", stopWatch.ElapsedMilliseconds)); } + else + { + ReadXmlStreamed(readerStream, hashedStream); + + System.Diagnostics.Debug.WriteLine(String.Format("ReadXmlStreamed: {0}ms", stopWatch.ElapsedMilliseconds)); + } readerStream.Close(); // GC.KeepAlive(br); diff --git a/src/KeePassLib2Android/Serialization/KdbxFile.Write.cs b/src/KeePassLib2Android/Serialization/KdbxFile.Write.cs index fbc31e6c..3d2ba9f4 100644 --- a/src/KeePassLib2Android/Serialization/KdbxFile.Write.cs +++ b/src/KeePassLib2Android/Serialization/KdbxFile.Write.cs @@ -101,7 +101,7 @@ namespace KeePassLib.Serialization m_pbStreamStartBytes = cr.GetRandomBytes(32); Stream writerStream; - if(m_format == KdbxFormat.Default) + if(m_format == KdbxFormat.Default || m_format == KdbxFormat.ProtocolBuffers) { WriteHeader(hashedStream); // Also flushes the stream @@ -122,17 +122,24 @@ namespace KeePassLib.Serialization writerStream = hashedStream; else { Debug.Assert(false); throw new FormatException("KdbFormat"); } - /* - m_xmlWriter = new XmlTextWriter(writerStream, encNoBom); - WriteDocument(pgDataSource); + var stopWatch = Stopwatch.StartNew(); - m_xmlWriter.Flush(); - m_xmlWriter.Close(); - */ + if (m_format == KdbxFormat.ProtocolBuffers) + { + KdbpFile.WriteDocument(m_pwDatabase, writerStream, m_pbProtectedStreamKey, m_pbHashOfHeader); + } + else + { + m_xmlWriter = new XmlTextWriter(writerStream, encNoBom); + WriteDocument(pgDataSource); - KdbpFile.WriteDocument(m_pwDatabase, writerStream, m_pbProtectedStreamKey, m_pbHashOfHeader); + m_xmlWriter.Flush(); + m_xmlWriter.Close(); + } writerStream.Close(); + + System.Diagnostics.Debug.WriteLine(String.Format("{1}: {0}ms", stopWatch.ElapsedMilliseconds, m_format == KdbxFormat.ProtocolBuffers ? "KdbpFile.WriteDocument" : "Xml WriteDocument")); } finally { CommonCleanUpWrite(sSaveTo, hashedStream); } } diff --git a/src/KeePassLib2Android/Serialization/KdbxFile.cs b/src/KeePassLib2Android/Serialization/KdbxFile.cs index b1cd287a..9fc980f8 100644 --- a/src/KeePassLib2Android/Serialization/KdbxFile.cs +++ b/src/KeePassLib2Android/Serialization/KdbxFile.cs @@ -52,7 +52,8 @@ namespace KeePassLib.Serialization /// /// Use this flag when exporting data to a plain-text XML file. /// - PlainXml + PlainXml, + ProtocolBuffers } /// diff --git a/src/KeePassLib2Android/Serialization/ProtoBuf/KdbpFile.cs b/src/KeePassLib2Android/Serialization/ProtoBuf/KdbpFile.cs index 326d391b..a5827357 100644 --- a/src/KeePassLib2Android/Serialization/ProtoBuf/KdbpFile.cs +++ b/src/KeePassLib2Android/Serialization/ProtoBuf/KdbpFile.cs @@ -1,18 +1,29 @@ using System; using System.Collections.Generic; -using System.Text; -using ProtoBuf; using System.Drawing; -using KeePassLib.Collections; -using KeePassLib.Security; -using KeePassLib.Cryptography; using System.IO; +using KeePassLib.Collections; +using KeePassLib.Cryptography; +using KeePassLib.Security; +using KeePassLib.Utility; +using ProtoBuf; using ProtoBuf.Meta; namespace KeePassLib.Serialization { internal class KdbpFile { + public const string FileNameExtension = "kdbp"; + + /// + /// Determines whether the database pointed to by the specified ioc should be (de)serialised in default (xml) or protocol buffers format. + /// + public static KdbxFormat GetFormatToUse(IOConnectionInfo ioc) + { + // If the filename ends in .kdbp, use ProtocolBuffers format. + return UrlUtil.GetExtension(UrlUtil.GetFileName(ioc.Path)).Equals(KdbpFile.FileNameExtension, StringComparison.OrdinalIgnoreCase) ? KdbxFormat.ProtocolBuffers : KdbxFormat.Default; + } + public static void WriteDocument(PwDatabase database, Stream stream, byte[] protectedStreamKey, byte[] hashOfHeader) { var context = new SerializationContext