Browse Source

#61381 - PushbackInputStreams passed to ZipHelper may not hold 8 bytes

pull/1601/head
Antony Liu 2 weeks ago
parent
commit
1bc8142ae4
  1. 83
      main/Util/BufferedInputStream.cs
  2. 10
      main/Util/FileInputStream.cs
  3. 43
      main/Util/IOUtils.cs
  4. 2
      testcases/main/POIFS/Macros/TestVBAMacroReader.cs
  5. 34
      testcases/openxml4net/TestPackage.cs

83
main/Util/BufferedInputStream.cs

@ -46,6 +46,89 @@ namespace NPOI.Util
}
buf = new byte[size];
}
public override int Read(byte[] b, int off, int len)
{
//getBufIfOpen(); // Check for closed stream
if ((off | len | (off + len) | (b.Length - (off + len))) < 0) {
throw new IndexOutOfRangeException();
} else if (len == 0) {
return 0;
}
int n = 0;
for (;;) {
int nread = Read1(b, off + n, len - n);
if (nread <= 0)
return (n == 0) ? nread : n;
n += nread;
if (n >= len)
return n;
// if not closed but no bytes available, return
InputStream input = this.input;
if (input != null && input.Available() <= 0)
return n;
}
}
private int Read1(byte[] b, int off, int len) {
int avail = count - pos;
if (avail <= 0) {
/* If the requested length is at least as large as the buffer, and
if there is no mark/reset activity, do not bother to copy the
bytes into the local buffer. In this way buffered streams will
cascade harmlessly. */
if (len >= buf.Length && markpos < 0) {
return input.Read(b, off, len);
}
Fill();
avail = count - pos;
if (avail <= 0) return -1;
}
int cnt = (avail < len) ? avail : len;
Array.Copy(buf, pos, b, off, cnt);
pos += cnt;
return cnt;
}
private void Fill()
{
byte[] buffer = buf;
if (markpos < 0)
pos = 0; /* no mark: throw away the buffer */
else if (pos >= buffer.Length) /* no room left in buffer */
if (markpos > 0) { /* can throw away early part of the buffer */
int sz = pos - markpos;
Array.Copy(buffer, markpos, buffer, 0, sz);
pos = sz;
markpos = 0;
} else if (buffer.Length >= marklimit) {
markpos = -1; /* buffer got too big, invalidate mark */
pos = 0; /* drop buffer contents */
} else if (buffer.Length >= MAX_BUFFER_SIZE) {
throw new OutOfMemoryException("Required array size too large");
} else { /* grow buffer */
int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?
pos * 2 : MAX_BUFFER_SIZE;
if (nsz > marklimit)
nsz = marklimit;
byte[] nbuf = new byte[nsz];
Array.Copy(buffer, 0, nbuf, 0, pos);
//if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
// // Can't replace buf if there was an async close.
// // Note: This would need to be changed if fill()
// // is ever made accessible to multiple threads.
// // But for now, the only way CAS can fail is via close.
// // assert buf == null;
// throw new IOException("Stream closed");
//}
this.buf = nbuf;
buffer = nbuf;
}
count = pos;
int n = input.Read(buffer, pos, buffer.Length - pos);
if (n > 0)
count = n + pos;
}
public override void Mark(int readlimit) {
marklimit = readlimit;
markpos = pos;

10
main/Util/FileInputStream.cs

@ -38,6 +38,11 @@ namespace NPOI.Util
set { inner.Position = value;}
}
public override int Available()
{
return (int)(inner.Length - inner.Position);
}
public override void Flush()
{
throw new NotImplementedException();
@ -53,6 +58,11 @@ namespace NPOI.Util
return inner.Read(b, off, len);
}
public override void Reset()
{
base.Reset();
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();

43
main/Util/IOUtils.cs

@ -68,28 +68,29 @@ namespace NPOI.Util
/// </summary>
public static byte[] PeekFirst8Bytes(InputStream stream)
{
return PeekFirstNBytes(stream, 8);
// We want to peek at the first 8 bytes
stream.Mark(8);
byte[] header = new byte[8];
int read = IOUtils.ReadFully(stream, header);
if(read < 1)
throw new EmptyFileException();
// Wind back those 8 bytes
if(stream is PushbackInputStream)
{
//PushbackInputStream pin = (PushbackInputStream)stream;
//pin.Unread(header, 0, read);
stream.Position -= read;
}
else
{
stream.Reset();
}
return header;
//stream.Mark(8);
//byte[] header = new byte[8];
//int read = IOUtils.ReadFully(stream, header);
//if(read < 1)
// throw new EmptyFileException();
//// Wind back those 8 bytes
//if(stream is PushbackInputStream)
//{
// //PushbackInputStream pin = (PushbackInputStream)stream;
// //pin.Unread(header, 0, read);
// stream.Position -= read;
//}
//else
//{
// stream.Reset();
//}
//return header;
}
public static byte[] PeekFirstNBytes(Stream stream, int limit)

2
testcases/main/POIFS/Macros/TestVBAMacroReader.cs

@ -84,7 +84,6 @@ namespace TestCases.POIFS.Macros
//////////////////////////////// From Stream /////////////////////////////
[Test]
[Ignore("Fix VBAMacroReader")]
public void HSSFfromStream()
{
FromStream(POIDataSamples.GetSpreadSheetInstance(), "SimpleMacro.xls");
@ -111,7 +110,6 @@ namespace TestCases.POIFS.Macros
}
[Test]
[Ignore("Fix VBAMacroReader")]
public void HWPFfromStream()
{
FromStream(POIDataSamples.GetDocumentInstance(), "SimpleMacro.doc");

34
testcases/openxml4net/TestPackage.cs

@ -1070,31 +1070,37 @@ namespace TestCases.OpenXml4Net.OPC
}
[Test]
[Ignore("")]
public void TestTooShortFilterStreams()
{
Stream xssf;
Stream hssf = POIDataSamples.GetSpreadSheetInstance().GetFile("SampleSS.xls");
Stream hssf;
InputStream[] isList = {
//new PushbackInputStream(new FileInputStream(xssf), 2),
//new BufferedInputStream(new FileInputStream(xssf), 2),
new PushbackInputStream(new FileInputStream(hssf), 2),
new BufferedInputStream(new FileInputStream(hssf), 2),
};
//InputStream[] isList = {
// new PushbackInputStream(new FileInputStream(xssf), 2),
// new BufferedInputStream(new FileInputStream(xssf), 2),
// new PushbackInputStream(new FileInputStream(hssf), 2),
// new BufferedInputStream(new FileInputStream(hssf), 2),
//};
try {
xssf = OpenXml4NetTestDataSamples.OpenSampleStream("sample.xlsx");
WorkbookFactory.Create(new PushbackInputStream(new FileInputStream(xssf), 2));
xssf = OpenXml4NetTestDataSamples.OpenSampleStream("sample.xlsx");
WorkbookFactory.Create(new BufferedInputStream(new FileInputStream(xssf), 2));
foreach (Stream is1 in isList) {
WorkbookFactory.Create(is1);
}
hssf = POIDataSamples.GetSpreadSheetInstance().GetFile("SampleSS.xls");
WorkbookFactory.Create(new PushbackInputStream(new FileInputStream(hssf), 2));
hssf = POIDataSamples.GetSpreadSheetInstance().GetFile("SampleSS.xls");
WorkbookFactory.Create(new BufferedInputStream(new FileInputStream(hssf), 2));
//foreach(InputStream is1 in isList)
//{
// WorkbookFactory.Create(is1);
//}
} finally {
foreach (Stream is1 in isList) {
IOUtils.CloseQuietly(is1);
}
//foreach(InputStream is1 in isList)
//{
// IOUtils.CloseQuietly(is1);
//}
}
}
}

Loading…
Cancel
Save