1437 lines
36 KiB
C#
1437 lines
36 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
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";
|
|
|
|
/// <summary>
|
|
/// Determines whether the database pointed to by the specified ioc should be (de)serialised in default (xml) or protocol buffers format.
|
|
/// </summary>
|
|
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
|
|
{
|
|
Context = new BufferContext(database,
|
|
new CryptoRandomStream(CrsAlgorithm.Salsa20, protectedStreamKey), hashOfHeader)
|
|
};
|
|
|
|
RuntimeTypeModel.Default.Serialize(stream, new PwDatabaseBuffer(database), context);
|
|
}
|
|
|
|
public static void ReadDocument(PwDatabase database, Stream stream, byte[] protectedStreamKey, byte[] expectedHashOfHeader)
|
|
{
|
|
|
|
var context = new BufferContext(database, new CryptoRandomStream(CrsAlgorithm.Salsa20, protectedStreamKey));
|
|
|
|
// Deserialisation will occur into the database already in context.
|
|
RuntimeTypeModel.Default.Deserialize(stream, null, typeof(PwDatabaseBuffer), new SerializationContext { Context = context });
|
|
|
|
if (expectedHashOfHeader.Length > 0 &&
|
|
!KeePassLib.Utility.MemUtil.ArraysEqual(context.HeaderHash, expectedHashOfHeader))
|
|
{
|
|
throw new IOException(KeePassLib.Resources.KLRes.FileCorrupted);
|
|
}
|
|
}
|
|
|
|
private class BufferContext
|
|
{
|
|
// ProtectedBinary objects may be referred to multipe times by entry histories, so reference them only once by ensuring a 1:1 mapping to the buffer wrapping them.
|
|
public readonly Dictionary<ProtectedBinary, NamedProtectedBinaryBuffer> BinaryPool = new Dictionary<ProtectedBinary, NamedProtectedBinaryBuffer>();
|
|
|
|
public readonly PwDatabase Database;
|
|
public readonly CryptoRandomStream RandomStream;
|
|
public byte[] HeaderHash;
|
|
|
|
public BufferContext(PwDatabase database, CryptoRandomStream randomStream, byte[] pbHashOfHeader = null)
|
|
{
|
|
Database = database;
|
|
RandomStream = randomStream;
|
|
HeaderHash = pbHashOfHeader;
|
|
}
|
|
}
|
|
|
|
[ProtoContract]
|
|
private class PwDatabaseBuffer
|
|
{
|
|
#region Serialization
|
|
|
|
private PwDatabase mDatabase;
|
|
private PwDeletedObjectListBuffer mDeletedObjects;
|
|
private PwCustomIconListBuffer mCustomIcons;
|
|
|
|
public PwDatabaseBuffer(PwDatabase database)
|
|
{
|
|
mDatabase = database;
|
|
mDeletedObjects = new PwDeletedObjectListBuffer(mDatabase.DeletedObjects);
|
|
mCustomIcons = new PwCustomIconListBuffer(mDatabase.CustomIcons);
|
|
}
|
|
|
|
[ProtoBeforeSerialization]
|
|
private void BeforeSerialization(SerializationContext context)
|
|
{
|
|
var bufferContext = (BufferContext)context.Context;
|
|
|
|
System.Diagnostics.Debug.Assert(mDatabase == bufferContext.Database);
|
|
|
|
HeaderHash = bufferContext.HeaderHash;
|
|
}
|
|
#endregion
|
|
|
|
#region Deserialization
|
|
public PwDatabaseBuffer()
|
|
{
|
|
}
|
|
|
|
[ProtoBeforeDeserialization]
|
|
private void BeforeDeserialization(SerializationContext context)
|
|
{
|
|
var bufferContext = (BufferContext)context.Context;
|
|
|
|
mDatabase = bufferContext.Database;
|
|
mDeletedObjects = new PwDeletedObjectListBuffer(mDatabase.DeletedObjects);
|
|
mCustomIcons = new PwCustomIconListBuffer(mDatabase.CustomIcons);
|
|
}
|
|
|
|
[ProtoAfterDeserialization]
|
|
private void AfterDeserialization(SerializationContext context)
|
|
{
|
|
var bufferContext = (BufferContext)context.Context;
|
|
|
|
bufferContext.HeaderHash = HeaderHash;
|
|
}
|
|
#endregion
|
|
|
|
[ProtoMember(1)]
|
|
public string Generator
|
|
{
|
|
get { return PwDatabase.LocalizedAppName; }
|
|
set { /* Ignore */ }
|
|
}
|
|
|
|
[ProtoMember(2, OverwriteList = true)]
|
|
public byte[] HeaderHash;
|
|
|
|
[ProtoMember(3)]
|
|
public string Name
|
|
{
|
|
get { return mDatabase.Name; }
|
|
set { mDatabase.Name = value; }
|
|
}
|
|
|
|
[ProtoMember(4)]
|
|
public DateTime NameChanged
|
|
{
|
|
get { return mDatabase.NameChanged; }
|
|
set { mDatabase.NameChanged = value; }
|
|
}
|
|
|
|
[ProtoMember(5)]
|
|
public string Description
|
|
{
|
|
get { return mDatabase.Description; }
|
|
set { mDatabase.Description = value; }
|
|
}
|
|
|
|
[ProtoMember(6)]
|
|
public DateTime DescriptionChanged
|
|
{
|
|
get { return mDatabase.DescriptionChanged; }
|
|
set { mDatabase.DescriptionChanged = value; }
|
|
}
|
|
|
|
[ProtoMember(7)]
|
|
public string DefaultUserName
|
|
{
|
|
get { return mDatabase.DefaultUserName; }
|
|
set { mDatabase.DefaultUserName = value; }
|
|
}
|
|
|
|
[ProtoMember(8)]
|
|
public DateTime DefaultUserNameChanged
|
|
{
|
|
get { return mDatabase.DefaultUserNameChanged; }
|
|
set { mDatabase.DefaultUserNameChanged = value; }
|
|
}
|
|
|
|
[ProtoMember(9)]
|
|
public uint MaintenanceHistoryDays
|
|
{
|
|
get { return mDatabase.MaintenanceHistoryDays; }
|
|
set { mDatabase.MaintenanceHistoryDays = value; }
|
|
}
|
|
|
|
[ProtoMember(10)]
|
|
public int Color
|
|
{
|
|
get { return mDatabase.Color.ToArgb(); }
|
|
set { mDatabase.Color = System.Drawing.Color.FromArgb(value); }
|
|
}
|
|
|
|
[ProtoMember(11)]
|
|
public DateTime MasterKeyChanged
|
|
{
|
|
get { return mDatabase.MasterKeyChanged; }
|
|
set { mDatabase.MasterKeyChanged = value; }
|
|
}
|
|
|
|
[ProtoMember(12)]
|
|
public long MasterKeyChangeRec
|
|
{
|
|
get { return mDatabase.MasterKeyChangeRec; }
|
|
set { mDatabase.MasterKeyChangeRec = value; }
|
|
}
|
|
|
|
[ProtoMember(13)]
|
|
public long MasterKeyChangeForce
|
|
{
|
|
get { return mDatabase.MasterKeyChangeForce; }
|
|
set { mDatabase.MasterKeyChangeForce = value; }
|
|
}
|
|
|
|
[ProtoMember(14)]
|
|
public MemoryProtectionConfigBuffer MemoryProtection
|
|
{
|
|
get { return new MemoryProtectionConfigBuffer(mDatabase.MemoryProtection); }
|
|
set { mDatabase.MemoryProtection = value.MemoryProtectionConfig; }
|
|
}
|
|
|
|
[ProtoMember(15)]
|
|
public PwCustomIconListBuffer CustomIcons
|
|
{
|
|
get { return mCustomIcons; }
|
|
}
|
|
|
|
[ProtoMember(16)]
|
|
public bool RecycleBinEnabled
|
|
{
|
|
get { return mDatabase.RecycleBinEnabled; }
|
|
set { mDatabase.RecycleBinEnabled = value; }
|
|
}
|
|
|
|
[ProtoMember(17, OverwriteList = true)]
|
|
public byte[] RecycleBinUuid
|
|
{
|
|
get { return mDatabase.RecycleBinUuid.UuidBytes; }
|
|
set { mDatabase.RecycleBinUuid = new PwUuid(value); }
|
|
}
|
|
|
|
[ProtoMember(18)]
|
|
public DateTime RecycleBinChanged
|
|
{
|
|
get { return mDatabase.RecycleBinChanged; }
|
|
set { mDatabase.RecycleBinChanged = value; }
|
|
}
|
|
|
|
[ProtoMember(19, OverwriteList = true)]
|
|
public byte[] EntryTemplatesGroup
|
|
{
|
|
get { return mDatabase.EntryTemplatesGroup.UuidBytes; }
|
|
set { mDatabase.EntryTemplatesGroup = new PwUuid(value); }
|
|
}
|
|
|
|
[ProtoMember(20)]
|
|
public DateTime EntryTemplatesGroupChanged
|
|
{
|
|
get { return mDatabase.EntryTemplatesGroupChanged; }
|
|
set { mDatabase.EntryTemplatesGroupChanged = value; }
|
|
}
|
|
|
|
[ProtoMember(21)]
|
|
public int HistoryMaxItems
|
|
{
|
|
get { return mDatabase.HistoryMaxItems; }
|
|
set { mDatabase.HistoryMaxItems = value; }
|
|
}
|
|
|
|
[ProtoMember(22)]
|
|
public long HistoryMaxSize
|
|
{
|
|
get { return mDatabase.HistoryMaxSize; }
|
|
set { mDatabase.HistoryMaxSize = value; }
|
|
}
|
|
|
|
[ProtoMember(23, OverwriteList = true)]
|
|
public byte[] LastSelectedGroup
|
|
{
|
|
get { return mDatabase.LastSelectedGroup.UuidBytes; }
|
|
set { mDatabase.LastSelectedGroup = new PwUuid(value); }
|
|
}
|
|
|
|
[ProtoMember(24, OverwriteList = true)]
|
|
public byte[] LastTopVisibleGroup
|
|
{
|
|
get { return mDatabase.LastTopVisibleGroup.UuidBytes; }
|
|
set { mDatabase.LastTopVisibleGroup = new PwUuid(value); }
|
|
}
|
|
|
|
[ProtoMember(25)]
|
|
public StringDictionaryExBuffer CustomData
|
|
{
|
|
get { return new StringDictionaryExBuffer(mDatabase.CustomData); }
|
|
set { mDatabase.CustomData = value.StringDictionaryEx; }
|
|
}
|
|
|
|
[ProtoMember(27)]
|
|
public PwGroupBuffer RootGroup
|
|
{
|
|
get { return new PwGroupBuffer(mDatabase.RootGroup); }
|
|
set { mDatabase.RootGroup = value.Group; }
|
|
}
|
|
|
|
[ProtoMember(28)]
|
|
public PwDeletedObjectListBuffer DeletedObjects
|
|
{
|
|
get { return mDeletedObjects; }
|
|
}
|
|
}
|
|
|
|
[ProtoContract]
|
|
private class StringDictionaryExBuffer : IEnumerable<KeyValuePair<String, String>>
|
|
{
|
|
#region Serialization
|
|
private StringDictionaryEx mStringDictionaryEx;
|
|
|
|
public StringDictionaryExBuffer(StringDictionaryEx stringDictionaryEx)
|
|
{
|
|
mStringDictionaryEx = stringDictionaryEx;
|
|
}
|
|
#endregion
|
|
|
|
#region Deserialization
|
|
public StringDictionaryExBuffer()
|
|
{
|
|
mStringDictionaryEx = new StringDictionaryEx();
|
|
}
|
|
|
|
public StringDictionaryEx StringDictionaryEx { get { return mStringDictionaryEx; } }
|
|
|
|
public void Add(KeyValuePair<String, String> kvp)
|
|
{
|
|
mStringDictionaryEx.Set(kvp.Key, kvp.Value);
|
|
}
|
|
#endregion
|
|
|
|
public IEnumerator<KeyValuePair<String, String>> GetEnumerator()
|
|
{
|
|
return mStringDictionaryEx.GetEnumerator();
|
|
}
|
|
|
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
|
{
|
|
return GetEnumerator();
|
|
}
|
|
}
|
|
|
|
[ProtoContract]
|
|
private class PwCustomIconListBuffer : IEnumerable<PwCustomIconBuffer>
|
|
{
|
|
private List<PwCustomIcon> mCustomIcons;
|
|
#region Serialization
|
|
public PwCustomIconListBuffer(List<PwCustomIcon> customIcons)
|
|
{
|
|
mCustomIcons = customIcons;
|
|
}
|
|
#endregion
|
|
|
|
#region Deserialization
|
|
public void Add(PwCustomIconBuffer item)
|
|
{
|
|
mCustomIcons.Add(item.CustomIcon);
|
|
}
|
|
#endregion
|
|
|
|
public IEnumerator<PwCustomIconBuffer> GetEnumerator()
|
|
{
|
|
foreach (var customIcon in mCustomIcons)
|
|
{
|
|
yield return new PwCustomIconBuffer(customIcon);
|
|
}
|
|
}
|
|
|
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
|
{
|
|
return GetEnumerator();
|
|
}
|
|
}
|
|
|
|
[ProtoContract]
|
|
private class PwCustomIconBuffer
|
|
{
|
|
#region Serialization
|
|
private PwCustomIcon mCustomIcon;
|
|
public PwCustomIconBuffer(PwCustomIcon CustomIcon)
|
|
{
|
|
mCustomIcon = CustomIcon;
|
|
Uuid = mCustomIcon.Uuid.UuidBytes;
|
|
ImageData = mCustomIcon.ImageDataPng;
|
|
}
|
|
#endregion
|
|
|
|
#region Deserialization
|
|
public PwCustomIconBuffer()
|
|
{
|
|
}
|
|
|
|
[ProtoAfterDeserialization]
|
|
private void AfterDeserialization(SerializationContext context)
|
|
{
|
|
mCustomIcon = new PwCustomIcon(new PwUuid(Uuid), ImageData);
|
|
}
|
|
|
|
public PwCustomIcon CustomIcon { get { return mCustomIcon; } }
|
|
#endregion
|
|
|
|
[ProtoMember(1, OverwriteList = true)]
|
|
public byte[] Uuid;
|
|
|
|
[ProtoMember(2, OverwriteList = true)]
|
|
public byte[] ImageData;
|
|
}
|
|
|
|
[ProtoContract]
|
|
private class MemoryProtectionConfigBuffer
|
|
{
|
|
#region Serialization
|
|
private readonly MemoryProtectionConfig mMemoryProtectionConfig;
|
|
|
|
public MemoryProtectionConfigBuffer(MemoryProtectionConfig memoryProtectionConfig)
|
|
{
|
|
mMemoryProtectionConfig = memoryProtectionConfig;
|
|
}
|
|
#endregion
|
|
|
|
#region Deserialization
|
|
public MemoryProtectionConfigBuffer()
|
|
{
|
|
mMemoryProtectionConfig = new MemoryProtectionConfig();
|
|
}
|
|
|
|
public MemoryProtectionConfig MemoryProtectionConfig { get { return mMemoryProtectionConfig; } }
|
|
#endregion
|
|
|
|
[ProtoMember(1)]
|
|
public bool ProtectTitle
|
|
{
|
|
get { return mMemoryProtectionConfig.ProtectTitle; }
|
|
set { mMemoryProtectionConfig.ProtectTitle = value; }
|
|
}
|
|
|
|
[ProtoMember(2)]
|
|
public bool ProtectUserName
|
|
{
|
|
get { return mMemoryProtectionConfig.ProtectUserName; }
|
|
set { mMemoryProtectionConfig.ProtectUserName = value; }
|
|
}
|
|
|
|
[ProtoMember(3)]
|
|
public bool ProtectPassword
|
|
{
|
|
get { return mMemoryProtectionConfig.ProtectPassword; }
|
|
set { mMemoryProtectionConfig.ProtectPassword = value; }
|
|
}
|
|
|
|
[ProtoMember(4)]
|
|
public bool ProtectUrl
|
|
{
|
|
get { return mMemoryProtectionConfig.ProtectUrl; }
|
|
set { mMemoryProtectionConfig.ProtectUrl = value; }
|
|
}
|
|
|
|
[ProtoMember(5)]
|
|
public bool ProtectNotes
|
|
{
|
|
get { return mMemoryProtectionConfig.ProtectNotes; }
|
|
set { mMemoryProtectionConfig.ProtectNotes = value; }
|
|
}
|
|
}
|
|
|
|
[ProtoContract]
|
|
private class PwDeletedObjectListBuffer : PwObjectListBufferBase<PwDeletedObject, PwDeletedObjectBuffer>
|
|
{
|
|
#region Serialization
|
|
public PwDeletedObjectListBuffer(PwObjectList<PwDeletedObject> objectList)
|
|
: base(objectList)
|
|
{
|
|
}
|
|
|
|
protected override PwDeletedObjectBuffer CreateBuffer(PwDeletedObject item)
|
|
{
|
|
return new PwDeletedObjectBuffer(item);
|
|
}
|
|
#endregion
|
|
|
|
#region Deserialization
|
|
public PwDeletedObjectListBuffer()
|
|
: base()
|
|
{
|
|
}
|
|
|
|
public override void Add(PwDeletedObjectBuffer item)
|
|
{
|
|
ObjectList.Add(item.DeletedObject);
|
|
}
|
|
#endregion
|
|
}
|
|
|
|
[ProtoContract]
|
|
private class PwDeletedObjectBuffer
|
|
{
|
|
#region Serialization
|
|
private readonly PwDeletedObject mDeletedObject;
|
|
|
|
public PwDeletedObjectBuffer(PwDeletedObject deletedObject)
|
|
{
|
|
mDeletedObject = deletedObject;
|
|
}
|
|
#endregion
|
|
|
|
#region Deserialization
|
|
public PwDeletedObjectBuffer()
|
|
{
|
|
mDeletedObject = new PwDeletedObject();
|
|
}
|
|
|
|
public PwDeletedObject DeletedObject { get { return mDeletedObject; } }
|
|
#endregion
|
|
|
|
[ProtoMember(1, OverwriteList = true)]
|
|
public byte[] Uuid
|
|
{
|
|
get { return mDeletedObject.Uuid.UuidBytes; }
|
|
set { mDeletedObject.Uuid = new PwUuid(value); }
|
|
}
|
|
|
|
[ProtoMember(2)]
|
|
public DateTime DeletionTime
|
|
{
|
|
get { return mDeletedObject.DeletionTime; }
|
|
set { mDeletedObject.DeletionTime = value; }
|
|
}
|
|
}
|
|
|
|
[ProtoContract]
|
|
private class PwGroupBuffer
|
|
{
|
|
#region Serialization
|
|
private readonly PwGroup mGroup;
|
|
private readonly PwGroupEntryListBuffer mEntries;
|
|
private readonly PwGroupGroupListBuffer mGroups;
|
|
|
|
public PwGroupBuffer(PwGroup group)
|
|
{
|
|
mGroup = group;
|
|
mEntries = new PwGroupEntryListBuffer(mGroup);
|
|
mGroups = new PwGroupGroupListBuffer(mGroup);
|
|
}
|
|
#endregion
|
|
|
|
#region Deserialization
|
|
public PwGroupBuffer()
|
|
{
|
|
mGroup = new PwGroup(false, false);
|
|
mEntries = new PwGroupEntryListBuffer(mGroup);
|
|
mGroups = new PwGroupGroupListBuffer(mGroup);
|
|
}
|
|
|
|
public PwGroup Group { get { return mGroup; } }
|
|
#endregion
|
|
|
|
[ProtoMember(1, OverwriteList = true)]
|
|
public byte[] Uuid
|
|
{
|
|
get { return mGroup.Uuid.UuidBytes; }
|
|
set { mGroup.Uuid = new PwUuid(value); }
|
|
}
|
|
|
|
[ProtoMember(2)]
|
|
public string Name
|
|
{
|
|
get { return mGroup.Name; }
|
|
set { mGroup.Name = value; }
|
|
}
|
|
|
|
[ProtoMember(3)]
|
|
public string Notes
|
|
{
|
|
get { return mGroup.Notes; }
|
|
set { mGroup.Notes = value; }
|
|
}
|
|
|
|
[ProtoMember(4)]
|
|
public PwIcon IconId
|
|
{
|
|
get { return mGroup.IconId; }
|
|
set { mGroup.IconId = value; }
|
|
}
|
|
|
|
[ProtoMember(5, OverwriteList = true)]
|
|
public byte[] CustomIconUuid
|
|
{
|
|
get { return mGroup.CustomIconUuid.EqualsValue(PwUuid.Zero) ? null : mGroup.CustomIconUuid.UuidBytes; ; }
|
|
set { mGroup.CustomIconUuid = value == null ? PwUuid.Zero : new PwUuid(value); }
|
|
}
|
|
|
|
[ProtoMember(6)]
|
|
public bool IsExpanded
|
|
{
|
|
get { return mGroup.IsExpanded; }
|
|
set { mGroup.IsExpanded = value; }
|
|
}
|
|
|
|
[ProtoMember(7)]
|
|
public string DefaultAutoTypeSequence
|
|
{
|
|
get { return mGroup.DefaultAutoTypeSequence; }
|
|
set { mGroup.DefaultAutoTypeSequence = value; }
|
|
}
|
|
|
|
[ProtoMember(8)]
|
|
public DateTime LastModificationTime
|
|
{
|
|
get { return mGroup.LastModificationTime; }
|
|
set { mGroup.LastModificationTime = value; }
|
|
}
|
|
|
|
[ProtoMember(9)]
|
|
public DateTime CreationTime
|
|
{
|
|
get { return mGroup.CreationTime; }
|
|
set { mGroup.CreationTime = value; }
|
|
}
|
|
|
|
[ProtoMember(10)]
|
|
public DateTime LastAccessTime
|
|
{
|
|
get { return mGroup.LastAccessTime; }
|
|
set { mGroup.LastAccessTime = value; }
|
|
}
|
|
|
|
[ProtoMember(11)]
|
|
public DateTime ExpiryTime
|
|
{
|
|
get { return mGroup.ExpiryTime; }
|
|
set { mGroup.ExpiryTime = value; }
|
|
}
|
|
|
|
[ProtoMember(12)]
|
|
public bool Expires
|
|
{
|
|
get { return mGroup.Expires; }
|
|
set { mGroup.Expires = value; }
|
|
}
|
|
|
|
[ProtoMember(13)]
|
|
public ulong UsageCount
|
|
{
|
|
get { return mGroup.UsageCount; }
|
|
set { mGroup.UsageCount = value; }
|
|
}
|
|
|
|
[ProtoMember(14)]
|
|
public DateTime LocationChanged
|
|
{
|
|
get { return mGroup.LocationChanged; }
|
|
set { mGroup.LocationChanged = value; }
|
|
}
|
|
|
|
[ProtoMember(15)]
|
|
public bool? EnableAutoType
|
|
{
|
|
get { return mGroup.EnableAutoType; }
|
|
set { mGroup.EnableAutoType = value; }
|
|
}
|
|
|
|
[ProtoMember(16)]
|
|
public bool? EnableSearching
|
|
{
|
|
get { return mGroup.EnableSearching; }
|
|
set { mGroup.EnableSearching = value; }
|
|
}
|
|
|
|
[ProtoMember(17, OverwriteList = true)]
|
|
public byte[] LastTopVisibleEntry
|
|
{
|
|
get { return mGroup.LastTopVisibleEntry.UuidBytes; }
|
|
set { mGroup.LastTopVisibleEntry = new PwUuid(value); }
|
|
}
|
|
|
|
[ProtoMember(18)]
|
|
public PwGroupGroupListBuffer Groups
|
|
{
|
|
get { return mGroups; }
|
|
}
|
|
|
|
[ProtoMember(19)]
|
|
public PwGroupEntryListBuffer Entries
|
|
{
|
|
get { return mEntries; }
|
|
}
|
|
}
|
|
|
|
private abstract class PwObjectListBufferBase<TData, TDataBuffer> : IEnumerable<TDataBuffer>
|
|
where TData : class, KeePassLib.Interfaces.IDeepCloneable<TData>
|
|
{
|
|
#region Serialization
|
|
private PwObjectList<TData> mObjectList;
|
|
|
|
protected PwObjectListBufferBase(PwObjectList<TData> objectList)
|
|
{
|
|
mObjectList = objectList;
|
|
}
|
|
|
|
protected abstract TDataBuffer CreateBuffer(TData item);
|
|
#endregion
|
|
|
|
#region Deserialization
|
|
protected PwObjectListBufferBase()
|
|
{
|
|
mObjectList = new PwObjectList<TData>();
|
|
}
|
|
|
|
public PwObjectList<TData> ObjectList { get { return mObjectList; } }
|
|
|
|
public abstract void Add(TDataBuffer item);
|
|
#endregion
|
|
|
|
public IEnumerator<TDataBuffer> GetEnumerator()
|
|
{
|
|
foreach (var item in mObjectList)
|
|
{
|
|
yield return CreateBuffer(item);
|
|
}
|
|
}
|
|
|
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
|
{
|
|
return GetEnumerator();
|
|
}
|
|
}
|
|
|
|
[ProtoContract]
|
|
private class PwGroupGroupListBuffer : PwObjectListBufferBase<PwGroup, PwGroupBuffer>
|
|
{
|
|
#region Serialization
|
|
private PwGroup mGroup;
|
|
public PwGroupGroupListBuffer(PwGroup group)
|
|
: base(group.Groups)
|
|
{
|
|
mGroup = group;
|
|
}
|
|
|
|
protected override PwGroupBuffer CreateBuffer(PwGroup item)
|
|
{
|
|
return new PwGroupBuffer(item);
|
|
}
|
|
#endregion
|
|
|
|
#region Deserialization
|
|
public override void Add(PwGroupBuffer item)
|
|
{
|
|
mGroup.AddGroup(item.Group, true);
|
|
}
|
|
#endregion
|
|
}
|
|
|
|
[ProtoContract]
|
|
private class PwGroupEntryListBuffer : PwObjectListBufferBase<PwEntry, PwEntryBuffer>
|
|
{
|
|
#region Serialization
|
|
private PwGroup mGroup;
|
|
public PwGroupEntryListBuffer(PwGroup group)
|
|
: base(group.Entries)
|
|
{
|
|
mGroup = group;
|
|
}
|
|
|
|
protected override PwEntryBuffer CreateBuffer(PwEntry item)
|
|
{
|
|
return new PwEntryBuffer(item);
|
|
}
|
|
#endregion
|
|
|
|
#region Deserialization
|
|
public override void Add(PwEntryBuffer item)
|
|
{
|
|
mGroup.AddEntry(item.Entry, true);
|
|
}
|
|
#endregion
|
|
}
|
|
|
|
[ProtoContract]
|
|
private class PwEntryListBuffer : PwObjectListBufferBase<PwEntry, PwEntryBuffer>
|
|
{
|
|
#region Serialization
|
|
public PwEntryListBuffer(PwObjectList<PwEntry> entryList)
|
|
: base(entryList)
|
|
{
|
|
}
|
|
|
|
protected override PwEntryBuffer CreateBuffer(PwEntry item)
|
|
{
|
|
return new PwEntryBuffer(item);
|
|
}
|
|
#endregion
|
|
|
|
#region Deserialization
|
|
public PwEntryListBuffer()
|
|
: base()
|
|
{
|
|
}
|
|
|
|
public override void Add(PwEntryBuffer item)
|
|
{
|
|
ObjectList.Add(item.Entry);
|
|
}
|
|
#endregion
|
|
}
|
|
|
|
[ProtoContract]
|
|
private class PwEntryBuffer
|
|
{
|
|
#region Serialization
|
|
private readonly PwEntry mEntry;
|
|
private ProtectedStandardFieldDictionaryBuffer mEntryStandardStrings;
|
|
private ProtectedCustomFieldDictionaryBuffer mEntryCustomStrings;
|
|
private NamedProtectedBinaryListBuffer mEntryBinaries;
|
|
|
|
public PwEntryBuffer(PwEntry entry)
|
|
{
|
|
mEntry = entry;
|
|
}
|
|
|
|
[ProtoBeforeSerialization]
|
|
private void BeforeSerialization(SerializationContext context)
|
|
{
|
|
var bufferContext = (BufferContext)context.Context;
|
|
|
|
// ProtectedStringDictionaryBuffer nver gets its own ProtoBeforeSerialization called as it's a list of objects rather than an object itself
|
|
List<KeyValuePair<String, ProtectedString>> customFields;
|
|
mEntryStandardStrings = new ProtectedStandardFieldDictionaryBuffer(mEntry.Strings, (int)mEntry.Strings.UCount, bufferContext, out customFields);
|
|
mEntryCustomStrings = new ProtectedCustomFieldDictionaryBuffer(customFields);
|
|
mEntryBinaries = new NamedProtectedBinaryListBuffer(mEntry.Binaries, (int)mEntry.Binaries.UCount, bufferContext);
|
|
}
|
|
#endregion
|
|
|
|
#region Deserialization
|
|
public PwEntryBuffer()
|
|
{
|
|
mEntry = new PwEntry(false, false);
|
|
mEntryStandardStrings = new ProtectedStandardFieldDictionaryBuffer(mEntry.Strings);
|
|
mEntryCustomStrings = new ProtectedCustomFieldDictionaryBuffer(mEntry.Strings);
|
|
mEntryBinaries = new NamedProtectedBinaryListBuffer(mEntry.Binaries);
|
|
}
|
|
|
|
public PwEntry Entry { get { return mEntry; } }
|
|
#endregion
|
|
|
|
[ProtoMember(1, OverwriteList = true)]
|
|
public byte[] Uuid
|
|
{
|
|
get { return mEntry.Uuid.UuidBytes; }
|
|
set { mEntry.SetUuid(new PwUuid(value), false); }
|
|
}
|
|
|
|
[ProtoMember(2)]
|
|
public PwIcon IconId
|
|
{
|
|
get { return mEntry.IconId; }
|
|
set { mEntry.IconId = value; }
|
|
}
|
|
|
|
[ProtoMember(3, OverwriteList = true)]
|
|
public byte[] CustomIconUuid
|
|
{
|
|
get { return mEntry.CustomIconUuid.EqualsValue(PwUuid.Zero) ? null : mEntry.CustomIconUuid.UuidBytes; }
|
|
set { mEntry.CustomIconUuid = value == null ? PwUuid.Zero : new PwUuid(value); }
|
|
}
|
|
|
|
[ProtoMember(4)]
|
|
public int ForegroundColor
|
|
{
|
|
get { return mEntry.ForegroundColor.ToArgb(); }
|
|
set { mEntry.ForegroundColor = Color.FromArgb(value); }
|
|
}
|
|
|
|
[ProtoMember(5)]
|
|
public int BackgroundColor
|
|
{
|
|
get { return mEntry.BackgroundColor.ToArgb(); }
|
|
set { mEntry.BackgroundColor = Color.FromArgb(value); }
|
|
}
|
|
|
|
[ProtoMember(6)]
|
|
public string OverrideUrl
|
|
{
|
|
get { return mEntry.OverrideUrl; }
|
|
set { mEntry.OverrideUrl = value; }
|
|
}
|
|
|
|
[ProtoMember(7)]
|
|
public IList<String> Tags
|
|
{
|
|
get { return mEntry.Tags; }
|
|
}
|
|
|
|
[ProtoMember(8)]
|
|
public DateTime LastModificationTime
|
|
{
|
|
get { return mEntry.LastModificationTime; }
|
|
set { mEntry.LastModificationTime = value; }
|
|
}
|
|
|
|
[ProtoMember(9)]
|
|
public DateTime CreationTime
|
|
{
|
|
get { return mEntry.CreationTime; }
|
|
set { mEntry.CreationTime = value; }
|
|
}
|
|
|
|
[ProtoMember(10)]
|
|
public DateTime LastAccessTime
|
|
{
|
|
get { return mEntry.LastAccessTime; }
|
|
set { mEntry.LastAccessTime = value; }
|
|
}
|
|
|
|
[ProtoMember(11)]
|
|
public DateTime ExpiryTime
|
|
{
|
|
get { return mEntry.ExpiryTime; }
|
|
set { mEntry.ExpiryTime = value; }
|
|
}
|
|
|
|
[ProtoMember(12)]
|
|
public bool Expires
|
|
{
|
|
get { return mEntry.Expires; }
|
|
set { mEntry.Expires = value; }
|
|
}
|
|
|
|
[ProtoMember(13)]
|
|
public ulong UsageCount
|
|
{
|
|
get { return mEntry.UsageCount; }
|
|
set { mEntry.UsageCount = value; }
|
|
}
|
|
|
|
[ProtoMember(14)]
|
|
public DateTime LocationChanged
|
|
{
|
|
get { return mEntry.LocationChanged; }
|
|
set { mEntry.LocationChanged = value; }
|
|
}
|
|
|
|
[ProtoMember(15)]
|
|
public ProtectedStandardFieldDictionaryBuffer StandardStrings
|
|
{
|
|
get { return mEntryStandardStrings; }
|
|
}
|
|
|
|
[ProtoMember(16)]
|
|
public ProtectedCustomFieldDictionaryBuffer CustomStrings
|
|
{
|
|
get { return mEntryCustomStrings; }
|
|
}
|
|
|
|
[ProtoMember(17, AsReference = true)]
|
|
public NamedProtectedBinaryListBuffer Binaries
|
|
{
|
|
get { return mEntryBinaries; }
|
|
}
|
|
|
|
[ProtoMember(18)]
|
|
public AutoTypeConfigBuffer AutoType
|
|
{
|
|
get { return new AutoTypeConfigBuffer(mEntry.AutoType); }
|
|
set { mEntry.AutoType = value.AutoTypeConfig; }
|
|
}
|
|
|
|
[ProtoMember(19)]
|
|
public PwEntryListBuffer History
|
|
{
|
|
get { return new PwEntryListBuffer(mEntry.History); }
|
|
set { mEntry.History = value.ObjectList; }
|
|
}
|
|
|
|
}
|
|
|
|
private abstract class ProtectedStringDictionaryBuffer<TKey> : IEnumerable<KeyValuePair<TKey, ProtectedStringBuffer>>
|
|
{
|
|
#region Serialization
|
|
private List<KeyValuePair<TKey, ProtectedStringBuffer>> mProtectedStringBuffers;
|
|
|
|
/// <summary>
|
|
/// Serialisation constructor. Reads strings from dictionary, does not write to it
|
|
/// </summary>
|
|
protected ProtectedStringDictionaryBuffer(int capacity)
|
|
{
|
|
mProtectedStringBuffers = new List<KeyValuePair<TKey, ProtectedStringBuffer>>(capacity);
|
|
}
|
|
|
|
protected void AddStringField(TKey key, ProtectedString value, bool? overrideProtect)
|
|
{
|
|
mProtectedStringBuffers.Add(new KeyValuePair<TKey, ProtectedStringBuffer>(key, new ProtectedStringBuffer(value, overrideProtect)));
|
|
}
|
|
|
|
public IEnumerator<KeyValuePair<TKey, ProtectedStringBuffer>> GetEnumerator()
|
|
{
|
|
return mProtectedStringBuffers.GetEnumerator();
|
|
}
|
|
|
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
|
{
|
|
return GetEnumerator();
|
|
}
|
|
#endregion
|
|
|
|
#region Deserialization
|
|
private readonly ProtectedStringDictionary mDictionary;
|
|
|
|
/// <summary>
|
|
/// Deerialisation constructor. Writes strings to dictionary, does read from it
|
|
/// </summary>
|
|
protected ProtectedStringDictionaryBuffer(ProtectedStringDictionary dictionary)
|
|
{
|
|
mDictionary = dictionary;
|
|
}
|
|
|
|
public void Add(KeyValuePair<TKey, ProtectedStringBuffer> item)
|
|
{
|
|
mDictionary.Set(GetFieldName(item.Key), item.Value.ProtectedString);
|
|
}
|
|
|
|
protected abstract string GetFieldName(TKey key);
|
|
|
|
#endregion
|
|
}
|
|
|
|
[ProtoContract]
|
|
private class ProtectedCustomFieldDictionaryBuffer : ProtectedStringDictionaryBuffer<String>
|
|
{
|
|
public ProtectedCustomFieldDictionaryBuffer(List<KeyValuePair<String, ProtectedString>> entryStrings)
|
|
: base(entryStrings.Count)
|
|
{
|
|
foreach (var kvp in entryStrings)
|
|
{
|
|
System.Diagnostics.Debug.Assert(!PwDefs.IsStandardField(kvp.Key));
|
|
AddStringField(kvp.Key, kvp.Value, null);
|
|
}
|
|
}
|
|
|
|
public ProtectedCustomFieldDictionaryBuffer(ProtectedStringDictionary dictionary)
|
|
: base(dictionary)
|
|
{ }
|
|
|
|
protected override string GetFieldName(string key)
|
|
{
|
|
return key;
|
|
}
|
|
}
|
|
|
|
[ProtoContract]
|
|
private class ProtectedStandardFieldDictionaryBuffer : ProtectedStringDictionaryBuffer<ProtectedStandardFieldDictionaryBuffer.StandardField>
|
|
{
|
|
public enum StandardField
|
|
{
|
|
Title,
|
|
UserName,
|
|
Password,
|
|
Url,
|
|
Notes
|
|
}
|
|
|
|
public ProtectedStandardFieldDictionaryBuffer(IEnumerable<KeyValuePair<String, ProtectedString>> entryStrings, int entryStringCount, BufferContext context,
|
|
out List<KeyValuePair<String, ProtectedString>> customFields) // Perf optimisation - return the custom fields so we don't have to determine them again
|
|
: base(entryStringCount)
|
|
{
|
|
customFields = new List<KeyValuePair<string, ProtectedString>>(entryStringCount);
|
|
|
|
var database = context.Database;
|
|
|
|
foreach (var kvp in entryStrings)
|
|
{
|
|
var field = GetField(kvp.Key);
|
|
|
|
if (field.HasValue)
|
|
{
|
|
// Logic from KdbxFile.Write
|
|
|
|
bool? overrideProtect = null;
|
|
// Adjust memory protection setting (which might be different
|
|
// from the database default, e.g. due to an import which
|
|
// didn't specify the correct setting)
|
|
switch (field.Value)
|
|
{
|
|
case StandardField.Title:
|
|
overrideProtect = database.MemoryProtection.ProtectTitle;
|
|
break;
|
|
case StandardField.UserName:
|
|
overrideProtect = database.MemoryProtection.ProtectUserName;
|
|
break;
|
|
case StandardField.Password:
|
|
overrideProtect = database.MemoryProtection.ProtectPassword;
|
|
break;
|
|
case StandardField.Url:
|
|
overrideProtect = database.MemoryProtection.ProtectUrl;
|
|
break;
|
|
case StandardField.Notes:
|
|
overrideProtect = database.MemoryProtection.ProtectNotes;
|
|
break;
|
|
}
|
|
|
|
AddStringField(field.Value, kvp.Value, overrideProtect);
|
|
}
|
|
else
|
|
{
|
|
customFields.Add(kvp);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static StandardField? GetField(string fieldName)
|
|
{
|
|
switch (fieldName)
|
|
{
|
|
case PwDefs.TitleField:
|
|
return StandardField.Title;
|
|
case PwDefs.UserNameField:
|
|
return StandardField.UserName;
|
|
case PwDefs.PasswordField:
|
|
return StandardField.Password;
|
|
case PwDefs.UrlField:
|
|
return StandardField.Url;
|
|
case PwDefs.NotesField:
|
|
return StandardField.Notes;
|
|
|
|
default:
|
|
System.Diagnostics.Debug.Assert(!PwDefs.IsStandardField(fieldName));
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public ProtectedStandardFieldDictionaryBuffer(ProtectedStringDictionary dictionary)
|
|
: base(dictionary)
|
|
{ }
|
|
|
|
protected override string GetFieldName(StandardField key)
|
|
{
|
|
switch (key)
|
|
{
|
|
case StandardField.Title:
|
|
return PwDefs.TitleField;
|
|
case StandardField.UserName:
|
|
return PwDefs.UserNameField;
|
|
case StandardField.Password:
|
|
return PwDefs.PasswordField;
|
|
case StandardField.Url:
|
|
return PwDefs.UrlField;
|
|
case StandardField.Notes:
|
|
return PwDefs.NotesField;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
}
|
|
}
|
|
|
|
[ProtoContract]
|
|
private class ProtectedStringBuffer
|
|
{
|
|
#region Serialisation
|
|
private ProtectedString mProtectedString;
|
|
|
|
public ProtectedStringBuffer(ProtectedString protectedString, bool? overrideProtect)
|
|
{
|
|
mProtectedString = protectedString;
|
|
IsProtected = overrideProtect.GetValueOrDefault(mProtectedString.IsProtected);
|
|
}
|
|
|
|
[ProtoBeforeSerialization]
|
|
private void BeforeSerialization(SerializationContext context)
|
|
{
|
|
if (IsProtected)
|
|
{
|
|
Value = mProtectedString.ReadXorredString(((BufferContext)context.Context).RandomStream);
|
|
}
|
|
else
|
|
{
|
|
Value = mProtectedString.ReadUtf8();
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Deserialisation
|
|
public ProtectedStringBuffer()
|
|
{
|
|
}
|
|
|
|
[ProtoAfterDeserialization]
|
|
private void AfterDeserialization(SerializationContext context)
|
|
{
|
|
if (IsProtected)
|
|
{
|
|
byte[] pbPad = ((BufferContext)context.Context).RandomStream.GetRandomBytes((uint)Value.Length);
|
|
mProtectedString = new ProtectedString(IsProtected, new XorredBuffer(Value, pbPad));
|
|
}
|
|
else
|
|
{
|
|
mProtectedString = new ProtectedString(IsProtected, Value);
|
|
}
|
|
}
|
|
|
|
public ProtectedString ProtectedString { get { return mProtectedString; } }
|
|
|
|
#endregion
|
|
|
|
[ProtoMember(1)]
|
|
public bool IsProtected;
|
|
|
|
[ProtoMember(2, OverwriteList = true)]
|
|
public byte[] Value;
|
|
}
|
|
|
|
[ProtoContract]
|
|
private class NamedProtectedBinaryListBuffer : IEnumerable<NamedProtectedBinaryBuffer>
|
|
{
|
|
#region Serialisation
|
|
private readonly List<NamedProtectedBinaryBuffer> mNamedBinaries;
|
|
|
|
public NamedProtectedBinaryListBuffer(IEnumerable<KeyValuePair<String, ProtectedBinary>> binaries, int binariesCount, BufferContext context)
|
|
{
|
|
mNamedBinaries = new List<NamedProtectedBinaryBuffer>(binariesCount);
|
|
foreach (var kvp in binaries)
|
|
{
|
|
NamedProtectedBinaryBuffer namedProtectedBinaryBuffer;
|
|
if (!context.BinaryPool.TryGetValue(kvp.Value, out namedProtectedBinaryBuffer))
|
|
{
|
|
// Hasn't been put in the pool yet, so create it
|
|
namedProtectedBinaryBuffer = new NamedProtectedBinaryBuffer(kvp);
|
|
context.BinaryPool.Add(kvp.Value, namedProtectedBinaryBuffer);
|
|
}
|
|
mNamedBinaries.Add(namedProtectedBinaryBuffer);
|
|
}
|
|
}
|
|
|
|
public IEnumerator<NamedProtectedBinaryBuffer> GetEnumerator()
|
|
{
|
|
return mNamedBinaries.GetEnumerator();
|
|
}
|
|
|
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
|
{
|
|
return GetEnumerator();
|
|
}
|
|
#endregion
|
|
|
|
#region Deserialization
|
|
private readonly ProtectedBinaryDictionary mBinaryDictionary;
|
|
|
|
public NamedProtectedBinaryListBuffer(ProtectedBinaryDictionary binaryDictionary)
|
|
{
|
|
mBinaryDictionary = binaryDictionary;
|
|
}
|
|
|
|
public void Add(NamedProtectedBinaryBuffer item)
|
|
{
|
|
mBinaryDictionary.Set(item.Name, item.ProtectedBinary);
|
|
}
|
|
#endregion
|
|
}
|
|
|
|
[ProtoContract]
|
|
private class NamedProtectedBinaryBuffer
|
|
{
|
|
#region Serialization
|
|
private ProtectedBinary mProtectedBinary;
|
|
public NamedProtectedBinaryBuffer(KeyValuePair<string, ProtectedBinary> namedBinary)
|
|
{
|
|
Name = namedBinary.Key;
|
|
mProtectedBinary = namedBinary.Value;
|
|
IsProtected = mProtectedBinary.IsProtected;
|
|
}
|
|
|
|
[ProtoBeforeSerialization]
|
|
private void BeforeSerialization(SerializationContext context)
|
|
{
|
|
if (IsProtected)
|
|
{
|
|
Value = mProtectedBinary.ReadXorredData(((BufferContext)context.Context).RandomStream);
|
|
}
|
|
else
|
|
{
|
|
Value = mProtectedBinary.ReadData();
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Deserialisation
|
|
public NamedProtectedBinaryBuffer()
|
|
{
|
|
}
|
|
|
|
[ProtoAfterDeserialization]
|
|
private void AfterDeserialization(SerializationContext context)
|
|
{
|
|
if (IsProtected)
|
|
{
|
|
byte[] pbPad = ((BufferContext)context.Context).RandomStream.GetRandomBytes((uint)Value.Length);
|
|
mProtectedBinary = new ProtectedBinary(IsProtected, new XorredBuffer(Value, pbPad));
|
|
}
|
|
else
|
|
{
|
|
mProtectedBinary = new ProtectedBinary(IsProtected, Value);
|
|
}
|
|
}
|
|
|
|
public ProtectedBinary ProtectedBinary { get { return mProtectedBinary; } }
|
|
|
|
#endregion
|
|
|
|
[ProtoMember(1)]
|
|
public string Name;
|
|
|
|
[ProtoMember(2)]
|
|
public bool IsProtected;
|
|
|
|
[ProtoMember(3, OverwriteList = true)]
|
|
public byte[] Value;
|
|
}
|
|
|
|
[ProtoContract]
|
|
private class AutoTypeConfigBuffer
|
|
{
|
|
private readonly AutoTypeAssociationsBuffer mAutoTypeAssociationsBuffer;
|
|
#region Serialization
|
|
private AutoTypeConfig mAutoTypeConfig;
|
|
public AutoTypeConfigBuffer(AutoTypeConfig autoTypeConfig)
|
|
{
|
|
mAutoTypeConfig = autoTypeConfig;
|
|
mAutoTypeAssociationsBuffer = new AutoTypeAssociationsBuffer(mAutoTypeConfig);
|
|
}
|
|
#endregion
|
|
|
|
#region Deserialization
|
|
public AutoTypeConfigBuffer()
|
|
{
|
|
mAutoTypeConfig = new AutoTypeConfig();
|
|
mAutoTypeAssociationsBuffer = new AutoTypeAssociationsBuffer(mAutoTypeConfig);
|
|
}
|
|
|
|
public AutoTypeConfig AutoTypeConfig { get { return mAutoTypeConfig; } }
|
|
#endregion
|
|
|
|
[ProtoMember(1)]
|
|
public bool Enabled
|
|
{
|
|
get { return mAutoTypeConfig.Enabled; }
|
|
set { mAutoTypeConfig.Enabled = value; }
|
|
}
|
|
|
|
[ProtoMember(2)]
|
|
public AutoTypeObfuscationOptions ObfuscationOptions
|
|
{
|
|
get { return mAutoTypeConfig.ObfuscationOptions; }
|
|
set { mAutoTypeConfig.ObfuscationOptions = value; }
|
|
}
|
|
|
|
[ProtoMember(3)]
|
|
public string DefaultSequence
|
|
{
|
|
get { return mAutoTypeConfig.DefaultSequence; }
|
|
set { mAutoTypeConfig.DefaultSequence = value; }
|
|
}
|
|
|
|
[ProtoMember(4)]
|
|
public AutoTypeAssociationsBuffer Associations
|
|
{
|
|
get { return mAutoTypeAssociationsBuffer; }
|
|
}
|
|
}
|
|
|
|
[ProtoContract]
|
|
private class AutoTypeAssociationsBuffer : IEnumerable<AutoTypeAssociationBuffer>
|
|
{
|
|
#region Serialization
|
|
private AutoTypeConfig mAutoTypeConfig;
|
|
|
|
public AutoTypeAssociationsBuffer(AutoTypeConfig autoTypeConfig)
|
|
{
|
|
mAutoTypeConfig = autoTypeConfig;
|
|
}
|
|
|
|
public IEnumerator<AutoTypeAssociationBuffer> GetEnumerator()
|
|
{
|
|
foreach (var autoTypeAssociation in mAutoTypeConfig.Associations)
|
|
{
|
|
yield return new AutoTypeAssociationBuffer(autoTypeAssociation);
|
|
}
|
|
}
|
|
|
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
|
{
|
|
return GetEnumerator();
|
|
}
|
|
#endregion
|
|
|
|
#region Deserialization
|
|
public void Add(AutoTypeAssociationBuffer value)
|
|
{
|
|
mAutoTypeConfig.Add(value.AutoTypeAssociation);
|
|
}
|
|
#endregion
|
|
}
|
|
|
|
[ProtoContract]
|
|
private class AutoTypeAssociationBuffer
|
|
{
|
|
#region Serialization
|
|
private AutoTypeAssociation mAutoTypeAssociation;
|
|
|
|
public AutoTypeAssociationBuffer(AutoTypeAssociation autoTypeAssociation)
|
|
{
|
|
mAutoTypeAssociation = autoTypeAssociation;
|
|
}
|
|
#endregion
|
|
|
|
#region Deserialization
|
|
public AutoTypeAssociationBuffer()
|
|
{
|
|
mAutoTypeAssociation = new AutoTypeAssociation();
|
|
}
|
|
|
|
public AutoTypeAssociation AutoTypeAssociation { get { return mAutoTypeAssociation; } }
|
|
#endregion
|
|
|
|
[ProtoMember(1)]
|
|
public string WindowName
|
|
{
|
|
get { return mAutoTypeAssociation.WindowName; }
|
|
set { mAutoTypeAssociation.WindowName = value; }
|
|
}
|
|
|
|
[ProtoMember(2)]
|
|
public string Sequence
|
|
{
|
|
get { return mAutoTypeAssociation.Sequence; }
|
|
set { mAutoTypeAssociation.Sequence = value; }
|
|
}
|
|
}
|
|
}
|
|
}
|