diff --git a/BurnOutSharp/External/libgsf/GsfMSOleImpl.cs b/BurnOutSharp/External/libgsf/GsfMSOleImpl.cs
index b7344410..01b05a71 100644
--- a/BurnOutSharp/External/libgsf/GsfMSOleImpl.cs
+++ b/BurnOutSharp/External/libgsf/GsfMSOleImpl.cs
@@ -20,61 +20,540 @@
* USA
*/
+using System;
+using System.Linq;
+using System.Text;
+using static LibGSF.GsfUtils;
+
namespace LibGSF
{
- public static class GsfMSOleImpl
+ #region Enums
+
+ internal enum DIRENT_TYPE : byte
{
- public const int OLE_HEADER_SIZE = 0x200; /* independent of big block size size */
- public const int OLE_HEADER_SIGNATURE = 0x00;
- public const int OLE_HEADER_CLSID = 0x08; /* See ReadClassStg */
- public const int OLE_HEADER_MINOR_VER = 0x18; /* 0x33 and 0x3e have been seen */
- public const int OLE_HEADER_MAJOR_VER = 0x1a; /* 0x3 been seen in wild */
- public const int OLE_HEADER_BYTE_ORDER = 0x1c; /* 0xfe 0xff == Intel Little Endian */
- public const int OLE_HEADER_BB_SHIFT = 0x1e;
- public const int OLE_HEADER_SB_SHIFT = 0x20;
- /* 0x22..0x27 reserved == 0 */
- public const int OLE_HEADER_CSECTDIR = 0x28;
- public const int OLE_HEADER_NUM_BAT = 0x2c;
- public const int OLE_HEADER_DIRENT_START = 0x30;
- /* 0x34..0x37 transacting signature must be 0 */
- public const int OLE_HEADER_THRESHOLD = 0x38;
- public const int OLE_HEADER_SBAT_START = 0x3c;
- public const int OLE_HEADER_NUM_SBAT = 0x40;
- public const int OLE_HEADER_METABAT_BLOCK = 0x44;
- public const int OLE_HEADER_NUM_METABAT = 0x48;
- public const int OLE_HEADER_START_BAT = 0x4c;
- public const int BAT_INDEX_SIZE = 4;
- public const int OLE_HEADER_METABAT_SIZE = ((OLE_HEADER_SIZE - OLE_HEADER_START_BAT) / BAT_INDEX_SIZE);
+ DIRENT_TYPE_INVALID = 0,
+ DIRENT_TYPE_DIR = 1,
+ DIRENT_TYPE_FILE = 2,
+ DIRENT_TYPE_LOCKBYTES = 3,
+ DIRENT_TYPE_PROPERTY = 4,
+ DIRENT_TYPE_ROOTDIR = 5,
+ }
+
+ #endregion
+
+ #region Classes
+
+ ///
+ /// MS-OLE Header (.msi)
+ ///
+ internal class MSOleHeader
+ {
+ #region Constants
+
+ ///
+ /// Independent of big block size size
+ ///
+ public const int OLE_HEADER_SIZE = 0x200;
+
+ ///
+ /// OLE Signature as a byte array
+ ///
+ public static readonly byte[] SIGNATURE_BYTES = { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 };
+
+ ///
+ /// OLE Signature as an unsigned Int64
+ ///
+ public const ulong SIGNATURE_VALUE = 0x00E11AB1A1E011CFD0;
+
+ #region Offsets
+
+ private const int OLE_HEADER_SIGNATURE = 0x00;
+
+ private const int OLE_HEADER_CLSID = 0x08;
+
+ private const int OLE_HEADER_MINOR_VER = 0x18;
+
+ private const int OLE_HEADER_MAJOR_VER = 0x1a;
+
+ private const int OLE_HEADER_BYTE_ORDER = 0x1c;
+
+ private const int OLE_HEADER_BB_SHIFT = 0x1e;
+
+ private const int OLE_HEADER_SB_SHIFT = 0x20;
+
+ private const int OLE_HEADER_RESERVED = 0x22;
+
+ private const int OLE_HEADER_CSECTDIR = 0x28;
+
+ private const int OLE_HEADER_NUM_BAT = 0x2c;
+
+ private const int OLE_HEADER_DIRENT_START = 0x30;
+
+ private const int OLE_HEADER_TRANSACTING_SIGNATURE = 0x34;
+
+ private const int OLE_HEADER_THRESHOLD = 0x38;
+
+ private const int OLE_HEADER_SBAT_START = 0x3c;
+
+ private const int OLE_HEADER_NUM_SBAT = 0x40;
+
+ private const int OLE_HEADER_METABAT_BLOCK = 0x44;
+
+ private const int OLE_HEADER_NUM_METABAT = 0x48;
+
+ private const int OLE_HEADER_START_BAT = 0x4c;
+
+ #endregion
+
+ #endregion
+
+ #region Properties
+
+ /// 0x00
+ public byte[] SIGNATURE { get; set; }
+
+ ///
+ /// See ReadClassStg
+ ///
+ /// 0x08
+ public byte[] CLSID { get; set; }
+
+ ///
+ /// 0x33 and 0x3E have been seen
+ ///
+ /// 0x18
+ public ushort MINOR_VER { get; set; }
+
+ ///
+ /// 0x03 been seen in wild
+ ///
+ /// 0x1A
+ public ushort MAJOR_VER { get; set; }
+
+ ///
+ /// 0xFE 0xFF == Intel Little Endian
+ ///
+ /// 0x1C
+ public ushort BYTE_ORDER { get; set; }
+
+ /// 0x1E
+ public ushort BB_SHIFT { get; set; }
+
+ /// 0x20
+ public ushort SB_SHIFT { get; set; }
+
+ ///
+ /// 0x22..0x27 reserved == 0
+ ///
+ /// 0x22
+ public byte[] RESERVED { get; set; }
+
+ /// 0x28
+ public uint CSECTDIR { get; set; }
+
+ /// 0x2C
+ public uint NUM_BAT { get; set; }
+
+ /// 0x30
+ public uint DIRENT_START { get; set; }
+
+ ///
+ /// 0x34..0x37 transacting signature must be 0
+ ///
+ /// 0x34
+ public uint TRANSACTING_SIGNATURE { get; set; }
+
+ /// 0x38
+ public uint THRESHOLD { get; set; }
+
+ /// 0x3C
+ public uint SBAT_START { get; set; }
+
+ /// 0x40
+ public uint NUM_SBAT { get; set; }
+
+ /// 0x44
+ public uint METABAT_BLOCK { get; set; }
+
+ /// 0x48
+ public uint NUM_METABAT { get; set; }
+
+ /// 0x4C
+ public uint START_BAT { get; set; }
+
+ #endregion
+
+ #region Derived Properties
+
+ public int BB_SIZE => 1 << BB_SHIFT;
+
+ public int BB_FILTER => BB_SIZE << 1;
+
+ public int SB_SIZE => 1 << SB_SHIFT;
+
+ public int SB_FILTER => SB_SIZE << 1;
+
+ #endregion
+
+ #region Constructor
+
+ ///
+ /// Private constructor
+ ///
+ private MSOleHeader() { }
+
+ ///
+ /// Create a new default MSOleHeader
+ ///
+ public static MSOleHeader CreateDefault()
+ {
+ MSOleHeader header = new MSOleHeader();
+
+ header.SIGNATURE = SIGNATURE_BYTES;
+ header.CLSID = new byte[16];
+ header.MINOR_VER = 0x003E;
+ header.MAJOR_VER = 0x0003;
+ header.BYTE_ORDER = 0xFFFE;
+ header.BB_SHIFT = 0x0009;
+ header.SB_SHIFT = 0x0006;
+ header.RESERVED = new byte[6];
+ header.CSECTDIR = 0x00000000;
+ header.NUM_BAT = 0x00000000;
+ header.DIRENT_START = 0xFFFFFFFF;
+ header.TRANSACTING_SIGNATURE = 0x00000000;
+ header.THRESHOLD = 0x00001000;
+
+ // Remainder have default values for their types
+
+ return header;
+ }
+
+ ///
+ /// Create a new MSOleHeader from data
+ ///
+ public static MSOleHeader Create(byte[] data, int ptr, ref Exception err)
+ {
+ if (data == null || data.Length < OLE_HEADER_SIZE)
+ return null;
+
+ MSOleHeader header = new MSOleHeader();
+
+ header.SIGNATURE = new byte[8];
+ Array.Copy(data, ptr + OLE_HEADER_SIGNATURE, header.SIGNATURE, 0, 8);
+
+ if (!header.SIGNATURE.SequenceEqual(SIGNATURE_BYTES))
+ {
+ err = new ArgumentException("Signature is malformed");
+ return null;
+ }
+
+ header.CLSID = new byte[16];
+ Array.Copy(data, ptr + OLE_HEADER_CLSID, header.CLSID, 0, 16);
+ header.MINOR_VER = GSF_LE_GET_GUINT16(data, ptr + OLE_HEADER_MINOR_VER);
+ header.MAJOR_VER = GSF_LE_GET_GUINT16(data, ptr + OLE_HEADER_MAJOR_VER);
+ header.BYTE_ORDER = GSF_LE_GET_GUINT16(data, ptr + OLE_HEADER_BYTE_ORDER);
+ header.BB_SHIFT = GSF_LE_GET_GUINT16(data, ptr + OLE_HEADER_BB_SHIFT);
+ header.SB_SHIFT = GSF_LE_GET_GUINT16(data, ptr + OLE_HEADER_SB_SHIFT);
+ header.RESERVED = new byte[6];
+ Array.Copy(data, ptr + OLE_HEADER_RESERVED, header.RESERVED, 0, 6);
+ header.CSECTDIR = GSF_LE_GET_GUINT32(data, ptr + OLE_HEADER_CSECTDIR);
+ header.NUM_BAT = GSF_LE_GET_GUINT32(data, ptr + OLE_HEADER_NUM_BAT);
+ header.DIRENT_START = GSF_LE_GET_GUINT32(data, ptr + OLE_HEADER_DIRENT_START);
+ header.TRANSACTING_SIGNATURE = GSF_LE_GET_GUINT32(data, ptr + OLE_HEADER_TRANSACTING_SIGNATURE);
+
+ if (header.TRANSACTING_SIGNATURE != 0)
+ {
+ err = new ArgumentException("Transacting signature must be 0");
+ return null;
+ }
+
+ header.THRESHOLD = GSF_LE_GET_GUINT32(data, ptr + OLE_HEADER_THRESHOLD);
+ header.SBAT_START = GSF_LE_GET_GUINT32(data, ptr + OLE_HEADER_SBAT_START);
+ header.NUM_SBAT = GSF_LE_GET_GUINT32(data, ptr + OLE_HEADER_NUM_SBAT);
+ header.METABAT_BLOCK = GSF_LE_GET_GUINT32(data, ptr + OLE_HEADER_METABAT_BLOCK);
+ header.NUM_METABAT = GSF_LE_GET_GUINT32(data, ptr + OLE_HEADER_NUM_METABAT);
+ header.START_BAT = GSF_LE_GET_GUINT32(data, ptr + OLE_HEADER_START_BAT);
+
+ return header;
+ }
+
+ ///
+ /// Write to data from an existing MSOleHeader
+ ///
+ public bool Write(byte[] data, int ptr)
+ {
+ if (data == null || data.Length < OLE_HEADER_SIZE)
+ return false;
+
+ Array.Copy(SIGNATURE, 0, data, ptr + OLE_HEADER_SIGNATURE, SIGNATURE.Length);
+ Array.Copy(CLSID, 0, data, ptr + OLE_HEADER_CLSID, CLSID.Length);
+ GSF_LE_SET_GUINT16(data, ptr + OLE_HEADER_MINOR_VER, MINOR_VER);
+ GSF_LE_SET_GUINT16(data, ptr + OLE_HEADER_MAJOR_VER, MAJOR_VER);
+ GSF_LE_SET_GUINT16(data, ptr + OLE_HEADER_BYTE_ORDER, BYTE_ORDER);
+ GSF_LE_SET_GUINT16(data, ptr + OLE_HEADER_BB_SHIFT, BB_SHIFT);
+ GSF_LE_SET_GUINT16(data, ptr + OLE_HEADER_SB_SHIFT, SB_SHIFT);
+ Array.Copy(RESERVED, 0, data, ptr + OLE_HEADER_RESERVED, RESERVED.Length);
+ GSF_LE_SET_GUINT32(data, ptr + OLE_HEADER_CSECTDIR, CSECTDIR);
+ GSF_LE_SET_GUINT32(data, ptr + OLE_HEADER_NUM_BAT, NUM_BAT);
+ GSF_LE_SET_GUINT32(data, ptr + OLE_HEADER_DIRENT_START, DIRENT_START);
+ GSF_LE_SET_GUINT32(data, ptr + OLE_HEADER_TRANSACTING_SIGNATURE, TRANSACTING_SIGNATURE);
+ GSF_LE_SET_GUINT32(data, ptr + OLE_HEADER_THRESHOLD, THRESHOLD);
+ GSF_LE_SET_GUINT32(data, ptr + OLE_HEADER_SBAT_START, SBAT_START);
+ GSF_LE_SET_GUINT32(data, ptr + OLE_HEADER_NUM_SBAT, NUM_SBAT);
+ GSF_LE_SET_GUINT32(data, ptr + OLE_HEADER_METABAT_BLOCK, METABAT_BLOCK);
+ GSF_LE_SET_GUINT32(data, ptr + OLE_HEADER_START_BAT, START_BAT);
+
+ return true;
+ }
+
+ #endregion
+ }
+
+ ///
+ /// MS-OLE Directory Entry (.msi)
+ ///
+ internal class MSOleDirectoryEntry
+ {
+ #region Constants
public const int DIRENT_MAX_NAME_SIZE = 0x40;
- public const int DIRENT_DETAILS_SIZE = 0x40;
- public const int DIRENT_SIZE = (DIRENT_MAX_NAME_SIZE + DIRENT_DETAILS_SIZE);
- public const int DIRENT_NAME_LEN = 0x40; /* length in bytes incl 0 terminator */
- public const int DIRENT_TYPE = 0x42;
- public const int DIRENT_COLOUR = 0x43;
- public const int DIRENT_PREV = 0x44;
- public const int DIRENT_NEXT = 0x48;
- public const int DIRENT_CHILD = 0x4c;
- public const int DIRENT_CLSID = 0x50; /* only for dirs */
- public const int DIRENT_USERFLAGS = 0x60; /* only for dirs */
- public const int DIRENT_CREATE_TIME = 0x64; /* for files */
- public const int DIRENT_MODIFY_TIME = 0x6c; /* for files */
- public const int DIRENT_FIRSTBLOCK = 0x74;
- public const int DIRENT_FILE_SIZE = 0x78;
- /* 0x7c..0x7f reserved == 0 */
- public const int DIRENT_TYPE_INVALID = 0;
- public const int DIRENT_TYPE_DIR = 1;
- public const int DIRENT_TYPE_FILE = 2;
- public const int DIRENT_TYPE_LOCKBYTES = 3; /* ? */
- public const int DIRENT_TYPE_PROPERTY = 4; /* ? */
- public const int DIRENT_TYPE_ROOTDIR = 5;
+ public const int DIRENT_DETAILS_SIZE = 0x40;
+
+ public const int DIRENT_SIZE = (DIRENT_MAX_NAME_SIZE + DIRENT_DETAILS_SIZE);
+
public const uint DIRENT_MAGIC_END = 0xffffffff;
+ #region Offsets
+
+ private const int DIRENT_NAME = 0x00;
+
+ private const int DIRENT_NAME_LEN = 0x40;
+
+ private const int DIRENT_TYPE_FLAG = 0x42;
+
+ private const int DIRENT_COLOR = 0x43;
+
+ private const int DIRENT_PREV = 0x44;
+
+ private const int DIRENT_NEXT = 0x48;
+
+ private const int DIRENT_CHILD = 0x4c;
+
+ private const int DIRENT_CLSID = 0x50;
+
+ private const int DIRENT_USERFLAGS = 0x60;
+
+ private const int DIRENT_CREATE_TIME = 0x64;
+
+ private const int DIRENT_MODIFY_TIME = 0x6C;
+
+ private const int DIRENT_FIRSTBLOCK = 0x74;
+
+ private const int DIRENT_FILE_SIZE = 0x78;
+
+ private const int DIRENT_RESERVED = 0x7C;
+
+ #endregion
+
+ #endregion
+
+ #region Properties
+
+ /// 0x00
+ public byte[] NAME { get; set; }
+
+ ///
+ /// Length in bytes incl 0 terminator
+ ///
+ /// 0x40
+ public ushort NAME_LEN { get; set; }
+
+ /// 0x42
+ public DIRENT_TYPE TYPE_FLAG { get; set; }
+
+ /// 0x43
+ public byte COLOR { get; set; }
+
+ /// 0x44
+ public uint PREV { get; set; }
+
+ /// 0x48
+ public uint NEXT { get; set; }
+
+ /// 0x4C
+ public uint CHILD { get; set; }
+
+ ///
+ /// Only for dirs
+ ///
+ /// 0x50
+ public byte[] CLSID { get; set; }
+
+ ///
+ /// Only for dirs
+ ///
+ /// 0x60
+ public uint USERFLAGS { get; set; }
+
+ ///
+ /// For files
+ ///
+ /// 0x64
+ public ulong CREATE_TIME { get; set; }
+
+ ///
+ /// For files
+ ///
+ /// 0x6C
+ public ulong MODIFY_TIME { get; set; }
+
+ /// 0x74
+ public uint FIRSTBLOCK { get; set; }
+
+ /// 0x78
+ public uint FILE_SIZE { get; set; }
+
+ ///
+ /// 0x7c..0x7f reserved == 0
+ ///
+ /// 0x7C
+ public uint RESERVED { get; set; }
+
+ #endregion
+
+ #region Derived Properties
+
+ public string NAME_STRING
+ {
+ get
+ {
+ if (NAME_LEN <= 0 || NAME_LEN > DIRENT_MAX_NAME_SIZE)
+ return null;
+
+ // !#%!@$#^
+ // Sometimes, rarely, people store the stream name as ascii
+ // rather than utf16. Do a validation first just in case.
+ int end;
+ try { end = new UnicodeEncoding(false, true).GetCharCount(NAME); }
+ catch { end = -1; }
+
+ if (end == -1)
+ {
+ byte[] direntNameBytes = Encoding.Convert(Encoding.ASCII, Encoding.UTF8, NAME);
+ return Encoding.UTF8.GetString(direntNameBytes);
+ }
+ else
+ {
+ byte[] direntNameBytes = Encoding.Convert(Encoding.Unicode, Encoding.UTF8, NAME);
+ return Encoding.UTF8.GetString(direntNameBytes);
+ }
+ }
+ }
+
+ public bool IS_DIRECTORY => TYPE_FLAG != DIRENT_TYPE.DIRENT_TYPE_FILE;
+
+ #endregion
+
+ #region Constructor
+
+ ///
+ /// Private constructor
+ ///
+ private MSOleDirectoryEntry() { }
+
+ ///
+ /// Create a new default MSOleDirectoryEntry
+ ///
+ public static MSOleDirectoryEntry CreateDefault()
+ {
+ // TODO: Figure out if there are any sane defaults
+ return new MSOleDirectoryEntry();
+ }
+
+ ///
+ /// Create a new MSOleDirectoryEntry from data
+ ///
+ public static MSOleDirectoryEntry Create(byte[] data, int ptr, ref Exception err)
+ {
+ if (data == null || data.Length < DIRENT_SIZE)
+ return null;
+
+ MSOleDirectoryEntry directoryEntry = new MSOleDirectoryEntry();
+
+ directoryEntry.NAME = new byte[DIRENT_MAX_NAME_SIZE];
+ Array.Copy(data, ptr + DIRENT_NAME, directoryEntry.NAME, 0, directoryEntry.NAME.Length);
+ directoryEntry.NAME_LEN = GSF_LE_GET_GUINT16(data, ptr + DIRENT_NAME_LEN);
+ directoryEntry.TYPE_FLAG = (DIRENT_TYPE)GSF_LE_GET_GUINT8(data, ptr + DIRENT_TYPE_FLAG);
+
+ if (directoryEntry.TYPE_FLAG != DIRENT_TYPE.DIRENT_TYPE_DIR
+ && directoryEntry.TYPE_FLAG != DIRENT_TYPE.DIRENT_TYPE_FILE
+ && directoryEntry.TYPE_FLAG != DIRENT_TYPE.DIRENT_TYPE_ROOTDIR)
+ {
+ err = new Exception($"Unknown stream type 0x{directoryEntry.TYPE_FLAG:x}");
+ return null;
+ }
+
+ directoryEntry.COLOR = GSF_LE_GET_GUINT8(data, ptr + DIRENT_COLOR);
+ directoryEntry.PREV = GSF_LE_GET_GUINT32(data, ptr + DIRENT_PREV);
+ directoryEntry.NEXT = GSF_LE_GET_GUINT32(data, ptr + DIRENT_NEXT);
+ directoryEntry.CHILD = GSF_LE_GET_GUINT32(data, ptr + DIRENT_CHILD);
+ directoryEntry.CLSID = new byte[0x10];
+ Array.Copy(data, ptr + DIRENT_CLSID, directoryEntry.CLSID, 0, directoryEntry.CLSID.Length);
+ directoryEntry.USERFLAGS = GSF_LE_GET_GUINT32(data, ptr + DIRENT_USERFLAGS);
+ directoryEntry.CREATE_TIME = GSF_LE_GET_GUINT64(data, ptr + DIRENT_CREATE_TIME);
+ directoryEntry.MODIFY_TIME = GSF_LE_GET_GUINT64(data, ptr + DIRENT_MODIFY_TIME);
+ directoryEntry.FIRSTBLOCK = GSF_LE_GET_GUINT32(data, ptr + DIRENT_FIRSTBLOCK);
+ directoryEntry.FILE_SIZE = GSF_LE_GET_GUINT32(data, ptr + DIRENT_FILE_SIZE);
+ directoryEntry.RESERVED = GSF_LE_GET_GUINT32(data, ptr + DIRENT_RESERVED);
+
+ return directoryEntry;
+ }
+
+ ///
+ /// Write to data from an existing MSOleHeader
+ ///
+ public bool Write(byte[] data, int ptr)
+ {
+ if (data == null || data.Length < DIRENT_SIZE)
+ return false;
+
+ Array.Copy(NAME, 0, data, ptr + DIRENT_NAME, NAME.Length);
+ GSF_LE_SET_GUINT16(data, ptr + DIRENT_NAME_LEN, NAME_LEN);
+ GSF_LE_SET_GUINT8(data, ptr + DIRENT_TYPE_FLAG, (byte)TYPE_FLAG);
+ GSF_LE_SET_GUINT8(data, ptr + DIRENT_COLOR, COLOR);
+ GSF_LE_SET_GUINT32(data, ptr + DIRENT_PREV, PREV);
+ GSF_LE_SET_GUINT32(data, ptr + DIRENT_NEXT, NEXT);
+ GSF_LE_SET_GUINT32(data, ptr + DIRENT_CHILD, CHILD);
+ Array.Copy(CLSID, 0, data, ptr + DIRENT_CLSID, CLSID.Length);
+ GSF_LE_SET_GUINT32(data, ptr + DIRENT_USERFLAGS, USERFLAGS);
+ GSF_LE_SET_GUINT64(data, ptr + DIRENT_CREATE_TIME, CREATE_TIME);
+ GSF_LE_SET_GUINT64(data, ptr + DIRENT_MODIFY_TIME, MODIFY_TIME);
+ GSF_LE_SET_GUINT32(data, ptr + DIRENT_FIRSTBLOCK, FIRSTBLOCK);
+ GSF_LE_SET_GUINT32(data, ptr + DIRENT_FILE_SIZE, FILE_SIZE);
+ GSF_LE_SET_GUINT32(data, ptr + DIRENT_RESERVED, RESERVED);
+
+ return true;
+ }
+
+ #endregion
+ }
+
+ public static class GsfMSOleImpl
+ {
+ public const int OLE_HEADER_CSECTDIR = 0x28;
+ public const int OLE_HEADER_NUM_BAT = 0x2C;
+ public const int OLE_HEADER_SBAT_START = 0x3C;
+ public const int OLE_HEADER_START_BAT = 0x4C;
+ public const int BAT_INDEX_SIZE = 4;
+ public const int OLE_HEADER_METABAT_SIZE = ((MSOleHeader.OLE_HEADER_SIZE - OLE_HEADER_START_BAT) / BAT_INDEX_SIZE);
+
/* flags in the block allocation list to denote special blocks */
public const uint BAT_MAGIC_UNUSED = 0xffffffff; /* -1 */
public const uint BAT_MAGIC_END_OF_CHAIN = 0xfffffffe; /* -2 */
public const uint BAT_MAGIC_BAT = 0xfffffffd; /* a bat block, -3 */
public const uint BAT_MAGIC_METABAT = 0xfffffffc; /* a metabat block -4 */
}
+
+ #endregion
}
diff --git a/BurnOutSharp/External/libgsf/Input/GsfInfileMSOle.cs b/BurnOutSharp/External/libgsf/Input/GsfInfileMSOle.cs
index dcf576f1..fd022322 100644
--- a/BurnOutSharp/External/libgsf/Input/GsfInfileMSOle.cs
+++ b/BurnOutSharp/External/libgsf/Input/GsfInfileMSOle.cs
@@ -27,8 +27,6 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.Linq;
-using System.Text;
using static LibGSF.GsfMSOleImpl;
using static LibGSF.GsfUtils;
@@ -130,7 +128,7 @@ namespace LibGSF.Input
public bool IsDirectory { get; set; }
- public List Children { get; set; }
+ public List Children { get; set; } = new List();
///
/// 16 byte GUID used by some apps
@@ -343,7 +341,7 @@ namespace LibGSF.Input
//if (FALSE && first_block != last_block)
// Console.Error.WriteLine($"Check if {first_block}-{last_block} of {Bat.NumBlocks} are contiguous.");
- while (++i <= last_block && ++raw_block == Bat.Block[i]);
+ while (++i <= last_block && ++raw_block == Bat.Block[i]) ;
if (i > last_block)
{
@@ -388,7 +386,7 @@ namespace LibGSF.Input
}
///
- public override bool Seek(long offset, SeekOrigin whence)
+ protected override bool SeekImpl(long offset, SeekOrigin whence)
{
CurBlock = BAT_MAGIC_UNUSED;
return false;
@@ -469,7 +467,7 @@ namespace LibGSF.Input
// OLE_HEADER_SIZE is fixed at 512, but the sector containing the
// header is padded out to BigBlock.Size (sector size) when BigBlock.Size > 512.
- if (Input.Seek(Math.Max(OLE_HEADER_SIZE, Info.BigBlock.Size) + (block << Info.BigBlock.Shift) + offset, SeekOrigin.Begin))
+ if (Input.Seek(Math.Max(MSOleHeader.OLE_HEADER_SIZE, Info.BigBlock.Size) + (block << Info.BigBlock.Shift) + offset, SeekOrigin.Begin))
return false;
return true;
@@ -495,7 +493,7 @@ namespace LibGSF.Input
/// either from the OLE header, or a meta-bat block.
///
/// A pointer to the element after the last position filled
- private uint[] ReadMetabat(uint[] bats, int batsPtr, uint max_bat, uint[] metabat, uint metabat_end)
+ private int? ReadMetabat(uint[] bats, int batsPtr, uint max_bat, uint[] metabat, uint metabat_end)
{
for (int metabatPtr = 0; metabatPtr < metabat_end; metabatPtr++)
{
@@ -530,7 +528,7 @@ namespace LibGSF.Input
}
}
- return bats;
+ return batsPtr;
}
///
@@ -538,8 +536,7 @@ namespace LibGSF.Input
///
private static void GetUnsignedInts(uint[] dst, byte[] src, int srcPtr, int num_bytes)
{
- int dstPtr = 0;
- for (; (num_bytes -= BAT_INDEX_SIZE) >= 0; srcPtr += BAT_INDEX_SIZE)
+ for (int dstPtr = 0; (num_bytes -= BAT_INDEX_SIZE) >= 0; srcPtr += BAT_INDEX_SIZE)
{
dst[dstPtr++] = GSF_LE_GET_GUINT32(src, srcPtr);
}
@@ -582,13 +579,13 @@ namespace LibGSF.Input
/// parent is optional.
private MSOleDirent CreateDirectoryEntry(uint entry, MSOleDirent parent, bool[] seen_before)
{
- if (entry >= DIRENT_MAGIC_END)
+ if (entry >= MSOleDirectoryEntry.DIRENT_MAGIC_END)
return null;
- if (entry > uint.MaxValue / DIRENT_SIZE)
+ if (entry > uint.MaxValue / MSOleDirectoryEntry.DIRENT_SIZE)
return null;
- uint block = ((entry * DIRENT_SIZE) >> Info.BigBlock.Shift);
+ uint block = ((entry * MSOleDirectoryEntry.DIRENT_SIZE) >> Info.BigBlock.Shift);
if (block >= Bat.NumBlocks)
return null;
@@ -602,70 +599,44 @@ namespace LibGSF.Input
return null;
int dataPtr = 0; // data[0]
- dataPtr += (int)((DIRENT_SIZE * entry) % Info.BigBlock.Size);
+ dataPtr += (int)((MSOleDirectoryEntry.DIRENT_SIZE * entry) % Info.BigBlock.Size);
- byte type = GSF_LE_GET_GUINT8(data, dataPtr + DIRENT_TYPE);
- if (type != DIRENT_TYPE_DIR && type != DIRENT_TYPE_FILE && type != DIRENT_TYPE_ROOTDIR)
+ Exception err = null;
+ MSOleDirectoryEntry directoryEntry = MSOleDirectoryEntry.Create(data, dataPtr, ref err);
+ if (err != null)
{
- Console.Error.WriteLine($"Unknown stream type 0x{type:x}");
+ Console.Error.WriteLine(err.Message);
return null;
}
- if (parent == null && type != DIRENT_TYPE_ROOTDIR)
+ if (parent == null && directoryEntry.TYPE_FLAG != DIRENT_TYPE.DIRENT_TYPE_ROOTDIR)
{
// See bug 346118.
Console.Error.WriteLine("Root directory is not marked as such.");
- type = DIRENT_TYPE_ROOTDIR;
+ directoryEntry.TYPE_FLAG = DIRENT_TYPE.DIRENT_TYPE_ROOTDIR;
}
// It looks like directory (and root directory) sizes are sometimes bogus
- uint size = GSF_LE_GET_GUINT32(data, dataPtr + DIRENT_FILE_SIZE);
- if (!(type == DIRENT_TYPE_DIR || type == DIRENT_TYPE_ROOTDIR || size <= (uint)Input.Size))
+ if (!(directoryEntry.TYPE_FLAG == DIRENT_TYPE.DIRENT_TYPE_DIR || directoryEntry.TYPE_FLAG == DIRENT_TYPE.DIRENT_TYPE_ROOTDIR || directoryEntry.FILE_SIZE <= (uint)Input.Size))
return null;
- ulong ft = GSF_LE_GET_GUINT64(data, dataPtr + DIRENT_MODIFY_TIME);
-
MSOleDirent dirent = new MSOleDirent
{
Index = (int)entry,
- Size = (int)size,
- ModTime = DateTimeFromFileTime(ft),
+ Size = (int)directoryEntry.FILE_SIZE,
+ ModTime = DateTimeFromFileTime(directoryEntry.MODIFY_TIME),
+
+ // Store the class id which is 16 byte identifier used by some apps
+ ClassID = directoryEntry.CLSID,
+
+ // Root dir is always big block
+ UseSmallBlock = parent != null && (directoryEntry.FILE_SIZE < Info.Threshold),
+ FirstBlock = directoryEntry.FIRSTBLOCK,
+ IsDirectory = directoryEntry.IS_DIRECTORY,
+ Children = new List(),
};
- // Store the class id which is 16 byte identifier used by some apps
- Array.Copy(data, dataPtr + DIRENT_CLSID, dirent.ClassID, 0, dirent.ClassID.Length);
-
- // Root dir is always big block
- dirent.UseSmallBlock = parent != null && (size < Info.Threshold);
- dirent.FirstBlock = GSF_LE_GET_GUINT32(data, dataPtr + DIRENT_FIRSTBLOCK);
- dirent.IsDirectory = (type != DIRENT_TYPE_FILE);
- dirent.Children = null;
-
- uint prev = GSF_LE_GET_GUINT32(data, dataPtr + DIRENT_PREV);
- uint next = GSF_LE_GET_GUINT32(data, dataPtr + DIRENT_NEXT);
- uint child = GSF_LE_GET_GUINT32(data, dataPtr + DIRENT_CHILD);
- ushort name_len = GSF_LE_GET_GUINT16(data, dataPtr + DIRENT_NAME_LEN);
-
- dirent.Name = null;
- if (0 < name_len && name_len <= DIRENT_MAX_NAME_SIZE)
- {
- // !#%!@$#^
- // Sometimes, rarely, people store the stream name as ascii
- // rather than utf16. Do a validation first just in case.
- int end;
- try { end = new UTF8Encoding(false, true).GetCharCount(data); }
- catch { end = -1; }
-
- if (end == -1 || (end + 1) != name_len)
- {
- byte[] direntNameBytes = Encoding.Convert(Encoding.ASCII, Encoding.UTF8, data, 0, end);
- dirent.Name = Encoding.UTF8.GetString(direntNameBytes);
- }
- else
- {
- dirent.Name = Encoding.UTF8.GetString(data, 0, end + 1);
- }
- }
+ dirent.Name = directoryEntry.NAME_STRING.TrimEnd('\0');
// Be really anal in the face of screwups
if (dirent.Name == null)
@@ -680,12 +651,12 @@ namespace LibGSF.Input
}
// NOTE : These links are a tree, not a linked list
- CreateDirectoryEntry(prev, parent, seen_before);
- CreateDirectoryEntry(next, parent, seen_before);
+ CreateDirectoryEntry(directoryEntry.PREV, parent, seen_before);
+ CreateDirectoryEntry(directoryEntry.NEXT, parent, seen_before);
if (dirent.IsDirectory)
- CreateDirectoryEntry(child, dirent, seen_before);
- else if (child != DIRENT_MAGIC_END)
+ CreateDirectoryEntry(directoryEntry.CHILD, dirent, seen_before);
+ else if (directoryEntry.CHILD != MSOleDirectoryEntry.DIRENT_MAGIC_END)
Console.Error.WriteLine("A non directory stream with children ?");
return dirent;
@@ -721,43 +692,29 @@ namespace LibGSF.Input
/// True on error setting if it is supplied.
private bool InitInfo(ref Exception err)
{
- byte[] header;
-
- // Check the header
- byte[] signature = { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 };
- if (Input.Seek(0, SeekOrigin.Begin)
- || (header = Input.Read(OLE_HEADER_SIZE, null)) == null
- || !new ReadOnlySpan(header, 0, signature.Length).SequenceEqual(signature))
+ // Seek to the header
+ if (Input.Seek(0, SeekOrigin.Begin))
{
- err = new Exception("No OLE2 signature");
+ err = new Exception("Cannot seek to header");
return true;
}
- ushort bb_shift = GSF_LE_GET_GUINT16(header, OLE_HEADER_BB_SHIFT);
- ushort sb_shift = GSF_LE_GET_GUINT16(header, OLE_HEADER_SB_SHIFT);
- uint num_bat = GSF_LE_GET_GUINT32(header, OLE_HEADER_NUM_BAT);
- uint num_sbat = GSF_LE_GET_GUINT32(header, OLE_HEADER_NUM_SBAT);
- uint threshold = GSF_LE_GET_GUINT32(header, OLE_HEADER_THRESHOLD);
- uint dirent_start = GSF_LE_GET_GUINT32(header, OLE_HEADER_DIRENT_START);
- uint metabat_block = GSF_LE_GET_GUINT32(header, OLE_HEADER_METABAT_BLOCK);
- uint num_metabat = GSF_LE_GET_GUINT32(header, OLE_HEADER_NUM_METABAT);
+ byte[] header = Input.Read(MSOleHeader.OLE_HEADER_SIZE, null);
+ if (header == null)
+ {
+ err = new Exception("Header could not be read");
+ return true;
+ }
- //if (gsf_debug_flag("OLE2"))
- //{
- // Console.Error.WriteLine($"bb_shift=%d (size=%d)", bb_shift, 1 << bb_shift);
- // Console.Error.WriteLine($"sb_shift=%d (size=%d)", sb_shift, 1 << sb_shift);
- // Console.Error.WriteLine($"num_bat=%d (0x%08x)", num_bat, num_bat);
- // Console.Error.WriteLine($"num_sbat=%d (0x%08x)", num_sbat, num_sbat);
- // Console.Error.WriteLine($"threshold=%d (0x%08x)", threshold, threshold);
- // Console.Error.WriteLine($"dirent_start=0x%08x", dirent_start);
- // Console.Error.WriteLine($"num_metabat=%d (0x%08x)", num_metabat, num_metabat);
- //}
+ MSOleHeader headerImpl = MSOleHeader.Create(header, 0, ref err);
+ if (headerImpl == null)
+ return true;
// Some sanity checks
// 1) There should always be at least 1 BAT block
// 2) It makes no sense to have a block larger than 2^31 for now.
// Maybe relax this later, but not much.
- if (6 > bb_shift || bb_shift >= 31 || sb_shift > bb_shift || (Input.Size >> bb_shift) < 1)
+ if (6 > headerImpl.BB_SHIFT || headerImpl.BB_SHIFT >= 31 || headerImpl.SB_SHIFT > headerImpl.BB_SHIFT || (Input.Size >> headerImpl.BB_SHIFT) < 1)
{
err = new Exception("Unreasonable block sizes");
return true;
@@ -765,21 +722,21 @@ namespace LibGSF.Input
MSOleInfo info = new MSOleInfo
{
- BigBlock = new MSOleInfo.MSOleInfoBlock(),
- SmallBlock = new MSOleInfo.MSOleInfoBlock(),
+ BigBlock = new MSOleInfo.MSOleInfoBlock { Bat = new MSOleBAT() },
+ SmallBlock = new MSOleInfo.MSOleInfoBlock { Bat = new MSOleBAT() },
};
info.RefCount = 1;
- info.BigBlock.Shift = bb_shift;
- info.BigBlock.Size = 1 << info.BigBlock.Shift;
- info.BigBlock.Filter = info.BigBlock.Size << 1;
- info.SmallBlock.Shift = sb_shift;
- info.SmallBlock.Size = 1 << info.SmallBlock.Shift;
- info.SmallBlock.Filter = info.SmallBlock.Size << 1;
- info.Threshold = threshold;
- info.SBatStart = GSF_LE_GET_GUINT32(header, OLE_HEADER_SBAT_START);
- info.NumSbat = num_sbat;
- info.MaxBlock = (Input.Size - OLE_HEADER_SIZE + info.BigBlock.Size - 1) / info.BigBlock.Size;
+ info.BigBlock.Shift = headerImpl.BB_SHIFT;
+ info.BigBlock.Size = headerImpl.BB_SIZE;
+ info.BigBlock.Filter = headerImpl.BB_FILTER;
+ info.SmallBlock.Shift = headerImpl.SB_SHIFT;
+ info.SmallBlock.Size = headerImpl.SB_SIZE;
+ info.SmallBlock.Filter = headerImpl.SB_FILTER;
+ info.Threshold = headerImpl.THRESHOLD;
+ info.SBatStart = headerImpl.SBAT_START;
+ info.NumSbat = headerImpl.NUM_SBAT;
+ info.MaxBlock = (Input.Size - MSOleHeader.OLE_HEADER_SIZE + info.BigBlock.Size - 1) / info.BigBlock.Size;
info.SmallBlockFile = null;
Info = info;
@@ -789,18 +746,19 @@ namespace LibGSF.Input
uint[] metabat = null;
uint last;
- uint[] ptr;
+ int? ptr = null;
// Very rough heuristic, just in case
- if (num_bat < info.MaxBlock && info.NumSbat < info.MaxBlock)
+ uint num_bat = headerImpl.NUM_BAT;
+ if (num_bat < info.MaxBlock && headerImpl.NUM_SBAT < info.MaxBlock)
{
- info.BigBlock.Bat.NumBlocks = (uint)(num_bat * (info.BigBlock.Size / BAT_INDEX_SIZE));
+ info.BigBlock.Bat.NumBlocks = (uint)(num_bat * (headerImpl.BB_SIZE / BAT_INDEX_SIZE));
info.BigBlock.Bat.Block = new uint[info.BigBlock.Bat.NumBlocks];
- metabat = new uint[Math.Max(info.BigBlock.Size, OLE_HEADER_SIZE)];
+ metabat = new uint[Math.Max(headerImpl.BB_SIZE, MSOleHeader.OLE_HEADER_SIZE)];
// Reading the elements invalidates this memory, make copy
- GetUnsignedInts(metabat, header, OLE_HEADER_START_BAT, OLE_HEADER_SIZE - OLE_HEADER_START_BAT);
+ GetUnsignedInts(metabat, header, OLE_HEADER_START_BAT, MSOleHeader.OLE_HEADER_SIZE - OLE_HEADER_START_BAT);
last = num_bat;
if (last > OLE_HEADER_METABAT_SIZE)
last = OLE_HEADER_METABAT_SIZE;
@@ -808,12 +766,9 @@ namespace LibGSF.Input
ptr = ReadMetabat(info.BigBlock.Bat.Block, 0, info.BigBlock.Bat.NumBlocks, metabat, last);
num_bat -= last;
}
- else
- {
- ptr = null;
- }
- int ptrPtr = 0; // ptr[0]
+ uint metabat_block = headerImpl.METABAT_BLOCK;
+ uint num_metabat = headerImpl.NUM_METABAT;
last = (uint)((info.BigBlock.Size - BAT_INDEX_SIZE) / BAT_INDEX_SIZE);
while (ptr != null && num_metabat-- > 0)
@@ -854,13 +809,11 @@ namespace LibGSF.Input
num_bat -= last;
}
- ptr = ReadMetabat(ptr, ptrPtr, info.BigBlock.Bat.NumBlocks, metabat, last);
+ ptr = ReadMetabat(info.BigBlock.Bat.Block, ptr.Value, info.BigBlock.Bat.NumBlocks, metabat, last);
}
bool fail = (ptr == null);
- metabat = ptr = null;
-
if (fail)
{
err = new Exception("Inconsistent block allocation table");
@@ -868,7 +821,7 @@ namespace LibGSF.Input
}
// Read the directory's bat, we do not know the size
- if (MSOleBAT.Create(Info.BigBlock.Bat, 0, dirent_start, out MSOleBAT tempBat))
+ if (MSOleBAT.Create(Info.BigBlock.Bat, 0, headerImpl.DIRENT_START, out MSOleBAT tempBat))
{
err = new Exception("Problems making block allocation table");
return true;
@@ -877,7 +830,7 @@ namespace LibGSF.Input
Bat = tempBat;
// Read the directory
- bool[] seen_before = new bool[(Bat.NumBlocks << info.BigBlock.Shift) * DIRENT_SIZE + 1];
+ bool[] seen_before = new bool[(Bat.NumBlocks << info.BigBlock.Shift) * MSOleDirectoryEntry.DIRENT_SIZE + 1];
DirectoryEntry = info.RootDir = CreateDirectoryEntry(0, null, seen_before);
if (DirectoryEntry == null)
{
diff --git a/BurnOutSharp/External/libgsf/Input/GsfInfileTar.cs b/BurnOutSharp/External/libgsf/Input/GsfInfileTar.cs
index 8a7e8d71..c17e5dd2 100644
--- a/BurnOutSharp/External/libgsf/Input/GsfInfileTar.cs
+++ b/BurnOutSharp/External/libgsf/Input/GsfInfileTar.cs
@@ -199,7 +199,7 @@ namespace LibGSF.Input
protected override byte[] ReadImpl(int num_bytes, byte[] optional_buffer, int bufferPtr = 0) => null;
///
- public override bool Seek(long offset, SeekOrigin whence) => false;
+ protected override bool SeekImpl(long offset, SeekOrigin whence) => false;
///
public override GsfInput ChildByIndex(int i, ref Exception error)
diff --git a/BurnOutSharp/External/libgsf/Input/GsfInfileZip.cs b/BurnOutSharp/External/libgsf/Input/GsfInfileZip.cs
index 541db3ea..babcc24c 100644
--- a/BurnOutSharp/External/libgsf/Input/GsfInfileZip.cs
+++ b/BurnOutSharp/External/libgsf/Input/GsfInfileZip.cs
@@ -269,7 +269,7 @@ namespace LibGSF.Input
private static bool warned = false;
///
- public override bool Seek(long offset, SeekOrigin whence)
+ protected override bool SeekImpl(long offset, SeekOrigin whence)
{
long pos = offset;
diff --git a/BurnOutSharp/External/libgsf/Input/GsfInput.cs b/BurnOutSharp/External/libgsf/Input/GsfInput.cs
index 9bd77e38..33ae65b7 100644
--- a/BurnOutSharp/External/libgsf/Input/GsfInput.cs
+++ b/BurnOutSharp/External/libgsf/Input/GsfInput.cs
@@ -176,7 +176,7 @@ namespace LibGSF.Input
/// the end of the stream, or to the current location.
///
/// True on error.
- public virtual bool Seek(long offset, SeekOrigin whence)
+ public bool Seek(long offset, SeekOrigin whence)
{
long pos = offset;
@@ -196,7 +196,7 @@ namespace LibGSF.Input
if (pos == CurrentOffset)
return false;
- if (Seek(offset, whence))
+ if (SeekImpl(offset, whence))
return true;
CurrentOffset = pos;
@@ -524,6 +524,8 @@ namespace LibGSF.Input
protected virtual byte[] ReadImpl(int num_bytes, byte[] optional_buffer, int bufferPtr = 0) => null;
+ protected virtual bool SeekImpl(long offset, SeekOrigin whence) => false;
+
#endregion
}
}
diff --git a/BurnOutSharp/External/libgsf/Input/GsfInputGZip.cs b/BurnOutSharp/External/libgsf/Input/GsfInputGZip.cs
index d692a94d..49bb6626 100644
--- a/BurnOutSharp/External/libgsf/Input/GsfInputGZip.cs
+++ b/BurnOutSharp/External/libgsf/Input/GsfInputGZip.cs
@@ -261,7 +261,7 @@ namespace LibGSF.Input
private static bool warned = false;
///
- public override bool Seek(long offset, SeekOrigin whence)
+ protected override bool SeekImpl(long offset, SeekOrigin whence)
{
long pos = offset;
diff --git a/BurnOutSharp/External/libgsf/Input/GsfInputGio.cs b/BurnOutSharp/External/libgsf/Input/GsfInputGio.cs
index a1f7cf65..7662045d 100644
--- a/BurnOutSharp/External/libgsf/Input/GsfInputGio.cs
+++ b/BurnOutSharp/External/libgsf/Input/GsfInputGio.cs
@@ -162,7 +162,7 @@ namespace LibGSF.Input
}
///
- public override bool Seek(long offset, SeekOrigin whence)
+ protected override bool SeekImpl(long offset, SeekOrigin whence)
{
if (Stream == null)
return true;
diff --git a/BurnOutSharp/External/libgsf/Input/GsfInputHTTP.cs b/BurnOutSharp/External/libgsf/Input/GsfInputHTTP.cs
index 7b0cdc81..6255a27c 100644
--- a/BurnOutSharp/External/libgsf/Input/GsfInputHTTP.cs
+++ b/BurnOutSharp/External/libgsf/Input/GsfInputHTTP.cs
@@ -138,7 +138,7 @@ namespace LibGSF.Input
}
///
- public override bool Seek(long offset, SeekOrigin whence) => false;
+ protected override bool SeekImpl(long offset, SeekOrigin whence) => false;
#endregion
diff --git a/BurnOutSharp/External/libgsf/Input/GsfInputMemory.cs b/BurnOutSharp/External/libgsf/Input/GsfInputMemory.cs
index f1df0456..6ec4bd20 100644
--- a/BurnOutSharp/External/libgsf/Input/GsfInputMemory.cs
+++ b/BurnOutSharp/External/libgsf/Input/GsfInputMemory.cs
@@ -96,7 +96,7 @@ namespace LibGSF.Input
}
///
- public override bool Seek(long offset, SeekOrigin whence) => false;
+ protected override bool SeekImpl(long offset, SeekOrigin whence) => false;
#endregion
}
diff --git a/BurnOutSharp/External/libgsf/Input/GsfInputProxy.cs b/BurnOutSharp/External/libgsf/Input/GsfInputProxy.cs
index 895a15dd..d6514a85 100644
--- a/BurnOutSharp/External/libgsf/Input/GsfInputProxy.cs
+++ b/BurnOutSharp/External/libgsf/Input/GsfInputProxy.cs
@@ -104,7 +104,7 @@ namespace LibGSF.Input
}
///
- public override bool Seek(long offset, SeekOrigin whence) => false;
+ protected override bool SeekImpl(long offset, SeekOrigin whence) => false;
#endregion
}
diff --git a/BurnOutSharp/External/libgsf/Input/GsfInputStdio.cs b/BurnOutSharp/External/libgsf/Input/GsfInputStdio.cs
index 4357c891..0a5bc586 100644
--- a/BurnOutSharp/External/libgsf/Input/GsfInputStdio.cs
+++ b/BurnOutSharp/External/libgsf/Input/GsfInputStdio.cs
@@ -206,7 +206,7 @@ namespace LibGSF.Input
}
///
- public override bool Seek(long offset, SeekOrigin whence)
+ protected override bool SeekImpl(long offset, SeekOrigin whence)
{
if (File == null)
return true;
diff --git a/BurnOutSharp/External/libgsf/Input/GsfInputTextline.cs b/BurnOutSharp/External/libgsf/Input/GsfInputTextline.cs
index 4dae7867..ce1f01e5 100644
--- a/BurnOutSharp/External/libgsf/Input/GsfInputTextline.cs
+++ b/BurnOutSharp/External/libgsf/Input/GsfInputTextline.cs
@@ -85,7 +85,7 @@ namespace LibGSF.Input
}
///
- public override bool Seek(long offset, SeekOrigin whence)
+ protected override bool SeekImpl(long offset, SeekOrigin whence)
{
Remainder = null;
bool res = Source.Seek(offset, whence);
diff --git a/BurnOutSharp/External/libgsf/Input/GsfStructuredBlob.cs b/BurnOutSharp/External/libgsf/Input/GsfStructuredBlob.cs
index 7997f559..3193fb9c 100644
--- a/BurnOutSharp/External/libgsf/Input/GsfStructuredBlob.cs
+++ b/BurnOutSharp/External/libgsf/Input/GsfStructuredBlob.cs
@@ -90,7 +90,7 @@ namespace LibGSF.Input
}
///
- public override bool Seek(long offset, SeekOrigin whence) => false;
+ protected override bool SeekImpl(long offset, SeekOrigin whence) => false;
///
public override int NumChildren() => Children != null ? Children.Length : -1;
diff --git a/BurnOutSharp/External/libgsf/Output/GsfOutfileMSOle.cs b/BurnOutSharp/External/libgsf/Output/GsfOutfileMSOle.cs
index d2dea292..efaab52e 100644
--- a/BurnOutSharp/External/libgsf/Output/GsfOutfileMSOle.cs
+++ b/BurnOutSharp/External/libgsf/Output/GsfOutfileMSOle.cs
@@ -192,19 +192,20 @@ namespace LibGSF.Output
ole.RegisterChild(ole);
// Build the header
- byte[] buf = Enumerable.Repeat(0xFF, OLE_HEADER_SIZE).ToArray();
- Array.Copy(default_header, buf, default_header.Length);
+ byte[] buf = Enumerable.Repeat(0xFF, MSOleHeader.OLE_HEADER_SIZE).ToArray();
- GSF_LE_SET_GUINT16(buf, OLE_HEADER_BB_SHIFT, (ushort)ole.BigBlock.Shift);
- GSF_LE_SET_GUINT16(buf, OLE_HEADER_SB_SHIFT, (ushort)ole.SmallBlock.Shift);
+ MSOleHeader header = MSOleHeader.CreateDefault();
+ header.BB_SHIFT = (ushort)ole.BigBlock.Shift;
+ header.SB_SHIFT = (ushort)ole.SmallBlock.Shift;
// 4k sector OLE files seen in the wild have version 4
if (ole.BigBlock.Size == 4096)
- GSF_LE_SET_GUINT16(buf, OLE_HEADER_MAJOR_VER, 4);
+ header.MAJOR_VER = 4;
- sink.Write(OLE_HEADER_SIZE, buf);
+ header.Write(buf, 0);
+ sink.Write(MSOleHeader.OLE_HEADER_SIZE, buf);
- // Header must be padded out to bb.size with zeros
+ // Header must be padded out to BigBlock.Size with zeros
ole.PadZero();
return ole;
@@ -476,7 +477,7 @@ namespace LibGSF.Output
/// pad_zero to move to the start of the next block, then get the block number.
/// This avoids fence post type problems with partial blocks.
///
- private int CurrentBlock() => (int)((Sink.CurrentOffset - OLE_HEADER_SIZE) >> BigBlock.Shift);
+ private int CurrentBlock() => (int)((Sink.CurrentOffset - MSOleHeader.OLE_HEADER_SIZE) >> BigBlock.Shift);
private int BytesLeftInBlock()
{
@@ -534,8 +535,6 @@ namespace LibGSF.Output
if (bufi != 0)
sink.Write(bufi * BAT_INDEX_SIZE, buf);
-
- bufi = 0;
}
private static void WriteConst(GsfOutput sink, uint value, int n)
@@ -574,7 +573,7 @@ namespace LibGSF.Output
///
private bool WriteDirectory()
{
- byte[] buf = new byte[OLE_HEADER_SIZE];
+ byte[] buf = new byte[MSOleHeader.OLE_HEADER_SIZE];
uint next;
uint xbat_pos;
int metabat_size = BigBlock.Size / BAT_INDEX_SIZE - 1;
@@ -631,15 +630,15 @@ namespace LibGSF.Output
PadBatUnused(0);
int num_sbat = CurrentBlock() - sbat_start;
- int name_len = 0;
-
// Write dirents
int dirent_start = CurrentBlock();
for (int i = 0; i < elem.Count; i++)
{
GsfOutfileMSOle child = elem[i];
- buf = Enumerable.Repeat(0, DIRENT_SIZE).ToArray();
+ buf = Enumerable.Repeat(0, MSOleDirectoryEntry.DIRENT_SIZE).ToArray();
+
+ MSOleDirectoryEntry directoryEntry = MSOleDirectoryEntry.CreateDefault();
// Hard code 'Root Entry' for the root
if (i == 0 || child.Name != null)
@@ -648,39 +647,27 @@ namespace LibGSF.Output
byte[] nameUtf16Bytes = Encoding.UTF8.GetBytes(name);
nameUtf16Bytes = Encoding.Convert(Encoding.UTF8, Encoding.Unicode, nameUtf16Bytes);
- string nameUtf16 = Encoding.Unicode.GetString(nameUtf16Bytes);
- name_len = nameUtf16.Length;
- if (name_len >= DIRENT_MAX_NAME_SIZE)
- name_len = DIRENT_MAX_NAME_SIZE - 1;
+ ushort name_len = (ushort)nameUtf16Bytes.Length;
+ if (name_len >= MSOleDirectoryEntry.DIRENT_MAX_NAME_SIZE)
+ name_len = MSOleDirectoryEntry.DIRENT_MAX_NAME_SIZE - 1;
- // Be wary about endianness
- for (int j = 0; j < name_len; j++)
- {
- GSF_LE_SET_GUINT16(buf, j * 2, nameUtf16[j]);
- }
-
- name_len++;
+ directoryEntry.NAME = nameUtf16Bytes;
+ directoryEntry.NAME_LEN = (ushort)(name_len + 1);
}
- GSF_LE_SET_GUINT16(buf, DIRENT_NAME_LEN, (ushort)(name_len * 2));
-
if (child.Root == child)
{
- GSF_LE_SET_GUINT8(buf, DIRENT_TYPE, DIRENT_TYPE_ROOTDIR);
- GSF_LE_SET_GUINT32(buf, DIRENT_FIRSTBLOCK, (sb_data_size > 0) ? (uint)sb_data_start : BAT_MAGIC_END_OF_CHAIN);
- GSF_LE_SET_GUINT32(buf, DIRENT_FILE_SIZE, (uint)sb_data_size);
-
- // Write the class id
- Array.Copy(child.ClassID, 0, buf, DIRENT_CLSID, child.ClassID.Length);
+ directoryEntry.TYPE_FLAG = DIRENT_TYPE.DIRENT_TYPE_ROOTDIR;
+ directoryEntry.FIRSTBLOCK = (sb_data_size > 0) ? (uint)sb_data_start : BAT_MAGIC_END_OF_CHAIN;
+ directoryEntry.FILE_SIZE = (uint)sb_data_size;
+ directoryEntry.CLSID = child.ClassID;
}
else if (child.Type == MSOleOutfileType.MSOLE_DIR)
{
- GSF_LE_SET_GUINT8(buf, DIRENT_TYPE, DIRENT_TYPE_DIR);
- GSF_LE_SET_GUINT32(buf, DIRENT_FIRSTBLOCK, BAT_MAGIC_END_OF_CHAIN);
- GSF_LE_SET_GUINT32(buf, DIRENT_FILE_SIZE, 0);
-
- // Write the class id
- Array.Copy(child.ClassID, 0, buf, DIRENT_CLSID, child.ClassID.Length);
+ directoryEntry.TYPE_FLAG = DIRENT_TYPE.DIRENT_TYPE_DIR;
+ directoryEntry.FIRSTBLOCK = BAT_MAGIC_END_OF_CHAIN;
+ directoryEntry.FILE_SIZE = 0;
+ directoryEntry.CLSID = child.ClassID;
}
else
{
@@ -688,18 +675,19 @@ namespace LibGSF.Output
if (size != child.Parent.CurrentSize)
Console.Error.WriteLine("File too big");
- GSF_LE_SET_GUINT8(buf, DIRENT_TYPE, DIRENT_TYPE_FILE);
- GSF_LE_SET_GUINT32(buf, DIRENT_FIRSTBLOCK, (uint)child.FirstBlock);
- GSF_LE_SET_GUINT32(buf, DIRENT_FILE_SIZE, size);
+ directoryEntry.TYPE_FLAG = DIRENT_TYPE.DIRENT_TYPE_FILE;
+ directoryEntry.FIRSTBLOCK = (uint)child.FirstBlock;
+ directoryEntry.FILE_SIZE = size;
+ directoryEntry.CLSID = new byte[0x10];
}
- GSF_LE_SET_GUINT64(buf, DIRENT_MODIFY_TIME, (ulong)(child.ModTime?.ToFileTime() ?? 0));
+ directoryEntry.MODIFY_TIME = (ulong)(child.ModTime?.ToFileTime() ?? 0);
// Make everything black (red == 0)
- GSF_LE_SET_GUINT8(buf, DIRENT_COLOUR, 1);
+ directoryEntry.COLOR = 1;
GsfOutfileMSOle tmp = child.Container as GsfOutfileMSOle;
- next = DIRENT_MAGIC_END;
+ next = MSOleDirectoryEntry.DIRENT_MAGIC_END;
if (child.Root != child && tmp != null)
{
for (int j = 0; j < tmp.Content_Dir_Children.Count; j++)
@@ -719,19 +707,20 @@ namespace LibGSF.Output
}
// Make linked list rather than tree, only use next
- GSF_LE_SET_GUINT32(buf, DIRENT_PREV, DIRENT_MAGIC_END);
- GSF_LE_SET_GUINT32(buf, DIRENT_NEXT, next);
+ directoryEntry.PREV = MSOleDirectoryEntry.DIRENT_MAGIC_END;
+ directoryEntry.NEXT = next;
- uint child_index = DIRENT_MAGIC_END;
+ uint child_index = MSOleDirectoryEntry.DIRENT_MAGIC_END;
if (child.Type == MSOleOutfileType.MSOLE_DIR && child.Content_Dir_Children != null)
{
GsfOutfileMSOle first = child.Content_Dir_Children[0];
child_index = (uint)first.ChildIndex;
}
- GSF_LE_SET_GUINT32(buf, DIRENT_CHILD, child_index);
+ directoryEntry.CHILD = child_index;
- Sink.Write(DIRENT_SIZE, buf);
+ directoryEntry.Write(buf, 0);
+ Sink.Write(MSOleDirectoryEntry.DIRENT_SIZE, buf);
}
PadZero();
@@ -765,7 +754,7 @@ namespace LibGSF.Output
// by _tell and .cur_size may be out of sync. We don't
// want to loop forever here.
- long i = ((Sink.CurrentSize + BAT_INDEX_SIZE * (num_bat + num_xbat) - OLE_HEADER_SIZE - 1) >> BigBlock.Shift) + 1;
+ long i = ((Sink.CurrentSize + BAT_INDEX_SIZE * (num_bat + num_xbat) - MSOleHeader.OLE_HEADER_SIZE - 1) >> BigBlock.Shift) + 1;
i -= bat_start;
if (num_bat != i)
{
@@ -800,8 +789,6 @@ namespace LibGSF.Output
blocks = (int)num_bat;
}
- byte[] outerTemp;
-
// Fix up the header
if (BigBlock.Size == 4096)
{
diff --git a/BurnOutSharp/External/libmsi/LibmsiDatabase.cs b/BurnOutSharp/External/libmsi/LibmsiDatabase.cs
index 2dbaf17e..36e00d47 100644
--- a/BurnOutSharp/External/libmsi/LibmsiDatabase.cs
+++ b/BurnOutSharp/External/libmsi/LibmsiDatabase.cs
@@ -157,13 +157,13 @@ namespace LibMSI
internal int MediaTransformDiskId { get; set; }
- internal LinkedList Tables { get; set; }
+ internal LinkedList Tables { get; set; } = new LinkedList();
- internal LinkedList Transforms { get; set; }
+ internal LinkedList Transforms { get; set; } = new LinkedList();
- internal LinkedList Streams { get; set; }
+ internal LinkedList Streams { get; set; } = new LinkedList();
- internal LinkedList Storages { get; set; }
+ internal LinkedList Storages { get; set; } = new LinkedList();
#endregion