diff --git a/main/DDF/UnknownEscherRecord.cs b/main/DDF/UnknownEscherRecord.cs index 1d95bee76..507934988 100644 --- a/main/DDF/UnknownEscherRecord.cs +++ b/main/DDF/UnknownEscherRecord.cs @@ -54,14 +54,14 @@ public override int FillFields(byte[] data, int offset, IEscherRecordFactory rec int bytesRemaining = ReadHeader(data, offset); /* * Modified by Zhang Zhang - * Have a check between avaliable bytes and bytesRemaining, - * take the avaliable length if the bytesRemaining out of range. + * Have a check between available bytes and bytesRemaining, + * take the available length if the bytesRemaining out of range. * July 09, 2010 */ - int avaliable = data.Length - (offset + 8); - if (bytesRemaining > avaliable) + int available = data.Length - (offset + 8); + if (bytesRemaining > available) { - bytesRemaining = avaliable; + bytesRemaining = available; } if (IsContainerRecord) { @@ -82,6 +82,9 @@ public override int FillFields(byte[] data, int offset, IEscherRecordFactory rec } else { + if (bytesRemaining < 0) { + bytesRemaining = 0; + } _thedata = new byte[bytesRemaining]; Array.Copy(data, offset + 8, _thedata, 0, bytesRemaining); return bytesRemaining + 8; diff --git a/main/POIFS/Storage/HeaderBlock.cs b/main/POIFS/Storage/HeaderBlock.cs index a6cde8428..6c77f3199 100644 --- a/main/POIFS/Storage/HeaderBlock.cs +++ b/main/POIFS/Storage/HeaderBlock.cs @@ -71,7 +71,12 @@ public class HeaderBlock : HeaderBlockConstants 0x00, 0x00, // unused 0x00, 0x01 }; - + private static byte[] MAGIC_MSWRITEa = { + 0x31, (byte)0xbe, 0x00, 0x00 + }; + private static byte[] MAGIC_MSWRITEb = { + 0x32, (byte)0xbe, 0x00, 0x00 + }; private static byte _default_value = (byte)0xFF; /** * What big block Size the file uses. Most files @@ -146,6 +151,12 @@ public void PrivateHeaderBlock(byte[] data) + "Formats such as Office 2003 XML are not supported"); } + // Old MS Write raw stream + if (cmp(MAGIC_MSWRITEa, data) || cmp(MAGIC_MSWRITEb, data)) { + throw new NotOLE2FileException("The supplied data appears to be in the old MS Write format. " + + "NPOI doesn't currently support this format"); + } + // BIFF2 raw stream if (cmp(MAGIC_BIFF2, data)) { diff --git a/main/Util/FileInputStream.cs b/main/Util/FileInputStream.cs index 1febec6b2..885631db5 100644 --- a/main/Util/FileInputStream.cs +++ b/main/Util/FileInputStream.cs @@ -48,6 +48,11 @@ public override int Read() return inner.ReadByte(); } + public override int Read(byte[] b, int off, int len) + { + return inner.Read(b, off, len); + } + public override long Seek(long offset, SeekOrigin origin) { throw new NotImplementedException(); diff --git a/main/Util/IOUtils.cs b/main/Util/IOUtils.cs index e3966ca55..542767196 100644 --- a/main/Util/IOUtils.cs +++ b/main/Util/IOUtils.cs @@ -36,6 +36,11 @@ public class IOUtils { private static POILogger logger = POILogFactory.GetLogger(typeof(IOUtils)); + /// + /// The default buffer size to use for the skip() methods. + /// + private static int SKIP_BUFFER_SIZE = 2048; + private static byte[] SKIP_BYTE_BUFFER; /// /// The current set global allocation limit override, /// -1 means limits are applied per record type. @@ -417,6 +422,72 @@ public static void CloseQuietly(ICloseable closeable) } } + /// + /// + /// Skips bytes from an input byte stream. + /// This implementation guarantees that it will read as many bytes + /// as possible before giving up; this may not always be the case for + /// skip() implementations in subclasses of . + /// + /// + /// Note that the implementation uses rather + /// than delegating to . + /// This means that the method may be considerably less efficient than using the actual skip implementation, + /// this is done to guarantee that the correct number of bytes are skipped. + /// + /// + /// + /// + /// This mimics POI's . + /// If the end of file is reached before any bytes are read, returns -1. If + /// the end of the file is reached After some bytes are read, returns the + /// number of bytes read. If the end of the file isn't reached before len + /// bytes have been read, will return len bytes. + /// + /// + /// + /// + /// Copied nearly verbatim from commons-io 41a3e9c + /// + /// + /// byte stream to skip + /// number of bytes to skip. + /// number of bytes actually skipped. + /// if there is a problem reading the file + /// if toSkip is negative + /// @see InputStream#skip(long) + /// + public static long SkipFully(InputStream input, long toSkip) + { + if (toSkip < 0) { + throw new ArgumentException("Skip count must be non-negative, actual: " + toSkip); + } + if (toSkip == 0) { + return 0L; + } + /* + * N.B. no need to synchronize this because: - we don't care if the buffer is created multiple times (the data + * is ignored) - we always use the same size buffer, so if it it is recreated it will still be OK (if the buffer + * size were variable, we would need to synch. to ensure some other thread did not create a smaller one) + */ + if (SKIP_BYTE_BUFFER == null) { + SKIP_BYTE_BUFFER = new byte[SKIP_BUFFER_SIZE]; + } + long remain = toSkip; + while (remain > 0) { + // See https://issues.apache.org/jira/browse/IO-203 for why we use read() rather than delegating to skip() + long n = input.Read(SKIP_BYTE_BUFFER, 0, (int) Math.Min(remain, SKIP_BUFFER_SIZE)); + if (n <= 0) { // EOF + break; + } + remain -= n; + } + if (toSkip == remain) { + return -1L; + } + return toSkip - remain; + } + public static byte[] SafelyAllocate(long length, int maxLength) { SafelyAllocateCheck(length, maxLength); diff --git a/ooxml/XSSF/Extractor/XSSFExportToXml.cs b/ooxml/XSSF/Extractor/XSSFExportToXml.cs index 0617542a9..9f9332c17 100644 --- a/ooxml/XSSF/Extractor/XSSFExportToXml.cs +++ b/ooxml/XSSF/Extractor/XSSFExportToXml.cs @@ -168,7 +168,7 @@ public void ExportToXML(Stream os, String encoding, bool validate) if (table != null) { - List tableColumns = table.GetCTTable().tableColumns.GetTableColumnList(); + List tableColumns = table.GetColumns(); XSSFSheet sheet = table.GetXSSFSheet(); @@ -185,25 +185,20 @@ public void ExportToXML(Stream os, String encoding, bool validate) XmlNode tableRootNode = GetNodeByXPath(table.GetCommonXpath(), doc.FirstChild, doc, true); short startColumnIndex = table.StartCellReference.Col; - for (int j = startColumnIndex; j <= table.EndCellReference.Col; j++) + + foreach (XSSFTableColumn tableColumn in tableColumns) { - XSSFCell cell = (XSSFCell)row.GetCell(j); + XSSFCell cell = (XSSFCell)row.GetCell(startColumnIndex + tableColumn.ColumnIndex); if (cell != null) { - int tableColumnIndex = j - startColumnIndex; - if(tableColumnIndex < tableColumns.Count) + XSSFXmlColumnPr xmlColumnPr = tableColumn.GetXmlColumnPr(); + if (xmlColumnPr != null) { - CT_TableColumn ctTableColumn = tableColumns[tableColumnIndex]; - if(ctTableColumn.xmlColumnPr != null) - { - XSSFXmlColumnPr pointer = new XSSFXmlColumnPr(table, ctTableColumn,ctTableColumn.xmlColumnPr); - String localXPath = pointer.LocalXPath; - XmlNode currentNode = GetNodeByXPath(localXPath,tableRootNode,doc,false); - XSSFExportToXml.mapCellOnNode(cell, currentNode); - } + String localXPath = xmlColumnPr.LocalXPath; + XmlNode currentNode = GetNodeByXPath(localXPath,tableRootNode,doc,false); + mapCellOnNode(cell, currentNode); } } - } } @@ -230,7 +225,7 @@ public void ExportToXML(Stream os, String encoding, bool validate) ///////////////// //Output the XML XmlWriterSettings settings = new XmlWriterSettings(); - //settings.OmitXmlDeclaration=false; + settings.OmitXmlDeclaration = true; settings.Indent=true; settings.Encoding=Encoding.GetEncoding(encoding); //create string from xml tree diff --git a/ooxml/XSSF/Streaming/SheetDataWriter.cs b/ooxml/XSSF/Streaming/SheetDataWriter.cs index 9bbac6b89..29b63e9fc 100644 --- a/ooxml/XSSF/Streaming/SheetDataWriter.cs +++ b/ooxml/XSSF/Streaming/SheetDataWriter.cs @@ -14,16 +14,17 @@ the License. You may obtain a copy of the License at See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - -using System; -using System.Globalization; -using System.IO; -using System.Text; +using NPOI.OpenXmlFormats.Spreadsheet; using NPOI.SS.UserModel; using NPOI.SS.Util; using NPOI.Util; using NPOI.XSSF.Model; using NPOI.XSSF.UserModel; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; namespace NPOI.XSSF.Streaming { @@ -44,13 +45,13 @@ public class SheetDataWriter : ICloseable * If two cells contain the same string, then the cell value is the same index into SharedStringsTable */ private readonly SharedStringsTable _sharedStringSource; - private readonly StreamWriter _outputWriter; + private readonly StreamWriter _out; public SheetDataWriter() { TemporaryFileInfo = CreateTempFile(); OutputStream = CreateWriter(TemporaryFileInfo); - _outputWriter = new StreamWriter(OutputStream); + _out = new StreamWriter(OutputStream); } public SheetDataWriter(SharedStringsTable sharedStringsTable) : this() { @@ -116,7 +117,7 @@ public void Close() { try { - _outputWriter.Dispose(); + _out.Dispose(); OutputStream.Dispose(); } catch @@ -206,63 +207,53 @@ public void FlushRows(int rowCount, int lastRowNum, int lastRowCellsCount) NumberLastFlushedRow = Math.Max(lastRowNum, NumberLastFlushedRow); NumberOfCellsOfLastFlushedRow = lastRowCellsCount; - _outputWriter.Flush(); + _out.Flush(); OutputStream.Flush(); } private void BeginRow(int rownum, SXSSFRow row) { - WriteAsBytes("\n"); + _out.Write("\n"); } - //TODO: Fix test case TestCases.XSSF.UserModel.TestEncodingBelowAscii + public void WriteCell(int columnIndex, ICell cell) { if (cell == null) @@ -270,34 +261,28 @@ public void WriteCell(int columnIndex, ICell cell) return; } var cellRef = new CellReference(RowNum, columnIndex).FormatAsString(); - WriteAsBytes(""); + _out.Write('>'); break; } case CellType.Formula: { - WriteAsBytes(">"); - WriteAsBytes(""); - + _out.Write(">"); OutputQuotedString(cell.CellFormula); - - WriteAsBytes(""); + _out.Write(""); switch (cell.CachedFormulaResultType) { @@ -305,9 +290,9 @@ public void WriteCell(int columnIndex, ICell cell) double nval = cell.NumericCellValue; if (!Double.IsNaN(nval)) { - WriteAsBytes(""); - WriteAsBytes(nval); - WriteAsBytes(""); + _out.Write(""); + _out.Write(nval.ToString(CultureInfo.InvariantCulture)); + _out.Write(""); } break; default: @@ -322,55 +307,53 @@ public void WriteCell(int columnIndex, ICell cell) XSSFRichTextString rt = new XSSFRichTextString(cell.StringCellValue); int sRef = _sharedStringSource.AddEntry(rt.GetCTRst()); - WriteAsBytes(" t=\""); - WriteAsBytes("s"); - WriteAsBytes("\">"); - WriteAsBytes(""); - WriteAsBytes(sRef); - WriteAsBytes(""); + WriteAttribute("t", ST_CellType.s.ToString()); + _out.Write(">"); + _out.Write(sRef.ToString()); + _out.Write(""); } else { - WriteAsBytes(" t=\"inlineStr\">"); - WriteAsBytes(""); + _out.Write(">"); OutputQuotedString(cell.StringCellValue); - WriteAsBytes(""); + _out.Write(""); } break; } case CellType.Numeric: { - WriteAsBytes(" t=\"n\">"); - WriteAsBytes(""); - WriteAsBytes(cell.NumericCellValue); - WriteAsBytes(""); + WriteAttribute("t", "n"); + _out.Write(">"); + _out.Write(cell.NumericCellValue.ToString(CultureInfo.InvariantCulture)); + _out.Write(""); break; } case CellType.Boolean: { - WriteAsBytes(" t=\"b\">"); - WriteAsBytes(""); - WriteAsBytes(cell.BooleanCellValue ? "1" : "0"); - WriteAsBytes(""); + WriteAttribute("t", "b"); + _out.Write(">"); + _out.Write(cell.BooleanCellValue ? "1" : "0"); + _out.Write(""); break; } case CellType.Error: { FormulaError error = FormulaError.ForInt(cell.ErrorCellValue); - WriteAsBytes(" t=\"e\">"); - WriteAsBytes(""); - WriteAsBytes(error.String); - WriteAsBytes(""); + WriteAttribute("t", "e"); + _out.Write(">"); + _out.Write(error.String); + _out.Write(""); break; } default: @@ -378,32 +361,16 @@ public void WriteCell(int columnIndex, ICell cell) throw new InvalidOperationException("Invalid cell type: " + cell.CellType); } } - WriteAsBytes(""); + _out.Write(""); } - private void WriteAsBytes(string text) + private void WriteAttribute(string name, string value) { - _outputWriter.Write(text); - } - - private void WriteAsBytes(ArraySegment chars) - { - _outputWriter.Write(chars.Array, chars.Offset, chars.Count); - } - - private void WriteAsBytes(int value) - { - _outputWriter.Write(value); - } - - private void WriteAsBytes(float value) - { - _outputWriter.Write(value.ToString(CultureInfo.InvariantCulture)); - } - - private void WriteAsBytes(double value) - { - _outputWriter.Write(value.ToString(CultureInfo.InvariantCulture)); + _out.Write(' '); + _out.Write(name); + _out.Write("=\""); + _out.Write(value); + _out.Write('\"'); } /** @@ -422,7 +389,7 @@ private static bool HasLeadingTrailingSpaces(string str) } //Taken from jdk1.3/src/javax/swing/text/html/HTMLWriter.java - protected internal void OutputQuotedString(string s) + internal void OutputQuotedString(string s) { if (string.IsNullOrEmpty(s)) { @@ -438,123 +405,90 @@ protected internal void OutputQuotedString(string s) switch (c) { case '<': - if (counter > last) - { - WriteAsBytes(GetSubArray(chars, last, counter - last)); - } + WriteLastChars(_out, chars, last, counter); last = counter + 1; - WriteAsBytes("<"); + _out.Write("<"); break; case '>': - if (counter > last) - { - WriteAsBytes(GetSubArray(chars, last, counter - last)); - } + WriteLastChars(_out, chars, last, counter); last = counter + 1; - WriteAsBytes(">"); + _out.Write(">"); break; case '&': - if (counter > last) - { - WriteAsBytes(GetSubArray(chars, last, counter - last)); - } + WriteLastChars(_out, chars, last, counter); last = counter + 1; - WriteAsBytes("&"); + _out.Write("&"); break; case '"': - if (counter > last) - { - WriteAsBytes(GetSubArray(chars, last, counter - last)); - } + WriteLastChars(_out, chars, last, counter); last = counter + 1; - WriteAsBytes("""); + _out.Write("""); break; // Special characters case '\n': - if(counter > last) - { - WriteAsBytes(GetSubArray(chars, last, counter - last)); - } - WriteAsBytes(" "); + WriteLastChars(_out, chars, last, counter); + _out.Write(" "); last = counter + 1; break; case '\r': - if (counter > last) - { - WriteAsBytes(GetSubArray(chars, last, counter - last)); - } - WriteAsBytes(" "); + WriteLastChars(_out, chars, last, counter); + _out.Write(" "); last = counter + 1; break; case '\t': - if (counter > last) - { - WriteAsBytes(GetSubArray(chars, last, counter - last)); - } - WriteAsBytes(" "); + WriteLastChars(_out, chars, last, counter); + _out.Write(" "); last = counter + 1; break; case (char)0xa0: - if (counter > last) - { - WriteAsBytes(GetSubArray(chars, last, counter - last)); - } - WriteAsBytes(" "); + WriteLastChars(_out, chars, last, counter); + _out.Write(" "); last = counter + 1; break; default: // YK: XmlBeans silently replaces all ISO control characters ( < 32) with question marks. // the same rule applies to unicode surrogates and "not a character" symbols. - if (ReplaceWithQuestionMark(c)) + if (ReplaceWithQuestionMark(c)) { - if (counter > last) - { - WriteAsBytes(GetSubArray(chars, last, counter - last)); - } - WriteAsBytes("?"); + WriteLastChars(_out, chars, last, counter); + _out.Write('?'); last = counter + 1; } - else if (Char.IsLowSurrogate(c) || Char.IsHighSurrogate(c)) + else if (Char.IsHighSurrogate(c) || Char.IsLowSurrogate(c)) { - if (counter > last) - { - WriteAsBytes(GetSubArray(chars, last, counter - last)); - } - //WriteAsBytes(c); - _outputWriter.Write(c); + WriteLastChars(_out, chars, last, counter); + _out.Write(c); last = counter + 1; } else if (c > 127) { - if (counter > last) - { - WriteAsBytes(GetSubArray(chars, last, counter - last)); - } + WriteLastChars(_out, chars, last, counter); last = counter + 1; - // If the character is outside of UTF8, write the + // If the character is outside of ascii, write the // numeric value. - WriteAsBytes("&#"); - WriteAsBytes(c); - WriteAsBytes(";"); + _out.Write("&#"); + _out.Write(((int) c).ToString()); + _out.Write(";"); } break; } } if (last < length) { - WriteAsBytes(GetSubArray(chars, last, length - last)); + _out.Write(chars, last, length - last); } } - - private static ArraySegment GetSubArray(char[] oldArray, int skip, int take) - { - return new ArraySegment(oldArray, skip, take); + internal static bool ReplaceWithQuestionMark(char c) { + return c < ' ' || ('\uFFFE' <= c && c <= '\uFFFF'); } - public static bool ReplaceWithQuestionMark(char c) + private static void WriteLastChars(StreamWriter out1, char[] chars, int last, int counter) { - return c < ' ' || ('\uFFFE' <= c && c <= '\uFFFF'); + if (counter > last) { + out1.Write(chars, last, counter - last); + } } + /** * Deletes the temporary file that backed this sheet on disk. * @return true if the file was deleted, false if it wasn't. @@ -564,7 +498,7 @@ public bool Dispose() bool ret; try { - _outputWriter.Close(); + _out.Close(); OutputStream.Close(); } finally diff --git a/ooxml/XSSF/UserModel/XSSFSheet.cs b/ooxml/XSSF/UserModel/XSSFSheet.cs index 9ec08bef1..347998910 100644 --- a/ooxml/XSSF/UserModel/XSSFSheet.cs +++ b/ooxml/XSSF/UserModel/XSSFSheet.cs @@ -1777,10 +1777,8 @@ public void AutoSizeColumn(int column, bool useMergedCells) { width = maxColumnWidth; } - - IColumn col = GetColumn(column, true); - col.Width = width / 256; - col.IsBestFit = true; + SetColumnWidth(column, width); + columnHelper.SetColBestFit(column, true); } } diff --git a/testcases/main/POIFS/FileSystem/TestNotOLE2Exception.cs b/testcases/main/POIFS/FileSystem/TestNotOLE2Exception.cs new file mode 100644 index 000000000..f8836cdd2 --- /dev/null +++ b/testcases/main/POIFS/FileSystem/TestNotOLE2Exception.cs @@ -0,0 +1,123 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace TestCases.POIFS.FileSystem +{ + using NPOI.HSSF; + using NPOI.POIFS.FileSystem; + using NPOI.Util; + using NUnit.Framework; + using NUnit.Framework.Legacy; + using TestCases.HSSF; + + /// + /// Class to test that POIFS complains when given older non-OLE2 + /// formats. See also for OOXML + /// checks + /// + [TestFixture] + public class TestNotOLE2Exception + { + private static Stream OpenXLSSampleStream(string sampleFileName) + { + return HSSFTestDataSamples.OpenSampleFileStream(sampleFileName); + } + private static Stream OpenDOCSampleStream(string sampleFileName) + { + return POIDataSamples.GetDocumentInstance().OpenResourceAsStream(sampleFileName); + } + + [Test] + public void TestRawXMLException() + { + Stream in1 = OpenXLSSampleStream("SampleSS.xml"); + + try + { + new POIFSFileSystem(in1).Close(); + ClassicAssert.Fail("expected exception was not thrown"); + } + catch(NotOLE2FileException e) + { + // expected during successful test + POITestCase.AssertContains(e.Message, "The supplied data appears to be a raw XML file"); + POITestCase.AssertContains(e.Message, "Formats such as Office 2003 XML"); + } + } + + [Test] + public void TestMSWriteException() + { + Stream in1 = OpenDOCSampleStream("MSWriteOld.wri"); + + try + { + new POIFSFileSystem(in1).Close(); + ClassicAssert.Fail("expected exception was not thrown"); + } + catch(NotOLE2FileException e) + { + // expected during successful test + POITestCase.AssertContains(e.Message, "The supplied data appears to be in the old MS Write"); + POITestCase.AssertContains(e.Message, "doesn't currently support"); + } + } + + [Test] + public void TestBiff3Exception() + { + Stream in1 = OpenXLSSampleStream("testEXCEL_3.xls"); + + try + { + new POIFSFileSystem(in1).Close(); + ClassicAssert.Fail("expected exception was not thrown"); + } + catch(OldExcelFormatException e) + { + // expected during successful test + POITestCase.AssertContains(e.Message, "The supplied data appears to be in BIFF3 format"); + POITestCase.AssertContains(e.Message, "try OldExcelExtractor"); + } + } + + [Test] + public void TestBiff4Exception() + { + Stream in1 = OpenXLSSampleStream("testEXCEL_4.xls"); + + try + { + new POIFSFileSystem(in1).Close(); + ClassicAssert.Fail("expected exception was not thrown"); + } + catch(OldExcelFormatException e) + { + // expected during successful test + POITestCase.AssertContains(e.Message, "The supplied data appears to be in BIFF4 format"); + POITestCase.AssertContains(e.Message, "try OldExcelExtractor"); + } + } + } +} diff --git a/testcases/main/POIFS/FileSystem/TestOffice2007XMLException.cs b/testcases/main/POIFS/FileSystem/TestOffice2007XMLException.cs index 4cd165184..97373baa7 100644 --- a/testcases/main/POIFS/FileSystem/TestOffice2007XMLException.cs +++ b/testcases/main/POIFS/FileSystem/TestOffice2007XMLException.cs @@ -97,6 +97,14 @@ public void TestDetectAsPOIFS() // xls file is ConfirmIsPOIFS("SampleSS.xls", true); + // older biff formats aren't + ConfirmIsPOIFS("testEXCEL_3.xls", false); + ConfirmIsPOIFS("testEXCEL_4.xls", false); + + // newer excel formats are + ConfirmIsPOIFS("testEXCEL_5.xls", true); + ConfirmIsPOIFS("testEXCEL_95.xls", true); + // text file isn't ConfirmIsPOIFS("SampleSS.txt", false); } diff --git a/testcases/main/SS/UserModel/BaseTestBugzillaIssues.cs b/testcases/main/SS/UserModel/BaseTestBugzillaIssues.cs index 7e244f25a..350e09e4f 100644 --- a/testcases/main/SS/UserModel/BaseTestBugzillaIssues.cs +++ b/testcases/main/SS/UserModel/BaseTestBugzillaIssues.cs @@ -649,6 +649,7 @@ public void Bug51024() } [Test] + [Platform("Win")] public void Stackoverflow23114397() { IWorkbook wb = _testDataProvider.CreateWorkbook(); diff --git a/testcases/main/Util/TestIOUtils.cs b/testcases/main/Util/TestIOUtils.cs new file mode 100644 index 000000000..5c08289bd --- /dev/null +++ b/testcases/main/Util/TestIOUtils.cs @@ -0,0 +1,260 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace TestCases.Util +{ + using NPOI; + using NPOI.Util; + using NUnit.Framework; + using NUnit.Framework.Legacy; + /// + /// Class to test IOUtils + /// + [TestFixture] + public class TestIOUtils + { + + static FileInfo TMP = null; + static long LENGTH = new Random().Next(10000); + + [SetUp] + public void SetUp() + { + TMP = TempFile.CreateTempFile("poi-ioutils-", ""); + Stream os = TMP.Open(FileMode.OpenOrCreate); + for(int i = 0; i < LENGTH; i++) + { + os.WriteByte(0x01); + } + os.Flush(); + os.Close(); + + } + + [TearDown] + public void TearDown() + { + //noinspection ResultOfMethodCallIgnored + TMP.Delete(); + } + + [Test] + public void TestPeekFirst8Bytes() + { + ClassicAssert.IsTrue(Arrays.Equals(Encoding.UTF8.GetBytes("01234567"), + IOUtils.PeekFirst8Bytes(new ByteArrayInputStream(Encoding.UTF8.GetBytes("01234567"))))); + } + + [Test] + public void TestPeekFirst8BytesWithPushbackInputStream() + { + ClassicAssert.IsTrue(Arrays.Equals(Encoding.UTF8.GetBytes("01234567"), + IOUtils.PeekFirst8Bytes(new PushbackInputStream(new ByteArrayInputStream(Encoding.UTF8.GetBytes("01234567")), 8)))); + } + + [Test] + public void TestPeekFirst8BytesTooLessAvailable() + { + ClassicAssert.IsTrue(Arrays.Equals(new byte[] { 1, 2, 3, 0, 0, 0, 0, 0 }, + IOUtils.PeekFirst8Bytes(new ByteArrayInputStream(new byte[] { 1, 2, 3 }))) + ); + } + + [Test] + public void TestPeekFirst8BytesEmpty() + { + Assert.Throws(() => + IOUtils.PeekFirst8Bytes(new ByteArrayInputStream(new byte[] { })) + ); + } + + [Test] + public void TestToByteArray() + { + ClassicAssert.IsTrue(Arrays.Equals(new byte[] { 1, 2, 3 }, + IOUtils.ToByteArray(new MemoryStream(new byte[] { 1, 2, 3 }))) + ); + } + + [Test] + public void TestToByteArrayToSmall() + { + ClassicAssert.Throws(() => + ClassicAssert.IsTrue(Arrays.Equals(new byte[] { 1, 2, 3 }, + IOUtils.ToByteArray(new MemoryStream(new byte[] { 1, 2, 3 }), 10))) + ); + } + + [Test] + public void TestToByteArrayByteBuffer() + { + ClassicAssert.IsTrue(Arrays.Equals(new byte[] { 1, 2, 3 }, + IOUtils.ToByteArray(new ByteBuffer(new byte[] { 1, 2, 3 }, 0, 3), 10))); + } + + [Test] + public void TestToByteArrayByteBufferToSmall() + { + ClassicAssert.IsTrue(Arrays.Equals(new byte[] { 1, 2, 3, 4, 5, 6, 7 }, + IOUtils.ToByteArray(new ByteBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7 }, 0, 7), 3))); + } + + [Test] + public void TestSkipFully() + { + using InputStream is1 = new FileInputStream(TMP.Open(FileMode.OpenOrCreate)); + long skipped = IOUtils.SkipFully(is1, 20000L); + ClassicAssert.AreEqual(LENGTH, skipped, "length: "+LENGTH); + } + + [Test] + public void TestSkipFullyGtIntMax() + { + using InputStream is1 = new FileInputStream(TMP.Open(FileMode.OpenOrCreate)); + long skipped = IOUtils.SkipFully(is1, Int32.MaxValue + 20000L); + ClassicAssert.AreEqual(LENGTH, skipped, "length: "+LENGTH); + } + + [Test] + public void TestSkipFullyByteArray() + { + using MemoryStream bos = new MemoryStream(); + using InputStream is1 = new FileInputStream(TMP.Open(FileMode.OpenOrCreate)); + IOUtils.Copy(is1, bos); + long skipped = IOUtils.SkipFully(new ByteArrayInputStream(bos.ToArray()), 20000L); + ClassicAssert.AreEqual(LENGTH, skipped, "length: "+LENGTH); + } + + [Test] + public void TestSkipFullyByteArrayGtIntMax() + { + using MemoryStream bos = new MemoryStream(); + using InputStream is1 = new FileInputStream(TMP.Open(FileMode.OpenOrCreate)); + IOUtils.Copy(is1, bos); + long skipped = IOUtils.SkipFully(new ByteArrayInputStream(bos.ToArray()), Int32.MaxValue+ 20000L); + ClassicAssert.AreEqual(LENGTH, skipped, "length: "+LENGTH); + } + + [Test] + public void TestSkipFullyBug61294() + { + IOUtils.SkipFully(new ByteArrayInputStream(new byte[0]), 1); + } + + [Test] + public void TestZeroByte() + { + long skipped = IOUtils.SkipFully((new ByteArrayInputStream(new byte[0])), 100); + ClassicAssert.AreEqual(-1L, skipped, "zero byte"); + } + + [Test] + public void TestSkipZero() + { + using InputStream is1 = new FileInputStream(TMP.Open(FileMode.OpenOrCreate)); + long skipped = IOUtils.SkipFully(is1, 0); + ClassicAssert.AreEqual(0, skipped, "zero length"); + } + [Test] + public void TestSkipNegative() + { + ClassicAssert.Throws(() => + { + using InputStream is1 = new FileInputStream(TMP.Open(FileMode.OpenOrCreate)); + IOUtils.SkipFully(is1, -1); + }); + } + + [Test] + public void TestWonkyInputStream() + { + long skipped = IOUtils.SkipFully(new WonkyInputStream(), 10000); + ClassicAssert.AreEqual(10000, skipped, "length: "+LENGTH); + } + + /// + /// This returns 0 for the first call to skip and then reads + /// as requested. This tests that the fallback to read() works. + /// + private class WonkyInputStream : InputStream + { + int skipCalled = 0; + int readCalled = 0; + + public override bool CanRead => throw new NotImplementedException(); + + public override bool CanSeek => throw new NotImplementedException(); + + public override long Length => throw new NotImplementedException(); + + public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + public override int Read() + { + readCalled++; + return 0; + } + public override int Read(byte[] arr, int offset, int len) + { + readCalled++; + return len; + } + public override long Skip(long len) + { + skipCalled++; + if(skipCalled == 1) + { + return 0; + } + else if(skipCalled > 100) + { + return len; + } + else + { + return 100; + } + } + public override int Available() + { + return 100000; + } + + public override void Flush() + { + throw new NotImplementedException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } + + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + } + } +} diff --git a/testcases/ooxml/XSSF/Extractor/TestXSSFExportToXML.cs b/testcases/ooxml/XSSF/Extractor/TestXSSFExportToXML.cs index 2e70ed605..7e7bad43e 100644 --- a/testcases/ooxml/XSSF/Extractor/TestXSSFExportToXML.cs +++ b/testcases/ooxml/XSSF/Extractor/TestXSSFExportToXML.cs @@ -669,6 +669,20 @@ public void TestBug59026() ClassicAssert.IsNotNull(os.ToString("utf-8")); } } + + [Test] + public void TestExportTableWithNonMappedColumn_Bugzilla_61281() { + XSSFWorkbook wb = XSSFTestDataSamples.OpenSampleWorkbook("61281.xlsx"); + foreach (XSSFMap map in wb.GetCustomXMLMappings()) + { + XSSFExportToXml exporter = new XSSFExportToXml(map); + MemoryStream bos = new MemoryStream(); + exporter.ExportToXML(bos, true); + ClassicAssert.IsNotNull(DocumentHelper.ReadDocument(new MemoryStream(bos.ToArray()))); + string exportedXml = bos.ToString("UTF-8"); + ClassicAssert.AreEqual("1", Regex.Replace(exportedXml, "\\s+", "")); + } + } } public static class TestExtensions diff --git a/testcases/ooxml/XSSF/Streaming/SheetDataWriterTests.cs b/testcases/ooxml/XSSF/Streaming/SheetDataWriterTests.cs index ff3494584..38a43ba3c 100644 --- a/testcases/ooxml/XSSF/Streaming/SheetDataWriterTests.cs +++ b/testcases/ooxml/XSSF/Streaming/SheetDataWriterTests.cs @@ -31,7 +31,7 @@ public class SheetDataWriterTests private SheetDataWriter _objectToTest; private SXSSFRow _row; private ICell _cell; - + private ICellStyle _cellStyle; [SetUp] public void Init() { @@ -40,6 +40,7 @@ public void Init() var _workbook = Substitute.For(); var _sheet = Substitute.For(_workbook, _xssfsheet); _row = Substitute.For(_sheet); + _cellStyle = _workbook.CreateCellStyle(); _cell = Substitute.For(); } @@ -77,7 +78,7 @@ public void IfWritingRowWithCustomHeightShouldIncludeCustomHeightXml() var lines = File.ReadAllLines(_objectToTest.TemporaryFilePath()); ClassicAssert.True(lines.Length == 2); - ClassicAssert.AreEqual($"", lines[0]); + ClassicAssert.AreEqual($"", lines[0]); ClassicAssert.AreEqual("", lines[1]); } @@ -95,7 +96,7 @@ public void IfWritingRowWithZeroHeightShouldIncludeHiddenAttributeXml() var lines = File.ReadAllLines(_objectToTest.TemporaryFilePath()); ClassicAssert.True(lines.Length == 2); - ClassicAssert.AreEqual("