diff --git a/sources/OpenMcdf.Extensions/StreamDecorator.cs b/sources/OpenMcdf.Extensions/StreamDecorator.cs
index 0f19858d..ee3b04a1 100644
--- a/sources/OpenMcdf.Extensions/StreamDecorator.cs
+++ b/sources/OpenMcdf.Extensions/StreamDecorator.cs
@@ -54,14 +54,14 @@ public override long Position
///
public override int Read(byte[] buffer, int offset, int count)
{
- if (count > buffer.Length)
- throw new ArgumentException("Count parameter exceeds buffer size");
-
if (buffer == null)
- throw new ArgumentNullException("Buffer cannot be null");
+ throw new ArgumentNullException(nameof(buffer));
+
+ if (offset < 0)
+ throw new ArgumentOutOfRangeException(nameof(offset), "Offset must be a non-negative number");
- if (offset < 0 || count < 0)
- throw new ArgumentOutOfRangeException("Offset and Count parameters must be non-negative numbers");
+ if ((uint)count > buffer.Length - offset)
+ throw new ArgumentException("Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection");
if (position >= cfStream.Size)
return 0;
diff --git a/sources/OpenMcdf/CompoundFile.cs b/sources/OpenMcdf/CompoundFile.cs
index bf5de1c0..7f3f0340 100644
--- a/sources/OpenMcdf/CompoundFile.cs
+++ b/sources/OpenMcdf/CompoundFile.cs
@@ -1283,14 +1283,13 @@ List result
null,
sourceStream);
- byte[] nextDIFATSectorBuffer = new byte[4];
+ StreamRW difatStreamRW = new(difatStream);
int i = 0;
while (result.Count < header.FATSectorsNumber)
{
- difatStream.Read(nextDIFATSectorBuffer, 0, 4);
- nextSecID = BitConverter.ToInt32(nextDIFATSectorBuffer, 0);
+ nextSecID = difatStreamRW.ReadInt32();
EnsureUniqueSectorIndex(nextSecID, processedSectors);
@@ -1308,20 +1307,14 @@ List result
result.Add(s);
- //difatStream.Read(nextDIFATSectorBuffer, 0, 4);
- //nextSecID = BitConverter.ToInt32(nextDIFATSectorBuffer, 0);
-
if (difatStream.Position == (SectorSize - 4 + i * SectorSize))
{
// Skip DIFAT chain fields considering the possibility that the last FAT entry has been already read
- difatStream.Read(nextDIFATSectorBuffer, 0, 4);
- if (BitConverter.ToInt32(nextDIFATSectorBuffer, 0) == Sector.ENDOFCHAIN)
+ if (difatStreamRW.ReadInt32() == Sector.ENDOFCHAIN)
break;
- else
- {
- i++;
- continue;
- }
+
+ i++;
+ continue;
}
}
}
@@ -1576,13 +1569,14 @@ List directoryChain
using StreamView dirReader
= new StreamView(directoryChain, SectorSize, directoryChain.Count * SectorSize, null, sourceStream);
+ StreamRW dirReaderRW = new(dirReader);
+
while (dirReader.Position < directoryChain.Count * SectorSize)
{
- IDirectoryEntry de
- = DirectoryEntry.New(string.Empty, StgType.StgInvalid, directoryEntries);
+ IDirectoryEntry de = DirectoryEntry.New(string.Empty, StgType.StgInvalid, directoryEntries);
- //We are not inserting dirs. Do not use 'InsertNewDirectoryEntry'
- de.Read(dirReader, Version);
+ // We are not inserting dirs. Do not use 'InsertNewDirectoryEntry'
+ de.Read(dirReaderRW, Version);
}
}
@@ -1598,9 +1592,11 @@ List directorySectors
using StreamView sv = new StreamView(directorySectors, SectorSize, 0, null, sourceStream);
+ StreamRW svRW = new(sv);
+
foreach (IDirectoryEntry di in directoryEntries)
{
- di.Write(sv);
+ di.Write(svRW);
}
int delta = directoryEntries.Count;
@@ -1608,7 +1604,7 @@ List directorySectors
while (delta % (SectorSize / DIRECTORY_SIZE) != 0)
{
IDirectoryEntry dummy = DirectoryEntry.New(string.Empty, StgType.StgInvalid, directoryEntries);
- dummy.Write(sv);
+ dummy.Write(svRW);
delta++;
}
diff --git a/sources/OpenMcdf/DirectoryEntry.cs b/sources/OpenMcdf/DirectoryEntry.cs
index 01ba62e1..5a4e1b32 100644
--- a/sources/OpenMcdf/DirectoryEntry.cs
+++ b/sources/OpenMcdf/DirectoryEntry.cs
@@ -210,23 +210,21 @@ public override int GetHashCode()
return (int)fnv_hash(EntryName);
}
- public void Write(Stream stream)
+ public void Write(StreamRW streamRW)
{
- StreamRW rw = new StreamRW(stream);
-
- rw.Write(EntryName);
- rw.Write(nameLength);
- rw.Write((byte)StgType);
- rw.Write((byte)StgColor);
- rw.Write(LeftSibling);
- rw.Write(RightSibling);
- rw.Write(Child);
- rw.Write(storageCLSID);
- rw.Write(StateBits);
- rw.Write(CreationDate);
- rw.Write(ModifyDate);
- rw.Write(StartSect);
- rw.Write(Size);
+ streamRW.Write(EntryName);
+ streamRW.Write(nameLength);
+ streamRW.Write((byte)StgType);
+ streamRW.Write((byte)StgColor);
+ streamRW.Write(LeftSibling);
+ streamRW.Write(RightSibling);
+ streamRW.Write(Child);
+ streamRW.Write(storageCLSID);
+ streamRW.Write(StateBits);
+ streamRW.Write(CreationDate);
+ streamRW.Write(ModifyDate);
+ streamRW.Write(StartSect);
+ streamRW.Write(Size);
}
//public Byte[] ToByteArray()
@@ -256,18 +254,16 @@ public void Write(Stream stream)
// return ms.ToArray();
//}
- public void Read(Stream stream, CFSVersion ver = CFSVersion.Ver_3)
+ public void Read(StreamRW streamRW, CFSVersion ver = CFSVersion.Ver_3)
{
- StreamRW rw = new StreamRW(stream);
-
- rw.ReadBytes(EntryName);
- nameLength = rw.ReadUInt16();
- StgType = (StgType)rw.ReadByte();
+ streamRW.ReadBytes(EntryName);
+ nameLength = streamRW.ReadUInt16();
+ StgType = (StgType)streamRW.ReadByte();
//rw.ReadByte();//Ignore color, only black tree
- StgColor = (StgColor)rw.ReadByte();
- LeftSibling = rw.ReadInt32();
- RightSibling = rw.ReadInt32();
- Child = rw.ReadInt32();
+ StgColor = (StgColor)streamRW.ReadByte();
+ LeftSibling = streamRW.ReadInt32();
+ RightSibling = streamRW.ReadInt32();
+ Child = streamRW.ReadInt32();
// Thanks to bugaccount (BugTrack id 3519554)
if (StgType == StgType.StgInvalid)
@@ -277,23 +273,23 @@ public void Read(Stream stream, CFSVersion ver = CFSVersion.Ver_3)
Child = NOSTREAM;
}
- storageCLSID = rw.ReadGuid();
- StateBits = rw.ReadInt32();
- rw.ReadBytes(CreationDate);
- rw.ReadBytes(ModifyDate);
- StartSect = rw.ReadInt32();
+ storageCLSID = streamRW.ReadGuid();
+ StateBits = streamRW.ReadInt32();
+ streamRW.ReadBytes(CreationDate);
+ streamRW.ReadBytes(ModifyDate);
+ StartSect = streamRW.ReadInt32();
if (ver == CFSVersion.Ver_3)
{
// avoid dirty read for version 3 files (max size: 32bit integer)
// where most significant bits are not initialized to zero
- Size = rw.ReadInt32();
- rw.Seek(4, SeekOrigin.Current); // discard most significant 4 (possibly) dirty bytes
+ Size = streamRW.ReadInt32();
+ streamRW.Seek(4, SeekOrigin.Current); // discard most significant 4 (possibly) dirty bytes
}
else
{
- Size = rw.ReadInt64();
+ Size = streamRW.ReadInt64();
}
}
diff --git a/sources/OpenMcdf/IDirectoryEntry.cs b/sources/OpenMcdf/IDirectoryEntry.cs
index 9965487e..3d843fc4 100644
--- a/sources/OpenMcdf/IDirectoryEntry.cs
+++ b/sources/OpenMcdf/IDirectoryEntry.cs
@@ -21,7 +21,7 @@ internal interface IDirectoryEntry : IComparable, IRBNode
byte[] ModifyDate { get; set; }
string Name { get; }
ushort NameLength { get; set; }
- void Read(System.IO.Stream stream, CFSVersion ver = CFSVersion.Ver_3);
+ void Read(StreamRW streamRW, CFSVersion ver = CFSVersion.Ver_3);
int RightSibling { get; set; }
void SetEntryName(string entryName);
int SID { get; set; }
@@ -31,7 +31,7 @@ internal interface IDirectoryEntry : IComparable, IRBNode
StgColor StgColor { get; set; }
StgType StgType { get; set; }
Guid StorageCLSID { get; set; }
- void Write(System.IO.Stream stream);
+ void Write(StreamRW stream);
void Reset();
}
}
diff --git a/sources/OpenMcdf/StreamRW.cs b/sources/OpenMcdf/StreamRW.cs
index 3ea4c572..46b04f9c 100644
--- a/sources/OpenMcdf/StreamRW.cs
+++ b/sources/OpenMcdf/StreamRW.cs
@@ -21,6 +21,19 @@ public StreamRW(Stream stream)
this.stream = stream;
}
+ void ReadExactly(byte[] buffer, int offset, int count)
+ {
+ int totalRead = 0;
+ do
+ {
+ int read = stream.Read(buffer, offset + totalRead, count - totalRead);
+ if (read == 0)
+ throw new EndOfStreamException();
+
+ totalRead += read;
+ } while (totalRead < count);
+ }
+
public long Seek(long count, SeekOrigin origin)
{
return stream.Seek(count, origin);
@@ -28,31 +41,31 @@ public long Seek(long count, SeekOrigin origin)
public byte ReadByte()
{
- stream.Read(buffer, 0, 1);
+ ReadExactly(buffer, 0, sizeof(byte));
return buffer[0];
}
public ushort ReadUInt16()
{
- stream.Read(buffer, 0, 2);
+ ReadExactly(buffer, 0, sizeof(ushort));
return (ushort)(buffer[0] | (buffer[1] << 8));
}
public int ReadInt32()
{
- stream.Read(buffer, 0, 4);
+ ReadExactly(buffer, 0, sizeof(int));
return buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
}
public uint ReadUInt32()
{
- stream.Read(buffer, 0, 4);
+ ReadExactly(buffer, 0, sizeof(uint));
return (uint)(buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24));
}
public long ReadInt64()
{
- stream.Read(buffer, 0, 8);
+ ReadExactly(buffer, 0, sizeof(long));
uint ls = (uint)(buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24));
uint ms = (uint)((buffer[4]) | (buffer[5] << 8) | (buffer[6] << 16) | (buffer[7] << 24));
return (long)(((ulong)ms << 32) | ls);
@@ -60,19 +73,18 @@ public long ReadInt64()
public ulong ReadUInt64()
{
- stream.Read(buffer, 0, 8);
+ ReadExactly(buffer, 0, sizeof(ulong));
return (ulong)(buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24) | (buffer[4] << 32) | (buffer[5] << 40) | (buffer[6] << 48) | (buffer[7] << 56));
}
public void ReadBytes(byte[] result)
{
- // TODO: Check if the expected number of bytes were read
- stream.Read(result, 0, result.Length);
+ ReadExactly(result, 0, result.Length);
}
public Guid ReadGuid()
{
- stream.Read(buffer, 0, 16);
+ ReadExactly(buffer, 0, 16);
return new Guid(buffer);
}
diff --git a/sources/OpenMcdf/StreamView.cs b/sources/OpenMcdf/StreamView.cs
index b9f626dc..3da6467e 100644
--- a/sources/OpenMcdf/StreamView.cs
+++ b/sources/OpenMcdf/StreamView.cs
@@ -79,6 +79,15 @@ public override long Position
public override int Read(byte[] buffer, int offset, int count)
{
+ if (buffer is null)
+ throw new ArgumentNullException(nameof(buffer));
+
+ if (offset < 0)
+ throw new ArgumentOutOfRangeException(nameof(offset), "Offset must be a non-negative number");
+
+ if ((uint)count > buffer.Length - offset)
+ throw new ArgumentException("Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection");
+
int nRead = 0;
// Don't try to read more bytes than this stream contains.
@@ -157,14 +166,20 @@ public override long Seek(long offset, SeekOrigin origin)
switch (origin)
{
case SeekOrigin.Begin:
+ if (offset < 0)
+ throw new IOException("Seek before origin");
position = offset;
break;
case SeekOrigin.Current:
+ if (position + offset < 0)
+ throw new IOException("Seek before origin");
position += offset;
break;
case SeekOrigin.End:
+ if (Length - offset < 0)
+ throw new IOException("Seek before origin");
position = Length - offset;
break;
}