mirror of
https://github.com/LANCommander/RegParser.git
synced 2026-08-01 01:53:24 -04:00
184 lines
5.7 KiB
C#
184 lines
5.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace RegParserDotNet
|
|
{
|
|
public class RegParser
|
|
{
|
|
public RegParser() { }
|
|
|
|
public IEnumerable<RegistryEntry> Parse(string contents)
|
|
{
|
|
var keys = new List<RegistryEntry>();
|
|
|
|
string pathPattern = @"^\[(?<Path>.+)\]$";
|
|
|
|
using (var reader = new StringReader(contents))
|
|
{
|
|
string line;
|
|
string path = "";
|
|
string pathContents = "";
|
|
|
|
do
|
|
{
|
|
line = reader.ReadLine();
|
|
|
|
if (line != null)
|
|
{
|
|
var pathMatch = Regex.Match(line, pathPattern);
|
|
|
|
if (pathMatch.Success)
|
|
{
|
|
keys.AddRange(ParsePathContents(pathContents, path));
|
|
|
|
pathContents = "";
|
|
|
|
path = pathMatch.Groups["Path"].Value;
|
|
|
|
keys.Add(new RegistryEntry(path));
|
|
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
keys.AddRange(ParsePathContents(pathContents, path));
|
|
|
|
pathContents += line + "\n";
|
|
}
|
|
while (line != null);
|
|
}
|
|
|
|
return keys;
|
|
}
|
|
|
|
private IEnumerable<RegistryEntry> ParsePathContents(string pathContents, string path)
|
|
{
|
|
string propertyNamePattern = @"(?>(?<DefaultProperty>@)=|(?<!\\)""(?<PropertyName>.+)(?<!\\)""=)";
|
|
string dwordValuePattern = @"dword:(?<DwordValue>[0-9a-fA-F]+)$";
|
|
string stringValuePattern = @"(?!=\\)""(?<StringValue>.*)(?!=\\)""\s*$";
|
|
string binaryValuePattern = @"hex:(?<BinaryValue>(?:[0-9a-fA-F]{2},?)+\\(?:\n\s*(?:[0-9a-fA-F]{2},?)+\\?)*)";
|
|
|
|
var fullPattern = $"^{propertyNamePattern}(?>{dwordValuePattern}|{stringValuePattern}|{binaryValuePattern})";
|
|
|
|
var keys = new List<RegistryEntry>();
|
|
|
|
var matches = Regex.Matches(pathContents, fullPattern, RegexOptions.Multiline);
|
|
|
|
foreach (Match match in matches)
|
|
{
|
|
keys.Add(GetEntryFromMatch(match, path));
|
|
}
|
|
|
|
return keys;
|
|
}
|
|
|
|
private RegistryEntry GetEntryFromMatch(Match match, string path)
|
|
{
|
|
var entry = new RegistryEntry(path)
|
|
{
|
|
Type = GetTypeFromMatch(match),
|
|
Property = Regex.Unescape(match.Groups["PropertyName"].Value)
|
|
};
|
|
|
|
if (match.Groups["DefaultProperty"].Success)
|
|
entry.Property = match.Groups["DefaultProperty"].Value;
|
|
|
|
switch (entry.Type)
|
|
{
|
|
case RegistryValueType.REG_DWORD:
|
|
entry.Value = Int32.Parse(match.Groups["DwordValue"].Value, NumberStyles.HexNumber);
|
|
break;
|
|
|
|
case RegistryValueType.REG_BINARY:
|
|
entry.Value = HexToBytes(match.Groups["BinaryValue"].Value);
|
|
break;
|
|
|
|
case RegistryValueType.REG_SZ:
|
|
entry.Value = Regex.Unescape(match.Groups["StringValue"].Value);
|
|
break;
|
|
}
|
|
|
|
return entry;
|
|
}
|
|
|
|
private RegistryValueType GetTypeFromMatch(Match match)
|
|
{
|
|
|
|
var groupNames = new string[] {
|
|
"DwordValue",
|
|
"StringValue",
|
|
"BinaryValue"
|
|
};
|
|
|
|
foreach (var groupName in groupNames)
|
|
{
|
|
if (match.Groups[groupName].Success)
|
|
{
|
|
switch (groupName)
|
|
{
|
|
case "DwordValue":
|
|
return RegistryValueType.REG_DWORD;
|
|
|
|
case "StringValue":
|
|
return RegistryValueType.REG_SZ;
|
|
|
|
case "BinaryValue":
|
|
return RegistryValueType.REG_BINARY;
|
|
}
|
|
}
|
|
}
|
|
|
|
return RegistryValueType.REG_NONE;
|
|
}
|
|
|
|
private readonly static Dictionary<char, byte> HexMap = new Dictionary<char, byte>()
|
|
{
|
|
{ 'a', 0xA },{ 'b', 0xB },{ 'c', 0xC },{ 'd', 0xD },
|
|
{ 'e', 0xE },{ 'f', 0xF },{ 'A', 0xA },{ 'B', 0xB },
|
|
{ 'C', 0xC },{ 'D', 0xD },{ 'E', 0xE },{ 'F', 0xF },
|
|
{ '0', 0x0 },{ '1', 0x1 },{ '2', 0x2 },{ '3', 0x3 },
|
|
{ '4', 0x4 },{ '5', 0x5 },{ '6', 0x6 },{ '7', 0x7 },
|
|
{ '8', 0x8 },{ '9', 0x9 }
|
|
};
|
|
|
|
private byte[] HexToBytes(string hex)
|
|
{
|
|
if (String.IsNullOrWhiteSpace(hex))
|
|
throw new ArgumentException("Input can't be empty");
|
|
|
|
// Sanitize
|
|
hex = hex.Replace("0x", "").Replace(",", "").Replace("\\", "").Replace("\n", "").Replace(" ", "");
|
|
|
|
if (hex.Length % 2 != 0)
|
|
throw new ArgumentException("Hex string must be an even number of characters");
|
|
|
|
var bytes = new byte[hex.Length / 2];
|
|
|
|
char left;
|
|
char right;
|
|
|
|
try
|
|
{
|
|
int byteIndex = 0;
|
|
|
|
for (int i = 0; i < hex.Length; i += 2, byteIndex++)
|
|
{
|
|
left = hex[i];
|
|
right = hex[i + 1];
|
|
|
|
bytes[byteIndex] = (byte)((HexMap[left] << 4) | HexMap[right]);
|
|
}
|
|
|
|
return bytes;
|
|
}
|
|
catch (KeyNotFoundException)
|
|
{
|
|
throw new FormatException("Invalid hex string");
|
|
}
|
|
}
|
|
}
|
|
}
|