/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved. * * You can redistribute this program and/or modify it under the terms of * the GNU Lesser Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. */ using System; using System.Collections.Generic; using System.Text; using Utilities; namespace DiskAccessLibrary.VHD { public class DynamicDiskHeader { public const int Length = 1024; public const string DynamidDiskHeaderCookie = "cxsparse"; public string Cookie; // 8 bytes public ulong DataOffset; // The documentation says 0xFFFFFFFF, but all programs use 0xFFFFFFFFFFFFFFFF public ulong TableOffset; public uint HeaderVersion; public uint MaxTableEntries; public uint BlockSize; //public uint Checksum; public Guid ParentUniqueID; public uint ParentTimeStamp; public uint Reserved; public string ParentUnicodeName = String.Empty; // 8 bytes public ParentLocatorEntry ParentLocatorEntry1; public ParentLocatorEntry ParentLocatorEntry2; public ParentLocatorEntry ParentLocatorEntry3; public ParentLocatorEntry ParentLocatorEntry4; public ParentLocatorEntry ParentLocatorEntry5; public ParentLocatorEntry ParentLocatorEntry6; public ParentLocatorEntry ParentLocatorEntry7; public ParentLocatorEntry ParentLocatorEntry8; private bool m_isValid = true; public DynamicDiskHeader() { Cookie = DynamidDiskHeaderCookie; DataOffset = 0xFFFFFFFFFFFFFFFF; HeaderVersion = 0x00010000; } public DynamicDiskHeader(byte[] buffer) { Cookie = ByteReader.ReadAnsiString(buffer, 0x00, 8); DataOffset = BigEndianConverter.ToUInt64(buffer, 0x08); TableOffset = BigEndianConverter.ToUInt64(buffer, 0x10); HeaderVersion = BigEndianConverter.ToUInt32(buffer, 0x18); MaxTableEntries = BigEndianConverter.ToUInt32(buffer, 0x1C); BlockSize = BigEndianConverter.ToUInt32(buffer, 0x20); uint checksum = BigEndianConverter.ToUInt32(buffer, 0x24); ParentUniqueID = BigEndianConverter.ToGuid(buffer, 0x28); ParentTimeStamp = BigEndianConverter.ToUInt32(buffer, 0x38); Reserved = BigEndianConverter.ToUInt32(buffer, 0x3C); ParentUnicodeName = ByteReader.ReadUTF16String(buffer, 0x40, 256).TrimEnd('\0'); ParentLocatorEntry1 = new ParentLocatorEntry(buffer, 0x240); ParentLocatorEntry2 = new ParentLocatorEntry(buffer, 0x258); ParentLocatorEntry3 = new ParentLocatorEntry(buffer, 0x270); ParentLocatorEntry4 = new ParentLocatorEntry(buffer, 0x288); ParentLocatorEntry5 = new ParentLocatorEntry(buffer, 0x2A0); ParentLocatorEntry6 = new ParentLocatorEntry(buffer, 0x2B8); ParentLocatorEntry7 = new ParentLocatorEntry(buffer, 0x2D0); ParentLocatorEntry8 = new ParentLocatorEntry(buffer, 0x2E8); byte[] temp = (byte[])buffer.Clone(); BigEndianWriter.WriteInt32(temp, 0x24, 0); uint expectedChecksum = VHDFooter.CalculateChecksum(temp); m_isValid = String.Equals(Cookie, DynamidDiskHeaderCookie) && (checksum == expectedChecksum) && (HeaderVersion == 0x00010000); } public byte[] GetBytes() { byte[] buffer = new byte[Length]; ByteWriter.WriteAnsiString(buffer, 0x00, Cookie, 8); BigEndianWriter.WriteUInt64(buffer, 0x08, DataOffset); BigEndianWriter.WriteUInt64(buffer, 0x10, TableOffset); BigEndianWriter.WriteUInt32(buffer, 0x18, HeaderVersion); BigEndianWriter.WriteUInt32(buffer, 0x1C, MaxTableEntries); BigEndianWriter.WriteUInt32(buffer, 0x20, BlockSize); // We'll write the checksum later BigEndianWriter.WriteGuidBytes(buffer, 0x28, ParentUniqueID); BigEndianWriter.WriteUInt32(buffer, 0x38, ParentTimeStamp); BigEndianWriter.WriteUInt32(buffer, 0x3C, Reserved); ByteWriter.WriteUTF16String(buffer, 0x40, ParentUnicodeName, 256); ParentLocatorEntry1.WriteBytes(buffer, 0x240); ParentLocatorEntry2.WriteBytes(buffer, 0x258); ParentLocatorEntry3.WriteBytes(buffer, 0x270); ParentLocatorEntry4.WriteBytes(buffer, 0x288); ParentLocatorEntry5.WriteBytes(buffer, 0x2A0); ParentLocatorEntry6.WriteBytes(buffer, 0x2B8); ParentLocatorEntry7.WriteBytes(buffer, 0x2D0); ParentLocatorEntry8.WriteBytes(buffer, 0x2E8); uint checksum = VHDFooter.CalculateChecksum(buffer); BigEndianWriter.WriteUInt32(buffer, 0x24, checksum); return buffer; } } }