mirror of
https://github.com/ReneLergner/WPinternals.git
synced 2026-06-14 03:16:40 +10:00
305 lines
11 KiB
C#
305 lines
11 KiB
C#
//
|
|
// 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);
|
|
}
|
|
}
|
|
}
|
|
}
|