summaryrefslogtreecommitdiff
path: root/LibTSforge/PhysicalStore
diff options
context:
space:
mode:
authorWither OrNot2025-02-13 14:49:35 +0000
committerWither OrNot2025-02-13 14:49:37 +0000
commit0d59561bee4cf7db10d53a8aa58952ae65e856b5 (patch)
treeb2ddb66c883dd2ef75426de4c080f3121f0a8658 /LibTSforge/PhysicalStore
downloadTSforge-0d59561bee4cf7db10d53a8aa58952ae65e856b5.zip
Initial commit1.0.0
Co-authored-by: neko <[email protected]> Co-authored-by: Lyssa <[email protected]> Co-authored-by: abbodi1406 <[email protected]>
Diffstat (limited to 'LibTSforge/PhysicalStore')
-rw-r--r--LibTSforge/PhysicalStore/Common.cs21
-rw-r--r--LibTSforge/PhysicalStore/IPhysicalStore.cs92
-rw-r--r--LibTSforge/PhysicalStore/PhysicalStoreModern.cs411
-rw-r--r--LibTSforge/PhysicalStore/PhysicalStoreWin7.cs374
-rw-r--r--LibTSforge/PhysicalStore/VariableBag.cs187
5 files changed, 1085 insertions, 0 deletions
diff --git a/LibTSforge/PhysicalStore/Common.cs b/LibTSforge/PhysicalStore/Common.cs
new file mode 100644
index 0000000..f73f022
--- /dev/null
+++ b/LibTSforge/PhysicalStore/Common.cs
@@ -0,0 +1,21 @@
+namespace LibTSforge.PhysicalStore
+{
+ using System.Runtime.InteropServices;
+
+ public enum BlockType : uint
+ {
+ NONE,
+ NAMED,
+ ATTRIBUTE,
+ TIMER
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct Timer
+ {
+ public ulong Unknown;
+ public ulong Time1;
+ public ulong Time2;
+ public ulong Expiry;
+ }
+}
diff --git a/LibTSforge/PhysicalStore/IPhysicalStore.cs b/LibTSforge/PhysicalStore/IPhysicalStore.cs
new file mode 100644
index 0000000..e451281
--- /dev/null
+++ b/LibTSforge/PhysicalStore/IPhysicalStore.cs
@@ -0,0 +1,92 @@
+namespace LibTSforge.PhysicalStore
+{
+ using System;
+ using System.Collections.Generic;
+
+ public class PSBlock
+ {
+ public BlockType Type;
+ public uint Flags;
+ public uint Unknown = 0;
+ public byte[] Key;
+ public string KeyAsStr
+ {
+ get
+ {
+ return Utils.DecodeString(Key);
+ }
+ set
+ {
+ Key = Utils.EncodeString(value);
+ }
+ }
+ public byte[] Value;
+ public string ValueAsStr
+ {
+ get
+ {
+ return Utils.DecodeString(Value);
+ }
+ set
+ {
+ Value = Utils.EncodeString(value);
+ }
+ }
+ public uint ValueAsInt
+ {
+ get
+ {
+ return BitConverter.ToUInt32(Value, 0);
+ }
+ set
+ {
+ Value = BitConverter.GetBytes(value);
+ }
+ }
+ public byte[] Data;
+ public string DataAsStr
+ {
+ get
+ {
+ return Utils.DecodeString(Data);
+ }
+ set
+ {
+ Data = Utils.EncodeString(value);
+ }
+ }
+ public uint DataAsInt
+ {
+ get
+ {
+ return BitConverter.ToUInt32(Data, 0);
+ }
+ set
+ {
+ Data = BitConverter.GetBytes(value);
+ }
+ }
+ }
+
+ public interface IPhysicalStore : IDisposable
+ {
+ PSBlock GetBlock(string key, string value);
+ PSBlock GetBlock(string key, uint value);
+ void AddBlock(PSBlock block);
+ void AddBlocks(IEnumerable<PSBlock> blocks);
+ void SetBlock(string key, string value, byte[] data);
+ void SetBlock(string key, string value, string data);
+ void SetBlock(string key, string value, uint data);
+ void SetBlock(string key, uint value, byte[] data);
+ void SetBlock(string key, uint value, string data);
+ void SetBlock(string key, uint value, uint data);
+ void DeleteBlock(string key, string value);
+ void DeleteBlock(string key, uint value);
+ byte[] Serialize();
+ void Deserialize(byte[] data);
+ byte[] ReadRaw();
+ void WriteRaw(byte[] data);
+ IEnumerable<PSBlock> FindBlocks(string valueSearch);
+ IEnumerable<PSBlock> FindBlocks(uint valueSearch);
+ }
+}
diff --git a/LibTSforge/PhysicalStore/PhysicalStoreModern.cs b/LibTSforge/PhysicalStore/PhysicalStoreModern.cs
new file mode 100644
index 0000000..f697bea
--- /dev/null
+++ b/LibTSforge/PhysicalStore/PhysicalStoreModern.cs
@@ -0,0 +1,411 @@
+namespace LibTSforge.PhysicalStore
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using LibTSforge.Crypto;
+
+ public class ModernBlock
+ {
+ public BlockType Type;
+ public uint Flags;
+ public uint Unknown;
+ public byte[] Value;
+ public string ValueAsStr
+ {
+ get
+ {
+ return Utils.DecodeString(Value);
+ }
+ set
+ {
+ Value = Utils.EncodeString(value);
+ }
+ }
+ public uint ValueAsInt
+ {
+ get
+ {
+ return BitConverter.ToUInt32(Value, 0);
+ }
+ set
+ {
+ Value = BitConverter.GetBytes(value);
+ }
+ }
+ public byte[] Data;
+ public string DataAsStr
+ {
+ get
+ {
+ return Utils.DecodeString(Data);
+ }
+ set
+ {
+ Data = Utils.EncodeString(value);
+ }
+ }
+ public uint DataAsInt
+ {
+ get
+ {
+ return BitConverter.ToUInt32(Data, 0);
+ }
+ set
+ {
+ Data = BitConverter.GetBytes(value);
+ }
+ }
+
+ public void Encode(BinaryWriter writer)
+ {
+ writer.Write((uint)Type);
+ writer.Write(Flags);
+ writer.Write((uint)Value.Length);
+ writer.Write((uint)Data.Length);
+ writer.Write(Unknown);
+ writer.Write(Value);
+ writer.Write(Data);
+ }
+
+ public static ModernBlock Decode(BinaryReader reader)
+ {
+ uint type = reader.ReadUInt32();
+ uint flags = reader.ReadUInt32();
+
+ uint valueLen = reader.ReadUInt32();
+ uint dataLen = reader.ReadUInt32();
+ uint unk3 = reader.ReadUInt32();
+
+ byte[] value = reader.ReadBytes((int)valueLen);
+ byte[] data = reader.ReadBytes((int)dataLen);
+
+ return new ModernBlock
+ {
+ Type = (BlockType)type,
+ Flags = flags,
+ Unknown = unk3,
+ Value = value,
+ Data = data,
+ };
+ }
+ }
+
+ public sealed class PhysicalStoreModern : IPhysicalStore
+ {
+ private byte[] PreHeaderBytes = new byte[] { };
+ private readonly Dictionary<string, List<ModernBlock>> Data = new Dictionary<string, List<ModernBlock>>();
+ private readonly FileStream TSFile;
+ private readonly PSVersion Version;
+ private readonly bool Production;
+
+ public byte[] Serialize()
+ {
+ BinaryWriter writer = new BinaryWriter(new MemoryStream());
+ writer.Write(PreHeaderBytes);
+ writer.Write(Data.Keys.Count);
+
+ foreach (string key in Data.Keys)
+ {
+ List<ModernBlock> blocks = Data[key];
+ byte[] keyNameEnc = Utils.EncodeString(key);
+
+ writer.Write(keyNameEnc.Length);
+ writer.Write(keyNameEnc);
+ writer.Write(blocks.Count);
+ writer.Align(4);
+
+ foreach (ModernBlock block in blocks)
+ {
+ block.Encode(writer);
+ writer.Align(4);
+ }
+ }
+
+ return writer.GetBytes();
+ }
+
+ public void Deserialize(byte[] data)
+ {
+ BinaryReader reader = new BinaryReader(new MemoryStream(data));
+ PreHeaderBytes = reader.ReadBytes(8);
+
+ while (reader.BaseStream.Position < data.Length - 0x4)
+ {
+ uint numKeys = reader.ReadUInt32();
+
+ for (int i = 0; i < numKeys; i++)
+ {
+ uint lenKeyName = reader.ReadUInt32();
+ string keyName = Utils.DecodeString(reader.ReadBytes((int)lenKeyName)); uint numValues = reader.ReadUInt32();
+
+ reader.Align(4);
+
+ Data[keyName] = new List<ModernBlock>();
+
+ for (int j = 0; j < numValues; j++)
+ {
+ Data[keyName].Add(ModernBlock.Decode(reader));
+ reader.Align(4);
+ }
+ }
+ }
+ }
+
+ public void AddBlock(PSBlock block)
+ {
+ if (!Data.ContainsKey(block.KeyAsStr))
+ {
+ Data[block.KeyAsStr] = new List<ModernBlock>();
+ }
+
+ Data[block.KeyAsStr].Add(new ModernBlock
+ {
+ Type = block.Type,
+ Flags = block.Flags,
+ Unknown = block.Unknown,
+ Value = block.Value,
+ Data = block.Data
+ });
+ }
+
+ public void AddBlocks(IEnumerable<PSBlock> blocks)
+ {
+ foreach (PSBlock block in blocks)
+ {
+ AddBlock(block);
+ }
+ }
+
+ public PSBlock GetBlock(string key, string value)
+ {
+ List<ModernBlock> blocks = Data[key];
+
+ foreach (ModernBlock block in blocks)
+ {
+ if (block.ValueAsStr == value)
+ {
+ return new PSBlock
+ {
+ Type = block.Type,
+ Flags = block.Flags,
+ Key = Utils.EncodeString(key),
+ Value = block.Value,
+ Data = block.Data
+ };
+ }
+ }
+
+ return null;
+ }
+
+ public PSBlock GetBlock(string key, uint value)
+ {
+ List<ModernBlock> blocks = Data[key];
+
+ foreach (ModernBlock block in blocks)
+ {
+ if (block.ValueAsInt == value)
+ {
+ return new PSBlock
+ {
+ Type = block.Type,
+ Flags = block.Flags,
+ Key = Utils.EncodeString(key),
+ Value = block.Value,
+ Data = block.Data
+ };
+ }
+ }
+
+ return null;
+ }
+
+ public void SetBlock(string key, string value, byte[] data)
+ {
+ List<ModernBlock> blocks = Data[key];
+
+ for (int i = 0; i < blocks.Count; i++)
+ {
+ ModernBlock block = blocks[i];
+
+ if (block.ValueAsStr == value)
+ {
+ block.Data = data;
+ blocks[i] = block;
+ break;
+ }
+ }
+
+ Data[key] = blocks;
+ }
+
+ public void SetBlock(string key, uint value, byte[] data)
+ {
+ List<ModernBlock> blocks = Data[key];
+
+ for (int i = 0; i < blocks.Count; i++)
+ {
+ ModernBlock block = blocks[i];
+
+ if (block.ValueAsInt == value)
+ {
+ block.Data = data;
+ blocks[i] = block;
+ break;
+ }
+ }
+
+ Data[key] = blocks;
+ }
+
+ public void SetBlock(string key, string value, string data)
+ {
+ SetBlock(key, value, Utils.EncodeString(data));
+ }
+
+ public void SetBlock(string key, string value, uint data)
+ {
+ SetBlock(key, value, BitConverter.GetBytes(data));
+ }
+
+ public void SetBlock(string key, uint value, string data)
+ {
+ SetBlock(key, value, Utils.EncodeString(data));
+ }
+
+ public void SetBlock(string key, uint value, uint data)
+ {
+ SetBlock(key, value, BitConverter.GetBytes(data));
+ }
+
+ public void DeleteBlock(string key, string value)
+ {
+ if (Data.ContainsKey(key))
+ {
+ List<ModernBlock> blocks = Data[key];
+
+ foreach (ModernBlock block in blocks)
+ {
+ if (block.ValueAsStr == value)
+ {
+ blocks.Remove(block);
+ break;
+ }
+ }
+
+ Data[key] = blocks;
+ }
+ }
+
+ public void DeleteBlock(string key, uint value)
+ {
+ if (Data.ContainsKey(key))
+ {
+ List<ModernBlock> blocks = Data[key];
+
+ foreach (ModernBlock block in blocks)
+ {
+ if (block.ValueAsInt == value)
+ {
+ blocks.Remove(block);
+ break;
+ }
+ }
+
+ Data[key] = blocks;
+ }
+ }
+
+ public PhysicalStoreModern(string tsPath, bool production, PSVersion version)
+ {
+ TSFile = File.Open(tsPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
+ Deserialize(PhysStoreCrypto.DecryptPhysicalStore(TSFile.ReadAllBytes(), production));
+ TSFile.Seek(0, SeekOrigin.Begin);
+ Version = version;
+ Production = production;
+ }
+
+ public void Dispose()
+ {
+ if (TSFile.CanWrite)
+ {
+ byte[] data = PhysStoreCrypto.EncryptPhysicalStore(Serialize(), Production, Version);
+ TSFile.SetLength(data.LongLength);
+ TSFile.Seek(0, SeekOrigin.Begin);
+ TSFile.WriteAllBytes(data);
+ TSFile.Close();
+ }
+ }
+
+ public byte[] ReadRaw()
+ {
+ byte[] data = PhysStoreCrypto.DecryptPhysicalStore(TSFile.ReadAllBytes(), Production);
+ TSFile.Seek(0, SeekOrigin.Begin);
+ return data;
+ }
+
+ public void WriteRaw(byte[] data)
+ {
+ byte[] encrData = PhysStoreCrypto.EncryptPhysicalStore(data, Production, Version);
+ TSFile.SetLength(encrData.LongLength);
+ TSFile.Seek(0, SeekOrigin.Begin);
+ TSFile.WriteAllBytes(encrData);
+ TSFile.Close();
+ }
+
+ public IEnumerable<PSBlock> FindBlocks(string valueSearch)
+ {
+ List<PSBlock> results = new List<PSBlock>();
+
+ foreach (string key in Data.Keys)
+ {
+ List<ModernBlock> values = Data[key];
+
+ foreach (ModernBlock block in values)
+ {
+ if (block.ValueAsStr.Contains(valueSearch))
+ {
+ results.Add(new PSBlock
+ {
+ Type = block.Type,
+ Flags = block.Flags,
+ KeyAsStr = key,
+ Value = block.Value,
+ Data = block.Data
+ });
+ }
+ }
+ }
+
+ return results;
+ }
+
+ public IEnumerable<PSBlock> FindBlocks(uint valueSearch)
+ {
+ List<PSBlock> results = new List<PSBlock>();
+
+ foreach (string key in Data.Keys)
+ {
+ List<ModernBlock> values = Data[key];
+
+ foreach (ModernBlock block in values)
+ {
+ if (block.ValueAsInt == valueSearch)
+ {
+ results.Add(new PSBlock
+ {
+ Type = block.Type,
+ Flags = block.Flags,
+ KeyAsStr = key,
+ Value = block.Value,
+ Data = block.Data
+ });
+ }
+ }
+ }
+
+ return results;
+ }
+ }
+}
diff --git a/LibTSforge/PhysicalStore/PhysicalStoreWin7.cs b/LibTSforge/PhysicalStore/PhysicalStoreWin7.cs
new file mode 100644
index 0000000..c1af391
--- /dev/null
+++ b/LibTSforge/PhysicalStore/PhysicalStoreWin7.cs
@@ -0,0 +1,374 @@
+namespace LibTSforge.PhysicalStore
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using LibTSforge.Crypto;
+
+ public class Win7Block
+ {
+ public BlockType Type;
+ public uint Flags;
+ public byte[] Key;
+ public string KeyAsStr
+ {
+ get
+ {
+ return Utils.DecodeString(Key);
+ }
+ set
+ {
+ Key = Utils.EncodeString(value);
+ }
+ }
+ public byte[] Value;
+ public string ValueAsStr
+ {
+ get
+ {
+ return Utils.DecodeString(Value);
+ }
+ set
+ {
+ Value = Utils.EncodeString(value);
+ }
+ }
+ public uint ValueAsInt
+ {
+ get
+ {
+ return BitConverter.ToUInt32(Value, 0);
+ }
+ set
+ {
+ Value = BitConverter.GetBytes(value);
+ }
+ }
+ public byte[] Data;
+ public string DataAsStr
+ {
+ get
+ {
+ return Utils.DecodeString(Data);
+ }
+ set
+ {
+ Data = Utils.EncodeString(value);
+ }
+ }
+ public uint DataAsInt
+ {
+ get
+ {
+ return BitConverter.ToUInt32(Data, 0);
+ }
+ set
+ {
+ Data = BitConverter.GetBytes(value);
+ }
+ }
+
+ internal void Encode(BinaryWriter writer)
+ {
+ writer.Write((uint)Type);
+ writer.Write(Flags);
+ writer.Write(Key.Length);
+ writer.Write(Value.Length);
+ writer.Write(Data.Length);
+ writer.Write(Key);
+ writer.Write(Value);
+ writer.Write(Data);
+ }
+
+ internal static Win7Block Decode(BinaryReader reader)
+ {
+ uint type = reader.ReadUInt32();
+ uint flags = reader.ReadUInt32();
+
+ int keyLen = reader.ReadInt32();
+ int valueLen = reader.ReadInt32();
+ int dataLen = reader.ReadInt32();
+
+ byte[] key = reader.ReadBytes(keyLen);
+ byte[] value = reader.ReadBytes(valueLen);
+ byte[] data = reader.ReadBytes(dataLen);
+ return new Win7Block
+ {
+ Type = (BlockType)type,
+ Flags = flags,
+ Key = key,
+ Value = value,
+ Data = data,
+ };
+ }
+ }
+
+ public sealed class PhysicalStoreWin7 : IPhysicalStore
+ {
+ private byte[] PreHeaderBytes = new byte[] { };
+ private readonly List<Win7Block> Blocks = new List<Win7Block>();
+ private readonly FileStream TSPrimary;
+ private readonly FileStream TSSecondary;
+ private readonly bool Production;
+
+ public byte[] Serialize()
+ {
+ BinaryWriter writer = new BinaryWriter(new MemoryStream());
+ writer.Write(PreHeaderBytes);
+
+ foreach (Win7Block block in Blocks)
+ {
+ block.Encode(writer);
+ writer.Align(4);
+ }
+
+ return writer.GetBytes();
+ }
+
+ public void Deserialize(byte[] data)
+ {
+ int len = data.Length;
+
+ BinaryReader reader = new BinaryReader(new MemoryStream(data));
+ PreHeaderBytes = reader.ReadBytes(8);
+
+ while (reader.BaseStream.Position < len - 0x14)
+ {
+ Blocks.Add(Win7Block.Decode(reader));
+ reader.Align(4);
+ }
+ }
+
+ public void AddBlock(PSBlock block)
+ {
+ Blocks.Add(new Win7Block
+ {
+ Type = block.Type,
+ Flags = block.Flags,
+ Key = block.Key,
+ Value = block.Value,
+ Data = block.Data
+ });
+ }
+
+ public void AddBlocks(IEnumerable<PSBlock> blocks)
+ {
+ foreach (PSBlock block in blocks)
+ {
+ AddBlock(block);
+ }
+ }
+
+ public PSBlock GetBlock(string key, string value)
+ {
+ foreach (Win7Block block in Blocks)
+ {
+ if (block.KeyAsStr == key && block.ValueAsStr == value)
+ {
+ return new PSBlock
+ {
+ Type = block.Type,
+ Flags = block.Flags,
+ Key = block.Key,
+ Value = block.Value,
+ Data = block.Data
+ };
+ }
+ }
+
+ return null;
+ }
+
+ public PSBlock GetBlock(string key, uint value)
+ {
+ foreach (Win7Block block in Blocks)
+ {
+ if (block.KeyAsStr == key && block.ValueAsInt == value)
+ {
+ return new PSBlock
+ {
+ Type = block.Type,
+ Flags = block.Flags,
+ Key = block.Key,
+ Value = block.Value,
+ Data = block.Data
+ };
+ }
+ }
+
+ return null;
+ }
+
+ public void SetBlock(string key, string value, byte[] data)
+ {
+ for (int i = 0; i < Blocks.Count; i++)
+ {
+ Win7Block block = Blocks[i];
+
+ if (block.KeyAsStr == key && block.ValueAsStr == value)
+ {
+ block.Data = data;
+ Blocks[i] = block;
+ break;
+ }
+ }
+ }
+
+ public void SetBlock(string key, uint value, byte[] data)
+ {
+ for (int i = 0; i < Blocks.Count; i++)
+ {
+ Win7Block block = Blocks[i];
+
+ if (block.KeyAsStr == key && block.ValueAsInt == value)
+ {
+ block.Data = data;
+ Blocks[i] = block;
+ break;
+ }
+ }
+ }
+
+ public void SetBlock(string key, string value, string data)
+ {
+ SetBlock(key, value, Utils.EncodeString(data));
+ }
+
+ public void SetBlock(string key, string value, uint data)
+ {
+ SetBlock(key, value, BitConverter.GetBytes(data));
+ }
+
+ public void SetBlock(string key, uint value, string data)
+ {
+ SetBlock(key, value, Utils.EncodeString(data));
+ }
+
+ public void SetBlock(string key, uint value, uint data)
+ {
+ SetBlock(key, value, BitConverter.GetBytes(data));
+ }
+
+ public void DeleteBlock(string key, string value)
+ {
+ foreach (Win7Block block in Blocks)
+ {
+ if (block.KeyAsStr == key && block.ValueAsStr == value)
+ {
+ Blocks.Remove(block);
+ return;
+ }
+ }
+ }
+
+ public void DeleteBlock(string key, uint value)
+ {
+ foreach (Win7Block block in Blocks)
+ {
+ if (block.KeyAsStr == key && block.ValueAsInt == value)
+ {
+ Blocks.Remove(block);
+ return;
+ }
+ }
+ }
+
+ public PhysicalStoreWin7(string primaryPath, bool production)
+ {
+ TSPrimary = File.Open(primaryPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
+ TSSecondary = File.Open(primaryPath.Replace("-0.", "-1."), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
+ Production = production;
+
+ Deserialize(PhysStoreCrypto.DecryptPhysicalStore(TSPrimary.ReadAllBytes(), production));
+ TSPrimary.Seek(0, SeekOrigin.Begin);
+ }
+
+ public void Dispose()
+ {
+ if (TSPrimary.CanWrite && TSSecondary.CanWrite)
+ {
+ byte[] data = PhysStoreCrypto.EncryptPhysicalStore(Serialize(), Production, PSVersion.Win7);
+
+ TSPrimary.SetLength(data.LongLength);
+ TSSecondary.SetLength(data.LongLength);
+
+ TSPrimary.Seek(0, SeekOrigin.Begin);
+ TSSecondary.Seek(0, SeekOrigin.Begin);
+
+ TSPrimary.WriteAllBytes(data);
+ TSSecondary.WriteAllBytes(data);
+
+ TSPrimary.Close();
+ TSSecondary.Close();
+ }
+ }
+
+ public byte[] ReadRaw()
+ {
+ byte[] data = PhysStoreCrypto.DecryptPhysicalStore(TSPrimary.ReadAllBytes(), Production);
+ TSPrimary.Seek(0, SeekOrigin.Begin);
+ return data;
+ }
+
+ public void WriteRaw(byte[] data)
+ {
+ byte[] encrData = PhysStoreCrypto.EncryptPhysicalStore(data, Production, PSVersion.Win7);
+
+ TSPrimary.SetLength(encrData.LongLength);
+ TSSecondary.SetLength(encrData.LongLength);
+
+ TSPrimary.Seek(0, SeekOrigin.Begin);
+ TSSecondary.Seek(0, SeekOrigin.Begin);
+
+ TSPrimary.WriteAllBytes(encrData);
+ TSSecondary.WriteAllBytes(encrData);
+
+ TSPrimary.Close();
+ TSSecondary.Close();
+ }
+
+ public IEnumerable<PSBlock> FindBlocks(string valueSearch)
+ {
+ List<PSBlock> results = new List<PSBlock>();
+
+ foreach (Win7Block block in Blocks)
+ {
+ if (block.ValueAsStr.Contains(valueSearch))
+ {
+ results.Add(new PSBlock
+ {
+ Type = block.Type,
+ Flags = block.Flags,
+ Key = block.Key,
+ Value = block.Value,
+ Data = block.Data
+ });
+ }
+ }
+
+ return results;
+ }
+
+ public IEnumerable<PSBlock> FindBlocks(uint valueSearch)
+ {
+ List<PSBlock> results = new List<PSBlock>();
+
+ foreach (Win7Block block in Blocks)
+ {
+ if (block.ValueAsInt == valueSearch)
+ {
+ results.Add(new PSBlock
+ {
+ Type = block.Type,
+ Flags = block.Flags,
+ Key = block.Key,
+ Value = block.Value,
+ Data = block.Data
+ });
+ }
+ }
+
+ return results;
+ }
+ }
+}
diff --git a/LibTSforge/PhysicalStore/VariableBag.cs b/LibTSforge/PhysicalStore/VariableBag.cs
new file mode 100644
index 0000000..ddc2efe
--- /dev/null
+++ b/LibTSforge/PhysicalStore/VariableBag.cs
@@ -0,0 +1,187 @@
+namespace LibTSforge.PhysicalStore
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+
+ public enum CRCBlockType : uint
+ {
+ UINT = 1 << 0,
+ STRING = 1 << 1,
+ BINARY = 1 << 2
+ }
+
+ public class CRCBlock
+ {
+ public CRCBlockType DataType;
+ public byte[] Key;
+ public string KeyAsStr
+ {
+ get
+ {
+ return Utils.DecodeString(Key);
+ }
+ set
+ {
+ Key = Utils.EncodeString(value);
+ }
+ }
+ public byte[] Value;
+ public string ValueAsStr
+ {
+ get
+ {
+ return Utils.DecodeString(Value);
+ }
+ set
+ {
+ Value = Utils.EncodeString(value);
+ }
+ }
+ public uint ValueAsInt
+ {
+ get
+ {
+ return BitConverter.ToUInt32(Value, 0);
+ }
+ set
+ {
+ Value = BitConverter.GetBytes(value);
+ }
+ }
+
+ public void Encode(BinaryWriter writer)
+ {
+ uint crc = CRC();
+ writer.Write(crc);
+ writer.Write((uint)DataType);
+ writer.Write(Key.Length);
+ writer.Write(Value.Length);
+
+ writer.Write(Key);
+ writer.Align(8);
+
+ writer.Write(Value);
+ writer.Align(8);
+ }
+
+ public static CRCBlock Decode(BinaryReader reader)
+ {
+ uint crc = reader.ReadUInt32();
+ uint type = reader.ReadUInt32();
+ uint lenName = reader.ReadUInt32();
+ uint lenVal = reader.ReadUInt32();
+
+ byte[] key = reader.ReadBytes((int)lenName);
+ reader.Align(8);
+
+ byte[] value = reader.ReadBytes((int)lenVal);
+ reader.Align(8);
+
+ CRCBlock block = new CRCBlock
+ {
+ DataType = (CRCBlockType)type,
+ Key = key,
+ Value = value,
+ };
+
+ if (block.CRC() != crc)
+ {
+ throw new InvalidDataException("Invalid CRC in variable bag.");
+ }
+
+ return block;
+ }
+
+ public uint CRC()
+ {
+ BinaryWriter wtemp = new BinaryWriter(new MemoryStream());
+ wtemp.Write(0);
+ wtemp.Write((uint)DataType);
+ wtemp.Write(Key.Length);
+ wtemp.Write(Value.Length);
+ wtemp.Write(Key);
+ wtemp.Write(Value);
+ return Utils.CRC32(wtemp.GetBytes());
+ }
+ }
+
+ public class VariableBag
+ {
+ public List<CRCBlock> Blocks = new List<CRCBlock>();
+
+ public void Deserialize(byte[] data)
+ {
+ int len = data.Length;
+
+ BinaryReader reader = new BinaryReader(new MemoryStream(data));
+
+ while (reader.BaseStream.Position < len - 0x10)
+ {
+ Blocks.Add(CRCBlock.Decode(reader));
+ }
+ }
+
+ public byte[] Serialize()
+ {
+ BinaryWriter writer = new BinaryWriter(new MemoryStream());
+
+ foreach (CRCBlock block in Blocks)
+ {
+ block.Encode(writer);
+ }
+
+ return writer.GetBytes();
+ }
+
+ public CRCBlock GetBlock(string key)
+ {
+ foreach (CRCBlock block in Blocks)
+ {
+ if (block.KeyAsStr == key)
+ {
+ return block;
+ }
+ }
+
+ return null;
+ }
+
+ public void SetBlock(string key, byte[] value)
+ {
+ for (int i = 0; i < Blocks.Count; i++)
+ {
+ CRCBlock block = Blocks[i];
+
+ if (block.KeyAsStr == key)
+ {
+ block.Value = value;
+ Blocks[i] = block;
+ break;
+ }
+ }
+ }
+
+ public void DeleteBlock(string key)
+ {
+ foreach (CRCBlock block in Blocks)
+ {
+ if (block.KeyAsStr == key)
+ {
+ Blocks.Remove(block);
+ return;
+ }
+ }
+ }
+
+ public VariableBag(byte[] data)
+ {
+ Deserialize(data);
+ }
+
+ public VariableBag()
+ {
+
+ }
+ }
+}