From c2761bf4523deb05338672efeb2587107dd0b619 Mon Sep 17 00:00:00 2001
From: Nick Burch <nick@apache.org>
Date: Sun, 7 Sep 2008 18:32:51 +0000
Subject: [PATCH] Patch from bug #45738 - Initial HWPF support for Office Art
 Shapes

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@692918 13f79535-47bb-0310-9956-ffa450edef68
---
 src/documentation/content/xdocs/changes.xml   |   5 +-
 src/documentation/content/xdocs/status.xml    |   5 +-
 .../src/org/apache/poi/hwpf/HWPFDocument.java |  12 +++
 .../apache/poi/hwpf/model/ShapesTable.java    |  54 ++++++++++++
 .../org/apache/poi/hwpf/usermodel/Shape.java  |  74 ++++++++++++++++
 .../apache/poi/hwpf/data/WithArtShapes.doc    | Bin 0 -> 53760 bytes
 .../apache/poi/hwpf/usermodel/TestShapes.java |  83 ++++++++++++++++++
 7 files changed, 229 insertions(+), 4 deletions(-)
 create mode 100644 src/scratchpad/src/org/apache/poi/hwpf/model/ShapesTable.java
 create mode 100644 src/scratchpad/src/org/apache/poi/hwpf/usermodel/Shape.java
 create mode 100644 src/scratchpad/testcases/org/apache/poi/hwpf/data/WithArtShapes.doc
 create mode 100644 src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestShapes.java

diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml
index fe18530168..57934cb893 100644
--- a/src/documentation/content/xdocs/changes.xml
+++ b/src/documentation/content/xdocs/changes.xml
@@ -37,8 +37,9 @@
 
 		<!-- Don't forget to update status.xml too! -->
         <release version="3.1.1-alpha1" date="2008-??-??">
-           <action dev="POI-DEVELOPERS" type="fix">45720 Fixed HSSFWorkbook.cloneSheet to correctly clone sheets with drawings</action>
-           <action dev="POI-DEVELOPERS" type="fix">45728 Fix for SlideShow.reorderSlide in HSLF</action>
+           <action dev="POI-DEVELOPERS" type="add">45738 - Initial HWPF support for Office Art Shapes</action>
+           <action dev="POI-DEVELOPERS" type="fix">45720 - Fixed HSSFWorkbook.cloneSheet to correctly clone sheets with drawings</action>
+           <action dev="POI-DEVELOPERS" type="fix">45728 - Fix for SlideShow.reorderSlide in HSLF</action>
            <action dev="POI-DEVELOPERS" type="add">Initial support for embedded movies and controls in HSLF</action>
            <action dev="POI-DEVELOPERS" type="fix">45358 - signed/unsigned error when parsing 3-d area refs, performance problem evaluating area refs, and ClassCastExcecption in IF()</action>
            <action dev="POI-DEVELOPERS" type="add">Support for HPBF Publisher hyperlinks, including during text extraction</action>
diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml
index 0cc173d6b8..9cbedfcaf0 100644
--- a/src/documentation/content/xdocs/status.xml
+++ b/src/documentation/content/xdocs/status.xml
@@ -34,8 +34,9 @@
 	<!-- Don't forget to update changes.xml too! -->
     <changes>
         <release version="3.1.1-alpha1" date="2008-??-??">
-           <action dev="POI-DEVELOPERS" type="fix">45720 Fixed HSSFWorkbook.cloneSheet to correctly clone sheets with drawings</action>
-           <action dev="POI-DEVELOPERS" type="fix">45728 Fix for SlideShow.reorderSlide in HSLF</action>
+           <action dev="POI-DEVELOPERS" type="add">45738 - Initial HWPF support for Office Art Shapes</action>
+           <action dev="POI-DEVELOPERS" type="fix">45720 - Fixed HSSFWorkbook.cloneSheet to correctly clone sheets with drawings</action>
+           <action dev="POI-DEVELOPERS" type="fix">45728 - Fix for SlideShow.reorderSlide in HSLF</action>
            <action dev="POI-DEVELOPERS" type="add">Initial support for embedded movies and controls in HSLF</action>
            <action dev="POI-DEVELOPERS" type="fix">45358 - signed/unsigned error when parsing 3-d area refs, performance problem evaluating area refs, and ClassCastExcecption in IF()</action>
            <action dev="POI-DEVELOPERS" type="add">Support for HPBF Publisher hyperlinks, including during text extraction</action>
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java b/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java
index daf1c8e172..f1898c082b 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java
@@ -103,6 +103,9 @@ public class HWPFDocument extends POIDocument
   /** Escher Drawing Group information */
   protected EscherRecordHolder _dgg;
 
+  /** Holds Office Art objects */
+  protected ShapesTable _officeArts;
+
   protected HWPFDocument()
   {
      super(null, null);
@@ -252,6 +255,8 @@ public class HWPFDocument extends POIDocument
     
     // read in the pictures stream
     _pictures = new PicturesTable(this, _dataStream, _mainStream, _fspa, _dgg);
+    // And the art shapes stream
+    _officeArts = new ShapesTable(_tableStream, _fib);
 
     _st = new SectionTable(_mainStream, _tableStream, _fib.getFcPlcfsed(), _fib.getLcbPlcfsed(), fcMin, _tpt, _cpSplit);
     _ss = new StyleSheet(_tableStream, _fib.getFcStshf());
@@ -392,6 +397,13 @@ public class HWPFDocument extends POIDocument
   public PicturesTable getPicturesTable() {
 	  return _pictures;
   }
+  
+  /**
+   * @return ShapesTable object, that is able to extract office are shapes from this document
+   */
+  public ShapesTable getShapesTable() {
+	  return _officeArts;
+  }
 
   /**
    * Writes out the word file that is represented by an instance of this class.
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/ShapesTable.java b/src/scratchpad/src/org/apache/poi/hwpf/model/ShapesTable.java
new file mode 100644
index 0000000000..998ea2d8fe
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/ShapesTable.java
@@ -0,0 +1,54 @@
+/* ====================================================================
+   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.hwpf.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.hwpf.usermodel.Shape;
+
+public class ShapesTable {
+        private List _shapes;
+        private List _shapesVisibili;  //holds visible shapes
+
+        public ShapesTable(byte [] tblStream, FileInformationBlock fib) {
+                PlexOfCps binTable = new PlexOfCps(tblStream,
+                     fib.getFcPlcspaMom(), fib.getLcbPlcspaMom(), 26);
+
+                _shapes = new ArrayList();
+                _shapesVisibili = new ArrayList();
+
+
+                for(int i = 0; i < binTable.length(); i++) {
+                        GenericPropertyNode nodo = binTable.getProperty(i);
+
+                        Shape sh = new Shape(nodo);
+                        _shapes.add(sh);
+                        if(sh.isWithinDocument())
+                                _shapesVisibili.add(sh);
+                }
+        }
+
+        public List getAllShapes() {
+                return _shapes;
+        }
+
+        public List getVisibleShapes() {
+                return _shapesVisibili;
+        }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Shape.java b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Shape.java
new file mode 100644
index 0000000000..1f798b620c
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Shape.java
@@ -0,0 +1,74 @@
+/* ====================================================================
+   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.hwpf.usermodel;
+
+import org.apache.poi.hwpf.model.GenericPropertyNode;
+import org.apache.poi.util.LittleEndian;
+
+public class Shape {
+        int _id, _left, _right, _top, _bottom;
+        /**
+         * true if the Shape bounds are within document (for
+         * example, it's false if the image left corner is outside the doc, like for
+         * embedded documents)
+         */
+        boolean _inDoc; 
+
+        public Shape(GenericPropertyNode nodo) {
+                byte [] contenuto = nodo.getBytes();
+                _id = LittleEndian.getInt(contenuto);
+                _left = LittleEndian.getInt(contenuto, 4);
+                _top = LittleEndian.getInt(contenuto, 8);
+                _right = LittleEndian.getInt(contenuto, 12);
+                _bottom = LittleEndian.getInt(contenuto, 16);
+                _inDoc = (_left >= 0 && _right >= 0 && _top >= 0 && _bottom >=
+0);
+        }
+
+        public int getId() {
+                return _id;
+        }
+
+        public int getLeft() {
+                return _left;
+        }
+
+        public int getRight() {
+                return _right;
+        }
+
+        public int getTop() {
+                return _top;
+        }
+
+        public int getBottom() {
+                return _bottom;
+        }
+
+        public int getWidth() {
+                return _right - _left + 1;
+        }
+
+        public int getHeight() {
+                return _bottom - _top + 1;
+        }
+
+        public boolean isWithinDocument() {
+                return _inDoc;
+        }
+}
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/data/WithArtShapes.doc b/src/scratchpad/testcases/org/apache/poi/hwpf/data/WithArtShapes.doc
new file mode 100644
index 0000000000000000000000000000000000000000..27793c37a4605ddb4f206acf2134b088f8f5f4b7
GIT binary patch
literal 53760
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

literal 0
HcmV?d00001

diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestShapes.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestShapes.java
new file mode 100644
index 0000000000..273a03432b
--- /dev/null
+++ b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestShapes.java
@@ -0,0 +1,83 @@
+/*
+* 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.hwpf.usermodel;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.poi.hwpf.HWPFDocument;
+
+/**
+ * Test the shapes handling
+ */
+public class TestShapes extends TestCase {
+	private String dirname = System.getProperty("HWPF.testdata.path");
+
+    /**
+     * two shapes, second is a group
+     */
+    public void testShapes() throws Exception {
+    	HWPFDocument doc = new HWPFDocument(new FileInputStream(dirname + "/WithArtShapes.doc"));
+
+		List shapes = doc.getShapesTable().getAllShapes();
+		List vshapes = doc.getShapesTable().getVisibleShapes();
+
+		assertEquals(2, shapes.size());
+		assertEquals(2, vshapes.size());
+
+		Shape s1 = (Shape)shapes.get(0);
+		Shape s2 = (Shape)shapes.get(1);
+
+		assertEquals(3616, s1.getWidth());
+		assertEquals(1738, s1.getHeight());
+		assertEquals(true, s1.isWithinDocument());
+
+		assertEquals(4817, s2.getWidth());
+		assertEquals(2164, s2.getHeight());
+		assertEquals(true, s2.isWithinDocument());
+    	
+		
+		// Re-serialisze, check still there
+		ByteArrayOutputStream baos = new ByteArrayOutputStream();
+		doc.write(baos);
+		ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+		doc = new HWPFDocument(bais);
+		
+		shapes = doc.getShapesTable().getAllShapes();
+		vshapes = doc.getShapesTable().getVisibleShapes();
+
+		assertEquals(2, shapes.size());
+		assertEquals(2, vshapes.size());
+
+		s1 = (Shape)shapes.get(0);
+		s2 = (Shape)shapes.get(1);
+
+		assertEquals(3616, s1.getWidth());
+		assertEquals(1738, s1.getHeight());
+		assertEquals(true, s1.isWithinDocument());
+
+		assertEquals(4817, s2.getWidth());
+		assertEquals(2164, s2.getHeight());
+		assertEquals(true, s2.isWithinDocument());
+
+    }
+}