/// <summary> /// This constructor creates a named registry key, relative to an existing parent /// </summary> /// <param name="parent"></param> /// <param name="name"></param> public RegKeyEntry(RegKeyEntry parent, string name) { Parent = parent; Name = name; DefaultValue = null; RemoveFlag = false; }
/// <summary> /// Find or create a named registry value /// </summary> /// <param name="name">Name of the registry value</param> /// <returns>Newly created registry value or null if it cannot be created</returns> public RegValueEntry FindOrCreateValue(string name) { string key = null; if (name == null) { if (DefaultValue == null) { DefaultValue = new RegValueEntry(); } return(DefaultValue); } else { key = name.ToLower(); } if (Values.ContainsKey(key)) { return(Values[key]); } RegValueEntry result = new RegValueEntry(name); Values[key] = result; return(result); }
private static void WriteXmlFileFormat(XmlWriter writer, RegValueEntry value) { if (value.RemoveFlag) { if (value.IsDefaultValue) { writer.WriteStartElement("remove-default-value"); } else { writer.WriteStartElement("remove-value"); writer.WriteAttributeString("name", value.Name); } } else { writer.WriteStartElement(value.Kind.ToString()); if (!value.IsDefaultValue) { writer.WriteAttributeString("name", value.Name); } switch (value.Kind) { case RegValueEntryKind.DWord: case RegValueEntryKind.QWord: writer.WriteValue(value.Value.ToString()); break; case RegValueEntryKind.SZ: case RegValueEntryKind.ExpandSZ: EncodeStringValue(writer, value); break; case RegValueEntryKind.MultiSZ: EncodeMultiStringValue(writer, value); break; default: if ((value.Value != null) && (value.Value is byte[])) { WriteHexEncodedValue(writer, value.Kind, value.Value as byte[]); } else if ((value.Kind != RegValueEntryKind.Unknown) && (value.Kind != RegValueEntryKind.None)) { throw new Exception(string.Format("ERROR, XmlRegFileExporter() isn't prepared to handle data of type {0}", value.Kind)); } break; } } writer.WriteEndElement(); }
/// <summary> /// When creating a diff/merge file, asks the key to add a value based on an existing value /// </summary> /// <param name="key">existing key</param> /// <param name="value">existing value</param> public void AskToAddValue(RegKeyEntry key, RegValueEntry value) { key = AskToAddKey(key); if (value.IsDefaultValue) { key.DefaultValue = new RegValueEntry(value); } else { string valueName = value.Name.ToLower(); key.Values[valueName] = new RegValueEntry(value); } }
private static void EncodeStringValue(XmlWriter Writer, RegValueEntry value) { string content = value.Value.ToString(); if ((content.Trim() != "") && IsValidXmlString(content)) { Writer.WriteValue(content); } else { Writer.WriteAttributeString("encoding", "base-64"); Writer.WriteValue(EncodeBase64(content)); } }
private void ExpectValueNameDefinition(char c) { if (c == '"') { CurrentValue = CurrentKey.FindOrCreateValue(Buffer.ToString()); ParserState = ExpectEqualSign; } else if (c == '\\') { ParserState = ExpectQuotedCharInStringValueNameDefinition; } else { Buffer.Append(c); } }
private static void EncodeMultiStringValue(XmlWriter Writer, RegValueEntry value) { string[] content = (string[])value.Value; foreach (string line in content) { Writer.WriteStartElement("line"); if ((line.Trim() != "") && IsValidXmlString(line)) { Writer.WriteValue(line); } else { Writer.WriteAttributeString("encoding", "base-64"); Writer.WriteValue(EncodeBase64(line)); } Writer.WriteEndElement(); } }
private void CompareByteArrays(RegKeyEntry key, RegValueEntry value1, RegValueEntry value2) { byte[] a = value1.AsByteArray(); byte[] b = value2.AsByteArray(); if (a.Length != b.Length) { DataMismatches.Add(new DataMismatch(key, value1, value2)); } else { for (int i = 0; i < a.Length; ++i) { if (a[i] != b[i]) { DataMismatches.Add(new DataMismatch(key, value1, value2)); } } } }
private void CompareStringArrays(RegKeyEntry key, RegValueEntry value1, RegValueEntry value2) { string[] a = value1.Value as string[]; string[] b = value2.Value as string[]; if (a.Length != b.Length) { DataMismatches.Add(new DataMismatch(key, value1, value2)); } else { for (int i = 0; i < a.Length; ++i) { if (!a[i].Equals(b[i])) { DataMismatches.Add(new DataMismatch(key, value1, value2)); } } } }
private void ExpectStartOfLine(char c) { if (c == '\r') { } else if (c == '\n') { ++LineNumber; } else if (c == '[') { Buffer.Clear(); NumberOfClosingBracketsExpected = 0; ParserState = ExpectKeyPath; } else if (c == '@') { CurrentValue = CurrentKey.FindOrCreateValue(null); ParserState = ExpectEqualSign; } else if (c == '"') { Buffer.Clear(); ParserState = ExpectValueNameDefinition; } else if ((c == '#') && AllowHashtagComments) { Buffer.Clear(); ParserState = ExpectCommentUntilEndOfLine; } else if ((c == ';') && AllowSemicolonComments) { Buffer.Clear(); ParserState = ExpectCommentUntilEndOfLine; } else { throw SyntaxError("ERROR, don't support values yet; '{0}'", c); } }
private void CompareValues(RegKeyEntry key, RegValueEntry value1, RegValueEntry value2) { if (value1.Kind != value2.Kind) { KindMismatches.Add(new KindMismatch(key, value1, value2)); } else { if (value1.Value is byte[]) { CompareByteArrays(key, value1, value2); } else if (value1.Value is string[]) { CompareStringArrays(key, value1, value2); } else if (!value1.Value.Equals(value2.Value)) { DataMismatches.Add(new DataMismatch(key, value1, value2)); } } }
/// <summary> /// Copy constructor: takes an existing RegKeyEntry and creates a full clone of it /// </summary> /// <param name="objectSrc"></param> public RegKeyEntry(RegKeyEntry objectSrc) { Name = objectSrc.Name; Parent = objectSrc.Parent; foreach (string subkeyName in objectSrc.Keys.Keys) { Keys[subkeyName] = new RegKeyEntry(objectSrc.Keys[subkeyName]); Keys[subkeyName].Parent = this; } foreach (string valueName in objectSrc.Values.Keys) { Values[valueName] = new RegValueEntry(objectSrc.Values[valueName]); } if (objectSrc.DefaultValue == null) { DefaultValue = null; } else { DefaultValue = new RegValueEntry(objectSrc.DefaultValue); } }
private void ParseXmlContent(string content) { RegValueEntry CurrentValue = null; RegKeyEntry CurrentKey = null; StringBuilder CurrentContent = null; RegValueEntryKind CurrentKind = RegValueEntryKind.Unknown; bool isBase64Encoding = false; List <string> currentStringList = new List <string>(); using (XmlReader reader = XmlReader.Create(new StringReader(content))) { while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (reader.Name.Equals("registry")) { string version = reader.GetAttribute("version"); if (version == "2") { // ok, this version is supported } else { throw new System.Data.SyntaxErrorException("Unexpected XML format: must be using registry version 2.0 or higher"); } } else if (reader.Name.Equals("key")) { string name = reader.GetAttribute("name"); if (CurrentKey == null) { Trace.Assert(Result == null); Result = new RegKeyEntry(null, name); CurrentKey = Result; } else { RegKeyEntry newKey = new RegKeyEntry(CurrentKey, name); CurrentKey.Keys[newKey.Name.ToLower()] = newKey; if (!reader.IsEmptyElement) { CurrentKey = newKey; } } } else if ((CurrentKind == RegValueEntryKind.MultiSZ) && reader.Name.Equals("line")) { if (reader.IsEmptyElement) { currentStringList.Add(""); } else { CurrentContent = new StringBuilder(); string encoding = reader.GetAttribute("encoding"); isBase64Encoding = (encoding != null) && encoding.Equals("base-64"); } } else { try { CurrentKind = (RegValueEntryKind)Enum.Parse(typeof(RegValueEntryKind), reader.Name); } catch (ArgumentException) { throw new System.Data.SyntaxErrorException( string.Format("ERROR, {0} is not a valid entry in a registry .XML file", reader.Name)); } string name = reader.GetAttribute("name"); CurrentValue = new RegValueEntry(name); if (name == null) { CurrentKey.DefaultValue = CurrentValue; } else { CurrentKey.Values[name.ToLower()] = CurrentValue; } if (reader.IsEmptyElement) { if (RegValueEntryKind.SZ == CurrentKind) { CurrentValue.SetStringValue(""); } else if (RegValueEntryKind.ExpandSZ == CurrentKind) { CurrentValue.SetExpandedStringValue(""); } else if (RegValueEntryKind.DWord == CurrentKind) { CurrentValue.SetIntValue(0); } else if (RegValueEntryKind.QWord == CurrentKind) { CurrentValue.SetLongValue(0); } else if (RegValueEntryKind.MultiSZ == CurrentKind) { CurrentValue.SetMultiStringValue(new List <string>()); } else { CurrentValue.SetBinaryType(CurrentKind, new byte[] { }); } CurrentValue = null; } else { CurrentContent = new StringBuilder(); string encoding = reader.GetAttribute("encoding"); isBase64Encoding = (encoding != null) && encoding.Equals("base-64"); if (CurrentKind == RegValueEntryKind.MultiSZ) { currentStringList.Clear(); } else { CurrentContent = new StringBuilder(); } } } break; case XmlNodeType.Text: if (CurrentContent != null) { CurrentContent.Append(reader.Value); } break; case XmlNodeType.EndElement: if (reader.Name.Equals("key")) { Trace.Assert(CurrentKey != null); CurrentKey = CurrentKey.Parent; } else if ((CurrentKind == RegValueEntryKind.MultiSZ) && reader.Name.Equals("line")) { if (isBase64Encoding) { byte[] bytes = Convert.FromBase64String(CurrentContent.ToString()); currentStringList.Add(System.Text.Encoding.Unicode.GetString(bytes)); } else { currentStringList.Add(CurrentContent.ToString()); } } else if (reader.Name.Equals("registry")) { } else if (reader.Name.Equals(CurrentKind.ToString())) { if (RegValueEntryKind.SZ == CurrentKind) { if (isBase64Encoding) { byte[] bytes = Convert.FromBase64String(CurrentContent.ToString()); CurrentValue.SetStringValue(System.Text.Encoding.Unicode.GetString(bytes)); } else { CurrentValue.SetStringValue(CurrentContent.ToString()); } } else if (RegValueEntryKind.ExpandSZ == CurrentKind) { if (isBase64Encoding) { byte[] bytes = Convert.FromBase64String(CurrentContent.ToString()); CurrentValue.SetExpandedStringValue(System.Text.Encoding.Unicode.GetString(bytes)); } else { CurrentValue.SetExpandedStringValue(CurrentContent.ToString()); } } else if (RegValueEntryKind.DWord == CurrentKind) { string temp = CurrentContent.ToString(); if (temp.Contains("$$")) { CurrentValue.SetEscapedIntValue(temp); } else { CurrentValue.SetIntValue(int.Parse(temp)); } } else if (RegValueEntryKind.QWord == CurrentKind) { string temp = CurrentContent.ToString(); if (temp.Contains("$$")) { CurrentValue.SetEscapedLongValue(temp); } else { CurrentValue.SetLongValue(long.Parse(temp)); } } else if (RegValueEntryKind.MultiSZ == CurrentKind) { CurrentValue.SetMultiStringValue(currentStringList); currentStringList.Clear(); } else { CurrentValue.SetBinaryType(CurrentKind, DecodeHexByteArray(CurrentContent.ToString())); } CurrentValue = null; } break; } } } }
private void CompareRecursive(RegKeyEntry key1, RegKeyEntry key2) { // Acquire keys and sort them. List <string> sortedNames; sortedNames = key1.Keys.Keys.ToList(); sortedNames.Sort(); foreach (string keyName in sortedNames) { RegKeyEntry subkey1 = key1.Keys[keyName]; if (key2.Keys.ContainsKey(keyName)) { RegKeyEntry subkey2 = key2.Keys[keyName]; CompareRecursive(subkey1, subkey2); } else { // two forms are supported: either a single key (as in FOO=BAR), or a complete path (as in HKLM\BLA\BLUB=HKCU\SMA\BU) // we have a mismatch. It may happen that the key needs to be renamed, and then compared again if (Aliases.ContainsKey(keyName.ToLower())) { string aliasedName = Aliases[keyName.ToLower()].ToLower(); if (key2.Keys.ContainsKey(aliasedName)) { RegKeyEntry subkey2 = key2.Keys[aliasedName]; CompareRecursive(subkey1, subkey2); } else { MissingKeysIn2.Add(subkey1); } } else { MissingKeysIn2.Add(subkey1); } } } if (key1.DefaultValue != null) { Debug.Assert(key1.DefaultValue.IsDefaultValue); if (key2.DefaultValue == null) { MissingValuesIn2.Add(new MissingValue(key1, key1.DefaultValue)); } } else if (key2.DefaultValue != null) { Debug.Assert(key2.DefaultValue.IsDefaultValue); MissingValuesIn1.Add(new MissingValue(key2, key2.DefaultValue)); } sortedNames = key1.Values.Keys.ToList(); sortedNames.Sort(); foreach (string valueName in sortedNames) { RegValueEntry value1 = key1.Values[valueName]; if (key2.Values.ContainsKey(valueName)) { CompareValues(key1, value1, key2.Values[valueName]); } else { MissingValuesIn2.Add(new MissingValue(key1, value1)); } } sortedNames = key2.Values.Keys.ToList(); sortedNames.Sort(); foreach (string valueName in sortedNames) { RegValueEntry value2 = key2.Values[valueName]; if (!key1.Values.ContainsKey(valueName)) { MissingValuesIn1.Add(new MissingValue(key2, value2)); } } sortedNames = key2.Keys.Keys.ToList(); sortedNames.Sort(); foreach (string keyName in sortedNames) { if (!key1.Keys.ContainsKey(keyName)) { if (Aliases.ContainsKey(keyName.ToLower())) { string aliasedName = Aliases[keyName.ToLower()].ToLower(); if (!key1.Keys.ContainsKey(aliasedName)) { MissingKeysIn1.Add(key2.Keys[keyName]); } } else { MissingKeysIn1.Add(key2.Keys[keyName]); } } } }
/// <summary> /// Copy Constructor /// </summary> /// <param name="objectSrc"></param> public RegValueEntry(RegValueEntry objectSrc) { Name = objectSrc.Name; Value = objectSrc.Value; Kind = objectSrc.Kind; }