Skip to content

Commit

Permalink
Fix xls ministream handling.
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkPflug committed Apr 25, 2024
1 parent 51ba659 commit 7322388
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 54 deletions.
7 changes: 2 additions & 5 deletions source/Sylvan.Data.Excel/Packaging/Ole2Package+Ole2Entry.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace Sylvan.Data.Excel;

Expand Down Expand Up @@ -107,8 +105,7 @@ public Stream Open()
if (this.StreamSize < Package.miniSectorCutoff)
{
var sectors = this.Package.GetMiniStreamSectors(this.StartSector).ToArray();
throw new NotImplementedException();
//return new Ole2MiniStream(this.Package, sectors, StreamSize);
return new Ole2MiniStream(this.Package, this.Package.miniStream, sectors, StreamSize);
}
else
{
Expand Down
38 changes: 17 additions & 21 deletions source/Sylvan.Data.Excel/Packaging/Ole2Package+Ole2MiniStream.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace Sylvan.Data.Excel;

Expand All @@ -22,9 +21,11 @@ public sealed class Ole2MiniStream : Stream
uint sector;

long streamPos;
Stream miniStream;

public Ole2MiniStream(Ole2Package package, uint[] sectors, long length)
public Ole2MiniStream(Ole2Package package, Stream miniStream, uint[] sectors, long length)
{
this.miniStream = miniStream;
this.package = package;
this.sectors = sectors;
this.sectorIdx = 0;
Expand Down Expand Up @@ -63,41 +64,40 @@ public override long Seek(long offset, SeekOrigin origin)
pos = this.length + offset;
break;
}
if (pos < 0 || pos > this.length)
if (pos < 0)
{
throw new ArgumentOutOfRangeException(nameof(offset));
}

this.position = pos;
var idx = pos / this.sectorLen;
var idx = pos / MiniSectorSize;

this.sectorIdx = (int)idx;
this.sectorOff = (int) (pos - (idx * sectorLen));
this.sectorOff = (int) (pos - (idx * MiniSectorSize));
this.sector = this.sectors[sectorIdx];
return this.position;
}

public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
public override int Read(byte[] buffer, int offset, int count)
{
if (offset + count > buffer.Length)
throw new ArgumentOutOfRangeException();

//Debug.WriteLine($"{offset} {count} {this.position}");

var sectors = this.sectors;

int bytesRead = 0;
var c = count;
var z = (int) Math.Min(count, this.length - position);

while (bytesRead < count && position < length)
{
var readLen = 0;
var readStart = (sector + 1) * sectorLen + sectorOff;
var readStart = sector * MiniSectorSize + sectorOff;
var curSector = sector;

while (readLen < c)
while (readLen < z)
{
if (this.sectorOff >= this.sectorLen)
if (this.sectorOff >= MiniSectorSize)
{
sectorOff = 0;
sectorIdx++;
Expand All @@ -119,8 +119,9 @@ public override async Task<int> ReadAsync(byte[] buffer, int offset, int count,
sector = curSector = nextSector;
}

var sectorAvail = this.sectorLen - this.sectorOff;
var sectorRead = Math.Min(sectorAvail, c - readLen);
var sectorAvail = MiniSectorSize - this.sectorOff;
Debug.WriteLine("SA: " + sectorAvail);
var sectorRead = Math.Min(sectorAvail, z - readLen);

readLen += sectorRead;
this.sectorOff += sectorRead;
Expand All @@ -129,7 +130,7 @@ public override async Task<int> ReadAsync(byte[] buffer, int offset, int count,
// avoid seek if we are already positioned.
if (streamPos != readStart)
{
package.stream.Seek(readStart, SeekOrigin.Begin);
package.miniStream.Seek(readStart, SeekOrigin.Begin);
streamPos = readStart;
}

Expand All @@ -138,7 +139,7 @@ public override async Task<int> ReadAsync(byte[] buffer, int offset, int count,
int len = 0;
while (len < readLen)
{
int l = await package.stream.ReadAsync(buffer, offset, readLen).ConfigureAwait(false);
int l = package.miniStream.Read(buffer, offset, readLen);
if (l == 0)
throw new IOException();//"Unexpectedly encountered end of Ole2Package Stream"
len += l;
Expand All @@ -152,11 +153,6 @@ public override async Task<int> ReadAsync(byte[] buffer, int offset, int count,
return bytesRead;
}

public override int Read(byte[] buffer, int offset, int count)
{
return ReadAsync(buffer, offset, count, default).GetAwaiter().GetResult();
}

public override void Flush()
{
}
Expand Down
5 changes: 3 additions & 2 deletions source/Sylvan.Data.Excel/Packaging/Ole2Package+Ole2Stream.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Threading;

namespace Sylvan.Data.Excel;

Expand Down Expand Up @@ -44,7 +45,7 @@ public override long Position
}
set
{
Seek(value - this.position, SeekOrigin.Current);
Seek(value, SeekOrigin.Begin);
}
}

Expand Down
41 changes: 16 additions & 25 deletions source/Sylvan.Data.Excel/Packaging/Ole2Package.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ sealed partial class Ole2Package
const uint MiniSectorCutoff = 0x1000;
const int HeaderFatSectorListCount = 109;
const int DirectoryEntrySize = 0x80;
const int MiniSectorSize = 0x40;

BinaryReader reader;
Stream stream;
Stream miniStream;

int sectorSize;
ushort verMinor;
Expand Down Expand Up @@ -61,19 +63,28 @@ public Ole2Entry GetEntry(int entryIdx)

public Ole2Package(Stream iStream)
{

this.stream = iStream;
this.reader = new BinaryReader(iStream, Encoding.Unicode);
this.fatSectorList = Array.Empty<uint>();
this.miniFatSectorList = Array.Empty<uint>();
this.entryList = Array.Empty<Ole2Entry>();
LoadHeader();
LoadDirectoryEntries();

if (RootEntry.StartSector <= MaxSector)
{
var miniStreamSectors = GetStreamSectors(RootEntry.StartSector).ToArray();

this.miniStream = new Ole2Stream(this, miniStreamSectors, RootEntry.StreamSize);
}
else
{
this.miniStream = Stream.Null;
}
}

void LoadHeader()
{

BinaryReader reader = new BinaryReader(stream, Encoding.Unicode);

ulong magic = reader.ReadUInt64();
Expand Down Expand Up @@ -123,7 +134,7 @@ void LoadHeader()

this.fatSectorCount = reader.ReadUInt32();

directorySectorStart = reader.ReadUInt32();
this.directorySectorStart = reader.ReadUInt32();


uint sig = reader.ReadUInt32();
Expand Down Expand Up @@ -209,7 +220,7 @@ void LoadMiniFatSectorList()
int diCount = sectorSize / 4 - 1;

for (int k = 0; k < diCount; k++)
fatSectorList[i++] = reader.ReadUInt32();
miniFatSectorList[i++] = reader.ReadUInt32();

// read next difat location
sect = reader.ReadUInt32();
Expand Down Expand Up @@ -247,32 +258,12 @@ IEnumerable<uint> GetMiniStreamSectors(uint startSector)
do
{
yield return sector;
sector = NextMiniSector(sector);
sector = miniFatSectorList[sector];
if (sector == startSector || sector == 0)
throw new InvalidDataException();
} while (sector != EndOfChain);
}

public uint NextMiniSector(uint sector)
{
throw new NotImplementedException();
//uint fatSectIdx = (uint)(sector / (sectorSize / 4));
//uint fatSectOff = (uint)(sector % (sectorSize / 4));

//uint fatPage = miniSectorCutoff[fatSectIdx];

//stream.Seek(SectorOffset(fatPage) + (fatSectOff * 4), SeekOrigin.Begin);
//return reader.ReadUInt32();
}


IEnumerable<Ole2Entry> GetEntries()
{
var root = this.RootEntry;
foreach (var entry in EnumerateEntry(root))
yield return entry;
}

IEnumerable<Ole2Entry> EnumerateEntry(Ole2Entry entry)
{
yield return entry;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ sealed partial class XlsWorkbookReader
{
sealed class RecordReader
{
const int BufferSize = 0x40000;
const int BufferSize = 0x10000;
const int MaxRecordSize = 8228;

Stream stream;
Expand Down

0 comments on commit 7322388

Please sign in to comment.