This mostly only makes thrown exceptions a bit more consistent or may allow some broken documents to be still read. git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1906322 13f79535-47bb-0310-9956-ffa450edef68tags/REL_5_2_4
@@ -224,6 +224,9 @@ public class ReadOnlySharedStringsTable extends DefaultHandler implements Shared | |||
@Override | |||
public RichTextString getItemAt(int idx) { | |||
if (strings == null || idx >= strings.size()) { | |||
throw new IllegalStateException("Cannot get item at " + idx + " with strings: " + strings); | |||
} | |||
return new XSSFRichTextString(strings.get(idx)); | |||
} | |||
@@ -300,6 +300,9 @@ public class XSSFReader { | |||
* @throws IOException if there is an I/O issue reading the data | |||
*/ | |||
protected SheetIterator(PackagePart wb) throws IOException, InvalidFormatException { | |||
if (wb == null) { | |||
throw new InvalidFormatException("Cannot create sheet-iterator with missing package part for workbook"); | |||
} | |||
/* | |||
* The order of sheets is defined by the order of CTSheet elements in workbook.xml |
@@ -3751,6 +3751,10 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet, OoxmlSheetEx | |||
} | |||
protected void write(OutputStream out) throws IOException { | |||
if (worksheet == null) { | |||
throw new POIXMLException("Cannot write invalid sheet, internal data is missing"); | |||
} | |||
boolean setToNull = false; | |||
if(worksheet.sizeOfColsArray() == 1) { | |||
CTCols col = worksheet.getColsArray(0); |
@@ -59,6 +59,10 @@ public class XWPFComments extends POIXMLDocumentPart { | |||
*/ | |||
public XWPFComments(POIXMLDocumentPart parent, PackagePart part) { | |||
super(parent, part); | |||
if (!(getParent() instanceof XWPFDocument)) { | |||
throw new IllegalStateException("Parent is not a XWPFDocuemnt: " + getParent()); | |||
} | |||
this.document = (XWPFDocument) getParent(); | |||
if (this.document == null) { |
@@ -32,6 +32,11 @@ public class XWPFPicture { | |||
public XWPFPicture(CTPicture ctPic, XWPFRun run) { | |||
this.run = run; | |||
this.ctPic = ctPic; | |||
if (ctPic == null || ctPic.getNvPicPr() == null || ctPic.getNvPicPr().getCNvPr() == null) { | |||
throw new IllegalArgumentException("Found missing data while reading picture data from " + ctPic); | |||
} | |||
description = ctPic.getNvPicPr().getCNvPr().getDescr(); | |||
} | |||
@@ -82,8 +82,11 @@ public final class HDGFDiagram extends POIReadOnlyDocument { | |||
trailerPointer = ptrFactory.createPointer(_docstream, 0x24); | |||
// Now grab the trailer | |||
trailer = (TrailerStream) | |||
Stream.createStream(trailerPointer, _docstream, chunkFactory, ptrFactory); | |||
Stream stream = Stream.createStream(trailerPointer, _docstream, chunkFactory, ptrFactory); | |||
if (!(stream instanceof TrailerStream)) { | |||
throw new IllegalStateException("Stream is not a TrailerStream: " + stream); | |||
} | |||
trailer = (TrailerStream)stream; | |||
// Finally, find all our streams | |||
trailer.findChildren(_docstream); |
@@ -82,9 +82,8 @@ public class HSLFTabStopPropCollection extends TextProp { | |||
leo.writeShort(count); | |||
for (HSLFTabStop ts : tabStops) { | |||
leo.writeShort(ts.getPosition()); | |||
leo.writeShort(ts.getType().nativeId); | |||
leo.writeShort(ts.getType() == null ? TabStopType.LEFT.nativeId : ts.getType().nativeId); | |||
} | |||
} | |||
@Override |
@@ -128,7 +128,7 @@ public class SlideAtomLayout implements GenericRecord { | |||
public void writeOut(OutputStream out) throws IOException { | |||
// Write the geometry | |||
byte[] buf = new byte[4]; | |||
LittleEndian.putInt(buf, 0, geometry.getNativeId()); | |||
LittleEndian.putInt(buf, 0, geometry == null ? 0 : geometry.getNativeId()); | |||
out.write(buf); | |||
// Write the placeholder IDs | |||
out.write(placeholderIDs); |
@@ -318,10 +318,14 @@ public final class HSLFSlideShowImpl extends POIDocument implements Closeable { | |||
recordMap.put(usrOffset, usr); | |||
int psrOffset = usr.getPersistPointersOffset(); | |||
PersistPtrHolder ptr = (PersistPtrHolder) Record.buildRecordAtOffset(docstream, psrOffset); | |||
if (ptr == null) { | |||
Record record = Record.buildRecordAtOffset(docstream, psrOffset); | |||
if (record == null) { | |||
throw new CorruptPowerPointFileException("Powerpoint document is missing a PersistPtrHolder at " + psrOffset); | |||
} | |||
if (!(record instanceof PersistPtrHolder)) { | |||
throw new CorruptPowerPointFileException("Record is not a PersistPtrHolder: " + record + " at " + psrOffset); | |||
} | |||
PersistPtrHolder ptr = (PersistPtrHolder) record; | |||
recordMap.put(psrOffset, ptr); | |||
for (Map.Entry<Integer, Integer> entry : ptr.getSlideLocationsLookup().entrySet()) { | |||
@@ -609,6 +613,9 @@ public final class HSLFSlideShowImpl extends POIDocument implements Closeable { | |||
CountingOS cos = new CountingOS(); | |||
for (Record record : _records) { | |||
// all top level records are position dependent | |||
if (!(record instanceof PositionDependentRecord)) { | |||
throw new CorruptPowerPointFileException("Record is not a position dependent record: " + record); | |||
} | |||
PositionDependentRecord pdr = (PositionDependentRecord) record; | |||
int oldPos = pdr.getLastOnDiskOffset(); | |||
int newPos = cos.size(); | |||
@@ -987,6 +994,10 @@ public final class HSLFSlideShowImpl extends POIDocument implements Closeable { | |||
throw new CorruptPowerPointFileException("Document record is missing"); | |||
} | |||
if (documentRecord.getPPDrawingGroup() == null) { | |||
throw new CorruptPowerPointFileException("Drawing group is missing"); | |||
} | |||
EscherContainerRecord blipStore; | |||
EscherContainerRecord dggContainer = documentRecord.getPPDrawingGroup().getDggContainer(); |
@@ -24,6 +24,7 @@ import java.io.InputStream; | |||
import java.text.SimpleDateFormat; | |||
import java.util.Arrays; | |||
import java.util.Collections; | |||
import java.util.Date; | |||
import java.util.Iterator; | |||
import java.util.Locale; | |||
@@ -127,7 +128,7 @@ public class OutlookTextExtractor implements POIOLE2TextExtractor { | |||
// First try via the proper chunk | |||
SimpleDateFormat f = new SimpleDateFormat("E, d MMM yyyy HH:mm:ss Z", Locale.ROOT); | |||
f.setTimeZone(LocaleUtil.getUserTimeZone()); | |||
s.append("Date: ").append(f.format(msg.getMessageDate().getTime())).append("\n"); | |||
s.append("Date: ").append(f.format(msg.getMessageDate() == null ? new Date(0) : msg.getMessageDate().getTime())).append("\n"); | |||
} catch (ChunkNotFoundException e) { | |||
try { | |||
// Failing that try via the raw headers |
@@ -142,7 +142,7 @@ public class Sttb | |||
// cchData | |||
size += LittleEndianConsts.SHORT_SIZE; | |||
// data | |||
size += 2 * data.length(); | |||
size += 2 * (data == null ? 0 : data.length()); | |||
} | |||
} | |||
else | |||
@@ -152,7 +152,7 @@ public class Sttb | |||
// cchData | |||
size += LittleEndianConsts.BYTE_SIZE; | |||
// data | |||
size += data.length(); | |||
size += (data == null ? 0 : data.length()); | |||
} | |||
} | |||
@@ -81,7 +81,12 @@ final class LinkTable { | |||
int nCRNs = _countRecord.getNumberOfCRNs(); | |||
CRNRecord[] crns = new CRNRecord[nCRNs]; | |||
for (int i = 0; i < crns.length; i++) { | |||
crns[i] = (CRNRecord) rs.getNext(); | |||
Record record = rs.getNext(); | |||
if (!(record instanceof CRNRecord)) { | |||
throw new IllegalStateException("Record is not a CRNRecord: " + | |||
(record == null ? "<null>" : record.getClass() + ": " + record) ); | |||
} | |||
crns[i] = (CRNRecord) record; | |||
} | |||
_crns = crns; | |||
} |
@@ -44,7 +44,7 @@ public class AgileEncryptionVerifier extends EncryptionVerifier { | |||
} | |||
} | |||
if (keyData == null) { | |||
if (keyData == null || keyData.getHashSize() == null) { | |||
throw new IllegalArgumentException("encryptedKey not set"); | |||
} | |||
@@ -105,12 +105,16 @@ public final class PropertyTable implements BATManaged { | |||
PropertyFactory.convertToProperties(data, _properties); | |||
} | |||
if (_properties.get(0) != null) { | |||
populatePropertyTree((DirectoryProperty) _properties.get(0)); | |||
Property property = _properties.get(0); | |||
if (property != null) { | |||
if (property instanceof DirectoryProperty) { | |||
populatePropertyTree((DirectoryProperty) property); | |||
} else { | |||
throw new IOException("Invalid format, cannot convert property " + property + " to DirectoryProperty"); | |||
} | |||
} | |||
} | |||
/** | |||
* Add a property to the list of properties we manage | |||
* |
@@ -371,6 +371,10 @@ public class DataFormatter { | |||
} | |||
private Format getFormat(double cellValue, int formatIndex, String formatStrIn, boolean use1904Windowing) { | |||
if (formatStrIn == null) { | |||
throw new IllegalArgumentException("Missing input format for value " + cellValue + " and index " + formatIndex); | |||
} | |||
checkForLocaleChange(); | |||
// Might be better to separate out the n p and z formats, falling back to p when n and z are not set. |
@@ -22,8 +22,11 @@ import static org.junit.jupiter.api.Assertions.assertNotEquals; | |||
import static org.junit.jupiter.api.Assertions.assertNotNull; | |||
import static org.junit.jupiter.api.Assertions.assertNull; | |||
import static org.junit.jupiter.api.Assertions.assertSame; | |||
import static org.junit.jupiter.api.Assertions.assertThrows; | |||
import static org.junit.jupiter.api.Assertions.assertTrue; | |||
import java.io.ByteArrayInputStream; | |||
import java.io.IOException; | |||
import java.util.Arrays; | |||
import java.util.Collections; | |||
import java.util.LinkedHashMap; | |||
@@ -32,6 +35,7 @@ import java.util.Map; | |||
import org.apache.poi.hssf.HSSFTestDataSamples; | |||
import org.apache.poi.hssf.record.BOFRecord; | |||
import org.apache.poi.hssf.record.CRNCountRecord; | |||
import org.apache.poi.hssf.record.CountryRecord; | |||
import org.apache.poi.hssf.record.EOFRecord; | |||
import org.apache.poi.hssf.record.ExternSheetRecord; | |||
@@ -39,11 +43,13 @@ import org.apache.poi.hssf.record.ExternalNameRecord; | |||
import org.apache.poi.hssf.record.NameCommentRecord; | |||
import org.apache.poi.hssf.record.NameRecord; | |||
import org.apache.poi.hssf.record.Record; | |||
import org.apache.poi.hssf.record.RecordInputStream; | |||
import org.apache.poi.hssf.record.SSTRecord; | |||
import org.apache.poi.hssf.record.SupBookRecord; | |||
import org.apache.poi.hssf.usermodel.HSSFCell; | |||
import org.apache.poi.hssf.usermodel.HSSFWorkbook; | |||
import org.apache.poi.ss.formula.ptg.NameXPtg; | |||
import org.apache.poi.util.LittleEndian; | |||
import org.junit.jupiter.api.Test; | |||
/** | |||
@@ -51,7 +57,7 @@ import org.junit.jupiter.api.Test; | |||
*/ | |||
final class TestLinkTable { | |||
/** | |||
/* | |||
* The example file attached to bugzilla 45046 is a clear example of Name records being present | |||
* without an External Book (SupBook) record. Excel has no trouble reading this file.<br> | |||
* TODO get OOO documentation updated to reflect this (that EXTERNALBOOK is optional). | |||
@@ -59,61 +65,64 @@ final class TestLinkTable { | |||
* It's not clear what exact steps need to be taken in Excel to create such a workbook | |||
*/ | |||
@Test | |||
void testLinkTableWithoutExternalBookRecord_bug45046() { | |||
void testLinkTableWithoutExternalBookRecord_bug45046() throws IOException { | |||
// Bug 45046 b: DEFINEDNAME is part of LinkTable | |||
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("ex45046-21984.xls"); | |||
// some other sanity checks | |||
assertEquals(3, wb.getNumberOfSheets()); | |||
String formula = wb.getSheetAt(0).getRow(4).getCell(13).getCellFormula(); | |||
try (HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("ex45046-21984.xls")) { | |||
// some other sanity checks | |||
assertEquals(3, wb.getNumberOfSheets()); | |||
String formula = wb.getSheetAt(0).getRow(4).getCell(13).getCellFormula(); | |||
// The reported symptom of this bugzilla is an earlier bug (already fixed) | |||
// This is observable in version 3.0 | |||
assertNotEquals("ipcSummenproduktIntern($P5,N$6,$A$9,N$5)", formula); | |||
// The reported symptom of this bugzilla is an earlier bug (already fixed) | |||
// This is observable in version 3.0 | |||
assertNotEquals("ipcSummenproduktIntern($P5,N$6,$A$9,N$5)", formula); | |||
assertEquals("ipcSummenproduktIntern($C5,N$2,$A$9,N$1)", formula); | |||
assertEquals("ipcSummenproduktIntern($C5,N$2,$A$9,N$1)", formula); | |||
} | |||
} | |||
@Test | |||
void testMultipleExternSheetRecords_bug45698() { | |||
void testMultipleExternSheetRecords_bug45698() throws IOException { | |||
// Bug: Extern sheet is part of LinkTable | |||
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("ex45698-22488.xls"); | |||
// some other sanity checks | |||
assertEquals(7, wb.getNumberOfSheets()); | |||
try (HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("ex45698-22488.xls")) { | |||
// some other sanity checks | |||
assertEquals(7, wb.getNumberOfSheets()); | |||
} | |||
} | |||
@Test | |||
void testExtraSheetRefs_bug45978() { | |||
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("ex45978-extraLinkTableSheets.xls"); | |||
/* | |||
ex45978-extraLinkTableSheets.xls is a cut-down version of attachment 22561. | |||
The original file produces the same error. | |||
This bug was caused by a combination of invalid sheet indexes in the EXTERNSHEET | |||
record, and eager initialisation of the extern sheet references. Note - the workbook | |||
has 2 sheets, but the EXTERNSHEET record refers to sheet indexes 0, 1 and 2. | |||
Offset 0x3954 (14676) | |||
recordid = 0x17, size = 32 | |||
[EXTERNSHEET] | |||
numOfRefs = 5 | |||
refrec #0: extBook=0 firstSheet=0 lastSheet=0 | |||
refrec #1: extBook=1 firstSheet=2 lastSheet=2 | |||
refrec #2: extBook=2 firstSheet=1 lastSheet=1 | |||
refrec #3: extBook=0 firstSheet=-1 lastSheet=-1 | |||
refrec #4: extBook=0 firstSheet=1 lastSheet=1 | |||
[/EXTERNSHEET] | |||
As it turns out, the formula in question doesn't even use externSheetIndex #1 - it | |||
uses #4, which resolves to sheetIndex 1 -> 'Data'. | |||
It is not clear exactly what externSheetIndex #4 would refer to. Excel seems to | |||
display such a formula as "''!$A2", but then complains of broken link errors. | |||
*/ | |||
HSSFCell cell = wb.getSheetAt(0).getRow(1).getCell(1); | |||
// Bug: IndexOutOfBoundsException - Index: 2, Size: 2 | |||
String cellFormula = cell.getCellFormula(); | |||
assertEquals("Data!$A2", cellFormula); | |||
void testExtraSheetRefs_bug45978() throws IOException { | |||
try (HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("ex45978-extraLinkTableSheets.xls")) { | |||
/* | |||
ex45978-extraLinkTableSheets.xls is a cut-down version of attachment 22561. | |||
The original file produces the same error. | |||
This bug was caused by a combination of invalid sheet indexes in the EXTERNSHEET | |||
record, and eager initialisation of the extern sheet references. Note - the workbook | |||
has 2 sheets, but the EXTERNSHEET record refers to sheet indexes 0, 1 and 2. | |||
Offset 0x3954 (14676) | |||
recordid = 0x17, size = 32 | |||
[EXTERNSHEET] | |||
numOfRefs = 5 | |||
refrec #0: extBook=0 firstSheet=0 lastSheet=0 | |||
refrec #1: extBook=1 firstSheet=2 lastSheet=2 | |||
refrec #2: extBook=2 firstSheet=1 lastSheet=1 | |||
refrec #3: extBook=0 firstSheet=-1 lastSheet=-1 | |||
refrec #4: extBook=0 firstSheet=1 lastSheet=1 | |||
[/EXTERNSHEET] | |||
As it turns out, the formula in question doesn't even use externSheetIndex #1 - it | |||
uses #4, which resolves to sheetIndex 1 -> 'Data'. | |||
It is not clear exactly what externSheetIndex #4 would refer to. Excel seems to | |||
display such a formula as "''!$A2", but then complains of broken link errors. | |||
*/ | |||
HSSFCell cell = wb.getSheetAt(0).getRow(1).getCell(1); | |||
// Bug: IndexOutOfBoundsException - Index: 2, Size: 2 | |||
String cellFormula = cell.getCellFormula(); | |||
assertEquals("Data!$A2", cellFormula); | |||
} | |||
} | |||
/** | |||
@@ -122,7 +131,6 @@ final class TestLinkTable { | |||
*/ | |||
@Test | |||
void testMissingExternSheetRecord_bug47001b() { | |||
Record[] recs = { | |||
SupBookRecord.createAddInFunctions(), | |||
new SSTRecord(), | |||
@@ -136,8 +144,30 @@ final class TestLinkTable { | |||
} | |||
@Test | |||
void testNameCommentRecordBetweenNameRecords() { | |||
void testCRNCountRecordInvalid() { | |||
byte[] data = new byte[22]; | |||
LittleEndian.putShort(data, 0, CRNCountRecord.sid); | |||
LittleEndian.putShort(data, 2, (short)18); | |||
LittleEndian.putShort(data, 4, (short)55); | |||
LittleEndian.putInt(data, 6, 56); | |||
RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(data)); | |||
in.nextRecord(); | |||
Record[] recs = { | |||
SupBookRecord.createAddInFunctions(), | |||
new CRNCountRecord(in), | |||
new SSTRecord(), | |||
}; | |||
List<org.apache.poi.hssf.record.Record> recList = Arrays.asList(recs); | |||
WorkbookRecordList wrl = new WorkbookRecordList(); | |||
assertThrows(IllegalStateException.class, | |||
() -> new LinkTable(recList, 0, wrl, Collections.emptyMap())); | |||
} | |||
@Test | |||
void testNameCommentRecordBetweenNameRecords() { | |||
final Record[] recs = { | |||
new NameRecord(), | |||
new NameCommentRecord("name1", "comment1"), | |||
@@ -251,6 +281,5 @@ final class TestLinkTable { | |||
assertEquals(0, tbl.resolveNameXIx(namex2.getSheetRefIndex(), namex2.getNameIndex())); | |||
assertEquals("ISEVEN", tbl.resolveNameXText(namex2.getSheetRefIndex(), namex2.getNameIndex(), null)); | |||
} | |||
} |