]> source.dussan.org Git - poi.git/commitdiff
#60499 - Deleting a picture that is used twice on a slide corrupt the slide
authorAndreas Beeker <kiwiwings@apache.org>
Sun, 17 Sep 2017 22:45:03 +0000 (22:45 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Sun, 17 Sep 2017 22:45:03 +0000 (22:45 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1808661 13f79535-47bb-0310-9956-ffa450edef68

src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java
src/ooxml/testcases/org/apache/poi/TestPOIXMLDocument.java
src/ooxml/testcases/org/apache/poi/xslf/TestXSLFBugs.java
test-data/slideshow/bug60499.pptx [new file with mode: 0644]

index c5afb154465c5a18f7b9a874bc2de3fb327309f9..5b6add51ab86d195976ad293d321f79369c438fc 100644 (file)
@@ -231,15 +231,35 @@ public class POIXMLDocumentPart {
      * @return the target part of the relation, or null, if none exists
      */
     public final POIXMLDocumentPart getRelationById(String id) {
-        RelationPart rp = relations.get(id);
+        RelationPart rp = getRelationPartById(id);
         return (rp == null) ? null : rp.getDocumentPart();
     }
 
     /**
-     * Returns the {@link PackageRelationship#getId()} of the
+     * Returns the target {@link RelationPart}, where a
+     * {@link PackageRelationship} is set from the {@link PackagePart} of this
+     * {@link POIXMLDocumentPart} to the {@link PackagePart} of the target
+     * {@link POIXMLDocumentPart} with a {@link PackageRelationship#getId()}
+     * matching the given parameter value.
+     *
+     * @param id
+     *            The relation id to look for
+     * @return the target relation part, or null, if none exists
+     * 
+     * @since 4.0.0
+     */
+    public final RelationPart getRelationPartById(String id) {
+        return relations.get(id);
+    }
+
+    /**
+     * Returns the first {@link PackageRelationship#getId()} of the
      * {@link PackageRelationship}, that sources from the {@link PackagePart} of
      * this {@link POIXMLDocumentPart} to the {@link PackagePart} of the given
-     * parameter value.
+     * parameter value.<p>
+     * 
+     * There can be multiple references to the given {@link POIXMLDocumentPart}
+     * and only the first in the order of creation is returned.
      *
      * @param part
      *            The {@link POIXMLDocumentPart} for which the according
@@ -292,7 +312,11 @@ public class POIXMLDocumentPart {
 
     /**
      * Remove the relation to the specified part in this package and remove the
-     * part, if it is no longer needed.
+     * part, if it is no longer needed.<p>
+     * 
+     * If there are multiple relationships to the same part, this will only
+     * remove the first relationship in the order of creation. The removal
+     * via the part id ({@link #removeRelation(String)} is preferred.
      * 
      * @param part the part which relation is to be removed from this document
      */
@@ -302,7 +326,11 @@ public class POIXMLDocumentPart {
 
     /**
      * Remove the relation to the specified part in this package and remove the
-     * part, if it is no longer needed and flag is set to true.
+     * part, if it is no longer needed and flag is set to true.<p>
+     *
+     * If there are multiple relationships to the same part, this will only
+     * remove the first relationship in the order of creation. The removal
+     * via the part id ({@link #removeRelation(String,boolean)} is preferred.
      *
      * @param part
      *            The related part, to which the relation shall be removed.
@@ -311,18 +339,53 @@ public class POIXMLDocumentPart {
      *            needed any longer.
      * @return true, if the relation was removed
      */
-    protected final boolean removeRelation(POIXMLDocumentPart part, boolean removeUnusedParts){
+    protected final boolean removeRelation(POIXMLDocumentPart part, boolean removeUnusedParts) {
         String id = getRelationId(part);
-        if (id == null) {
+        return removeRelation(id, removeUnusedParts);
+    }
+
+    /**
+     * Remove the relation to the specified part in this package and remove the
+     * part, if it is no longer needed.<p>
+     * 
+     * If there are multiple relationships to the same part, this will only
+     * remove the first relationship in the order of creation. The removal
+     * via the part id ({@link #removeRelation(String)} is preferred.
+     * 
+     * @param partId the part id which relation is to be removed from this document
+     * 
+     * @since 4.0.0
+     */
+    protected final void removeRelation(String partId) {
+        removeRelation(partId, true);
+    }
+
+    /**
+     * Remove the relation to the specified part in this package and remove the
+     * part, if it is no longer needed and flag is set to true.<p>
+     *
+     * @param partId
+     *            The related part id, to which the relation shall be removed.
+     * @param removeUnusedParts
+     *            true, if the part shall be removed from the package if not
+     *            needed any longer.
+     * @return true, if the relation was removed
+     * 
+     * @since 4.0.0
+     */
+    private final boolean removeRelation(String partId, boolean removeUnusedParts) {
+        RelationPart rp = relations.get(partId);
+        if (rp == null) {
             // part is not related with this POIXMLDocumentPart
             return false;
         }
+        POIXMLDocumentPart part = rp.getDocumentPart();
         /* decrement usage counter */
         part.decrementRelationCounter();
         /* remove packagepart relationship */
-        getPackagePart().removeRelationship(id);
+        getPackagePart().removeRelationship(partId);
         /* remove POIXMLDocument from relations */
-        relations.remove(id);
+        relations.remove(partId);
 
         if (removeUnusedParts) {
             /* if last relation to target part was removed, delete according target part */
@@ -338,6 +401,8 @@ public class POIXMLDocumentPart {
         return true;
     }
 
+    
+    
     /**
      * Returns the parent POIXMLDocumentPart. All parts except root have not-null parent.
      *
index aed2ff7c497533d30111d1c78bce1d594ef35daa..148f5cd6a7b0cf60bc6ef046e4f279b9ea0922a6 100644 (file)
@@ -612,7 +612,6 @@ implements XSLFShapeContainer, Sheet<XSLFShape,XSLFTextParagraph> {
      * @param pictureShape the picture shapes whose relation is to be removed
      */
     void removePictureRelation(XSLFPictureShape pictureShape) {
-        POIXMLDocumentPart pd = getRelationById(pictureShape.getBlipId());
-        removeRelation(pd);
+        removeRelation(pictureShape.getBlipId());
     }
 }
\ No newline at end of file
index e443fa3106d6d02d6fdf13f87cc8e2baaedf0713..cfa5873cc54eaaccec790b70e84afb06c39adcad 100644 (file)
@@ -243,7 +243,7 @@ implements Slide<XSLFShape,XSLFTextParagraph> {
         if (bgThis != null) {
             if (bgThis.isSetBgPr() && bgThis.getBgPr().isSetBlipFill()) {
                 String oldId = bgThis.getBgPr().getBlipFill().getBlip().getEmbed();
-                removeRelation(getRelationById(oldId));
+                removeRelation(oldId);
             }
             _slide.getCSld().unsetBg();
         }
index 90e13aecd4c6122ade42a161af16bdcd034c1eb7..21c003c297a60bedece1e74ec703bc9c108c3e84 100644 (file)
@@ -280,7 +280,7 @@ public final class TestPOIXMLDocument {
         assertNull(part.getRelationById(null));
         assertNull(part.getRelationId(null));
         assertFalse(part.removeRelation(null, true));
-        part.removeRelation(null);
+        part.removeRelation((POIXMLDocumentPart)null);
         assertEquals("",part.toString());
         part.onDocumentCreate();
         //part.getTargetPart(null);
index 6f8fd2121c1f233d41311141e6dcf1ddacfc9e5f..5a5c7bfa77d43f299f1d61dc3d43cba61a6cd3b7 100644 (file)
@@ -20,6 +20,7 @@ import static org.apache.poi.POITestCase.assertContains;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -30,17 +31,24 @@ import java.awt.RenderingHints;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Rectangle2D;
 import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.URI;
 import java.util.Collection;
+import java.util.Optional;
+import java.util.stream.Collectors;
 
 import javax.imageio.ImageIO;
 
 import org.apache.poi.POIDataSamples;
 import org.apache.poi.POIXMLDocumentPart;
 import org.apache.poi.POIXMLDocumentPart.RelationPart;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.openxml4j.opc.PackagePartName;
+import org.apache.poi.openxml4j.opc.PackagingURIHelper;
 import org.apache.poi.sl.draw.DrawPaint;
 import org.apache.poi.sl.usermodel.PaintStyle;
 import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
@@ -49,6 +57,7 @@ import org.apache.poi.sl.usermodel.PictureData;
 import org.apache.poi.sl.usermodel.PictureData.PictureType;
 import org.apache.poi.sl.usermodel.ShapeType;
 import org.apache.poi.sl.usermodel.VerticalAlignment;
+import org.apache.poi.util.IOUtils;
 import org.apache.poi.xslf.extractor.XSLFPowerPointExtractor;
 import org.apache.poi.xslf.usermodel.XMLSlideShow;
 import org.apache.poi.xslf.usermodel.XSLFAutoShape;
@@ -76,6 +85,50 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
 public class TestXSLFBugs {
     private static final POIDataSamples slTests = POIDataSamples.getSlideShowInstance();
 
+    @Test
+    public void bug60499() throws IOException, InvalidFormatException {
+        InputStream is = slTests.openResourceAsStream("bug60499.pptx");
+        byte buf[] = IOUtils.toByteArray(is);
+        is.close();
+
+        PackagePartName ppn = PackagingURIHelper.createPartName("/ppt/media/image1.png");
+        
+        XMLSlideShow ppt1 = new XMLSlideShow(new ByteArrayInputStream(buf));
+        XSLFSlide slide1 = ppt1.getSlides().get(0);
+        
+        Optional<XSLFShape> shapeToDelete1 =
+            slide1.getShapes().stream().filter(s -> s instanceof XSLFPictureShape).findFirst();
+        
+        assertTrue(shapeToDelete1.isPresent());
+        slide1.removeShape(shapeToDelete1.get());
+        slide1.getRelationParts().stream()
+            .allMatch(rp -> "rId1,rId3".contains(rp.getRelationship().getId()) ); 
+        
+        assertNotNull(ppt1.getPackage().getPart(ppn));
+        ppt1.close();
+
+        XMLSlideShow ppt2 = new XMLSlideShow(new ByteArrayInputStream(buf));
+        XSLFSlide slide2 = ppt2.getSlides().get(0);
+
+        Optional<XSLFShape> shapeToDelete2 =
+            slide2.getShapes().stream().filter(s -> s instanceof XSLFPictureShape).skip(1).findFirst();
+        assertTrue(shapeToDelete2.isPresent());
+        slide2.removeShape(shapeToDelete2.get());
+        slide2.getRelationParts().stream()
+            .allMatch(rp -> "rId1,rId2".contains(rp.getRelationship().getId()) ); 
+        assertNotNull(ppt2.getPackage().getPart(ppn));
+        ppt2.close();
+
+        XMLSlideShow ppt3 = new XMLSlideShow(new ByteArrayInputStream(buf));
+        XSLFSlide slide3 = ppt3.getSlides().get(0);
+        slide3.getShapes().stream()
+            .filter(s -> s instanceof XSLFPictureShape)
+            .collect(Collectors.toList())
+            .forEach(s -> slide3.removeShape(s));
+        assertNull(ppt3.getPackage().getPart(ppn));
+        ppt3.close();
+    }
+    
     @Test
     public void bug51187() throws Exception {
        XMLSlideShow ss1 = XSLFTestDataSamples.openSampleDocument("51187.pptx");
diff --git a/test-data/slideshow/bug60499.pptx b/test-data/slideshow/bug60499.pptx
new file mode 100644 (file)
index 0000000..300873d
Binary files /dev/null and b/test-data/slideshow/bug60499.pptx differ