diff --git a/poi-integration/src/test/java/org/apache/poi/stress/SpreadsheetHandler.java b/poi-integration/src/test/java/org/apache/poi/stress/SpreadsheetHandler.java index 1e57bb856a..40f103b523 100644 --- a/poi-integration/src/test/java/org/apache/poi/stress/SpreadsheetHandler.java +++ b/poi-integration/src/test/java/org/apache/poi/stress/SpreadsheetHandler.java @@ -37,6 +37,8 @@ public abstract class SpreadsheetHandler extends AbstractFileHandler { // try to access some of the content readContent(wb); + extractEmbedded(wb); + // write out the file writeToArray(wb); diff --git a/poi-ooxml/src/main/java/org/apache/poi/ooxml/POIXMLDocumentPart.java b/poi-ooxml/src/main/java/org/apache/poi/ooxml/POIXMLDocumentPart.java index 9a619a410f..56dda3039f 100644 --- a/poi-ooxml/src/main/java/org/apache/poi/ooxml/POIXMLDocumentPart.java +++ b/poi-ooxml/src/main/java/org/apache/poi/ooxml/POIXMLDocumentPart.java @@ -259,7 +259,7 @@ public class POIXMLDocumentPart { */ public final POIXMLDocumentPart getRelationById(String id) { RelationPart rp = getRelationPartById(id); - return (rp == null) ? null : rp.getDocumentPart(); + return rp == null ? null : rp.getDocumentPart(); } /** @@ -797,7 +797,7 @@ public class POIXMLDocumentPart { * @since 5.3.0 */ public final HyperlinkRelationship createHyperlink(URI uri, boolean isExternal, String relId) { - PackageRelationship pr = packagePart.addRelationship(uri, isExternal ? TargetMode.EXTERNAL : TargetMode.INTERNAL, + packagePart.addRelationship(uri, isExternal ? TargetMode.EXTERNAL : TargetMode.INTERNAL, PackageRelationshipTypes.HYPERLINK_PART, relId); HyperlinkRelationship hyperlink = new HyperlinkRelationship(this, uri, isExternal, relId); referenceRelationships.put(relId, hyperlink); diff --git a/poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XSLFTable.java b/poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XSLFTable.java index eb02744437..eeb48af8a7 100644 --- a/poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XSLFTable.java +++ b/poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XSLFTable.java @@ -340,6 +340,9 @@ public class XSLFTable extends XSLFGraphicFrame implements Iterable arc.execute(new Path2D.Double(), ctx)); + } +} diff --git a/poi-ooxml/src/test/java/org/apache/poi/xslf/usermodel/TestXSLFTable.java b/poi-ooxml/src/test/java/org/apache/poi/xslf/usermodel/TestXSLFTable.java index 827bed7243..9529309a2a 100644 --- a/poi-ooxml/src/test/java/org/apache/poi/xslf/usermodel/TestXSLFTable.java +++ b/poi-ooxml/src/test/java/org/apache/poi/xslf/usermodel/TestXSLFTable.java @@ -19,6 +19,7 @@ package org.apache.poi.xslf.usermodel; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; @@ -80,6 +81,7 @@ class TestXSLFTable { tab.removeColumn(0); tab.removeColumn(tab.getNumberOfColumns() - 1); assertEquals(data[0].length, tab.getNumberOfColumns()); + assertNull(tab.getTableStyle()); int startRow = rowIdx-1; @@ -163,7 +165,7 @@ class TestXSLFTable { XSLFSlide slide = ppt.getSlides().get(3); List shapes = slide.getShapes(); assertEquals(1, shapes.size()); - assertTrue(shapes.get(0) instanceof XSLFTable); + assertInstanceOf(XSLFTable.class, shapes.get(0)); XSLFTable tbl = (XSLFTable)shapes.get(0); assertEquals(3, tbl.getNumberOfColumns()); assertEquals(6, tbl.getNumberOfRows()); @@ -175,6 +177,7 @@ class TestXSLFTable { assertEquals(90.0, tbl.getColumnWidth(0), 0); assertEquals(240.0, tbl.getColumnWidth(1), 0); assertEquals(150.0, tbl.getColumnWidth(2), 0); + assertNotNull(tbl.getTableStyle()); for(XSLFTableRow row : tbl){ // all rows have the same height @@ -207,7 +210,7 @@ class TestXSLFTable { assertNotNull(tbl.getCTTable()); assertNotNull(tbl.getCTTable().getTblGrid()); assertNotNull(tbl.getCTTable().getTblPr()); - assertTrue(tbl.getXmlObject() instanceof CTGraphicalObjectFrame); + assertInstanceOf(CTGraphicalObjectFrame.class, tbl.getXmlObject()); assertEquals("Table 2", tbl.getShapeName()); assertEquals(2, tbl.getShapeId()); assertEquals(0, tbl.getRows().size()); @@ -216,6 +219,7 @@ class TestXSLFTable { assertEquals(0, tbl.getNumberOfColumns()); assertEquals(0, tbl.getNumberOfRows()); + assertNull(tbl.getTableStyle()); XSLFTableRow row0 = tbl.addRow(); assertNotNull(row0.getXmlObject()); @@ -281,6 +285,7 @@ class TestXSLFTable { XMLSlideShow ss = XSLFTestDataSamples.openSampleDocument("shapes.pptx"); XSLFSlide sl = ss.getSlides().get(0); XSLFTable tab = (XSLFTable)sl.getShapes().get(4); + assertNotNull(tab.getTableStyle()); sl.removeShape(tab); XMLSlideShow ss2 = XSLFTestDataSamples.writeOutAndReadBack(ss); @@ -305,6 +310,7 @@ class TestXSLFTable { XSLFTableCell tc0 = tr.addCell(); tc0.setText("bla bla bla bla"); tab.setColumnWidth(0, 50); + assertNull(tab.getTableStyle()); // usually text height == 88, but font rendering is platform dependent // so we use something more reliable @@ -355,13 +361,14 @@ class TestXSLFTable { new DrawTableShape(newTable).setAllBorders(3., StrokeStyle.LineDash.LG_DASH_DOT, Color.BLUE); assertEquals(3, newTable.getCTTable().getTblGrid().sizeOfGridColArray()); + assertNull(newTable.getTableStyle()); } } private void verifyTableCellStyleColors(XSLFTableCell cell, String text, Color fontColor, Color fillColor) { assertEquals(text, cell.getText()); PaintStyle colorText1 = cell.getTextParagraphs().get(0).getTextRuns().get(0).getFontColor(); - assertTrue(colorText1 instanceof PaintStyle.SolidPaint); + assertInstanceOf(PaintStyle.SolidPaint.class, colorText1); assertEquals(fontColor, ((PaintStyle.SolidPaint)colorText1).getSolidColor().getColor()); assertEquals(fillColor, cell.getFillColor()); } @@ -374,11 +381,12 @@ class TestXSLFTable { List shapes = ppt.getSlides().get(0).getShapes(); assertEquals(1, shapes.size()); - assertTrue(shapes.get(0) instanceof XSLFTable); + assertInstanceOf(XSLFTable.class, shapes.get(0)); XSLFTable tbl = (XSLFTable)shapes.get(0); assertEquals(4, tbl.getNumberOfColumns()); assertEquals(4, tbl.getNumberOfRows()); assertNotNull(tbl.getCTTable()); + assertNotNull(tbl.getTableStyle()); // Yellow font color due to "first row" table style verifyTableCellStyleColors(tbl.getRows().get(0).getCells().get(0), "Text 1", @@ -403,11 +411,12 @@ class TestXSLFTable { shapes = ppt.getSlides().get(1).getShapes(); assertEquals(1, shapes.size()); - assertTrue(shapes.get(0) instanceof XSLFTable); + assertInstanceOf(XSLFTable.class, shapes.get(0)); tbl = (XSLFTable)shapes.get(0); assertEquals(4, tbl.getNumberOfColumns()); assertEquals(4, tbl.getNumberOfRows()); assertNotNull(tbl.getCTTable()); + assertNotNull(tbl.getTableStyle()); // Green font color due to "first column" table style verifyTableCellStyleColors(tbl.getRows().get(0).getCells().get(0), "Text 1", diff --git a/poi-ooxml/src/test/java9/module-info.java b/poi-ooxml/src/test/java9/module-info.java index ab8306e8a1..bd058c8243 100644 --- a/poi-ooxml/src/test/java9/module-info.java +++ b/poi-ooxml/src/test/java9/module-info.java @@ -200,6 +200,7 @@ module org.apache.poi.ooxml { opens org.apache.poi.xssf.streaming to org.junit.platform.commons; opens org.apache.poi.xssf.util to org.junit.platform.commons; opens org.apache.poi.xslf.draw to org.junit.platform.commons; + opens org.apache.poi.xslf.draw.geom to org.junit.platform.commons; opens org.apache.poi.xslf.usermodel to org.junit.platform.commons; opens org.apache.poi.xslf.model to org.junit.platform.commons; opens org.apache.poi.xslf.util to org.junit.platform.commons; diff --git a/poi/src/main/java/org/apache/poi/hssf/model/InternalSheet.java b/poi/src/main/java/org/apache/poi/hssf/model/InternalSheet.java index 570494d830..d50dabfcbb 100644 --- a/poi/src/main/java/org/apache/poi/hssf/model/InternalSheet.java +++ b/poi/src/main/java/org/apache/poi/hssf/model/InternalSheet.java @@ -1075,6 +1075,10 @@ public final class InternalSheet { } private void setColumn(int column, Short xfStyle, Integer width, Integer level, Boolean hidden, Boolean collapsed) { + if (_columnInfos == null) { + throw new IllegalStateException("Cannot group column range with missing column-infos"); + } + _columnInfos.setColumn( column, xfStyle, width, level, hidden, collapsed ); } @@ -1087,6 +1091,9 @@ public final class InternalSheet { * if false indenting will be removed by one level. */ public void groupColumnRange(int fromColumn, int toColumn, boolean indent) { + if (_columnInfos == null) { + throw new IllegalStateException("Cannot group column range with missing column-infos"); + } // Set the level for each column _columnInfos.groupColumnRange( fromColumn, toColumn, indent); diff --git a/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFPicture.java b/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFPicture.java index 48269513d0..3b2cd4505d 100644 --- a/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFPicture.java +++ b/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFPicture.java @@ -52,25 +52,27 @@ public class HSSFPicture extends HSSFSimpleShape implements Picture { /** * Constructs a picture object. */ - public HSSFPicture( HSSFShape parent, HSSFAnchor anchor ) - { + public HSSFPicture( HSSFShape parent, HSSFAnchor anchor ) { super( parent, anchor ); super.setShapeType(OBJECT_TYPE_PICTURE); CommonObjectDataSubRecord cod = (CommonObjectDataSubRecord) getObjRecord().getSubRecords().get(0); cod.setObjectType(CommonObjectDataSubRecord.OBJECT_TYPE_PICTURE); } - public int getPictureIndex() - { - EscherSimpleProperty property = getOptRecord().lookup(EscherPropertyTypes.BLIP__BLIPTODISPLAY); - if (null == property){ + public int getPictureIndex() { + EscherOptRecord optRecord = getOptRecord(); + if (optRecord == null) { + return -1; + } + + EscherSimpleProperty property = optRecord.lookup(EscherPropertyTypes.BLIP__BLIPTODISPLAY); + if (null == property) { return -1; } return property.getPropertyValue(); } - public void setPictureIndex( int pictureIndex ) - { + public void setPictureIndex( int pictureIndex ) { setPropertyValue(new EscherSimpleProperty( EscherPropertyTypes.BLIP__BLIPTODISPLAY, false, true, pictureIndex)); } @@ -95,7 +97,7 @@ public class HSSFPicture extends HSSFSimpleShape implements Picture { *

*/ @Override - public void resize(){ + public void resize() { resize(Double.MAX_VALUE); } @@ -152,7 +154,7 @@ public class HSSFPicture extends HSSFSimpleShape implements Picture { * @since 3.0.2 */ @Override - public HSSFClientAnchor getPreferredSize(){ + public HSSFClientAnchor getPreferredSize() { return getPreferredSize(1.0); } @@ -163,7 +165,7 @@ public class HSSFPicture extends HSSFSimpleShape implements Picture { * @return HSSFClientAnchor with the preferred size for this image * @since 3.0.2 */ - public HSSFClientAnchor getPreferredSize(double scale){ + public HSSFClientAnchor getPreferredSize(double scale) { return getPreferredSize(scale, scale); } @@ -176,7 +178,7 @@ public class HSSFPicture extends HSSFSimpleShape implements Picture { * @since 3.11 */ @Override - public HSSFClientAnchor getPreferredSize(double scaleX, double scaleY){ + public HSSFClientAnchor getPreferredSize(double scaleX, double scaleY) { ImageUtils.setPreferredSize(this, scaleX, scaleY); return getClientAnchor(); } @@ -187,7 +189,7 @@ public class HSSFPicture extends HSSFSimpleShape implements Picture { * @return image dimension in pixels */ @Override - public Dimension getImageDimension(){ + public Dimension getImageDimension() { InternalWorkbook iwb = getPatriarch().getSheet().getWorkbook().getWorkbook(); EscherBSERecord bse = iwb.getBSERecord(getPictureIndex()); byte[] data = bse.getBlipRecord().getPicturedata(); @@ -206,7 +208,7 @@ public class HSSFPicture extends HSSFSimpleShape implements Picture { * @return picture data for this shape or {@code null} if picture wasn't embedded, i.e. external linked */ @Override - public HSSFPictureData getPictureData(){ + public HSSFPictureData getPictureData() { int picIdx = getPictureIndex(); if (picIdx == -1) { return null; @@ -249,7 +251,7 @@ public class HSSFPicture extends HSSFSimpleShape implements Picture { : StringUtil.getFromUnicodeLE(propFile.getComplexData()).trim(); } - public void setFileName(String data){ + public void setFileName(String data) { // TODO: add trailing \u0000? byte[] bytes = StringUtil.getToUnicodeLE(data); EscherComplexProperty prop = new EscherComplexProperty(EscherPropertyTypes.BLIP__BLIPFILENAME, true, bytes.length); diff --git a/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFShape.java b/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFShape.java index d9c98e3063..5946403a96 100644 --- a/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFShape.java +++ b/poi/src/main/java/org/apache/poi/hssf/usermodel/HSSFShape.java @@ -115,6 +115,10 @@ public abstract class HSSFShape implements Shape { */ void setShapeId(int shapeId){ EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID); + if (spRecord == null) { + throw new IllegalStateException("Did not have an EscherSpRecord, cannot set shape id " + shapeId); + } + spRecord.setShapeId(shapeId); CommonObjectDataSubRecord cod = (CommonObjectDataSubRecord) _objRecord.getSubRecords().get(0); cod.setObjectId((short) (shapeId%1024)); diff --git a/poi/src/main/java/org/apache/poi/sl/draw/DrawTextParagraph.java b/poi/src/main/java/org/apache/poi/sl/draw/DrawTextParagraph.java index 189f9eabfe..28c43e6a95 100644 --- a/poi/src/main/java/org/apache/poi/sl/draw/DrawTextParagraph.java +++ b/poi/src/main/java/org/apache/poi/sl/draw/DrawTextParagraph.java @@ -591,10 +591,10 @@ public class DrawTextParagraph implements Drawable { final Map att = new HashMap<>(); final List attList = new ArrayList<>(); - for (TextRun run : paragraph){ + for (TextRun run : paragraph) { String runText = getRenderableText(graphics, run); // skip empty runs - if (runText.isEmpty()) { + if (runText == null || runText.isEmpty()) { continue; } diff --git a/poi/src/main/java/org/apache/poi/sl/draw/geom/ArcToCommandIf.java b/poi/src/main/java/org/apache/poi/sl/draw/geom/ArcToCommandIf.java index 6e5942ea89..17b6d99191 100644 --- a/poi/src/main/java/org/apache/poi/sl/draw/geom/ArcToCommandIf.java +++ b/poi/src/main/java/org/apache/poi/sl/draw/geom/ArcToCommandIf.java @@ -60,6 +60,10 @@ public interface ArcToCommandIf extends PathCommand { double invStart = Math.atan2(rx * Math.sin(radStart), ry * Math.cos(radStart)); Point2D pt = path.getCurrentPoint(); + if (pt == null) { + throw new IllegalStateException("Cannot draw arc without valid point"); + } + // calculate top/left corner double x0 = pt.getX() - rx * Math.cos(invStart) - rx; double y0 = pt.getY() - ry * Math.sin(invStart) - ry; diff --git a/poi/src/main/java/org/apache/poi/ss/extractor/EmbeddedExtractor.java b/poi/src/main/java/org/apache/poi/ss/extractor/EmbeddedExtractor.java index a59d8368e4..aa895e7fee 100644 --- a/poi/src/main/java/org/apache/poi/ss/extractor/EmbeddedExtractor.java +++ b/poi/src/main/java/org/apache/poi/ss/extractor/EmbeddedExtractor.java @@ -260,7 +260,7 @@ public class EmbeddedExtractor implements Iterable { int pictureBytesLen = idxEnd-idxStart+6; byte[] pdfBytes = IOUtils.safelyClone(pictureBytes, idxStart, pictureBytesLen, MAX_RECORD_LENGTH); - String filename = source.getShapeName().trim(); + String filename = source.getShapeName() == null ? "empty" : source.getShapeName().trim(); if (!endsWithIgnoreCase(filename, ".pdf")) { filename += ".pdf"; } diff --git a/poi/src/test/java/org/apache/poi/hssf/model/TestInternalSheet.java b/poi/src/test/java/org/apache/poi/hssf/model/TestInternalSheet.java new file mode 100644 index 0000000000..db82c1ec7e --- /dev/null +++ b/poi/src/test/java/org/apache/poi/hssf/model/TestInternalSheet.java @@ -0,0 +1,72 @@ +/* ==================================================================== + 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. +==================================================================== */ +package org.apache.poi.hssf.model; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.List; + +import org.apache.poi.hssf.record.BOFRecord; +import org.apache.poi.hssf.record.EOFRecord; +import org.apache.poi.hssf.record.WindowTwoRecord; +import org.apache.poi.util.RecordFormatException; +import org.junit.jupiter.api.Test; + +class TestInternalSheet { + @Test + void testEmptySheet() { + InternalSheet sheet = InternalSheet.createSheet(); + sheet.groupColumnRange(0, 0, true); + sheet.groupRowRange(0, 0, true); + sheet.setDefaultColumnStyle(0, 0); + } + + @Test + void testMissingBOFRecord() { + assertThrows(RecordFormatException.class, + () -> InternalSheet.createSheet(new RecordStream( + List.of(new BOFRecord()), 0))); + } + + + @Test + void testInvalidBOFRecord() { + assertThrows(RecordFormatException.class, + () -> InternalSheet.createSheet(new RecordStream( + List.of(new BOFRecord()), 0))); + } + + @Test + void testInvalidBOFRecord2() { + assertThrows(RecordFormatException.class, + () -> InternalSheet.createSheet(new RecordStream( + List.of(BOFRecord.createSheetBOF()), 0))); + } + + @Test + void testEmptyRecordStream() { + InternalSheet sheet = InternalSheet.createSheet(new RecordStream( + List.of(BOFRecord.createSheetBOF(), + new WindowTwoRecord(), + EOFRecord.instance), 0)); + assertThrows(IllegalStateException.class, + () -> sheet.groupColumnRange(0, 0, true)); + sheet.groupRowRange(0, 0, true); + assertThrows(IllegalStateException.class, + () -> sheet.setDefaultColumnStyle(0, 0)); + } +} diff --git a/poi/src/test/java/org/apache/poi/hssf/usermodel/TestHSSFComment.java b/poi/src/test/java/org/apache/poi/hssf/usermodel/TestHSSFComment.java index 5644733467..0420827997 100644 --- a/poi/src/test/java/org/apache/poi/hssf/usermodel/TestHSSFComment.java +++ b/poi/src/test/java/org/apache/poi/hssf/usermodel/TestHSSFComment.java @@ -22,10 +22,12 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; +import org.apache.poi.ddf.EscherContainerRecord; import org.apache.poi.ddf.EscherSpRecord; import org.apache.poi.hssf.HSSFITestDataProvider; import org.apache.poi.hssf.HSSFTestDataSamples; @@ -362,6 +364,7 @@ final class TestHSSFComment extends BaseTestCellComment { void existingFileWithComment() throws IOException { try (HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("drawings.xls")) { HSSFSheet sheet = wb.getSheet("comments"); + assertNotNull(sheet); HSSFPatriarch drawing = sheet.getDrawingPatriarch(); assertEquals(1, drawing.getChildren().size()); HSSFComment comment = (HSSFComment) drawing.getChildren().get(0); @@ -434,4 +437,11 @@ final class TestHSSFComment extends BaseTestCellComment { assertEquals(2024, comment.getNoteRecord().getShapeId()); } } + + @Test + void getEmptyShape() throws IOException { + HSSFComment shape = new HSSFComment(new EscherContainerRecord(), null, null, null); + assertThrows(IllegalStateException.class, + () -> shape.setShapeId(1)); + } } diff --git a/poi/src/test/java/org/apache/poi/hssf/usermodel/TestHSSFPicture.java b/poi/src/test/java/org/apache/poi/hssf/usermodel/TestHSSFPicture.java index 3ff14c846e..aa5d42ba2f 100644 --- a/poi/src/test/java/org/apache/poi/hssf/usermodel/TestHSSFPicture.java +++ b/poi/src/test/java/org/apache/poi/hssf/usermodel/TestHSSFPicture.java @@ -21,6 +21,7 @@ import static org.apache.poi.hssf.HSSFTestDataSamples.openSampleWorkbook; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import java.io.IOException; import java.util.Arrays; @@ -28,6 +29,10 @@ import java.util.List; import org.apache.poi.POIDataSamples; import org.apache.poi.ddf.EscherBSERecord; +import org.apache.poi.ddf.EscherContainerRecord; +import org.apache.poi.ddf.EscherOptRecord; +import org.apache.poi.ddf.EscherPropertyTypes; +import org.apache.poi.ddf.EscherTextboxRecord; import org.apache.poi.hssf.HSSFITestDataProvider; import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.model.InternalSheet; @@ -285,4 +290,25 @@ final class TestHSSFPicture extends BaseTestPicture { } } + @Test + void testEmptyOptRecord() throws IOException { + try (HSSFWorkbook wb = new HSSFWorkbook()) { + HSSFSheet sh = wb.createSheet("Pictures"); + HSSFPatriarch dr = sh.createDrawingPatriarch(); + HSSFShapeGroup gr = dr.createGroup(new HSSFClientAnchor()); + HSSFPicture pic = new HSSFPicture(gr, new HSSFClientAnchor()) { + @Override + protected EscherContainerRecord createSpContainer() { + EscherContainerRecord spContainer = super.createSpContainer(); + EscherOptRecord opt = spContainer.getChildById(EscherOptRecord.RECORD_ID); + spContainer.removeChildRecord(opt); + spContainer.removeChildRecord(spContainer.getChildById(EscherTextboxRecord.RECORD_ID)); + return spContainer; + } + }; + + assertNull(pic.getOptRecord()); + assertEquals(-1, pic.getPictureIndex()); + } + } } diff --git a/test-data/spreadsheet/moodle.iamm.fr_pluginfile.php_2971_mod_resource_content_4_evaluation_module_decouverte_qesamed.xls b/test-data/spreadsheet/moodle.iamm.fr_pluginfile.php_2971_mod_resource_content_4_evaluation_module_decouverte_qesamed.xls new file mode 100644 index 0000000000..747d3370c0 Binary files /dev/null and b/test-data/spreadsheet/moodle.iamm.fr_pluginfile.php_2971_mod_resource_content_4_evaluation_module_decouverte_qesamed.xls differ diff --git a/test-data/spreadsheet/stress.xls b/test-data/spreadsheet/stress.xls index 0ff3b117ca..17d8e2afca 100644 Binary files a/test-data/spreadsheet/stress.xls and b/test-data/spreadsheet/stress.xls differ