diff --git a/BurnOutSharp/External/libgsf/GsfMSOleImpl.cs b/BurnOutSharp/External/libgsf/GsfMSOleImpl.cs
index 01b05a71..e557c47f 100644
--- a/BurnOutSharp/External/libgsf/GsfMSOleImpl.cs
+++ b/BurnOutSharp/External/libgsf/GsfMSOleImpl.cs
@@ -163,6 +163,9 @@ namespace LibGSF
/// 0x34
public uint TRANSACTING_SIGNATURE { get; set; }
+ ///
+ /// Transition between small and big blocks
+ ///
/// 0x38
public uint THRESHOLD { get; set; }
@@ -185,6 +188,11 @@ namespace LibGSF
#region Derived Properties
+ ///
+ /// Indicate if the contents are Intel Little-Endian
+ ///
+ public bool LITTLE_ENDIAN => BYTE_ORDER == 0xFFFE;
+
public int BB_SIZE => 1 << BB_SHIFT;
public int BB_FILTER => BB_SIZE << 1;
@@ -254,6 +262,15 @@ namespace LibGSF
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);
+
+ // It makes no sense to have a block larger than 2^31 for now.
+ // Maybe relax this later, but not much.
+ if (6 > header.BB_SHIFT || header.BB_SHIFT >= 31 || header.SB_SHIFT > header.BB_SHIFT)
+ {
+ err = new ArgumentException("Unreasonable block sizes");
+ return null;
+ }
+
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);
@@ -274,6 +291,13 @@ namespace LibGSF
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);
+ if (header.NUM_SBAT == 0
+ && header.SBAT_START != GsfMSOleImpl.BAT_MAGIC_END_OF_CHAIN
+ && header.SBAT_START != GsfMSOleImpl.BAT_MAGIC_UNUSED)
+ {
+ Console.Error.WriteLine("There are not supposed to be any blocks in the small block allocation table, yet there is a link to some. Ignoring it.");
+ }
+
return header;
}
@@ -385,7 +409,7 @@ namespace LibGSF
public uint CHILD { get; set; }
///
- /// Only for dirs
+ /// 16 byte GUID used by some apps; Only for dirs
///
/// 0x50
public byte[] CLSID { get; set; }
@@ -424,12 +448,15 @@ namespace LibGSF
#region Derived Properties
+ ///
+ /// Directory Entry name as a UTF-8 encoded string
+ ///
public string NAME_STRING
{
get
{
if (NAME_LEN <= 0 || NAME_LEN > DIRENT_MAX_NAME_SIZE)
- return null;
+ return string.Empty;
// !#%!@$#^
// Sometimes, rarely, people store the stream name as ascii
@@ -441,16 +468,24 @@ namespace LibGSF
if (end == -1)
{
byte[] direntNameBytes = Encoding.Convert(Encoding.ASCII, Encoding.UTF8, NAME);
- return Encoding.UTF8.GetString(direntNameBytes);
+ return Encoding.UTF8.GetString(direntNameBytes).TrimEnd('\0');
}
else
{
byte[] direntNameBytes = Encoding.Convert(Encoding.Unicode, Encoding.UTF8, NAME);
- return Encoding.UTF8.GetString(direntNameBytes);
+ return Encoding.UTF8.GetString(direntNameBytes).TrimEnd('\0');
}
}
}
+ ///
+ /// Last modified time as a nullable DateTime
+ ///
+ public DateTime? MODIFY_DATETIME => MODIFY_TIME == 0 ? (DateTime?)null : DateTime.FromFileTime((long)MODIFY_TIME);
+
+ ///
+ /// Determine if this entry is a directory
+ ///
public bool IS_DIRECTORY => TYPE_FLAG != DIRENT_TYPE.DIRENT_TYPE_FILE;
#endregion
diff --git a/BurnOutSharp/External/libgsf/Input/GsfInfileMSOle.cs b/BurnOutSharp/External/libgsf/Input/GsfInfileMSOle.cs
index 30df4ea3..a8384e8f 100644
--- a/BurnOutSharp/External/libgsf/Input/GsfInfileMSOle.cs
+++ b/BurnOutSharp/External/libgsf/Input/GsfInfileMSOle.cs
@@ -37,9 +37,16 @@ namespace LibGSF.Input
{
#region Properties
- public uint[] Block { get; set; } = null;
+ public uint[] Blocks { get; set; } = null;
- public uint NumBlocks { get; set; }
+ #endregion
+
+ #region Derived Properties
+
+ ///
+ /// Number of blocks in the BAT as an unsigned Int32
+ ///
+ public uint NumBlocks => (uint)(Blocks?.Length ?? 0);
#endregion
@@ -55,14 +62,13 @@ namespace LibGSF.Input
/// table for the list starting in .
///
/// A meta bat to connect to the raw blocks (small or large)
- /// An optional guess as to how many blocks are in the file
/// The first block in the list.
/// Where to store the result.
/// True on error.
- public static bool Create(MSOleBAT metabat, int size_guess, uint block, out MSOleBAT res)
+ public static bool Create(MSOleBAT metabat, uint block, out MSOleBAT res)
{
// NOTE : Only use size as a suggestion, sometimes it is wrong
- List bat = new List(size_guess);
+ List bat = new List();
byte[] used = new byte[1 + metabat.NumBlocks / 8];
while (block < metabat.NumBlocks)
@@ -74,14 +80,10 @@ namespace LibGSF.Input
used[block / 8] |= (byte)(1 << (int)(block & 0x7));
bat.Add(block);
- block = metabat.Block[block];
+ block = metabat.Blocks[block];
}
- res = new MSOleBAT
- {
- NumBlocks = (uint)bat.Count,
- Block = bat.ToArray(),
- };
+ res = new MSOleBAT { Blocks = bat.ToArray() };
if (block != BAT_MAGIC_END_OF_CHAIN)
{
@@ -94,19 +96,6 @@ namespace LibGSF.Input
}
#endregion
-
- #region Functions
-
- public void Release()
- {
- if (Block == null)
- return;
-
- NumBlocks = 0;
- Block = null;
- }
-
- #endregion
}
// TODO: Can this be made internal?
@@ -114,28 +103,18 @@ namespace LibGSF.Input
{
#region Properties
- public string Name { get; set; }
-
public GsfMSOleSortingKey Key { get; set; }
- public int Index { get; set; }
-
- public int Size { get; set; }
+ public uint Index { get; set; }
public bool UseSmallBlock { get; set; }
- public uint FirstBlock { get; set; }
-
- public bool IsDirectory { get; set; }
-
public List Children { get; set; } = new List();
///
- /// 16 byte GUID used by some apps
+ /// Internal representation of the MS-OLE directory entry header
///
- public byte[] ClassID { get; set; } = new byte[16];
-
- public DateTime? ModTime { get; set; }
+ internal MSOleDirectoryEntry Header { get; set; }
#endregion
@@ -143,7 +122,6 @@ namespace LibGSF.Input
public void Free()
{
- Name = null;
Key = null;
foreach (MSOleDirent child in Children)
@@ -152,7 +130,7 @@ namespace LibGSF.Input
}
Children = null;
- ModTime = null;
+ Header = null;
}
#endregion
@@ -161,37 +139,16 @@ namespace LibGSF.Input
// TODO: Can this be made internal?
public class MSOleInfo
{
- #region Classes
-
- public class MSOleInfoBlock
- {
- public MSOleBAT Bat { get; set; }
-
- public int Shift { get; set; }
-
- public int Filter { get; set; }
-
- public int Size { get; set; }
- }
-
- #endregion
-
#region Properties
- public MSOleInfoBlock BigBlock { get; set; }
+ public MSOleBAT BigBlockBat { get; set; }
- public MSOleInfoBlock SmallBlock { get; set; }
-
- public long MaxBlock { get; set; }
+ public MSOleBAT SmallBlockBat { get; set; }
///
- /// Transition between small and big blocks
+ /// Maximum number of blocks derived from total input length and block size
///
- public uint Threshold { get; set; }
-
- public uint SBatStart { get; set; }
-
- public uint NumSbat { get; set; }
+ public long MaxBlock { get; set; }
public MSOleDirent RootDir { get; set; }
@@ -199,6 +156,11 @@ namespace LibGSF.Input
public int RefCount { get; set; }
+ ///
+ /// Internal representation of the MS-OLE header
+ ///
+ internal MSOleHeader Header { get; set; }
+
#endregion
#region Functions
@@ -208,8 +170,6 @@ namespace LibGSF.Input
if (RefCount-- != 1)
return;
- BigBlock.Bat.Release();
- SmallBlock.Bat.Release();
if (RootDir != null)
{
RootDir.Free();
@@ -218,6 +178,8 @@ namespace LibGSF.Input
if (SmallBlockFile != null)
SmallBlockFile = null;
+
+ Header = null;
}
public MSOleInfo Ref()
@@ -298,7 +260,6 @@ namespace LibGSF.Input
Info = null;
}
- Bat.Release();
Stream = null;
}
@@ -327,25 +288,22 @@ namespace LibGSF.Input
}
// GsfInput guarantees that num_bytes > 0
- long first_block = (CurrentOffset >> Info.BigBlock.Shift);
- long last_block = ((CurrentOffset + num_bytes - 1) >> Info.BigBlock.Shift);
- long offset = CurrentOffset & Info.BigBlock.Filter;
+ long first_block = (CurrentOffset >> Info.Header.BB_SHIFT);
+ long last_block = ((CurrentOffset + num_bytes - 1) >> Info.Header.BB_SHIFT);
+ long offset = CurrentOffset & Info.Header.BB_FILTER;
if (last_block >= Bat.NumBlocks)
return null;
// Optimization: are all the raw blocks contiguous?
long i = first_block;
- long raw_block = Bat.Block[i];
+ long raw_block = Bat.Blocks[i];
- //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.Blocks[i]) ;
if (i > last_block)
{
- if (!SeekBlock(Bat.Block[first_block], offset))
+ if (!SeekBlock(Bat.Blocks[first_block], offset))
return null;
CurBlock = last_block;
@@ -366,11 +324,11 @@ namespace LibGSF.Input
int count;
for (i = first_block; i <= last_block; i++, ptr += count, num_bytes -= count)
{
- count = (int)(Info.BigBlock.Size - offset);
+ count = (int)(Info.Header.BB_SIZE - offset);
if (count > num_bytes)
count = num_bytes;
- if (!SeekBlock(Bat.Block[i], offset))
+ if (!SeekBlock(Bat.Blocks[i], offset))
return null;
if (Input.Read(count, optional_buffer, ptr) == null)
@@ -409,7 +367,7 @@ namespace LibGSF.Input
foreach (MSOleDirent dirent in DirectoryEntry.Children)
{
if (i-- <= 0)
- return dirent.Name;
+ return dirent.Header.NAME_STRING;
}
return null;
@@ -420,7 +378,7 @@ namespace LibGSF.Input
{
foreach (MSOleDirent dirent in DirectoryEntry.Children)
{
- if (dirent.Name != null && dirent.Name == name)
+ if (dirent.Header.NAME_STRING != null && dirent.Header.NAME_STRING == name)
return CreateChild(dirent, ref error);
}
@@ -433,7 +391,7 @@ namespace LibGSF.Input
if (DirectoryEntry == null)
return -1;
- if (!DirectoryEntry.IsDirectory)
+ if (!DirectoryEntry.Header.IS_DIRECTORY)
return -1;
return DirectoryEntry.Children.Count;
@@ -450,7 +408,7 @@ namespace LibGSF.Input
if (DirectoryEntry == null)
return false;
- Array.Copy(DirectoryEntry.ClassID, res, DirectoryEntry.ClassID.Length);
+ Array.Copy(DirectoryEntry.Header.CLSID, res, DirectoryEntry.Header.CLSID.Length);
return true;
}
@@ -465,8 +423,8 @@ namespace LibGSF.Input
return false;
// 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(MSOleHeader.OLE_HEADER_SIZE, Info.BigBlock.Size) + (block << Info.BigBlock.Shift) + offset, SeekOrigin.Begin))
+ // header is padded out to BB_SIZE (sector size) when BB_SIZE > 512.
+ if (Input.Seek(Math.Max(MSOleHeader.OLE_HEADER_SIZE, Info.Header.BB_SIZE) + (block << Info.Header.BB_SHIFT) + offset, SeekOrigin.Begin))
return false;
return true;
@@ -484,7 +442,7 @@ namespace LibGSF.Input
if (!SeekBlock(block, 0))
return null;
- return Input.Read(Info.BigBlock.Size, buffer);
+ return Input.Read(Info.Header.BB_SIZE, buffer);
}
///
@@ -502,7 +460,7 @@ namespace LibGSF.Input
if (bat == null)
return null;
- int end = Info.BigBlock.Size;
+ int end = Info.Header.BB_SIZE;
for (int batPtr = 0; batPtr < end; batPtr += BAT_INDEX_SIZE, batsPtr++)
{
bats[batsPtr] = GSF_LE_GET_GUINT32(bat, batPtr);
@@ -519,7 +477,7 @@ namespace LibGSF.Input
// 'unused' entries in the metabat. Let's assume that
// corresponds to lots of unused blocks
// http://bugzilla.gnome.org/show_bug.cgi?id=336858
- uint i = (uint)(Info.BigBlock.Size / BAT_INDEX_SIZE);
+ uint i = (uint)(Info.Header.BB_SIZE / BAT_INDEX_SIZE);
while (i-- > 0)
{
bats[batsPtr++] = BAT_MAGIC_UNUSED;
@@ -533,9 +491,9 @@ namespace LibGSF.Input
///
/// Copy some some raw data into an array of uint.
///
- private static void GetUnsignedInts(uint[] dst, byte[] src, int srcPtr, int num_bytes)
+ private static void GetUnsignedInts(uint[] dst, ref int dstPtr, byte[] src, int srcPtr, int num_bytes)
{
- for (int dstPtr = 0; (num_bytes -= BAT_INDEX_SIZE) >= 0; srcPtr += BAT_INDEX_SIZE)
+ for (; (num_bytes -= BAT_INDEX_SIZE) >= 0; srcPtr += BAT_INDEX_SIZE)
{
dst[dstPtr++] = GSF_LE_GET_GUINT32(src, srcPtr);
}
@@ -555,16 +513,14 @@ namespace LibGSF.Input
if (Info.SmallBlockFile is GsfInfileMSOle)
(Info.SmallBlockFile as GsfInfileMSOle).Info.Unref();
- if (Info.SmallBlock.Bat.Block != null)
+ if (Info.SmallBlockBat.Blocks != null)
return null;
- if (MSOleBAT.Create(Info.BigBlock.Bat, (int)Info.NumSbat, Info.SBatStart, out MSOleBAT meta_sbat))
+ if (MSOleBAT.Create(Info.BigBlockBat, Info.Header.SBAT_START, out MSOleBAT meta_sbat))
return null;
- Info.SmallBlock.Bat.NumBlocks = (uint)(meta_sbat.NumBlocks * (Info.BigBlock.Size / BAT_INDEX_SIZE));
- Info.SmallBlock.Bat.Block = new uint[Info.SmallBlock.Bat.NumBlocks];
- ReadMetabat(Info.SmallBlock.Bat.Block, 0, Info.SmallBlock.Bat.NumBlocks, meta_sbat.Block, meta_sbat.NumBlocks);
- meta_sbat.Release();
+ Info.SmallBlockBat.Blocks = new uint[meta_sbat.NumBlocks * (Info.Header.BB_SIZE / BAT_INDEX_SIZE)];
+ ReadMetabat(Info.SmallBlockBat.Blocks, 0, Info.SmallBlockBat.NumBlocks, meta_sbat.Blocks, meta_sbat.NumBlocks);
return Info.SmallBlockFile;
}
@@ -584,7 +540,7 @@ namespace LibGSF.Input
if (entry > uint.MaxValue / MSOleDirectoryEntry.DIRENT_SIZE)
return null;
- uint block = ((entry * MSOleDirectoryEntry.DIRENT_SIZE) >> Info.BigBlock.Shift);
+ uint block = ((entry * MSOleDirectoryEntry.DIRENT_SIZE) >> Info.Header.BB_SHIFT);
if (block >= Bat.NumBlocks)
return null;
@@ -593,12 +549,12 @@ namespace LibGSF.Input
seen_before[entry] = true;
- byte[] data = GetBlock(Bat.Block[block], null);
+ byte[] data = GetBlock(Bat.Blocks[block], null);
if (data == null)
return null;
int dataPtr = 0; // data[0]
- dataPtr += (int)((MSOleDirectoryEntry.DIRENT_SIZE * entry) % Info.BigBlock.Size);
+ dataPtr += (int)((MSOleDirectoryEntry.DIRENT_SIZE * entry) % Info.Header.BB_SIZE);
Exception err = null;
MSOleDirectoryEntry directoryEntry = MSOleDirectoryEntry.Create(data, dataPtr, ref err);
@@ -621,28 +577,16 @@ namespace LibGSF.Input
MSOleDirent dirent = new MSOleDirent
{
- Index = (int)entry,
- 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,
+ Key = GsfMSOleSortingKey.Create(directoryEntry.NAME_STRING),
+ Index = entry,
// Root dir is always big block
- UseSmallBlock = parent != null && (directoryEntry.FILE_SIZE < Info.Threshold),
- FirstBlock = directoryEntry.FIRSTBLOCK,
- IsDirectory = directoryEntry.IS_DIRECTORY,
+ UseSmallBlock = parent != null && (directoryEntry.FILE_SIZE < Info.Header.THRESHOLD),
Children = new List(),
+
+ Header = directoryEntry,
};
- dirent.Name = directoryEntry.NAME_STRING.TrimEnd('\0');
-
- // Be really anal in the face of screwups
- if (dirent.Name == null)
- dirent.Name = string.Empty;
-
- dirent.Key = GsfMSOleSortingKey.Create(dirent.Name);
-
if (parent != null)
{
parent.Children.Add(dirent);
@@ -653,7 +597,7 @@ namespace LibGSF.Input
CreateDirectoryEntry(directoryEntry.PREV, parent, seen_before);
CreateDirectoryEntry(directoryEntry.NEXT, parent, seen_before);
- if (dirent.IsDirectory)
+ if (dirent.Header.IS_DIRECTORY)
CreateDirectoryEntry(directoryEntry.CHILD, dirent, seen_before);
else if (directoryEntry.CHILD != MSOleDirectoryEntry.DIRENT_MAGIC_END)
Console.Error.WriteLine("A non directory stream with children ?");
@@ -707,72 +651,59 @@ namespace LibGSF.Input
MSOleHeader headerImpl = MSOleHeader.Create(header, 0, ref err);
if (headerImpl == null)
+ {
+ err = new Exception("Header could not be parsed");
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 > headerImpl.BB_SHIFT || headerImpl.BB_SHIFT >= 31 || headerImpl.SB_SHIFT > headerImpl.BB_SHIFT || (Input.Size >> headerImpl.BB_SHIFT) < 1)
+ // There should always be at least 1 BAT block
+ if ((Input.Size >> headerImpl.BB_SHIFT) < 1)
{
err = new Exception("Unreasonable block sizes");
return true;
}
- MSOleInfo info = new MSOleInfo
+ Info = new MSOleInfo
{
- BigBlock = new MSOleInfo.MSOleInfoBlock { Bat = new MSOleBAT() },
- SmallBlock = new MSOleInfo.MSOleInfoBlock { Bat = new MSOleBAT() },
+ BigBlockBat = new MSOleBAT(),
+ SmallBlockBat = new MSOleBAT(),
+ MaxBlock = (Input.Size - MSOleHeader.OLE_HEADER_SIZE + headerImpl.BB_SIZE - 1) / headerImpl.BB_SIZE,
+ RootDir = null,
+ SmallBlockFile = null,
+ RefCount = 1,
+
+ Header = headerImpl,
};
- info.RefCount = 1;
- 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;
-
- if (info.NumSbat == 0 && info.SBatStart != BAT_MAGIC_END_OF_CHAIN && info.SBatStart != BAT_MAGIC_UNUSED)
- Console.Error.WriteLine("There are not supposed to be any blocks in the small block allocation table, yet there is a link to some. Ignoring it.");
-
uint[] metabat = null;
+ int metabatPtr = 0; // metabat[0]
uint last;
int? ptr = null;
// Very rough heuristic, just in case
uint num_bat = headerImpl.NUM_BAT;
- if (num_bat < info.MaxBlock && headerImpl.NUM_SBAT < info.MaxBlock)
+ if (num_bat < Info.MaxBlock && headerImpl.NUM_SBAT < Info.MaxBlock)
{
- info.BigBlock.Bat.NumBlocks = (uint)(num_bat * (headerImpl.BB_SIZE / BAT_INDEX_SIZE));
- info.BigBlock.Bat.Block = new uint[info.BigBlock.Bat.NumBlocks];
+ Info.BigBlockBat.Blocks = new uint[num_bat * (headerImpl.BB_SIZE / BAT_INDEX_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, MSOleHeader.OLE_HEADER_SIZE - OLE_HEADER_START_BAT);
- last = num_bat;
- if (last > OLE_HEADER_METABAT_SIZE)
- last = OLE_HEADER_METABAT_SIZE;
- ptr = ReadMetabat(info.BigBlock.Bat.Block, 0, info.BigBlock.Bat.NumBlocks, metabat, last);
+ GetUnsignedInts(metabat, ref metabatPtr, header, OLE_HEADER_START_BAT, MSOleHeader.OLE_HEADER_SIZE - OLE_HEADER_START_BAT);
+
+ last = Math.Min(num_bat, OLE_HEADER_METABAT_SIZE);
+ ptr = ReadMetabat(Info.BigBlockBat.Blocks, 0, Info.BigBlockBat.NumBlocks, metabat, last); // TODO: Does this need to be offset by metabatPtr?
num_bat -= last;
}
uint metabat_block = headerImpl.METABAT_BLOCK;
uint num_metabat = headerImpl.NUM_METABAT;
- last = (uint)((info.BigBlock.Size - BAT_INDEX_SIZE) / BAT_INDEX_SIZE);
+ last = (uint)((Info.Header.BB_SIZE - BAT_INDEX_SIZE) / BAT_INDEX_SIZE);
while (ptr != null && num_metabat-- > 0)
{
- byte[] tmp = GetBlock(metabat_block, null);
+ byte[] tmp = GetBlock(metabat_block - 1, null);
if (tmp == null)
{
ptr = null;
@@ -780,7 +711,7 @@ namespace LibGSF.Input
}
// Reading the elements invalidates this memory, make copy
- GetUnsignedInts(metabat, tmp, 0, info.BigBlock.Size);
+ GetUnsignedInts(metabat, ref metabatPtr, tmp, 0, Info.Header.BB_SIZE);
if (num_metabat == 0)
{
@@ -808,7 +739,7 @@ namespace LibGSF.Input
num_bat -= last;
}
- ptr = ReadMetabat(info.BigBlock.Bat.Block, ptr.Value, info.BigBlock.Bat.NumBlocks, metabat, last);
+ ptr = ReadMetabat(Info.BigBlockBat.Blocks, ptr.Value, Info.BigBlockBat.NumBlocks, metabat, last);
}
bool fail = (ptr == null);
@@ -820,7 +751,7 @@ namespace LibGSF.Input
}
// Read the directory's bat, we do not know the size
- if (MSOleBAT.Create(Info.BigBlock.Bat, 0, headerImpl.DIRENT_START, out MSOleBAT tempBat))
+ if (MSOleBAT.Create(Info.BigBlockBat, headerImpl.DIRENT_START, out MSOleBAT tempBat))
{
err = new Exception("Problems making block allocation table");
return true;
@@ -829,8 +760,8 @@ namespace LibGSF.Input
Bat = tempBat;
// Read the directory
- bool[] seen_before = new bool[(Bat.NumBlocks << info.BigBlock.Shift) * MSOleDirectoryEntry.DIRENT_SIZE + 1];
- DirectoryEntry = info.RootDir = CreateDirectoryEntry(0, null, seen_before);
+ bool[] seen_before = new bool[(Bat.NumBlocks << Info.Header.BB_SHIFT) * MSOleDirectoryEntry.DIRENT_SIZE + 1];
+ DirectoryEntry = Info.RootDir = CreateDirectoryEntry(0, null, seen_before);
if (DirectoryEntry == null)
{
err = new Exception("Problems reading directory");
@@ -839,7 +770,7 @@ namespace LibGSF.Input
// The spec says to ignore modtime for root object. That doesn't
// keep files from actually have a modtime there.
- ModTime = DirectoryEntry.ModTime;
+ ModTime = DirectoryEntry.Header.MODIFY_DATETIME;
return false;
}
@@ -865,16 +796,16 @@ namespace LibGSF.Input
return null;
child.DirectoryEntry = dirent;
- child.Size = dirent.Size;
- child.ModTime = dirent.ModTime;
+ child.Size = dirent.Header.FILE_SIZE;
+ child.ModTime = dirent.Header.MODIFY_DATETIME;
// The root dirent defines the small block file
if (dirent.Index != 0)
{
- child.Name = dirent.Name;
+ child.Name = dirent.Header.NAME_STRING;
child.Container = this;
- if (dirent.IsDirectory)
+ if (dirent.Header.IS_DIRECTORY)
{
// Be wary. It seems as if some implementations pretend that the
// directories contain data
@@ -883,17 +814,13 @@ namespace LibGSF.Input
}
}
- MSOleInfo info = Info;
-
MSOleBAT metabat;
- int size_guess;
GsfInput sb_file = null;
// Build the bat
if (dirent.UseSmallBlock)
{
- metabat = info.SmallBlock.Bat;
- size_guess = dirent.Size >> info.SmallBlock.Shift;
+ metabat = Info.SmallBlockBat;
sb_file = GetSmallBlockFile();
if (sb_file == null)
{
@@ -903,11 +830,10 @@ namespace LibGSF.Input
}
else
{
- metabat = info.BigBlock.Bat;
- size_guess = dirent.Size >> info.BigBlock.Shift;
+ metabat = Info.BigBlockBat;
}
- if (MSOleBAT.Create(metabat, size_guess + 1, dirent.FirstBlock, out MSOleBAT tempBat))
+ if (MSOleBAT.Create(metabat, dirent.Header.FIRSTBLOCK, out MSOleBAT tempBat))
return null;
child.Bat = tempBat;
@@ -917,26 +843,27 @@ namespace LibGSF.Input
if (sb_file == null)
return null;
- int remaining = dirent.Size;
+ uint remaining = dirent.Header.FILE_SIZE;
child.Stream = new byte[remaining];
- for (uint i = 0; remaining > 0 && i < child.Bat.NumBlocks; i++, remaining -= info.SmallBlock.Size)
+ for (uint i = 0; remaining > 0 && i < child.Bat.NumBlocks; i++, remaining -= (uint)Info.Header.SB_SIZE)
{
- if (sb_file.Seek(child.Bat.Block[i] << info.SmallBlock.Shift, SeekOrigin.Begin)
- || sb_file.Read(Math.Min(remaining, info.SmallBlock.Size), child.Stream, (int)(i << info.SmallBlock.Shift)) == null)
+ if (sb_file.Seek(child.Bat.Blocks[i] << Info.Header.SB_SHIFT, SeekOrigin.Begin)
+ || sb_file.Read((int)Math.Min(remaining, Info.Header.SB_SIZE), child.Stream, (int)(i << Info.Header.SB_SHIFT)) == null)
{
- Console.Error.WriteLine($"Failure reading block {i} for '{dirent.Name}'");
+ Console.Error.WriteLine($"Failure reading block {i} for '{dirent.Header.NAME_STRING}'");
err = new Exception("Failure reading block");
return null;
}
}
- if (remaining > 0)
- {
- err = new Exception("Insufficient blocks");
- Console.Error.WriteLine($"Small-block file '{dirent.Name}' has insufficient blocks ({child.Bat.NumBlocks}) for the stated size ({dirent.Size})");
- return null;
- }
+ // TODO: Debug as to why this block would be hit
+ //if (remaining > 0)
+ //{
+ // err = new Exception("Insufficient blocks");
+ // Console.Error.WriteLine($"Small-block file '{dirent.Header.NAME_STRING}' has insufficient blocks ({child.Bat.NumBlocks}) for the stated size ({dirent.Header.FILE_SIZE})");
+ // return null;
+ //}
}
return child;