diff --git a/BurnOutSharp/FileType/MicrosoftCAB.cs b/BurnOutSharp/FileType/MicrosoftCAB.cs
index 035c6c8a..2eb2e3df 100644
--- a/BurnOutSharp/FileType/MicrosoftCAB.cs
+++ b/BurnOutSharp/FileType/MicrosoftCAB.cs
@@ -161,15 +161,61 @@ namespace BurnOutSharp.FileType
#region TEMPORARY AREA FOR MS-CAB FORMAT
- private const uint MSCABMaximumUncompressedFileSize = 0x7FFF8000;
+ internal class MSCABCabinet
+ {
+ #region Constants
- private const ushort MSCABMaximumFileCount = 0xFFFF;
+ ///
+ /// A maximum uncompressed size of an input file to store in CAB
+ ///
+ public const uint MaximumUncompressedFileSize = 0x7FFF8000;
- private const uint MSCABMaximumCabSize = 0x7FFFFFFF;
+ ///
+ /// A maximum file COUNT
+ ///
+ public const ushort MaximumFileCount = 0xFFFF;
- private const ushort MSCABMaximumFolderCount = 0xFFFF;
+ ///
+ /// A maximum size of a created CAB (compressed)
+ ///
+ public const uint MaximumCabSize = 0x7FFFFFFF;
- private const uint MSCABMaximumUncompressedFolderSize = 0x7FFF8000;
+ ///
+ /// A maximum CAB-folder COUNT
+ ///
+ public const ushort MaximumFolderCount = 0xFFFF;
+
+ ///
+ /// A maximum uncompressed data size in a CAB-folder
+ ///
+ public const uint MaximumUncompressedFolderSize = 0x7FFF8000;
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Cabinet header
+ ///
+ public CFHEADER Header { get; private set; }
+
+ ///
+ /// One or more CFFOLDER entries
+ ///
+ public CFFOLDER[] Folders { get; private set; }
+
+ ///
+ /// A series of one or more cabinet file (CFFILE) entries
+ ///
+ public CFFILE[] Files { get; private set; }
+
+ ///
+ /// The actual compressed file data in CFDATA entries.
+ ///
+ public CFDATA[] DataBlocks { get; private set; }
+
+ #endregion
+ }
///
/// The CFHEADER structure shown in the following packet diagram provides information about this
@@ -339,6 +385,119 @@ namespace BurnOutSharp.FileType
public byte[] DiskNext { get; private set; }
#endregion
+
+ #region Serialization
+
+ ///
+ /// Deserialize at into a CFHEADER object
+ ///
+ public static CFHEADER Deserialize(byte[] data, ref int dataPtr)
+ {
+ if (data == null || dataPtr < 0)
+ return null;
+
+ CFHEADER header = new CFHEADER();
+
+ header.Signature = BitConverter.ToUInt32(data, dataPtr); dataPtr += 4;
+ if (header.Signature != SignatureValue)
+ return null;
+
+ header.Reserved1 = BitConverter.ToUInt32(data, dataPtr); dataPtr += 4;
+ if (header.Reserved1 != 0x00000000)
+ return null;
+
+ header.CabinetSize = BitConverter.ToUInt32(data, dataPtr); dataPtr += 4;
+ if (header.CabinetSize > MSCABCabinet.MaximumCabSize)
+ return null;
+
+ header.Reserved2 = BitConverter.ToUInt32(data, dataPtr); dataPtr += 4;
+ if (header.Reserved2 != 0x00000000)
+ return null;
+
+ header.FilesOffset = BitConverter.ToUInt32(data, dataPtr); dataPtr += 4;
+
+ header.Reserved3 = BitConverter.ToUInt32(data, dataPtr); dataPtr += 4;
+ if (header.Reserved3 != 0x00000000)
+ return null;
+
+ header.VersionMinor = data[dataPtr++];
+ header.VersionMajor = data[dataPtr++];
+ if (header.VersionMajor != 0x00000001 || header.VersionMinor != 0x00000003)
+ return null;
+
+ header.FolderCount = BitConverter.ToUInt16(data, dataPtr); dataPtr += 2;
+ if (header.FolderCount > MSCABCabinet.MaximumFolderCount)
+ return null;
+
+ header.FileCount = BitConverter.ToUInt16(data, dataPtr); dataPtr += 2;
+ if (header.FileCount > MSCABCabinet.MaximumFileCount)
+ return null;
+
+ header.Flags = (HeaderFlags)BitConverter.ToUInt16(data, dataPtr); dataPtr += 2;
+ header.SetID = BitConverter.ToUInt16(data, dataPtr); dataPtr += 2;
+ header.CabinetIndex = BitConverter.ToUInt16(data, dataPtr); dataPtr += 2;
+
+ if (header.Flags.HasFlag(HeaderFlags.RESERVE_PRESENT))
+ {
+ header.HeaderReservedSize = BitConverter.ToUInt16(data, dataPtr); dataPtr += 2;
+ header.FolderReservedSize = data[dataPtr++];
+ header.DataReservedSize = data[dataPtr++];
+
+ if (header.HeaderReservedSize > 0)
+ {
+ header.ReservedData = new byte[header.HeaderReservedSize];
+ Array.Copy(data, dataPtr, header.ReservedData, 0, header.HeaderReservedSize);
+ dataPtr += header.HeaderReservedSize;
+ }
+ }
+
+ // TODO: Make string-finding block a helper method
+ if (header.Flags.HasFlag(HeaderFlags.PREV_CABINET))
+ {
+ int nullIndex = Array.IndexOf(data, 0x00, dataPtr);
+ int stringSize = nullIndex - dataPtr;
+ if (stringSize > 255)
+ return null;
+
+ header.CabinetPrev = new byte[stringSize];
+ Array.Copy(data, dataPtr, header.CabinetPrev, 0, stringSize);
+ dataPtr += stringSize;
+
+ nullIndex = Array.IndexOf(data, 0x00, dataPtr);
+ stringSize = nullIndex - dataPtr;
+ if (stringSize > 255)
+ return null;
+
+ header.DiskPrev = new byte[stringSize];
+ Array.Copy(data, dataPtr, header.DiskPrev, 0, stringSize);
+ dataPtr += stringSize;
+ }
+
+ if (header.Flags.HasFlag(HeaderFlags.NEXT_CABINET))
+ {
+ int nullIndex = Array.IndexOf(data, 0x00, dataPtr);
+ int stringSize = nullIndex - dataPtr;
+ if (stringSize > 255)
+ return null;
+
+ header.CabinetNext = new byte[stringSize];
+ Array.Copy(data, dataPtr, header.CabinetNext, 0, stringSize);
+ dataPtr += stringSize;
+
+ nullIndex = Array.IndexOf(data, 0x00, dataPtr);
+ stringSize = nullIndex - dataPtr;
+ if (stringSize > 255)
+ return null;
+
+ header.DiskNext = new byte[stringSize];
+ Array.Copy(data, dataPtr, header.DiskNext, 0, stringSize);
+ dataPtr += stringSize;
+ }
+
+ return header;
+ }
+
+ #endregion
}
[Flags]
@@ -416,6 +575,34 @@ namespace BurnOutSharp.FileType
public byte[] ReservedData { get; private set; }
#endregion
+
+ #region Serialization
+
+ ///
+ /// Deserialize at into a CFFOLDER object
+ ///
+ public static CFFOLDER Deserialize(byte[] data, ref int dataPtr, byte folderReservedSize = 0)
+ {
+ if (data == null || dataPtr < 0)
+ return null;
+
+ CFFOLDER folder = new CFFOLDER();
+
+ folder.CabStartOffset = BitConverter.ToUInt32(data, dataPtr); dataPtr += 4;
+ folder.DataCount = BitConverter.ToUInt16(data, dataPtr); dataPtr += 2;
+ folder.CompressionType = (CompressionType)BitConverter.ToUInt16(data, dataPtr); dataPtr += 2;
+
+ if (folderReservedSize > 0)
+ {
+ folder.ReservedData = new byte[folderReservedSize];
+ Array.Copy(data, dataPtr, folder.ReservedData, 0, folderReservedSize);
+ dataPtr += folderReservedSize;
+ }
+
+ return folder;
+ }
+
+ #endregion
}
internal enum CompressionType : ushort
@@ -510,6 +697,39 @@ namespace BurnOutSharp.FileType
public byte[] Name { get; private set; }
#endregion
+
+ #region Serialization
+
+ ///
+ /// Deserialize at into a CFFILE object
+ ///
+ public static CFFILE Deserialize(byte[] data, ref int dataPtr)
+ {
+ if (data == null || dataPtr < 0)
+ return null;
+
+ CFFILE file = new CFFILE();
+
+ file.FileSize = BitConverter.ToUInt32(data, dataPtr); dataPtr += 4;
+ file.FolderStartOffset = BitConverter.ToUInt32(data, dataPtr); dataPtr += 4;
+ file.FolderIndex = (FolderIndex)BitConverter.ToUInt16(data, dataPtr); dataPtr += 2;
+ file.Date = BitConverter.ToUInt16(data, dataPtr); dataPtr += 2;
+ file.Time = BitConverter.ToUInt16(data, dataPtr); dataPtr += 2;
+ file.Attributes = (FileAttributes)BitConverter.ToUInt16(data, dataPtr); dataPtr += 2;
+
+ int nullIndex = Array.IndexOf(data, 0x00, dataPtr);
+ int stringSize = nullIndex - dataPtr;
+ if (stringSize > 255)
+ return null;
+
+ file.Name = new byte[stringSize];
+ Array.Copy(data, dataPtr, file.Name, 0, stringSize);
+ dataPtr += stringSize;
+
+ return file;
+ }
+
+ #endregion
}
internal enum FolderIndex : ushort
@@ -621,6 +841,41 @@ namespace BurnOutSharp.FileType
public byte[] CompressedData { get; private set; }
#endregion
+
+ #region Serialization
+
+ ///
+ /// Deserialize at into a CFDATA object
+ ///
+ public static CFDATA Deserialize(byte[] data, ref int dataPtr, byte dataReservedSize = 0)
+ {
+ if (data == null || dataPtr < 0)
+ return null;
+
+ CFDATA dataBlock = new CFDATA();
+
+ dataBlock.Checksum = BitConverter.ToUInt32(data, dataPtr); dataPtr += 4;
+ dataBlock.CompressedSize = BitConverter.ToUInt16(data, dataPtr); dataPtr += 2;
+ dataBlock.UncompressedSize = BitConverter.ToUInt16(data, dataPtr); dataPtr += 2;
+
+ if (dataReservedSize > 0)
+ {
+ dataBlock.ReservedData = new byte[dataReservedSize];
+ Array.Copy(data, dataPtr, dataBlock.ReservedData, 0, dataReservedSize);
+ dataPtr += dataReservedSize;
+ }
+
+ if (dataBlock.CompressedSize > 0)
+ {
+ dataBlock.CompressedData = new byte[dataBlock.CompressedSize];
+ Array.Copy(data, dataPtr, dataBlock.CompressedData, 0, dataBlock.CompressedSize);
+ dataPtr += dataBlock.CompressedSize;
+ }
+
+ return dataBlock;
+ }
+
+ #endregion
}
///