Initial commit - WPinternals 2.6

This commit is contained in:
Rene Lergner
2018-10-25 22:35:49 +02:00
commit 396ae57f05
483 changed files with 159677 additions and 0 deletions
+217
View File
@@ -0,0 +1,217 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Registry
{
using System;
using System.Collections.Generic;
using System.IO;
/// <summary>
/// An internal structure within registry files, bins are the major unit of allocation in a registry hive.
/// </summary>
/// <remarks>Bins are divided into multiple cells, that contain actual registry data.</remarks>
internal sealed class Bin
{
private RegistryHive _hive;
private Stream _fileStream;
private long _streamPos;
private BinHeader _header;
private byte[] _buffer;
private List<Range<int, int>> _freeCells;
public Bin(RegistryHive hive, Stream stream)
{
_hive = hive;
_fileStream = stream;
_streamPos = stream.Position;
stream.Position = _streamPos;
byte[] buffer = Utilities.ReadFully(stream, 0x20);
_header = new BinHeader();
_header.ReadFrom(buffer, 0);
_fileStream.Position = _streamPos;
_buffer = Utilities.ReadFully(_fileStream, _header.BinSize);
// Gather list of all free cells.
_freeCells = new List<Range<int, int>>();
int pos = 0x20;
while (pos < _buffer.Length)
{
int size = Utilities.ToInt32LittleEndian(_buffer, pos);
if (size > 0)
{
_freeCells.Add(new Range<int, int>(pos, size));
}
pos += Math.Abs(size);
}
}
public Cell TryGetCell(int index)
{
int size = Utilities.ToInt32LittleEndian(_buffer, index - _header.FileOffset);
if (size >= 0)
{
return null;
}
return Cell.Parse(_hive, index, _buffer, index + 4 - _header.FileOffset);
}
public void FreeCell(int index)
{
int freeIndex = index - _header.FileOffset;
int len = Utilities.ToInt32LittleEndian(_buffer, freeIndex);
if (len >= 0)
{
throw new ArgumentException("Attempt to free non-allocated cell");
}
len = Math.Abs(len);
// If there's a free cell before this one, combine
int i = 0;
while (i < _freeCells.Count && _freeCells[i].Offset < freeIndex)
{
if (_freeCells[i].Offset + _freeCells[i].Count == freeIndex)
{
freeIndex = _freeCells[i].Offset;
len += _freeCells[i].Count;
_freeCells.RemoveAt(i);
}
else
{
++i;
}
}
// If there's a free cell after this one, combine
if (i < _freeCells.Count && _freeCells[i].Offset == freeIndex + len)
{
len += _freeCells[i].Count;
_freeCells.RemoveAt(i);
}
// Record the new free cell
_freeCells.Insert(i, new Range<int, int>(freeIndex, len));
// Free cells are indicated by length > 0
Utilities.WriteBytesLittleEndian(len, _buffer, freeIndex);
_fileStream.Position = _streamPos + freeIndex;
_fileStream.Write(_buffer, freeIndex, 4);
}
public bool UpdateCell(Cell cell)
{
int index = cell.Index - _header.FileOffset;
int allocSize = Math.Abs(Utilities.ToInt32LittleEndian(_buffer, index));
int newSize = cell.Size + 4;
if (newSize > allocSize)
{
return false;
}
cell.WriteTo(_buffer, index + 4);
_fileStream.Position = _streamPos + index;
_fileStream.Write(_buffer, index, newSize);
return true;
}
public byte[] ReadRawCellData(int cellIndex, int maxBytes)
{
int index = cellIndex - _header.FileOffset;
int len = Math.Abs(Utilities.ToInt32LittleEndian(_buffer, index));
byte[] result = new byte[Math.Min(len - 4, maxBytes)];
Array.Copy(_buffer, index + 4, result, 0, result.Length);
return result;
}
internal bool WriteRawCellData(int cellIndex, byte[] data, int offset, int count)
{
int index = cellIndex - _header.FileOffset;
int allocSize = Math.Abs(Utilities.ToInt32LittleEndian(_buffer, index));
int newSize = count + 4;
if (newSize > allocSize)
{
return false;
}
Array.Copy(data, offset, _buffer, index + 4, count);
_fileStream.Position = _streamPos + index;
_fileStream.Write(_buffer, index, newSize);
return true;
}
internal int AllocateCell(int size)
{
if (size < 8 || size % 8 != 0)
{
throw new ArgumentException("Invalid cell size");
}
// Very inefficient algorithm - will lead to fragmentation
for (int i = 0; i < _freeCells.Count; ++i)
{
int result = _freeCells[i].Offset + _header.FileOffset;
if (_freeCells[i].Count > size)
{
// Record the newly allocated cell
Utilities.WriteBytesLittleEndian(-size, _buffer, _freeCells[i].Offset);
_fileStream.Position = _streamPos + _freeCells[i].Offset;
_fileStream.Write(_buffer, _freeCells[i].Offset, 4);
// Keep the remainder of the free buffer as unallocated
_freeCells[i] = new Range<int, int>(_freeCells[i].Offset + size, _freeCells[i].Count - size);
Utilities.WriteBytesLittleEndian(_freeCells[i].Count, _buffer, _freeCells[i].Offset);
_fileStream.Position = _streamPos + _freeCells[i].Offset;
_fileStream.Write(_buffer, _freeCells[i].Offset, 4);
return result;
}
else if (_freeCells[i].Count == size)
{
// Record the whole of the free buffer as a newly allocated cell
Utilities.WriteBytesLittleEndian(-size, _buffer, _freeCells[i].Offset);
_fileStream.Position = _streamPos + _freeCells[i].Offset;
_fileStream.Write(_buffer, _freeCells[i].Offset, 4);
_freeCells.RemoveAt(i);
return result;
}
}
return -1;
}
}
}
+69
View File
@@ -0,0 +1,69 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Registry
{
using System;
using System.IO;
internal sealed class BinHeader : IByteArraySerializable
{
public const int HeaderSize = 0x20;
public int FileOffset;
public int BinSize;
private const uint Signature = 0x6E696268;
public BinHeader()
{
}
public int Size
{
get { return HeaderSize; }
}
public int ReadFrom(byte[] buffer, int offset)
{
uint sig = Utilities.ToUInt32LittleEndian(buffer, offset + 0);
if (sig != Signature)
{
throw new IOException("Invalid signature for registry bin");
}
FileOffset = Utilities.ToInt32LittleEndian(buffer, offset + 0x04);
BinSize = Utilities.ToInt32LittleEndian(buffer, offset + 0x08);
long unknown = Utilities.ToInt64LittleEndian(buffer, offset + 0x0C);
long unknown1 = Utilities.ToInt64LittleEndian(buffer, offset + 0x14);
int unknown2 = Utilities.ToInt32LittleEndian(buffer, offset + 0x1C);
return HeaderSize;
}
public void WriteTo(byte[] buffer, int offset)
{
Utilities.WriteBytesLittleEndian(Signature, buffer, offset + 0x00);
Utilities.WriteBytesLittleEndian(FileOffset, buffer, offset + 0x04);
Utilities.WriteBytesLittleEndian(BinSize, buffer, offset + 0x08);
}
}
}
+90
View File
@@ -0,0 +1,90 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Registry
{
/// <summary>
/// Base class for the different kinds of cell present in a hive.
/// </summary>
internal abstract class Cell : IByteArraySerializable
{
private int _index;
public Cell(int index)
{
_index = index;
}
public int Index
{
get { return _index; }
set { _index = value; }
}
public abstract int Size
{
get;
}
public abstract int ReadFrom(byte[] buffer, int offset);
public abstract void WriteTo(byte[] buffer, int offset);
internal static Cell Parse(RegistryHive hive, int index, byte[] buffer, int pos)
{
string type = Utilities.BytesToString(buffer, pos, 2);
Cell result = null;
switch (type)
{
case "nk":
result = new KeyNodeCell(index);
break;
case "sk":
result = new SecurityCell(index);
break;
case "vk":
result = new ValueCell(index);
break;
case "lh":
case "lf":
result = new SubKeyHashedListCell(hive, index);
break;
case "li":
case "ri":
result = new SubKeyIndirectListCell(hive, index);
break;
default:
throw new RegistryCorruptException("Unknown cell type '" + type + "'");
}
result.ReadFrom(buffer, pos);
return result;
}
}
}
+141
View File
@@ -0,0 +1,141 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Registry
{
using System;
using System.IO;
using System.Text;
internal sealed class HiveHeader : IByteArraySerializable
{
public const int HeaderSize = 512;
public int Sequence1;
public int Sequence2;
public DateTime Timestamp;
public int MajorVersion;
public int MinorVersion;
public int RootCell;
public int Length;
public uint Checksum;
public string Path;
public Guid Guid1;
public Guid Guid2;
private const uint Signature = 0x66676572;
public HiveHeader()
{
Sequence1 = 1;
Sequence2 = 1;
Timestamp = DateTime.UtcNow;
MajorVersion = 1;
MinorVersion = 3;
RootCell = -1;
Path = string.Empty;
Guid1 = Guid.NewGuid();
Guid2 = Guid.NewGuid();
}
public int Size
{
get { return HeaderSize; }
}
public int ReadFrom(byte[] buffer, int offset)
{
uint sig = Utilities.ToUInt32LittleEndian(buffer, offset + 0);
if (sig != Signature)
{
throw new IOException("Invalid signature for registry hive");
}
Sequence1 = Utilities.ToInt32LittleEndian(buffer, offset + 0x0004);
Sequence2 = Utilities.ToInt32LittleEndian(buffer, offset + 0x0008);
Timestamp = DateTime.FromFileTimeUtc(Utilities.ToInt64LittleEndian(buffer, offset + 0x000C));
MajorVersion = Utilities.ToInt32LittleEndian(buffer, 0x0014);
MinorVersion = Utilities.ToInt32LittleEndian(buffer, 0x0018);
int isLog = Utilities.ToInt32LittleEndian(buffer, 0x001C);
RootCell = Utilities.ToInt32LittleEndian(buffer, 0x0024);
Length = Utilities.ToInt32LittleEndian(buffer, 0x0028);
Path = Encoding.Unicode.GetString(buffer, 0x0030, 0x0040).Trim('\0');
Guid1 = Utilities.ToGuidLittleEndian(buffer, 0x0070);
Guid2 = Utilities.ToGuidLittleEndian(buffer, 0x0094);
Checksum = Utilities.ToUInt32LittleEndian(buffer, 0x01FC);
if (Sequence1 != Sequence2)
{
throw new NotImplementedException("Support for replaying registry log file");
}
if (Checksum != CalcChecksum(buffer, offset))
{
throw new IOException("Invalid checksum on registry file");
}
return HeaderSize;
}
public void WriteTo(byte[] buffer, int offset)
{
Utilities.WriteBytesLittleEndian(Signature, buffer, offset);
Utilities.WriteBytesLittleEndian(Sequence1, buffer, offset + 0x0004);
Utilities.WriteBytesLittleEndian(Sequence2, buffer, offset + 0x0008);
Utilities.WriteBytesLittleEndian(Timestamp.ToFileTimeUtc(), buffer, offset + 0x000C);
Utilities.WriteBytesLittleEndian(MajorVersion, buffer, offset + 0x0014);
Utilities.WriteBytesLittleEndian(MinorVersion, buffer, offset + 0x0018);
Utilities.WriteBytesLittleEndian((uint)1, buffer, offset + 0x0020); // Unknown - seems to be '1'
Utilities.WriteBytesLittleEndian(RootCell, buffer, offset + 0x0024);
Utilities.WriteBytesLittleEndian(Length, buffer, offset + 0x0028);
Encoding.Unicode.GetBytes(Path, 0, Path.Length, buffer, offset + 0x0030);
Utilities.WriteBytesLittleEndian((ushort)0, buffer, offset + 0x0030 + (Path.Length * 2));
Utilities.WriteBytesLittleEndian(Guid1, buffer, offset + 0x0070);
Utilities.WriteBytesLittleEndian(Guid2, buffer, offset + 0x0094);
Utilities.WriteBytesLittleEndian(CalcChecksum(buffer, offset), buffer, offset + 0x01FC);
}
private static uint CalcChecksum(byte[] buffer, int offset)
{
uint sum = 0;
for (int i = 0; i < 0x01FC; i += 4)
{
sum = sum ^ Utilities.ToUInt32LittleEndian(buffer, offset + i);
}
return sum;
}
}
}
+126
View File
@@ -0,0 +1,126 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Registry
{
using System;
internal sealed class KeyNodeCell : Cell
{
public RegistryKeyFlags Flags;
public DateTime Timestamp;
public int ParentIndex;
public int NumSubKeys;
public int SubKeysIndex;
public int NumValues;
public int ValueListIndex;
public int SecurityIndex;
public int ClassNameIndex;
/// <summary>
/// Number of bytes to represent largest subkey name in Unicode - no null terminator.
/// </summary>
public int MaxSubKeyNameBytes;
/// <summary>
/// Number of bytes to represent largest value name in Unicode - no null terminator.
/// </summary>
public int MaxValNameBytes;
/// <summary>
/// Number of bytes to represent largest value content (strings in Unicode, with null terminator - if stored).
/// </summary>
public int MaxValDataBytes;
public int IndexInParent;
public int ClassNameLength;
public string Name;
public KeyNodeCell(string name, int parentCellIndex)
: this(-1)
{
Flags = RegistryKeyFlags.Normal;
Timestamp = DateTime.UtcNow;
ParentIndex = parentCellIndex;
SubKeysIndex = -1;
ValueListIndex = -1;
SecurityIndex = -1;
ClassNameIndex = -1;
Name = name;
}
public KeyNodeCell(int index)
: base(index)
{
}
public override int Size
{
get { return 0x4C + Name.Length; }
}
public override int ReadFrom(byte[] buffer, int offset)
{
Flags = (RegistryKeyFlags)Utilities.ToUInt16LittleEndian(buffer, offset + 0x02);
Timestamp = DateTime.FromFileTimeUtc(Utilities.ToInt64LittleEndian(buffer, offset + 0x04));
ParentIndex = Utilities.ToInt32LittleEndian(buffer, offset + 0x10);
NumSubKeys = Utilities.ToInt32LittleEndian(buffer, offset + 0x14);
SubKeysIndex = Utilities.ToInt32LittleEndian(buffer, offset + 0x1C);
NumValues = Utilities.ToInt32LittleEndian(buffer, offset + 0x24);
ValueListIndex = Utilities.ToInt32LittleEndian(buffer, offset + 0x28);
SecurityIndex = Utilities.ToInt32LittleEndian(buffer, offset + 0x2C);
ClassNameIndex = Utilities.ToInt32LittleEndian(buffer, offset + 0x30);
MaxSubKeyNameBytes = Utilities.ToInt32LittleEndian(buffer, offset + 0x34);
MaxValNameBytes = Utilities.ToInt32LittleEndian(buffer, offset + 0x3C);
MaxValDataBytes = Utilities.ToInt32LittleEndian(buffer, offset + 0x40);
IndexInParent = Utilities.ToInt32LittleEndian(buffer, offset + 0x44);
int nameLength = Utilities.ToInt16LittleEndian(buffer, offset + 0x48);
ClassNameLength = Utilities.ToInt16LittleEndian(buffer, offset + 0x4A);
Name = Utilities.BytesToString(buffer, offset + 0x4C, nameLength);
return 0x4C + nameLength;
}
public override void WriteTo(byte[] buffer, int offset)
{
Utilities.StringToBytes("nk", buffer, offset, 2);
Utilities.WriteBytesLittleEndian((ushort)Flags, buffer, offset + 0x02);
Utilities.WriteBytesLittleEndian(Timestamp.ToFileTimeUtc(), buffer, offset + 0x04);
Utilities.WriteBytesLittleEndian(ParentIndex, buffer, offset + 0x10);
Utilities.WriteBytesLittleEndian(NumSubKeys, buffer, offset + 0x14);
Utilities.WriteBytesLittleEndian(SubKeysIndex, buffer, offset + 0x1C);
Utilities.WriteBytesLittleEndian(NumValues, buffer, offset + 0x24);
Utilities.WriteBytesLittleEndian(ValueListIndex, buffer, offset + 0x28);
Utilities.WriteBytesLittleEndian(SecurityIndex, buffer, offset + 0x2C);
Utilities.WriteBytesLittleEndian(ClassNameIndex, buffer, offset + 0x30);
Utilities.WriteBytesLittleEndian(IndexInParent, buffer, offset + 0x44);
Utilities.WriteBytesLittleEndian((ushort)Name.Length, buffer, offset + 0x48);
Utilities.WriteBytesLittleEndian(ClassNameLength, buffer, offset + 0x4A);
Utilities.StringToBytes(Name, buffer, offset + 0x4C, Name.Length);
}
public override string ToString()
{
return "Key:" + Name + "[" + Flags + "] <" + Timestamp + ">";
}
}
}
+74
View File
@@ -0,0 +1,74 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Registry
{
using System.Collections.Generic;
internal abstract class ListCell : Cell
{
public ListCell(int index)
: base(index)
{
}
/// <summary>
/// Gets the number of subkeys in this list.
/// </summary>
internal abstract int Count { get; }
/// <summary>
/// Searches for a key with a given name.
/// </summary>
/// <param name="name">The name to search for.</param>
/// <param name="cellIndex">The index of the cell, if found.</param>
/// <returns>The search result.</returns>
internal abstract int FindKey(string name, out int cellIndex);
/// <summary>
/// Enumerates all of the keys in the list.
/// </summary>
/// <param name="names">The list to populate.</param>
internal abstract void EnumerateKeys(List<string> names);
/// <summary>
/// Enumerates all of the keys in the list.
/// </summary>
/// <returns>Enumeration of key cells.</returns>
internal abstract IEnumerable<KeyNodeCell> EnumerateKeys();
/// <summary>
/// Adds a subkey to this list.
/// </summary>
/// <param name="name">The name of the subkey.</param>
/// <param name="cellIndex">The cell index of the subkey.</param>
/// <returns>The new cell index of the list, which may have changed.</returns>
internal abstract int LinkSubKey(string name, int cellIndex);
/// <summary>
/// Removes a subkey from this list.
/// </summary>
/// <param name="name">The name of the subkey.</param>
/// <returns>The new cell index of the list, which may have changed.</returns>
internal abstract int UnlinkSubKey(string name);
}
}
@@ -0,0 +1,70 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Registry
{
using System;
using System.Runtime.Serialization;
/// <summary>
/// Exception thrown when some corruption is found in the registry hive.
/// </summary>
[Serializable]
public class RegistryCorruptException : Exception
{
/// <summary>
/// Initializes a new instance of the RegistryCorruptException class.
/// </summary>
public RegistryCorruptException()
{
}
/// <summary>
/// Initializes a new instance of the RegistryCorruptException class.
/// </summary>
/// <param name="message">The exception message.</param>
public RegistryCorruptException(string message)
: base(message)
{
}
/// <summary>
/// Initializes a new instance of the RegistryCorruptException class.
/// </summary>
/// <param name="message">The exception message.</param>
/// <param name="innerException">The inner exception.</param>
public RegistryCorruptException(string message, Exception innerException)
: base(message, innerException)
{
}
/// <summary>
/// Initializes a new instance of the RegistryCorruptException class.
/// </summary>
/// <param name="info">The serialization info.</param>
/// <param name="context">The streaming context.</param>
protected RegistryCorruptException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
}
+404
View File
@@ -0,0 +1,404 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Registry
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.AccessControl;
/// <summary>
/// A registry hive.
/// </summary>
public sealed class RegistryHive : IDisposable
{
private const long BinStart = 4 * Sizes.OneKiB;
private Stream _fileStream;
private Ownership _ownsStream;
private HiveHeader _header;
private List<BinHeader> _bins;
/// <summary>
/// Initializes a new instance of the RegistryHive class.
/// </summary>
/// <param name="hive">The stream containing the registry hive.</param>
/// <remarks>
/// The created object does not assume ownership of the stream.
/// </remarks>
public RegistryHive(Stream hive)
: this(hive, Ownership.None)
{
}
/// <summary>
/// Initializes a new instance of the RegistryHive class.
/// </summary>
/// <param name="hive">The stream containing the registry hive.</param>
/// <param name="ownership">Whether the new object assumes object of the stream.</param>
public RegistryHive(Stream hive, Ownership ownership)
{
_fileStream = hive;
_fileStream.Position = 0;
_ownsStream = ownership;
byte[] buffer = Utilities.ReadFully(_fileStream, HiveHeader.HeaderSize);
_header = new HiveHeader();
_header.ReadFrom(buffer, 0);
_bins = new List<BinHeader>();
int pos = 0;
while (pos < _header.Length)
{
_fileStream.Position = BinStart + pos;
byte[] headerBuffer = Utilities.ReadFully(_fileStream, BinHeader.HeaderSize);
BinHeader header = new BinHeader();
header.ReadFrom(headerBuffer, 0);
_bins.Add(header);
pos += header.BinSize;
}
}
/// <summary>
/// Gets the root key in the registry hive.
/// </summary>
public RegistryKey Root
{
get { return new RegistryKey(this, GetCell<KeyNodeCell>(_header.RootCell)); }
}
/// <summary>
/// Creates a new (empty) registry hive.
/// </summary>
/// <param name="stream">The stream to contain the new hive.</param>
/// <returns>The new hive.</returns>
/// <remarks>
/// The returned object does not assume ownership of the stream.
/// </remarks>
public static RegistryHive Create(Stream stream)
{
return Create(stream, Ownership.None);
}
/// <summary>
/// Creates a new (empty) registry hive.
/// </summary>
/// <param name="stream">The stream to contain the new hive.</param>
/// <param name="ownership">Whether the returned object owns the stream.</param>
/// <returns>The new hive.</returns>
public static RegistryHive Create(Stream stream, Ownership ownership)
{
if (stream == null)
{
throw new ArgumentNullException("stream", "Attempt to create registry hive in null stream");
}
// Construct a file with minimal structure - hive header, plus one (empty) bin
BinHeader binHeader = new BinHeader();
binHeader.FileOffset = 0;
binHeader.BinSize = (int)(4 * Sizes.OneKiB);
HiveHeader hiveHeader = new HiveHeader();
hiveHeader.Length = binHeader.BinSize;
stream.Position = 0;
byte[] buffer = new byte[hiveHeader.Size];
hiveHeader.WriteTo(buffer, 0);
stream.Write(buffer, 0, buffer.Length);
buffer = new byte[binHeader.Size];
binHeader.WriteTo(buffer, 0);
stream.Position = BinStart;
stream.Write(buffer, 0, buffer.Length);
buffer = new byte[4];
Utilities.WriteBytesLittleEndian(binHeader.BinSize - binHeader.Size, buffer, 0);
stream.Write(buffer, 0, buffer.Length);
// Make sure the file is initialized out to the end of the firs bin
stream.Position = BinStart + binHeader.BinSize - 1;
stream.WriteByte(0);
// Temporary hive to perform construction of higher-level structures
RegistryHive newHive = new RegistryHive(stream);
KeyNodeCell rootCell = new KeyNodeCell("root", -1);
rootCell.Flags = RegistryKeyFlags.Normal | RegistryKeyFlags.Root;
newHive.UpdateCell(rootCell, true);
RegistrySecurity sd = new RegistrySecurity();
sd.SetSecurityDescriptorSddlForm("O:BAG:BAD:PAI(A;;KA;;;SY)(A;CI;KA;;;BA)", AccessControlSections.All);
SecurityCell secCell = new SecurityCell(sd);
newHive.UpdateCell(secCell, true);
secCell.NextIndex = secCell.Index;
secCell.PreviousIndex = secCell.Index;
newHive.UpdateCell(secCell, false);
rootCell.SecurityIndex = secCell.Index;
newHive.UpdateCell(rootCell, false);
// Ref the root cell from the hive header
hiveHeader.RootCell = rootCell.Index;
buffer = new byte[hiveHeader.Size];
hiveHeader.WriteTo(buffer, 0);
stream.Position = 0;
stream.Write(buffer, 0, buffer.Length);
// Finally, return the new hive
return new RegistryHive(stream, ownership);
}
/// <summary>
/// Creates a new (empty) registry hive.
/// </summary>
/// <param name="path">The file to create the new hive in.</param>
/// <returns>The new hive.</returns>
public static RegistryHive Create(string path)
{
return Create(new FileStream(path, FileMode.Create, FileAccess.ReadWrite), Ownership.Dispose);
}
/// <summary>
/// Disposes of this instance, freeing any underlying stream (if any).
/// </summary>
public void Dispose()
{
if (_fileStream != null && _ownsStream == Ownership.Dispose)
{
_fileStream.Dispose();
_fileStream = null;
}
}
internal K GetCell<K>(int index)
where K : Cell
{
Bin bin = GetBin(index);
if (bin != null)
{
return (K)bin.TryGetCell(index);
}
else
{
return null;
}
}
internal void FreeCell(int index)
{
Bin bin = GetBin(index);
if (bin != null)
{
bin.FreeCell(index);
}
}
internal int UpdateCell(Cell cell, bool canRelocate)
{
if (cell.Index == -1 && canRelocate)
{
cell.Index = AllocateRawCell(cell.Size);
}
Bin bin = GetBin(cell.Index);
if (bin != null)
{
if (bin.UpdateCell(cell))
{
return cell.Index;
}
else if (canRelocate)
{
int oldCell = cell.Index;
cell.Index = AllocateRawCell(cell.Size);
bin = GetBin(cell.Index);
if (!bin.UpdateCell(cell))
{
cell.Index = oldCell;
throw new RegistryCorruptException("Failed to migrate cell to new location");
}
FreeCell(oldCell);
return cell.Index;
}
else
{
throw new ArgumentException("Can't update cell, needs relocation but relocation disabled", "canRelocate");
}
}
else
{
throw new RegistryCorruptException("No bin found containing index: " + cell.Index);
}
}
internal byte[] RawCellData(int index, int maxBytes)
{
Bin bin = GetBin(index);
if (bin != null)
{
return bin.ReadRawCellData(index, maxBytes);
}
else
{
return null;
}
}
internal bool WriteRawCellData(int index, byte[] data, int offset, int count)
{
Bin bin = GetBin(index);
if (bin != null)
{
return bin.WriteRawCellData(index, data, offset, count);
}
else
{
throw new RegistryCorruptException("No bin found containing index: " + index);
}
}
internal int AllocateRawCell(int capacity)
{
int minSize = Utilities.RoundUp(capacity + 4, 8); // Allow for size header and ensure multiple of 8
// Incredibly inefficient algorithm...
foreach (var binHeader in _bins)
{
Bin bin = LoadBin(binHeader);
int cellIndex = bin.AllocateCell(minSize);
if (cellIndex >= 0)
{
return cellIndex;
}
}
BinHeader newBinHeader = AllocateBin(minSize);
Bin newBin = LoadBin(newBinHeader);
return newBin.AllocateCell(minSize);
}
private BinHeader FindBin(int index)
{
int binsIdx = _bins.BinarySearch(null, new BinFinder(index));
if (binsIdx >= 0)
{
return _bins[binsIdx];
}
return null;
}
private Bin GetBin(int cellIndex)
{
BinHeader binHeader = FindBin(cellIndex);
if (binHeader != null)
{
return LoadBin(binHeader);
}
return null;
}
private Bin LoadBin(BinHeader binHeader)
{
_fileStream.Position = BinStart + binHeader.FileOffset;
return new Bin(this, _fileStream);
}
private BinHeader AllocateBin(int minSize)
{
BinHeader lastBin = _bins[_bins.Count - 1];
BinHeader newBinHeader = new BinHeader();
newBinHeader.FileOffset = lastBin.FileOffset + lastBin.BinSize;
newBinHeader.BinSize = Utilities.RoundUp(minSize + newBinHeader.Size, 4 * (int)Sizes.OneKiB);
byte[] buffer = new byte[newBinHeader.Size];
newBinHeader.WriteTo(buffer, 0);
_fileStream.Position = BinStart + newBinHeader.FileOffset;
_fileStream.Write(buffer, 0, buffer.Length);
byte[] cellHeader = new byte[4];
Utilities.WriteBytesLittleEndian(newBinHeader.BinSize - newBinHeader.Size, cellHeader, 0);
_fileStream.Write(cellHeader, 0, 4);
// Update hive with new length
_header.Length = newBinHeader.FileOffset + newBinHeader.BinSize;
_header.Timestamp = DateTime.UtcNow;
_header.Sequence1++;
_header.Sequence2++;
_fileStream.Position = 0;
byte[] hiveHeader = Utilities.ReadFully(_fileStream, _header.Size);
_header.WriteTo(hiveHeader, 0);
_fileStream.Position = 0;
_fileStream.Write(hiveHeader, 0, hiveHeader.Length);
// Make sure the file is initialized to desired position
_fileStream.Position = BinStart + _header.Length - 1;
_fileStream.WriteByte(0);
_bins.Add(newBinHeader);
return newBinHeader;
}
private class BinFinder : IComparer<BinHeader>
{
private int _index;
public BinFinder(int index)
{
_index = index;
}
#region IComparer<BinHeader> Members
public int Compare(BinHeader x, BinHeader y)
{
if (x.FileOffset + x.BinSize < _index)
{
return -1;
}
else if (x.FileOffset > _index)
{
return 1;
}
else
{
return 0;
}
}
#endregion
}
}
}
+853
View File
@@ -0,0 +1,853 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Registry
{
using System;
using System.Collections.Generic;
using System.Security.AccessControl;
using System.Text;
/// <summary>
/// A key within a registry hive.
/// </summary>
public sealed class RegistryKey
{
private RegistryHive _hive;
private KeyNodeCell _cell;
internal RegistryKey(RegistryHive hive, KeyNodeCell cell)
{
_hive = hive;
_cell = cell;
}
/// <summary>
/// Gets the name of this key.
/// </summary>
public string Name
{
get
{
RegistryKey parent = Parent;
if (parent != null && ((parent.Flags & RegistryKeyFlags.Root) == 0))
{
return parent.Name + @"\" + _cell.Name;
}
else
{
return _cell.Name;
}
}
}
/// <summary>
/// Gets the number of child keys.
/// </summary>
public int SubKeyCount
{
get { return _cell.NumSubKeys; }
}
/// <summary>
/// Gets the number of values in this key.
/// </summary>
public int ValueCount
{
get { return _cell.NumValues; }
}
/// <summary>
/// Gets the time the key was last modified.
/// </summary>
public DateTime Timestamp
{
get { return _cell.Timestamp; }
}
/// <summary>
/// Gets the parent key, or <c>null</c> if this is the root key.
/// </summary>
public RegistryKey Parent
{
get
{
if ((_cell.Flags & RegistryKeyFlags.Root) == 0)
{
return new RegistryKey(_hive, _hive.GetCell<KeyNodeCell>(_cell.ParentIndex));
}
else
{
return null;
}
}
}
/// <summary>
/// Gets the flags of this registry key.
/// </summary>
public RegistryKeyFlags Flags
{
get { return _cell.Flags; }
}
/// <summary>
/// Gets the class name of this registry key.
/// </summary>
/// <remarks>Class name is rarely used.</remarks>
public string ClassName
{
get
{
if (_cell.ClassNameIndex > 0)
{
return Encoding.Unicode.GetString(_hive.RawCellData(_cell.ClassNameIndex, _cell.ClassNameLength));
}
return null;
}
}
/// <summary>
/// Gets an enumerator over all sub child keys.
/// </summary>
public IEnumerable<RegistryKey> SubKeys
{
get
{
if (_cell.NumSubKeys != 0)
{
ListCell list = _hive.GetCell<ListCell>(_cell.SubKeysIndex);
foreach (var key in list.EnumerateKeys())
{
yield return new RegistryKey(_hive, key);
}
}
}
}
/// <summary>
/// Gets an enumerator over all values in this key.
/// </summary>
private IEnumerable<RegistryValue> Values
{
get
{
if (_cell.NumValues != 0)
{
byte[] valueList = _hive.RawCellData(_cell.ValueListIndex, _cell.NumValues * 4);
for (int i = 0; i < _cell.NumValues; ++i)
{
int valueIndex = Utilities.ToInt32LittleEndian(valueList, i * 4);
yield return new RegistryValue(_hive, _hive.GetCell<ValueCell>(valueIndex));
}
}
}
}
/// <summary>
/// Gets the Security Descriptor applied to the registry key.
/// </summary>
/// <returns>The security descriptor as a RegistrySecurity instance.</returns>
public RegistrySecurity GetAccessControl()
{
if (_cell.SecurityIndex > 0)
{
SecurityCell secCell = _hive.GetCell<SecurityCell>(_cell.SecurityIndex);
return secCell.SecurityDescriptor;
}
return null;
}
/// <summary>
/// Gets the names of all child sub keys.
/// </summary>
/// <returns>The names of the sub keys.</returns>
public string[] GetSubKeyNames()
{
List<string> names = new List<string>();
if (_cell.NumSubKeys != 0)
{
_hive.GetCell<ListCell>(_cell.SubKeysIndex).EnumerateKeys(names);
}
return names.ToArray();
}
/// <summary>
/// Gets a named value stored within this key.
/// </summary>
/// <param name="name">The name of the value to retrieve.</param>
/// <returns>The value as a .NET object.</returns>
/// <remarks>The mapping from registry type of .NET type is as follows:
/// <list type="table">
/// <listheader>
/// <term>Value Type</term>
/// <term>.NET type</term>
/// </listheader>
/// <item>
/// <description>String</description>
/// <description>string</description>
/// </item>
/// <item>
/// <description>ExpandString</description>
/// <description>string</description>
/// </item>
/// <item>
/// <description>Link</description>
/// <description>string</description>
/// </item>
/// <item>
/// <description>DWord</description>
/// <description>uint</description>
/// </item>
/// <item>
/// <description>DWordBigEndian</description>
/// <description>uint</description>
/// </item>
/// <item>
/// <description>MultiString</description>
/// <description>string[]</description>
/// </item>
/// <item>
/// <description>QWord</description>
/// <description>ulong</description>
/// </item>
/// </list>
/// </remarks>
public object GetValue(string name)
{
return GetValue(name, null, Microsoft.Win32.RegistryValueOptions.None);
}
/// <summary>
/// Gets a named value stored within this key.
/// </summary>
/// <param name="name">The name of the value to retrieve.</param>
/// <param name="defaultValue">The default value to return, if no existing value is stored.</param>
/// <returns>The value as a .NET object.</returns>
/// <remarks>The mapping from registry type of .NET type is as follows:
/// <list type="table">
/// <listheader>
/// <term>Value Type</term>
/// <term>.NET type</term>
/// </listheader>
/// <item>
/// <description>String</description>
/// <description>string</description>
/// </item>
/// <item>
/// <description>ExpandString</description>
/// <description>string</description>
/// </item>
/// <item>
/// <description>Link</description>
/// <description>string</description>
/// </item>
/// <item>
/// <description>DWord</description>
/// <description>uint</description>
/// </item>
/// <item>
/// <description>DWordBigEndian</description>
/// <description>uint</description>
/// </item>
/// <item>
/// <description>MultiString</description>
/// <description>string[]</description>
/// </item>
/// <item>
/// <description>QWord</description>
/// <description>ulong</description>
/// </item>
/// </list>
/// </remarks>
public object GetValue(string name, object defaultValue)
{
return GetValue(name, defaultValue, Microsoft.Win32.RegistryValueOptions.None);
}
/// <summary>
/// Gets a named value stored within this key.
/// </summary>
/// <param name="name">The name of the value to retrieve.</param>
/// <param name="defaultValue">The default value to return, if no existing value is stored.</param>
/// <param name="options">Flags controlling how the value is processed before it's returned.</param>
/// <returns>The value as a .NET object.</returns>
/// <remarks>The mapping from registry type of .NET type is as follows:
/// <list type="table">
/// <listheader>
/// <term>Value Type</term>
/// <term>.NET type</term>
/// </listheader>
/// <item>
/// <description>String</description>
/// <description>string</description>
/// </item>
/// <item>
/// <description>ExpandString</description>
/// <description>string</description>
/// </item>
/// <item>
/// <description>Link</description>
/// <description>string</description>
/// </item>
/// <item>
/// <description>DWord</description>
/// <description>uint</description>
/// </item>
/// <item>
/// <description>DWordBigEndian</description>
/// <description>uint</description>
/// </item>
/// <item>
/// <description>MultiString</description>
/// <description>string[]</description>
/// </item>
/// <item>
/// <description>QWord</description>
/// <description>ulong</description>
/// </item>
/// </list>
/// </remarks>
public object GetValue(string name, object defaultValue, Microsoft.Win32.RegistryValueOptions options)
{
RegistryValue regVal = GetRegistryValue(name);
if (regVal != null)
{
if (regVal.DataType == RegistryValueType.ExpandString && (options & Microsoft.Win32.RegistryValueOptions.DoNotExpandEnvironmentNames) == 0)
{
return Environment.ExpandEnvironmentVariables((string)regVal.Value);
}
else
{
return regVal.Value;
}
}
return defaultValue;
}
/// <summary>
/// Sets a named value stored within this key.
/// </summary>
/// <param name="name">The name of the value to store.</param>
/// <param name="value">The value to store.</param>
public void SetValue(string name, object value)
{
SetValue(name, value, RegistryValueType.None);
}
/// <summary>
/// Sets a named value stored within this key.
/// </summary>
/// <param name="name">The name of the value to store.</param>
/// <param name="value">The value to store.</param>
/// <param name="valueType">The registry type of the data.</param>
public void SetValue(string name, object value, RegistryValueType valueType)
{
RegistryValue valObj = GetRegistryValue(name);
if (valObj == null)
{
valObj = AddRegistryValue(name);
}
valObj.SetValue(value, valueType);
}
/// <summary>
/// Deletes a named value stored within this key.
/// </summary>
/// <param name="name">The name of the value to delete.</param>
public void DeleteValue(string name)
{
DeleteValue(name, true);
}
/// <summary>
/// Deletes a named value stored within this key.
/// </summary>
/// <param name="name">The name of the value to delete.</param>
/// <param name="throwOnMissingValue">Throws ArgumentException if <c>name</c> doesn't exist.</param>
public void DeleteValue(string name, bool throwOnMissingValue)
{
bool foundValue = false;
if (_cell.NumValues != 0)
{
byte[] valueList = _hive.RawCellData(_cell.ValueListIndex, _cell.NumValues * 4);
int i = 0;
while (i < _cell.NumValues)
{
int valueIndex = Utilities.ToInt32LittleEndian(valueList, i * 4);
ValueCell valueCell = _hive.GetCell<ValueCell>(valueIndex);
if (string.Compare(valueCell.Name, name, StringComparison.OrdinalIgnoreCase) == 0)
{
foundValue = true;
_hive.FreeCell(valueIndex);
_cell.NumValues--;
_hive.UpdateCell(_cell, false);
break;
}
++i;
}
// Move following value's to fill gap
if (i < _cell.NumValues)
{
while (i < _cell.NumValues)
{
int valueIndex = Utilities.ToInt32LittleEndian(valueList, (i + 1) * 4);
Utilities.WriteBytesLittleEndian(valueIndex, valueList, i * 4);
++i;
}
_hive.WriteRawCellData(_cell.ValueListIndex, valueList, 0, _cell.NumValues * 4);
}
// TODO: Update maxbytes for value name and value content if this was the largest value for either.
// Windows seems to repair this info, if not accurate, though.
}
if (throwOnMissingValue && !foundValue)
{
throw new ArgumentException("No such value: " + name, "name");
}
}
/// <summary>
/// Gets the type of a named value.
/// </summary>
/// <param name="name">The name of the value to inspect.</param>
/// <returns>The value's type.</returns>
public RegistryValueType GetValueType(string name)
{
RegistryValue regVal = GetRegistryValue(name);
if (regVal != null)
{
return regVal.DataType;
}
return RegistryValueType.None;
}
/// <summary>
/// Gets the names of all values in this key.
/// </summary>
/// <returns>An array of strings containing the value names.</returns>
public string[] GetValueNames()
{
List<string> names = new List<string>();
foreach (var value in Values)
{
names.Add(value.Name);
}
return names.ToArray();
}
/// <summary>
/// Creates or opens a subkey.
/// </summary>
/// <param name="subkey">The relative path the the subkey.</param>
/// <returns>The subkey.</returns>
public RegistryKey CreateSubKey(string subkey)
{
if (string.IsNullOrEmpty(subkey))
{
return this;
}
string[] split = subkey.Split(new char[] { '\\' }, 2);
int cellIndex = FindSubKeyCell(split[0]);
if (cellIndex < 0)
{
KeyNodeCell newKeyCell = new KeyNodeCell(split[0], _cell.Index);
newKeyCell.SecurityIndex = _cell.SecurityIndex;
ReferenceSecurityCell(newKeyCell.SecurityIndex);
_hive.UpdateCell(newKeyCell, true);
LinkSubKey(split[0], newKeyCell.Index);
if (split.Length == 1)
{
return new RegistryKey(_hive, newKeyCell);
}
else
{
return new RegistryKey(_hive, newKeyCell).CreateSubKey(split[1]);
}
}
else
{
KeyNodeCell cell = _hive.GetCell<KeyNodeCell>(cellIndex);
if (split.Length == 1)
{
return new RegistryKey(_hive, cell);
}
else
{
return new RegistryKey(_hive, cell).CreateSubKey(split[1]);
}
}
}
/// <summary>
/// Opens a sub key.
/// </summary>
/// <param name="path">The relative path to the sub key.</param>
/// <returns>The sub key, or <c>null</c> if not found.</returns>
public RegistryKey OpenSubKey(string path)
{
if (string.IsNullOrEmpty(path))
{
return this;
}
string[] split = path.Split(new char[] { '\\' }, 2);
int cellIndex = FindSubKeyCell(split[0]);
if (cellIndex < 0)
{
return null;
}
else
{
KeyNodeCell cell = _hive.GetCell<KeyNodeCell>(cellIndex);
if (split.Length == 1)
{
return new RegistryKey(_hive, cell);
}
else
{
return new RegistryKey(_hive, cell).OpenSubKey(split[1]);
}
}
}
/// <summary>
/// Deletes a subkey and any child subkeys recursively. The string subkey is not case-sensitive.
/// </summary>
/// <param name="subkey">The subkey to delete.</param>
public void DeleteSubKeyTree(string subkey)
{
RegistryKey subKeyObj = OpenSubKey(subkey);
if (subKeyObj == null)
{
return;
}
if ((subKeyObj.Flags & RegistryKeyFlags.Root) != 0)
{
throw new ArgumentException("Attempt to delete root key");
}
foreach (var child in subKeyObj.GetSubKeyNames())
{
subKeyObj.DeleteSubKeyTree(child);
}
DeleteSubKey(subkey);
}
/// <summary>
/// Deletes the specified subkey. The string subkey is not case-sensitive.
/// </summary>
/// <param name="subkey">The subkey to delete.</param>
public void DeleteSubKey(string subkey)
{
DeleteSubKey(subkey, true);
}
/// <summary>
/// Deletes the specified subkey. The string subkey is not case-sensitive.
/// </summary>
/// <param name="subkey">The subkey to delete.</param>
/// <param name="throwOnMissingSubKey"><c>true</c> to throw an argument exception if <c>subkey</c> doesn't exist.</param>
public void DeleteSubKey(string subkey, bool throwOnMissingSubKey)
{
if (string.IsNullOrEmpty(subkey))
{
throw new ArgumentException("Invalid SubKey", "subkey");
}
string[] split = subkey.Split(new char[] { '\\' }, 2);
int subkeyCellIndex = FindSubKeyCell(split[0]);
if (subkeyCellIndex < 0)
{
if (throwOnMissingSubKey)
{
throw new ArgumentException("No such SubKey", "subkey");
}
else
{
return;
}
}
KeyNodeCell subkeyCell = _hive.GetCell<KeyNodeCell>(subkeyCellIndex);
if (split.Length == 1)
{
if (subkeyCell.NumSubKeys != 0)
{
throw new InvalidOperationException("The registry key has subkeys");
}
if (subkeyCell.ClassNameIndex != -1)
{
_hive.FreeCell(subkeyCell.ClassNameIndex);
subkeyCell.ClassNameIndex = -1;
subkeyCell.ClassNameLength = 0;
}
if (subkeyCell.SecurityIndex != -1)
{
DereferenceSecurityCell(subkeyCell.SecurityIndex);
subkeyCell.SecurityIndex = -1;
}
if (subkeyCell.SubKeysIndex != -1)
{
FreeSubKeys(subkeyCell);
}
if (subkeyCell.ValueListIndex != -1)
{
FreeValues(subkeyCell);
}
UnlinkSubKey(subkey);
_hive.FreeCell(subkeyCellIndex);
_hive.UpdateCell(_cell, false);
}
else
{
new RegistryKey(_hive, subkeyCell).DeleteSubKey(split[1], throwOnMissingSubKey);
}
}
private RegistryValue GetRegistryValue(string name)
{
if (name != null && name.Length == 0)
{
name = null;
}
if (_cell.NumValues != 0)
{
byte[] valueList = _hive.RawCellData(_cell.ValueListIndex, _cell.NumValues * 4);
for (int i = 0; i < _cell.NumValues; ++i)
{
int valueIndex = Utilities.ToInt32LittleEndian(valueList, i * 4);
ValueCell cell = _hive.GetCell<ValueCell>(valueIndex);
if (string.Compare(cell.Name, name, StringComparison.OrdinalIgnoreCase) == 0)
{
return new RegistryValue(_hive, cell);
}
}
}
return null;
}
private RegistryValue AddRegistryValue(string name)
{
byte[] valueList = _hive.RawCellData(_cell.ValueListIndex, _cell.NumValues * 4);
if (valueList == null)
{
valueList = new byte[0];
}
int insertIdx = 0;
while (insertIdx < _cell.NumValues)
{
int valueCellIndex = Utilities.ToInt32LittleEndian(valueList, insertIdx * 4);
ValueCell cell = _hive.GetCell<ValueCell>(valueCellIndex);
if (string.Compare(name, cell.Name, StringComparison.OrdinalIgnoreCase) < 0)
{
break;
}
++insertIdx;
}
// Allocate a new value cell (note _hive.UpdateCell does actual allocation).
ValueCell valueCell = new ValueCell(name);
_hive.UpdateCell(valueCell, true);
// Update the value list, re-allocating if necessary
byte[] newValueList = new byte[(_cell.NumValues * 4) + 4];
Array.Copy(valueList, 0, newValueList, 0, insertIdx * 4);
Utilities.WriteBytesLittleEndian(valueCell.Index, newValueList, insertIdx * 4);
Array.Copy(valueList, insertIdx * 4, newValueList, (insertIdx * 4) + 4, (_cell.NumValues - insertIdx) * 4);
if (_cell.ValueListIndex == -1 || !_hive.WriteRawCellData(_cell.ValueListIndex, newValueList, 0, newValueList.Length))
{
int newListCellIndex = _hive.AllocateRawCell(Utilities.RoundUp(newValueList.Length, 8));
_hive.WriteRawCellData(newListCellIndex, newValueList, 0, newValueList.Length);
if (_cell.ValueListIndex != -1)
{
_hive.FreeCell(_cell.ValueListIndex);
}
_cell.ValueListIndex = newListCellIndex;
}
// Record the new value and save this cell
_cell.NumValues++;
_hive.UpdateCell(_cell, false);
// Finally, set the data in the value cell
return new RegistryValue(_hive, valueCell);
}
private int FindSubKeyCell(string name)
{
if (_cell.NumSubKeys != 0)
{
ListCell listCell = _hive.GetCell<ListCell>(_cell.SubKeysIndex);
int cellIndex;
if (listCell.FindKey(name, out cellIndex) == 0)
{
return cellIndex;
}
}
return -1;
}
private void LinkSubKey(string name, int cellIndex)
{
if (_cell.SubKeysIndex == -1)
{
SubKeyHashedListCell newListCell = new SubKeyHashedListCell(_hive, "lf");
newListCell.Add(name, cellIndex);
_hive.UpdateCell(newListCell, true);
_cell.NumSubKeys = 1;
_cell.SubKeysIndex = newListCell.Index;
}
else
{
ListCell list = _hive.GetCell<ListCell>(_cell.SubKeysIndex);
_cell.SubKeysIndex = list.LinkSubKey(name, cellIndex);
_cell.NumSubKeys++;
}
_hive.UpdateCell(_cell, false);
}
private void UnlinkSubKey(string name)
{
if (_cell.SubKeysIndex == -1 || _cell.NumSubKeys == 0)
{
throw new InvalidOperationException("No subkey list");
}
ListCell list = _hive.GetCell<ListCell>(_cell.SubKeysIndex);
_cell.SubKeysIndex = list.UnlinkSubKey(name);
_cell.NumSubKeys--;
}
private void ReferenceSecurityCell(int cellIndex)
{
SecurityCell sc = _hive.GetCell<SecurityCell>(cellIndex);
sc.UsageCount++;
_hive.UpdateCell(sc, false);
}
private void DereferenceSecurityCell(int cellIndex)
{
SecurityCell sc = _hive.GetCell<SecurityCell>(cellIndex);
sc.UsageCount--;
if (sc.UsageCount == 0)
{
SecurityCell prev = _hive.GetCell<SecurityCell>(sc.PreviousIndex);
prev.NextIndex = sc.NextIndex;
_hive.UpdateCell(prev, false);
SecurityCell next = _hive.GetCell<SecurityCell>(sc.NextIndex);
next.PreviousIndex = sc.PreviousIndex;
_hive.UpdateCell(next, false);
_hive.FreeCell(cellIndex);
}
else
{
_hive.UpdateCell(sc, false);
}
}
private void FreeValues(KeyNodeCell cell)
{
if (cell.NumValues != 0 && cell.ValueListIndex != -1)
{
byte[] valueList = _hive.RawCellData(cell.ValueListIndex, cell.NumValues * 4);
for (int i = 0; i < cell.NumValues; ++i)
{
int valueIndex = Utilities.ToInt32LittleEndian(valueList, i * 4);
_hive.FreeCell(valueIndex);
}
_hive.FreeCell(cell.ValueListIndex);
cell.ValueListIndex = -1;
cell.NumValues = 0;
cell.MaxValDataBytes = 0;
cell.MaxValNameBytes = 0;
}
}
private void FreeSubKeys(KeyNodeCell subkeyCell)
{
if (subkeyCell.SubKeysIndex == -1)
{
throw new InvalidOperationException("No subkey list");
}
Cell list = _hive.GetCell<Cell>(subkeyCell.SubKeysIndex);
SubKeyIndirectListCell indirectList = list as SubKeyIndirectListCell;
if (indirectList != null)
{
////foreach (int listIndex in indirectList.CellIndexes)
for (int i = 0; i < indirectList.CellIndexes.Count; ++i)
{
int listIndex = indirectList.CellIndexes[i];
_hive.FreeCell(listIndex);
}
}
_hive.FreeCell(list.Index);
}
}
}
+113
View File
@@ -0,0 +1,113 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Registry
{
using System;
/// <summary>
/// The per-key flags present on registry keys.
/// </summary>
[Flags]
public enum RegistryKeyFlags : int
{
/// <summary>
/// Unknown purpose.
/// </summary>
Unknown0001 = 0x0001,
/// <summary>
/// Unknown purpose.
/// </summary>
Unknown0002 = 0x0002,
/// <summary>
/// The key is the root key in the registry hive.
/// </summary>
Root = 0x0004,
/// <summary>
/// Unknown purpose.
/// </summary>
Unknown0008 = 0x0008,
/// <summary>
/// The key is a link to another key.
/// </summary>
Link = 0x0010,
/// <summary>
/// This is a normal key.
/// </summary>
Normal = 0x0020,
/// <summary>
/// Unknown purpose.
/// </summary>
Unknown0040 = 0x0040,
/// <summary>
/// Unknown purpose.
/// </summary>
Unknown0080 = 0x0080,
/// <summary>
/// Unknown purpose.
/// </summary>
Unknown0100 = 0x0100,
/// <summary>
/// Unknown purpose.
/// </summary>
Unknown0200 = 0x0200,
/// <summary>
/// Unknown purpose.
/// </summary>
Unknown0400 = 0x0400,
/// <summary>
/// Unknown purpose.
/// </summary>
Unknown0800 = 0x0800,
/// <summary>
/// Unknown purpose.
/// </summary>
Unknown1000 = 0x1000,
/// <summary>
/// Unknown purpose.
/// </summary>
Unknown2000 = 0x2000,
/// <summary>
/// Unknown purpose.
/// </summary>
Unknown4000 = 0x4000,
/// <summary>
/// Unknown purpose.
/// </summary>
Unknown8000 = 0x8000
}
}
+304
View File
@@ -0,0 +1,304 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Registry
{
using System;
using System.Globalization;
using System.Text;
/// <summary>
/// A registry value.
/// </summary>
internal sealed class RegistryValue
{
private RegistryHive _hive;
private ValueCell _cell;
internal RegistryValue(RegistryHive hive, ValueCell cell)
{
_hive = hive;
_cell = cell;
}
/// <summary>
/// Gets the name of the value, or empty string if unnamed.
/// </summary>
public string Name
{
get { return _cell.Name ?? string.Empty; }
}
/// <summary>
/// Gets the type of the value.
/// </summary>
public RegistryValueType DataType
{
get { return _cell.DataType; }
}
/// <summary>
/// Gets the value data mapped to a .net object.
/// </summary>
/// <remarks>The mapping from registry type of .NET type is as follows:
/// <list type="table">
/// <listheader>
/// <term>Value Type</term>
/// <term>.NET type</term>
/// </listheader>
/// <item>
/// <description>String</description>
/// <description>string</description>
/// </item>
/// <item>
/// <description>ExpandString</description>
/// <description>string</description>
/// </item>
/// <item>
/// <description>Link</description>
/// <description>string</description>
/// </item>
/// <item>
/// <description>DWord</description>
/// <description>uint</description>
/// </item>
/// <item>
/// <description>DWordBigEndian</description>
/// <description>uint</description>
/// </item>
/// <item>
/// <description>MultiString</description>
/// <description>string[]</description>
/// </item>
/// <item>
/// <description>QWord</description>
/// <description>ulong</description>
/// </item>
/// </list>
/// </remarks>
public object Value
{
get
{
return ConvertToObject(GetData(), DataType);
}
}
/// <summary>
/// The raw value data as a byte array.
/// </summary>
/// <returns>The value as a raw byte array.</returns>
public byte[] GetData()
{
if (_cell.DataLength < 0)
{
int len = _cell.DataLength & 0x7FFFFFFF;
byte[] buffer = new byte[4];
Utilities.WriteBytesLittleEndian(_cell.DataIndex, buffer, 0);
byte[] result = new byte[len];
Array.Copy(buffer, result, len);
return result;
}
return _hive.RawCellData(_cell.DataIndex, _cell.DataLength);
}
/// <summary>
/// Sets the value as raw bytes, with no validation that enough data is specified for the given value type.
/// </summary>
/// <param name="data">The data to store.</param>
/// <param name="offset">The offset within <c>data</c> of the first byte to store.</param>
/// <param name="count">The number of bytes to store.</param>
/// <param name="valueType">The type of the data.</param>
public void SetData(byte[] data, int offset, int count, RegistryValueType valueType)
{
// If we can place the data in the DataIndex field, do that to save space / allocation
if ((valueType == RegistryValueType.Dword || valueType == RegistryValueType.DwordBigEndian) && count <= 4)
{
if (_cell.DataLength >= 0)
{
_hive.FreeCell(_cell.DataIndex);
}
_cell.DataLength = (int)((uint)count | 0x80000000);
_cell.DataIndex = Utilities.ToInt32LittleEndian(data, offset);
_cell.DataType = valueType;
}
else
{
if (_cell.DataIndex == -1 || _cell.DataLength < 0)
{
_cell.DataIndex = _hive.AllocateRawCell(count);
}
if (!_hive.WriteRawCellData(_cell.DataIndex, data, offset, count))
{
int newDataIndex = _hive.AllocateRawCell(count);
_hive.WriteRawCellData(newDataIndex, data, offset, count);
_hive.FreeCell(_cell.DataIndex);
_cell.DataIndex = newDataIndex;
}
_cell.DataLength = count;
_cell.DataType = valueType;
}
_hive.UpdateCell(_cell, false);
}
/// <summary>
/// Sets the value stored.
/// </summary>
/// <param name="value">The value to store.</param>
/// <param name="valueType">The registry type of the data.</param>
public void SetValue(object value, RegistryValueType valueType)
{
if (valueType == RegistryValueType.None)
{
if (value is int)
{
valueType = RegistryValueType.Dword;
}
else if (value is byte[])
{
valueType = RegistryValueType.Binary;
}
else if (value is string[])
{
valueType = RegistryValueType.MultiString;
}
else
{
valueType = RegistryValueType.String;
}
}
byte[] data = ConvertToData(value, valueType);
SetData(data, 0, data.Length, valueType);
}
/// <summary>
/// Gets a string representation of the registry value.
/// </summary>
/// <returns>The registry value as a string.</returns>
public override string ToString()
{
return Name + ":" + DataType + ":" + DataAsString();
}
private static object ConvertToObject(byte[] data, RegistryValueType type)
{
switch (type)
{
case RegistryValueType.String:
case RegistryValueType.ExpandString:
case RegistryValueType.Link:
return Encoding.Unicode.GetString(data).Trim('\0');
case RegistryValueType.Dword:
return Utilities.ToInt32LittleEndian(data, 0);
case RegistryValueType.DwordBigEndian:
return Utilities.ToInt32BigEndian(data, 0);
case RegistryValueType.MultiString:
string multiString = Encoding.Unicode.GetString(data).Trim('\0');
return multiString.Split('\0');
case RegistryValueType.QWord:
return string.Empty + Utilities.ToUInt64LittleEndian(data, 0);
default:
return data;
}
}
private static byte[] ConvertToData(object value, RegistryValueType valueType)
{
if (valueType == RegistryValueType.None)
{
throw new ArgumentException("Specific registry value type must be specified", "valueType");
}
byte[] data;
switch (valueType)
{
case RegistryValueType.String:
case RegistryValueType.ExpandString:
string strValue = value.ToString();
data = new byte[(strValue.Length * 2) + 2];
Encoding.Unicode.GetBytes(strValue, 0, strValue.Length, data, 0);
break;
case RegistryValueType.Dword:
data = new byte[4];
Utilities.WriteBytesLittleEndian((int)value, data, 0);
break;
case RegistryValueType.DwordBigEndian:
data = new byte[4];
Utilities.WriteBytesBigEndian((int)value, data, 0);
break;
case RegistryValueType.MultiString:
string multiStrValue = string.Join("\0", (string[])value) + "\0";
data = new byte[(multiStrValue.Length * 2) + 2];
Encoding.Unicode.GetBytes(multiStrValue, 0, multiStrValue.Length, data, 0);
break;
default:
data = (byte[])value;
break;
}
return data;
}
private string DataAsString()
{
switch (DataType)
{
case RegistryValueType.String:
case RegistryValueType.ExpandString:
case RegistryValueType.Link:
case RegistryValueType.Dword:
case RegistryValueType.DwordBigEndian:
case RegistryValueType.QWord:
return ConvertToObject(GetData(), DataType).ToString();
case RegistryValueType.MultiString:
return string.Join(",", (string[])ConvertToObject(GetData(), DataType));
default:
byte[] data = GetData();
string result = string.Empty;
for (int i = 0; i < Math.Min(data.Length, 8); ++i)
{
result += string.Format(CultureInfo.InvariantCulture, "{0:X2} ", (int)data[i]);
}
return result + string.Format(CultureInfo.InvariantCulture, " ({0} bytes)", data.Length);
}
}
}
}
+90
View File
@@ -0,0 +1,90 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Registry
{
/// <summary>
/// The types of registry values.
/// </summary>
public enum RegistryValueType : int
{
/// <summary>
/// Unknown type.
/// </summary>
None = 0x00,
/// <summary>
/// A unicode string.
/// </summary>
String = 0x01,
/// <summary>
/// A string containing environment variables.
/// </summary>
ExpandString = 0x02,
/// <summary>
/// Binary data.
/// </summary>
Binary = 0x03,
/// <summary>
/// A 32-bit integer.
/// </summary>
Dword = 0x04,
/// <summary>
/// A 32-bit integer.
/// </summary>
DwordBigEndian = 0x05,
/// <summary>
/// A registry link.
/// </summary>
Link = 0x06,
/// <summary>
/// A multistring.
/// </summary>
MultiString = 0x07,
/// <summary>
/// An unknown binary format.
/// </summary>
ResourceList = 0x08,
/// <summary>
/// An unknown binary format.
/// </summary>
FullResourceDescriptor = 0x09,
/// <summary>
/// An unknown binary format.
/// </summary>
ResourceRequirementsList = 0x0A,
/// <summary>
/// A 64-bit integer.
/// </summary>
QWord = 0x0B,
}
}
+112
View File
@@ -0,0 +1,112 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Registry
{
using System;
using System.Security.AccessControl;
internal sealed class SecurityCell : Cell
{
private int _prevIndex;
private int _nextIndex;
private int _usageCount;
private RegistrySecurity _secDesc;
public SecurityCell(RegistrySecurity secDesc)
: this(-1)
{
_secDesc = secDesc;
}
public SecurityCell(int index)
: base(index)
{
_prevIndex = -1;
_nextIndex = -1;
}
public int PreviousIndex
{
get { return _prevIndex; }
set { _prevIndex = value; }
}
public int NextIndex
{
get { return _nextIndex; }
set { _nextIndex = value; }
}
public int UsageCount
{
get { return _usageCount; }
set { _usageCount = value; }
}
public RegistrySecurity SecurityDescriptor
{
get { return _secDesc; }
}
public override int Size
{
get
{
int sdLen = _secDesc.GetSecurityDescriptorBinaryForm().Length;
return 0x14 + sdLen;
}
}
public override int ReadFrom(byte[] buffer, int offset)
{
_prevIndex = Utilities.ToInt32LittleEndian(buffer, offset + 0x04);
_nextIndex = Utilities.ToInt32LittleEndian(buffer, offset + 0x08);
_usageCount = Utilities.ToInt32LittleEndian(buffer, offset + 0x0C);
int secDescSize = Utilities.ToInt32LittleEndian(buffer, offset + 0x10);
byte[] secDesc = new byte[secDescSize];
Array.Copy(buffer, offset + 0x14, secDesc, 0, secDescSize);
_secDesc = new RegistrySecurity();
_secDesc.SetSecurityDescriptorBinaryForm(secDesc);
return 0x14 + secDescSize;
}
public override void WriteTo(byte[] buffer, int offset)
{
byte[] sd = _secDesc.GetSecurityDescriptorBinaryForm();
Utilities.StringToBytes("sk", buffer, offset, 2);
Utilities.WriteBytesLittleEndian(_prevIndex, buffer, offset + 0x04);
Utilities.WriteBytesLittleEndian(_nextIndex, buffer, offset + 0x08);
Utilities.WriteBytesLittleEndian(_usageCount, buffer, offset + 0x0C);
Utilities.WriteBytesLittleEndian(sd.Length, buffer, offset + 0x10);
Array.Copy(sd, 0, buffer, offset + 0x14, sd.Length);
}
public override string ToString()
{
return "SecDesc:" + _secDesc.GetSecurityDescriptorSddlForm(AccessControlSections.All) + " (refCount:" + _usageCount + ")";
}
}
}
+320
View File
@@ -0,0 +1,320 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Registry
{
using System;
using System.Collections.Generic;
using System.Globalization;
internal sealed class SubKeyHashedListCell : ListCell
{
private string _hashType;
private short _numElements;
private List<int> _subKeyIndexes;
private List<uint> _nameHashes;
private RegistryHive _hive;
public SubKeyHashedListCell(RegistryHive hive, string hashType)
: base(-1)
{
_hive = hive;
_hashType = hashType;
_subKeyIndexes = new List<int>();
_nameHashes = new List<uint>();
}
public SubKeyHashedListCell(RegistryHive hive, int index)
: base(index)
{
_hive = hive;
}
public override int Size
{
get { return 0x4 + (_numElements * 0x8); }
}
internal override int Count
{
get { return _subKeyIndexes.Count; }
}
public override int ReadFrom(byte[] buffer, int offset)
{
_hashType = Utilities.BytesToString(buffer, offset, 2);
_numElements = Utilities.ToInt16LittleEndian(buffer, offset + 2);
_subKeyIndexes = new List<int>(_numElements);
_nameHashes = new List<uint>(_numElements);
for (int i = 0; i < _numElements; ++i)
{
_subKeyIndexes.Add(Utilities.ToInt32LittleEndian(buffer, offset + 0x4 + (i * 0x8)));
_nameHashes.Add(Utilities.ToUInt32LittleEndian(buffer, offset + 0x4 + (i * 0x8) + 0x4));
}
return 0x4 + (_numElements * 0x8);
}
public override void WriteTo(byte[] buffer, int offset)
{
Utilities.StringToBytes(_hashType, buffer, offset, 2);
Utilities.WriteBytesLittleEndian(_numElements, buffer, offset + 0x2);
for (int i = 0; i < _numElements; ++i)
{
Utilities.WriteBytesLittleEndian(_subKeyIndexes[i], buffer, offset + 0x4 + (i * 0x8));
Utilities.WriteBytesLittleEndian(_nameHashes[i], buffer, offset + 0x4 + (i * 0x8) + 0x4);
}
}
/// <summary>
/// Adds a new entry.
/// </summary>
/// <param name="name">The name of the subkey.</param>
/// <param name="cellIndex">The cell index of the subkey.</param>
/// <returns>The index of the new entry.</returns>
internal int Add(string name, int cellIndex)
{
for (int i = 0; i < _numElements; ++i)
{
KeyNodeCell cell = _hive.GetCell<KeyNodeCell>(_subKeyIndexes[i]);
if (string.Compare(cell.Name, name, StringComparison.OrdinalIgnoreCase) > 0)
{
_subKeyIndexes.Insert(i, cellIndex);
_nameHashes.Insert(i, CalcHash(name));
_numElements++;
return i;
}
}
_subKeyIndexes.Add(cellIndex);
_nameHashes.Add(CalcHash(name));
return _numElements++;
}
internal override int FindKey(string name, out int cellIndex)
{
// Check first and last, to early abort if the name is outside the range of this list
int result = FindKeyAt(name, 0, out cellIndex);
if (result <= 0)
{
return result;
}
result = FindKeyAt(name, _subKeyIndexes.Count - 1, out cellIndex);
if (result >= 0)
{
return result;
}
KeyFinder finder = new KeyFinder(_hive, name);
int idx = _subKeyIndexes.BinarySearch(-1, finder);
cellIndex = finder.CellIndex;
return (idx < 0) ? -1 : 0;
}
internal override void EnumerateKeys(List<string> names)
{
for (int i = 0; i < _subKeyIndexes.Count; ++i)
{
names.Add(_hive.GetCell<KeyNodeCell>(_subKeyIndexes[i]).Name);
}
}
internal override IEnumerable<KeyNodeCell> EnumerateKeys()
{
for (int i = 0; i < _subKeyIndexes.Count; ++i)
{
yield return _hive.GetCell<KeyNodeCell>(_subKeyIndexes[i]);
}
}
internal override int LinkSubKey(string name, int cellIndex)
{
Add(name, cellIndex);
return _hive.UpdateCell(this, true);
}
internal override int UnlinkSubKey(string name)
{
int index = IndexOf(name);
if (index >= 0)
{
RemoveAt(index);
return _hive.UpdateCell(this, true);
}
return Index;
}
/// <summary>
/// Finds a subkey cell, returning it's index in this list.
/// </summary>
/// <param name="name">The name of the key to find.</param>
/// <returns>The index of the found key, or <c>-1</c>.</returns>
internal int IndexOf(string name)
{
foreach (var index in Find(name, 0))
{
KeyNodeCell cell = _hive.GetCell<KeyNodeCell>(_subKeyIndexes[index]);
if (cell.Name.ToUpperInvariant() == name.ToUpperInvariant())
{
return index;
}
}
return -1;
}
internal void RemoveAt(int index)
{
_nameHashes.RemoveAt(index);
_subKeyIndexes.RemoveAt(index);
_numElements--;
}
private uint CalcHash(string name)
{
uint hash = 0;
if (_hashType == "lh")
{
for (int i = 0; i < name.Length; ++i)
{
hash *= 37;
hash += char.ToUpper(name[i], CultureInfo.InvariantCulture);
}
}
else
{
string hashStr = name + "\0\0\0\0";
for (int i = 0; i < 4; ++i)
{
hash |= (uint)((hashStr[i] & 0xFF) << (i * 8));
}
}
return hash;
}
private int FindKeyAt(string name, int listIndex, out int cellIndex)
{
Cell cell = _hive.GetCell<Cell>(_subKeyIndexes[listIndex]);
if (cell == null)
{
cellIndex = 0;
return -1;
}
ListCell listCell = cell as ListCell;
if (listCell != null)
{
return listCell.FindKey(name, out cellIndex);
}
cellIndex = _subKeyIndexes[listIndex];
return string.Compare(name, ((KeyNodeCell)cell).Name, StringComparison.OrdinalIgnoreCase);
}
private IEnumerable<int> Find(string name, int start)
{
if (_hashType == "lh")
{
return FindByHash(name, start);
}
else
{
return FindByPrefix(name, start);
}
}
private IEnumerable<int> FindByHash(string name, int start)
{
uint hash = CalcHash(name);
for (int i = start; i < _nameHashes.Count; ++i)
{
if (_nameHashes[i] == hash)
{
yield return i;
}
}
}
private IEnumerable<int> FindByPrefix(string name, int start)
{
int compChars = Math.Min(name.Length, 4);
string compStr = name.Substring(0, compChars).ToUpperInvariant() + "\0\0\0\0";
for (int i = start; i < _nameHashes.Count; ++i)
{
bool match = true;
uint hash = _nameHashes[i];
for (int j = 0; j < 4; ++j)
{
char ch = (char)((hash >> (j * 8)) & 0xFF);
if (char.ToUpperInvariant(ch) != compStr[j])
{
match = false;
break;
}
}
if (match)
{
yield return i;
}
}
}
private class KeyFinder : IComparer<int>
{
private RegistryHive _hive;
private string _searchName;
public KeyFinder(RegistryHive hive, string searchName)
{
_hive = hive;
_searchName = searchName;
}
public int CellIndex { get; set; }
#region IComparer<int> Members
public int Compare(int x, int y)
{
// TODO: Be more efficient at ruling out no-hopes by using the hash values
KeyNodeCell cell = _hive.GetCell<KeyNodeCell>(x);
int result = string.Compare(((KeyNodeCell)cell).Name, _searchName, StringComparison.OrdinalIgnoreCase);
if (result == 0)
{
CellIndex = x;
}
return result;
}
#endregion
}
}
}
@@ -0,0 +1,310 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Registry
{
using System;
using System.Collections.Generic;
internal sealed class SubKeyIndirectListCell : ListCell
{
private RegistryHive _hive;
private string _listType;
private List<int> _listIndexes;
public SubKeyIndirectListCell(RegistryHive hive, int index)
: base(index)
{
_hive = hive;
}
public string ListType
{
get { return _listType; }
}
public List<int> CellIndexes
{
get { return _listIndexes; }
}
public override int Size
{
get { return 4 + (_listIndexes.Count * 4); }
}
internal override int Count
{
get
{
int total = 0;
foreach (var cellIndex in _listIndexes)
{
Cell cell = _hive.GetCell<Cell>(cellIndex);
ListCell listCell = cell as ListCell;
if (listCell != null)
{
total += listCell.Count;
}
else
{
total++;
}
}
return total;
}
}
public override int ReadFrom(byte[] buffer, int offset)
{
_listType = Utilities.BytesToString(buffer, offset, 2);
int numElements = Utilities.ToInt16LittleEndian(buffer, offset + 2);
_listIndexes = new List<int>(numElements);
for (int i = 0; i < numElements; ++i)
{
_listIndexes.Add(Utilities.ToInt32LittleEndian(buffer, offset + 0x4 + (i * 0x4)));
}
return 4 + (_listIndexes.Count * 4);
}
public override void WriteTo(byte[] buffer, int offset)
{
Utilities.StringToBytes(_listType, buffer, offset, 2);
Utilities.WriteBytesLittleEndian((ushort)_listIndexes.Count, buffer, offset + 2);
for (int i = 0; i < _listIndexes.Count; ++i)
{
Utilities.WriteBytesLittleEndian(_listIndexes[i], buffer, offset + 4 + (i * 4));
}
}
internal override int FindKey(string name, out int cellIndex)
{
if (_listIndexes.Count <= 0)
{
cellIndex = 0;
return -1;
}
// Check first and last, to early abort if the name is outside the range of this list
int result = DoFindKey(name, 0, out cellIndex);
if (result <= 0)
{
return result;
}
result = DoFindKey(name, _listIndexes.Count - 1, out cellIndex);
if (result >= 0)
{
return result;
}
KeyFinder finder = new KeyFinder(_hive, name);
int idx = _listIndexes.BinarySearch(-1, finder);
cellIndex = finder.CellIndex;
return (idx < 0) ? -1 : 0;
}
internal override void EnumerateKeys(List<string> names)
{
for (int i = 0; i < _listIndexes.Count; ++i)
{
Cell cell = _hive.GetCell<Cell>(_listIndexes[i]);
ListCell listCell = cell as ListCell;
if (listCell != null)
{
listCell.EnumerateKeys(names);
}
else
{
names.Add(((KeyNodeCell)cell).Name);
}
}
}
internal override IEnumerable<KeyNodeCell> EnumerateKeys()
{
for (int i = 0; i < _listIndexes.Count; ++i)
{
Cell cell = _hive.GetCell<Cell>(_listIndexes[i]);
ListCell listCell = cell as ListCell;
if (listCell != null)
{
foreach (var keyNodeCell in listCell.EnumerateKeys())
{
yield return keyNodeCell;
}
}
else
{
yield return (KeyNodeCell)cell;
}
}
}
internal override int LinkSubKey(string name, int cellIndex)
{
// Look for the first sublist that has a subkey name greater than name
if (ListType == "ri")
{
if (_listIndexes.Count == 0)
{
throw new NotImplementedException("Empty indirect list");
}
for (int i = 0; i < _listIndexes.Count - 1; ++i)
{
int tempIndex;
ListCell cell = _hive.GetCell<ListCell>(_listIndexes[i]);
if (cell.FindKey(name, out tempIndex) <= 0)
{
_listIndexes[i] = cell.LinkSubKey(name, cellIndex);
return _hive.UpdateCell(this, false);
}
}
ListCell lastCell = _hive.GetCell<ListCell>(_listIndexes[_listIndexes.Count - 1]);
_listIndexes[_listIndexes.Count - 1] = lastCell.LinkSubKey(name, cellIndex);
return _hive.UpdateCell(this, false);
}
else
{
for (int i = 0; i < _listIndexes.Count; ++i)
{
KeyNodeCell cell = _hive.GetCell<KeyNodeCell>(_listIndexes[i]);
if (string.Compare(name, cell.Name, StringComparison.OrdinalIgnoreCase) < 0)
{
_listIndexes.Insert(i, cellIndex);
return _hive.UpdateCell(this, true);
}
}
_listIndexes.Add(cellIndex);
return _hive.UpdateCell(this, true);
}
}
internal override int UnlinkSubKey(string name)
{
if (ListType == "ri")
{
if (_listIndexes.Count == 0)
{
throw new NotImplementedException("Empty indirect list");
}
for (int i = 0; i < _listIndexes.Count; ++i)
{
int tempIndex;
ListCell cell = _hive.GetCell<ListCell>(_listIndexes[i]);
if (cell.FindKey(name, out tempIndex) <= 0)
{
_listIndexes[i] = cell.UnlinkSubKey(name);
if (cell.Count == 0)
{
_hive.FreeCell(_listIndexes[i]);
_listIndexes.RemoveAt(i);
}
return _hive.UpdateCell(this, false);
}
}
}
else
{
for (int i = 0; i < _listIndexes.Count; ++i)
{
KeyNodeCell cell = _hive.GetCell<KeyNodeCell>(_listIndexes[i]);
if (string.Compare(name, cell.Name, StringComparison.OrdinalIgnoreCase) == 0)
{
_listIndexes.RemoveAt(i);
return _hive.UpdateCell(this, true);
}
}
}
return Index;
}
private int DoFindKey(string name, int listIndex, out int cellIndex)
{
Cell cell = _hive.GetCell<Cell>(_listIndexes[listIndex]);
ListCell listCell = cell as ListCell;
if (listCell != null)
{
return listCell.FindKey(name, out cellIndex);
}
cellIndex = _listIndexes[listIndex];
return string.Compare(name, ((KeyNodeCell)cell).Name, StringComparison.OrdinalIgnoreCase);
}
private class KeyFinder : IComparer<int>
{
private RegistryHive _hive;
private string _searchName;
public KeyFinder(RegistryHive hive, string searchName)
{
_hive = hive;
_searchName = searchName;
}
public int CellIndex { get; set; }
#region IComparer<int> Members
public int Compare(int x, int y)
{
Cell cell = _hive.GetCell<Cell>(x);
ListCell listCell = cell as ListCell;
int result;
if (listCell != null)
{
int cellIndex;
result = listCell.FindKey(_searchName, out cellIndex);
if (result == 0)
{
CellIndex = cellIndex;
}
return -result;
}
else
{
result = string.Compare(((KeyNodeCell)cell).Name, _searchName, StringComparison.OrdinalIgnoreCase);
if (result == 0)
{
CellIndex = x;
}
}
return result;
}
#endregion
}
}
}
+116
View File
@@ -0,0 +1,116 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Registry
{
internal sealed class ValueCell : Cell
{
private int _dataLength;
private int _dataIndex;
private RegistryValueType _type;
private ValueFlags _flags;
private string _name;
public ValueCell(string name)
: this(-1)
{
_name = name;
}
public ValueCell(int index)
: base(index)
{
_dataIndex = -1;
}
public int DataLength
{
get { return _dataLength; }
set { _dataLength = value; }
}
public int DataIndex
{
get { return _dataIndex; }
set { _dataIndex = value; }
}
public RegistryValueType DataType
{
get { return _type; }
set { _type = value; }
}
public string Name
{
get { return _name; }
}
public override int Size
{
get { return 0x14 + (string.IsNullOrEmpty(_name) ? 0 : _name.Length); }
}
public override int ReadFrom(byte[] buffer, int offset)
{
int nameLen = Utilities.ToUInt16LittleEndian(buffer, offset + 0x02);
_dataLength = Utilities.ToInt32LittleEndian(buffer, offset + 0x04);
_dataIndex = Utilities.ToInt32LittleEndian(buffer, offset + 0x08);
_type = (RegistryValueType)Utilities.ToInt32LittleEndian(buffer, offset + 0x0C);
_flags = (ValueFlags)Utilities.ToUInt16LittleEndian(buffer, offset + 0x10);
if ((_flags & ValueFlags.Named) != 0)
{
_name = Utilities.BytesToString(buffer, offset + 0x14, nameLen).Trim('\0');
}
return 0x14 + nameLen;
}
public override void WriteTo(byte[] buffer, int offset)
{
int nameLen;
if (string.IsNullOrEmpty(_name))
{
_flags &= ~ValueFlags.Named;
nameLen = 0;
}
else
{
_flags |= ValueFlags.Named;
nameLen = _name.Length;
}
Utilities.StringToBytes("vk", buffer, offset, 2);
Utilities.WriteBytesLittleEndian(nameLen, buffer, offset + 0x02);
Utilities.WriteBytesLittleEndian(_dataLength, buffer, offset + 0x04);
Utilities.WriteBytesLittleEndian(_dataIndex, buffer, offset + 0x08);
Utilities.WriteBytesLittleEndian((int)_type, buffer, offset + 0x0C);
Utilities.WriteBytesLittleEndian((ushort)_flags, buffer, offset + 0x10);
if (nameLen != 0)
{
Utilities.StringToBytes(_name, buffer, offset + 0x14, nameLen);
}
}
}
}
+47
View File
@@ -0,0 +1,47 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Registry
{
using System;
[Flags]
internal enum ValueFlags : ushort
{
Named = 0x0001,
Unknown0002 = 0x0002,
Unknown0004 = 0x0004,
Unknown0008 = 0x0008,
Unknown0010 = 0x0010,
Unknown0020 = 0x0020,
Unknown0040 = 0x0040,
Unknown0080 = 0x0080,
Unknown0100 = 0x0100,
Unknown0200 = 0x0200,
Unknown0400 = 0x0400,
Unknown0800 = 0x0800,
Unknown1000 = 0x1000,
Unknown2000 = 0x2000,
Unknown4000 = 0x4000,
Unknown8000 = 0x8000
}
}