Files
WPinternals/DiscUtils/Registry/SubKeyIndirectListCell.cs
T
2018-10-25 22:35:49 +02:00

311 lines
10 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.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
}
}
}