Skip to content

Commit

Permalink
Add and use FileFormatException
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremy-visionaid committed Nov 19, 2024
1 parent 80c5f88 commit 730b83a
Show file tree
Hide file tree
Showing 14 changed files with 61 additions and 46 deletions.
15 changes: 5 additions & 10 deletions OpenMcdf.Tests/BinaryReaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,31 +39,26 @@ public void ReadHeader(string fileName)

stream.CopyAllTo(memoryStream);
memoryStream.WriteByte(1); // Corrupt signature
Assert.ThrowsException<FormatException>(() => reader.ReadHeader());
Assert.ThrowsException<FileFormatException>(() => reader.ReadHeader());

stream.CopyAllTo(memoryStream);
memoryStream.Position = 24;
memoryStream.WriteByte(1); // Corrupt CLSID
Assert.ThrowsException<FormatException>(() => reader.ReadHeader());
Assert.ThrowsException<FileFormatException>(() => reader.ReadHeader());

stream.CopyAllTo(memoryStream);
memoryStream.Position = 26;
memoryStream.WriteByte(1); // Corrupt Major version
Assert.ThrowsException<FormatException>(() => reader.ReadHeader());
Assert.ThrowsException<FileFormatException>(() => reader.ReadHeader());

stream.CopyAllTo(memoryStream);
memoryStream.Position = 28;
memoryStream.WriteByte(1); // Corrupt byte order
Assert.ThrowsException<FormatException>(() => reader.ReadHeader());
Assert.ThrowsException<FileFormatException>(() => reader.ReadHeader());

stream.CopyAllTo(memoryStream);
memoryStream.Position = 32;
memoryStream.WriteByte(1); // Corrupt mini sector shift
Assert.ThrowsException<FormatException>(() => reader.ReadHeader());

stream.CopyAllTo(memoryStream);
memoryStream.Position = 32;
memoryStream.WriteByte(1); // Corrupt mini sector shift
Assert.ThrowsException<FormatException>(() => reader.ReadHeader());
Assert.ThrowsException<FileFormatException>(() => reader.ReadHeader());
}
}
16 changes: 8 additions & 8 deletions OpenMcdf/CfbBinaryReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,19 @@ public Header ReadHeader()
ReadExactly(buffer, 0, Header.Signature.Length);
Span<byte> signature = buffer.AsSpan(0, Header.Signature.Length);
if (!signature.SequenceEqual(Header.Signature))
throw new FormatException("Invalid header signature.");
throw new FileFormatException("Invalid header signature.");
header.CLSID = ReadGuid();
if (header.CLSID != Guid.Empty)
throw new FormatException($"Invalid header CLSID: {header.CLSID}.");
throw new FileFormatException($"Invalid header CLSID: {header.CLSID}.");
header.MinorVersion = ReadUInt16();
header.MajorVersion = ReadUInt16();
if (header.MajorVersion is not (ushort)Version.V3 and not (ushort)Version.V4)
throw new FormatException($"Unsupported major version: {header.MajorVersion}.");
throw new FileFormatException($"Unsupported major version: {header.MajorVersion}.");
else if (header.MinorVersion is not Header.ExpectedMinorVersion)
Trace.WriteLine($"Unexpected minor version: {header.MinorVersion}.");
ushort byteOrder = ReadUInt16();
if (byteOrder != Header.LittleEndian)
throw new FormatException($"Unsupported byte order: {byteOrder:X4}. Only little-endian is supported ({Header.LittleEndian:X4}).");
throw new FileFormatException($"Unsupported byte order: {byteOrder:X4}. Only little-endian is supported ({Header.LittleEndian:X4}).");
header.SectorShift = ReadUInt16();
header.MiniSectorShift = ReadUInt16();
FillBuffer(6);
Expand All @@ -95,7 +95,7 @@ public Header ReadHeader()
FillBuffer(4);
uint miniStreamCutoffSize = ReadUInt32();
if (miniStreamCutoffSize != Header.MiniStreamCutoffSize)
throw new FormatException($"Mini stream cutoff size must be {Header.MiniStreamCutoffSize} bytes.");
throw new FileFormatException($"Mini stream cutoff size must be {Header.MiniStreamCutoffSize} bytes.");
header.FirstMiniFatSectorId = ReadUInt32();
header.MiniFatSectorCount = ReadUInt32();
header.FirstDifatSectorId = ReadUInt32();
Expand All @@ -113,15 +113,15 @@ public StorageType ReadStorageType()
{
var type = (StorageType)ReadByte();
if (type is not StorageType.Storage and not StorageType.Stream and not StorageType.Root and not StorageType.Unallocated)
throw new FormatException($"Invalid storage type: {type}.");
throw new FileFormatException($"Invalid storage type: {type}.");
return type;
}

public NodeColor ReadColor()
{
var color = (NodeColor)ReadByte();
if (color is not NodeColor.Black and not NodeColor.Red)
throw new FormatException($"Invalid node color: {color}.");
throw new FileFormatException($"Invalid node color: {color}.");
return color;
}

Expand Down Expand Up @@ -154,7 +154,7 @@ public DirectoryEntry ReadDirectoryEntry(Version version, uint sid)
{
entry.StreamLength = ReadUInt32();
if (entry.StreamLength > DirectoryEntry.MaxV3StreamLength)
throw new FormatException($"Stream length {entry.StreamLength} exceeds maximum value {DirectoryEntry.MaxV3StreamLength}.");
throw new FileFormatException($"Stream length {entry.StreamLength} exceeds maximum value {DirectoryEntry.MaxV3StreamLength}.");
ReadUInt32(); // Skip unused 4 bytes
}
else if (version == Version.V4)
Expand Down
2 changes: 1 addition & 1 deletion OpenMcdf/DifatSectorEnumerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public void Add()
{
bool ok = MoveTo(header.DifatSectorCount - 1);
if (!ok)
throw new InvalidOperationException("Failed to move to last DIFAT sector.");
throw new FileFormatException("The DIFAT sector count is invalid.");

writer.Position = current.EndPosition - sizeof(uint);
writer.Write(newDifatSector.Id);
Expand Down
2 changes: 1 addition & 1 deletion OpenMcdf/DirectoryEntries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public bool TryGetDictionaryEntry(uint streamId, out DirectoryEntry? entry)
}

if (streamId > StreamId.Maximum)
throw new ArgumentException($"Invalid directory entry stream ID: ${streamId:X8}.", nameof(streamId));
throw new FileFormatException($"Invalid directory entry stream ID: ${streamId:X8}.");

uint chainIndex = GetChainIndexAndEntryIndex(streamId, out long entryIndex);
if (!fatChainEnumerator.MoveTo(chainIndex))
Expand Down
2 changes: 1 addition & 1 deletion OpenMcdf/DirectoryEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ public void Recycle(StorageType storageType, string name)
StorageType.Stream => EntryType.Stream,
StorageType.Storage => EntryType.Storage,
StorageType.Root => EntryType.Storage,
_ => throw new InvalidOperationException("Invalid storage type.")
_ => throw new FileFormatException($"Invalid storage type: {Type}.")
};

public EntryInfo ToEntryInfo(string path) => new(EntryType, path, NameString, StreamLength, CLSID, CreationTime, ModifiedTime);
Expand Down
4 changes: 2 additions & 2 deletions OpenMcdf/DirectoryTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public bool TryGetDirectoryEntry(string name, out DirectoryEntry? entry)
{
compare = DirectoryEntryComparer.Compare(leftChild.NameCharSpan, child.NameCharSpan);
if (compare >= 0)
throw new FormatException("Directory tree is not sorted.");
throw new FileFormatException("Directory tree is not sorted.");
}

child = leftChild;
Expand All @@ -55,7 +55,7 @@ public bool TryGetDirectoryEntry(string name, out DirectoryEntry? entry)
{
compare = DirectoryEntryComparer.Compare(rightChild.NameCharSpan, child.NameCharSpan);
if (compare <= 0)
throw new FormatException("Directory tree is not sorted.");
throw new FileFormatException("Directory tree is not sorted.");
}

child = rightChild;
Expand Down
6 changes: 3 additions & 3 deletions OpenMcdf/Fat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,17 +190,17 @@ internal void Validate()
{
Sector sector = new(entry.Index, Context.SectorSize);
if (entry.Value <= SectorType.Maximum && sector.EndPosition > Context.Length)
throw new FormatException($"FAT entry {entry} is beyond the end of the stream.");
throw new FileFormatException($"FAT entry {entry} is beyond the end of the stream.");
if (entry.Value == SectorType.Fat)
fatSectorCount++;
if (entry.Value == SectorType.Difat)
difatSectorCount++;
}

if (Context.Header.FatSectorCount != fatSectorCount)
throw new FormatException($"FAT sector count mismatch. Expected: {Context.Header.FatSectorCount} Actual: {fatSectorCount}.");
throw new FileFormatException($"FAT sector count mismatch. Expected: {Context.Header.FatSectorCount} Actual: {fatSectorCount}.");
if (Context.Header.DifatSectorCount != difatSectorCount)
throw new FormatException($"DIFAT sector count mismatch: Expected: {Context.Header.DifatSectorCount} Actual: {difatSectorCount}.");
throw new FileFormatException($"DIFAT sector count mismatch: Expected: {Context.Header.DifatSectorCount} Actual: {difatSectorCount}.");
}

[ExcludeFromCodeCoverage]
Expand Down
8 changes: 4 additions & 4 deletions OpenMcdf/FatStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public override int Read(byte[] buffer, int offset, int count)

uint chainIndex = GetFatChainIndexAndSectorOffset(position, out long sectorOffset);
if (!chain.MoveTo(chainIndex))
throw new FormatException($"The FAT chain was shorter than the stream length.");
throw new FileFormatException($"The FAT chain was shorter than the stream length.");

int realCount = Math.Min(count, maxCount);
int readCount = 0;
Expand All @@ -109,7 +109,7 @@ public override int Read(byte[] buffer, int offset, int count)
if (readCount >= realCount)
return readCount;
if (!chain.MoveNext())
throw new FormatException($"The FAT chain was shorter than the stream length.");
throw new FileFormatException($"The FAT chain was shorter than the stream length.");
};
}

Expand Down Expand Up @@ -215,7 +215,7 @@ public override int Read(Span<byte> buffer)

uint chainIndex = GetFatChainIndexAndSectorOffset(position, out long sectorOffset);
if (!chain.MoveTo(chainIndex))
throw new FormatException($"The FAT chain was shorter than the stream length.");
throw new FileFormatException($"The FAT chain was shorter than the stream length.");

int realCount = Math.Min(buffer.Length, maxCount);
int readCount = 0;
Expand All @@ -236,7 +236,7 @@ public override int Read(Span<byte> buffer)
if (readCount >= realCount)
return readCount;
if (!chain.MoveNext())
throw new FormatException($"The FAT chain was shorter than the stream length.");
throw new FileFormatException($"The FAT chain was shorter than the stream length.");
}
}

Expand Down
19 changes: 19 additions & 0 deletions OpenMcdf/FileFormatException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace OpenMcdf;

/// <summary>
/// The exception that is thrown when an compound file data stream contains invalid data.
/// </summary>
public class FileFormatException : FormatException
{
public FileFormatException()
{
}

public FileFormatException(string message) : base(message)
{
}

public FileFormatException(string message, Exception innerException) : base(message, innerException)
{
}
}
10 changes: 5 additions & 5 deletions OpenMcdf/Header.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public ushort MajorVersion
get => majorVersion; set
{
if (value is not 3 and not 4)
throw new FormatException($"Unsupported major version: {value}. Only 3 and 4 are supported");
throw new FileFormatException($"Unsupported major version: {value}. Only 3 and 4 are supported");
majorVersion = value;
}
}
Expand All @@ -57,9 +57,9 @@ public ushort SectorShift
get => sectorShift; set
{
if (MajorVersion == 3 && value != SectorShiftV3)
throw new FormatException($"Unsupported sector shift {value:X4}. Only {SectorShiftV3:X4} is supported for Major Version 3.");
throw new FileFormatException($"Unsupported sector shift {value:X4}. Only {SectorShiftV3:X4} is supported for Major Version 3.");
if (MajorVersion == 4 && value != SectorShiftV4)
throw new FormatException($"Unsupported sector shift {value:X4}. Only {SectorShiftV4:X4} is supported for Major Version 4.");
throw new FileFormatException($"Unsupported sector shift {value:X4}. Only {SectorShiftV4:X4} is supported for Major Version 4.");

sectorShift = value;
}
Expand All @@ -71,7 +71,7 @@ public ushort MiniSectorShift
set
{
if (value != ExpectedMiniSectorShift)
throw new FormatException($"Unsupported sector shift {value:X4}. Only {ExpectedMiniSectorShift:X4} is supported.");
throw new FileFormatException($"Unsupported sector shift {value:X4}. Only {ExpectedMiniSectorShift:X4} is supported.");

miniSectorShift = value;
}
Expand Down Expand Up @@ -130,7 +130,7 @@ public Header(Version version = Version.V3)
{
Version.V3 => SectorShiftV3,
Version.V4 => SectorShiftV4,
_ => throw new FormatException($"Unsupported version: {version}.")
_ => throw new FileFormatException($"Unsupported version: {version}.")
};
FirstDirectorySectorId = SectorType.EndOfChain;
DirectorySectorCount = 0; // Not used in v3
Expand Down
2 changes: 1 addition & 1 deletion OpenMcdf/MiniFat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ internal void Validate()
FatEntry current = miniFatEnumerator.Current;
if (current.Value <= SectorType.Maximum && miniFatEnumerator.CurrentSector.EndPosition > Context.MiniStream.Length)
{
throw new FormatException($"Mini FAT entry {current} is beyond the end of the mini stream.");
throw new FileFormatException($"Mini FAT entry {current} is beyond the end of the mini stream.");
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion OpenMcdf/MiniFatChainEnumerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public bool MoveNext()

uint nextIndex = index + 1;
if (nextIndex > SectorType.Maximum)
throw new FormatException("Mini FAT chain is corrupt.");
throw new FileFormatException("Mini FAT chain is corrupt.");

index = nextIndex;
current = sectorId;
Expand Down
12 changes: 6 additions & 6 deletions OpenMcdf/MiniFatStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public override int Read(byte[] buffer, int offset, int count)

uint chainIndex = GetMiniFatChainIndexAndSectorOffset(position, out long sectorOffset);
if (!miniChain.MoveTo(chainIndex))
throw new FormatException($"The mini FAT chain was shorter than the stream length.");
throw new FileFormatException($"The mini FAT chain was shorter than the stream length.");

FatStream miniStream = Context.MiniStream;
int realCount = Math.Min(count, maxCount);
Expand All @@ -100,7 +100,7 @@ public override int Read(byte[] buffer, int offset, int count)
if (readCount >= realCount)
return readCount;
if (!miniChain.MoveNext())
throw new FormatException($"The mini FAT chain was shorter than the stream length.");
throw new FileFormatException($"The mini FAT chain was shorter than the stream length.");
}
}

Expand Down Expand Up @@ -165,7 +165,7 @@ public override void Write(byte[] buffer, int offset, int count)

uint chainIndex = GetMiniFatChainIndexAndSectorOffset(position, out long sectorOffset);
if (!miniChain.MoveTo(chainIndex))
throw new InvalidOperationException($"Failed to move to mini FAT chain index: {chainIndex}.");
throw new FileFormatException($"Failed to move to mini FAT chain index: {chainIndex}.");

FatStream miniStream = Context.MiniStream;
int writeCount = 0;
Expand Down Expand Up @@ -211,7 +211,7 @@ public override int Read(Span<byte> buffer)

uint chainIndex = GetMiniFatChainIndexAndSectorOffset(position, out long sectorOffset);
if (!miniChain.MoveTo(chainIndex))
throw new FormatException($"The mini FAT chain was shorter than the stream length.");
throw new FileFormatException($"The mini FAT chain was shorter than the stream length.");

FatStream miniStream = Context.MiniStream;
int realCount = Math.Min(buffer.Length, maxCount);
Expand All @@ -233,7 +233,7 @@ public override int Read(Span<byte> buffer)
if (readCount >= realCount)
return readCount;
if (!miniChain.MoveNext())
throw new FormatException($"The mini FAT chain was shorter than the stream length.");
throw new FileFormatException($"The mini FAT chain was shorter than the stream length.");
}
}

Expand All @@ -251,7 +251,7 @@ public override void Write(ReadOnlySpan<byte> buffer)

uint chainIndex = GetMiniFatChainIndexAndSectorOffset(position, out long sectorOffset);
if (!miniChain.MoveTo(chainIndex))
throw new InvalidOperationException($"Failed to move to mini FAT chain index: {chainIndex}.");
throw new FileFormatException($"Failed to move to mini FAT chain index: {chainIndex}.");

FatStream miniStream = Context.MiniStream;
int writeCount = 0;
Expand Down
7 changes: 4 additions & 3 deletions StructuredStorageExplorer/MainForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.ComponentModel;
using System.Data;
using System.Globalization;
using FileFormatException = OpenMcdf.FileFormatException;

// Author Federico Blaseotto

Expand Down Expand Up @@ -110,7 +111,7 @@ private void CreateNewFile()

RefreshTree();
}
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException or FormatException)
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException or FileFormatException)
{
CloseCurrentFile();

Expand Down Expand Up @@ -149,7 +150,7 @@ private void LoadFile(string fileName)

RefreshTree();
}
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException or FormatException)
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException or FileFormatException)
{
CloseCurrentFile();

Expand Down Expand Up @@ -372,7 +373,7 @@ private void TreeView1_MouseUp(object sender, MouseEventArgs e)

propertyGrid1.SelectedObject = nodeSelection.EntryInfo;
}
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException or FormatException)
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException or FileFormatException)
{
CloseCurrentFile();

Expand Down

0 comments on commit 730b83a

Please sign in to comment.