]> source.dussan.org Git - poi.git/commitdiff
Patch from bug #44937 from Squeeself- Partial support for extracting Escher images...
authorNick Burch <nick@apache.org>
Tue, 20 May 2008 16:01:53 +0000 (16:01 +0000)
committerNick Burch <nick@apache.org>
Tue, 20 May 2008 16:01:53 +0000 (16:01 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@658302 13f79535-47bb-0310-9956-ffa450edef68

src/documentation/content/xdocs/changes.xml
src/documentation/content/xdocs/status.xml
src/java/org/apache/poi/ddf/EscherClientAnchorRecord.java
src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java
src/scratchpad/src/org/apache/poi/hwpf/model/EscherRecordHolder.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwpf/model/FSPA.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwpf/model/FSPATable.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java
src/scratchpad/src/org/apache/poi/hwpf/model/PicturesTable.java
src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java
src/scratchpad/testcases/org/apache/poi/hwpf/TestHWPFPictures.java

index 421404a944032f0684c60cb7aa74a4b6a4d09bfd..8dd956c16f1c7563b33e4d65b674e5e152e60003 100644 (file)
@@ -37,6 +37,7 @@
 
                <!-- Don't forget to update status.xml too! -->
         <release version="3.1-final" date="2008-06-??">
+           <action dev="POI-DEVELOPERS" type="add">44937 - Partial support for extracting Escher images from HWPF files</action>
            <action dev="POI-DEVELOPERS" type="fix">44824 - Avoid an infinite loop when reading some HWPF pictures</action>
            <action dev="POI-DEVELOPERS" type="fix">44898 - Correctly handle short last blocks in POIFS</action>
         </release>  
index da781461effe1cd046197ec220628e0d9075a4bb..796e2e203f3a4491c12085b962802f3e9481fad4 100644 (file)
@@ -34,6 +34,7 @@
        <!-- Don't forget to update changes.xml too! -->
     <changes>
         <release version="3.1-final" date="2008-06-??">
+           <action dev="POI-DEVELOPERS" type="add">44937 - Partial support for extracting Escher images from HWPF files</action>
            <action dev="POI-DEVELOPERS" type="fix">44824 - Avoid an infinite loop when reading some HWPF pictures</action>
            <action dev="POI-DEVELOPERS" type="fix">44898 - Correctly handle short last blocks in POIFS</action>
         </release>  
index f3d90c715d450a49453189c9921c834336073d53..ec3354c59952bac998f340f1d9fdaddd1afad284 100644 (file)
@@ -65,20 +65,27 @@ public class EscherClientAnchorRecord
         int size           = 0;
 
         // Always find 4 two byte entries. Sometimes find 9
-        field_1_flag   =  LittleEndian.getShort( data, pos + size );     size += 2;
-        field_2_col1   =  LittleEndian.getShort( data, pos + size );     size += 2;
-        field_3_dx1    =  LittleEndian.getShort( data, pos + size );     size += 2;
-        field_4_row1   =  LittleEndian.getShort( data, pos + size );     size += 2;
-        if(bytesRemaining >= 18) {
-                   field_5_dy1    =  LittleEndian.getShort( data, pos + size );     size += 2;
-                   field_6_col2   =  LittleEndian.getShort( data, pos + size );     size += 2;
-                   field_7_dx2    =  LittleEndian.getShort( data, pos + size );     size += 2;
-                   field_8_row2   =  LittleEndian.getShort( data, pos + size );     size += 2;
-                   field_9_dy2    =  LittleEndian.getShort( data, pos + size );     size += 2;
-                       shortRecord = false;
-        } else {
-                       shortRecord = true;
-               }
+        if (bytesRemaining == 4) // Word format only 4 bytes
+        {
+            // Not sure exactly what the format is quite yet, likely a reference to a PLC
+        }
+        else
+        {
+            field_1_flag   =  LittleEndian.getShort( data, pos + size );     size += 2;
+            field_2_col1   =  LittleEndian.getShort( data, pos + size );     size += 2;
+            field_3_dx1    =  LittleEndian.getShort( data, pos + size );     size += 2;
+            field_4_row1   =  LittleEndian.getShort( data, pos + size );     size += 2;
+            if(bytesRemaining >= 18) {
+                field_5_dy1    =  LittleEndian.getShort( data, pos + size );     size += 2;
+                field_6_col2   =  LittleEndian.getShort( data, pos + size );     size += 2;
+                field_7_dx2    =  LittleEndian.getShort( data, pos + size );     size += 2;
+                field_8_row2   =  LittleEndian.getShort( data, pos + size );     size += 2;
+                field_9_dy2    =  LittleEndian.getShort( data, pos + size );     size += 2;
+                shortRecord = false;
+            } else {
+                shortRecord = true;
+            }
+        }
         bytesRemaining -= size;
         remainingData  =  new byte[bytesRemaining];
         System.arraycopy( data, pos + size, remainingData, 0, bytesRemaining );
index a54e50de43c618c5a7d5f82507a0c88488c03d07..a43357f02146ea1950eb4b9914e04f2b6bcaf3d4 100644 (file)
@@ -53,10 +53,10 @@ public class HWPFDocument extends POIDocument
   protected FileInformationBlock _fib;
 
   /** main document stream buffer*/
-  private byte[] _mainStream;
+  protected byte[] _mainStream;
 
   /** table stream buffer*/
-  private byte[] _tableStream;
+  protected byte[] _tableStream;
 
   /** data stream buffer*/
   protected byte[] _dataStream;
@@ -93,6 +93,12 @@ public class HWPFDocument extends POIDocument
   
   /** Holds pictures table */
   protected PicturesTable _pictures;
+  
+  /** Holds FSBA (shape) information */
+  protected FSPATable _fspa;
+  
+  /** Escher Drawing Group information */
+  protected EscherRecordHolder _dgg;
 
   protected HWPFDocument()
   {
@@ -204,9 +210,6 @@ public class HWPFDocument extends POIDocument
     {
         _dataStream = new byte[0];
     }
-    
-    // read in the pictures stream
-    _pictures = new PicturesTable(this, _dataStream);
 
     // get the start of text in the main stream
     int fcMin = _fib.getFcMin();
@@ -226,6 +229,20 @@ public class HWPFDocument extends POIDocument
       _cbt.adjustForDelete(0, 0, cpMin);
       _pbt.adjustForDelete(0, 0, cpMin);
     }
+    
+    // Read FSPA and Escher information
+    _fspa = new FSPATable(_tableStream, _fib.getFcPlcspaMom(), _fib.getLcbPlcspaMom(), getTextTable().getTextPieces());
+    
+    if (_fib.getFcDggInfo() != 0)
+    {
+        _dgg = new EscherRecordHolder(_tableStream, _fib.getFcDggInfo(), _fib.getLcbDggInfo());
+    } else
+    {
+        _dgg = new EscherRecordHolder();
+    }
+    
+    // read in the pictures stream
+    _pictures = new PicturesTable(this, _dataStream, _mainStream, _fspa, _dgg);
 
     _st = new SectionTable(_mainStream, _tableStream, _fib.getFcPlcfsed(), _fib.getLcbPlcfsed(), fcMin, getTextTable().getTextPieces());
     _ss = new StyleSheet(_tableStream, _fib.getFcStshf());
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/EscherRecordHolder.java b/src/scratchpad/src/org/apache/poi/hwpf/model/EscherRecordHolder.java
new file mode 100644 (file)
index 0000000..4242dd4
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.apache.poi.hwpf.model;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.poi.ddf.DefaultEscherRecordFactory;
+import org.apache.poi.ddf.EscherContainerRecord;
+import org.apache.poi.ddf.EscherRecord;
+import org.apache.poi.ddf.EscherRecordFactory;
+
+/**
+ * Based on AbstractEscherRecordHolder fomr HSSF.
+ * 
+ * @author Squeeself
+ */
+public class EscherRecordHolder 
+{
+    protected ArrayList escherRecords = new ArrayList();
+    
+    public EscherRecordHolder()
+    {
+        
+    }
+    
+    public EscherRecordHolder(byte[] data, int offset, int size)
+    {
+        fillEscherRecords(data, offset, size);
+    }
+    
+    private void fillEscherRecords(byte[] data, int offset, int size)
+    {
+        EscherRecordFactory recordFactory = new DefaultEscherRecordFactory();
+        int pos = offset;
+        while ( pos < offset + size)
+        {
+            EscherRecord r = recordFactory.createRecord(data, pos);
+            escherRecords.add(r);
+            int bytesRead = r.fillFields(data, pos, recordFactory);
+            pos += bytesRead + 1; // There is an empty byte between each top-level record in a Word doc
+        }
+    }
+    
+    public List getEscherRecords()
+    {
+        return escherRecords;
+    }
+    
+    public String toString()
+    {
+        StringBuffer buffer = new StringBuffer();
+
+        final String nl = System.getProperty("line.separator");
+        if (escherRecords.size() == 0)
+            buffer.append("No Escher Records Decoded" + nl);
+        for ( Iterator iterator = escherRecords.iterator(); iterator.hasNext(); )
+        {
+            EscherRecord r = (EscherRecord) iterator.next();
+            buffer.append(r.toString());
+        }
+
+        return buffer.toString();
+    }
+    
+    /**
+     * If we have a EscherContainerRecord as one of our
+     *  children (and most top level escher holders do),
+     *  then return that.
+     */
+    public EscherContainerRecord getEscherContainer() {
+       for(Iterator it = escherRecords.iterator(); it.hasNext();) {
+               Object er = it.next();
+               if(er instanceof EscherContainerRecord) {
+                       return (EscherContainerRecord)er;
+               }
+       }
+       return null;
+    }
+
+    /**
+     * Descends into all our children, returning the
+     *  first EscherRecord with the given id, or null
+     *  if none found
+     */
+    public EscherRecord findFirstWithId(short id) {
+       return findFirstWithId(id, getEscherRecords());
+    }
+    private EscherRecord findFirstWithId(short id, List records) {
+       // Check at our level
+       for(Iterator it = records.iterator(); it.hasNext();) {
+               EscherRecord r = (EscherRecord)it.next();
+               if(r.getRecordId() == id) {
+                       return r;
+               }
+       }
+       
+       // Then check our children in turn
+       for(Iterator it = records.iterator(); it.hasNext();) {
+               EscherRecord r = (EscherRecord)it.next();
+               if(r.isContainerRecord()) {
+                       EscherRecord found =
+                               findFirstWithId(id, r.getChildRecords());
+                       if(found != null) {
+                               return found;
+                       }
+               }
+       }
+       
+       // Not found in this lot
+       return null;
+    }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/FSPA.java b/src/scratchpad/src/org/apache/poi/hwpf/model/FSPA.java
new file mode 100644 (file)
index 0000000..bb3d5de
--- /dev/null
@@ -0,0 +1,182 @@
+/* ====================================================================
+   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 org.apache.poi.util.BitField;
+import org.apache.poi.util.BitFieldFactory;
+import org.apache.poi.util.LittleEndian;
+
+/**
+ * File Shape Address structure
+ * 
+ * @author Squeeself
+ */
+public class FSPA 
+{
+    public static final int FSPA_SIZE = 26;
+    private int spid; // Shape identifier. Used to get data position
+    private int xaLeft; // Enclosing rectangle
+    private int yaTop; // Enclosing rectangle
+    private int xaRight; // Enclosing rectangle
+    private int yaBottom; // Enclosing rectangle
+    private short options;
+        private static BitField fHdr = BitFieldFactory.getInstance(0x0001); // 1 in undo when in header
+        private static BitField bx = BitFieldFactory.getInstance(0x0006); // x pos relative to anchor CP: 0 - page margin, 1 - top of page, 2 - text, 3 - reserved
+        private static BitField by = BitFieldFactory.getInstance(0x0018); // y pos relative to anchor CP: ditto
+        private static BitField wr = BitFieldFactory.getInstance(0x01E0); // Text wrapping mode: 0 - like 2 w/o absolute, 1 - no text next to shape, 2 - wrap around absolute object, 3 - wrap as if no object, 4 - wrap tightly around object, 5 - wrap tightly, allow holes, 6-15 - reserved
+        private static BitField wrk = BitFieldFactory.getInstance(0x1E00); // Text wrapping mode type (for modes 2&4): 0 - wrap both sides, 1 - wrap only left, 2 - wrap only right, 3 - wrap largest side
+        private static BitField fRcaSimple = BitFieldFactory.getInstance(0x2000); // Overwrites bx if set, forcing rectangle to be page relative
+        private static BitField fBelowText = BitFieldFactory.getInstance(0x4000); // if true, shape is below text, otherwise above
+        private static BitField fAnchorLock = BitFieldFactory.getInstance(0x8000); // if true, anchor is locked
+    private int cTxbx; // Count of textboxes in shape (undo doc only)
+    
+    public FSPA()
+    {
+    }
+    
+    public FSPA(byte[] bytes, int offset)
+    {
+        spid = LittleEndian.getInt(bytes, offset);
+        offset += LittleEndian.INT_SIZE;
+        xaLeft = LittleEndian.getInt(bytes, offset);
+        offset += LittleEndian.INT_SIZE;
+        yaTop = LittleEndian.getInt(bytes, offset);
+        offset += LittleEndian.INT_SIZE;
+        xaRight = LittleEndian.getInt(bytes, offset);
+        offset += LittleEndian.INT_SIZE;
+        yaBottom = LittleEndian.getInt(bytes, offset);
+        offset += LittleEndian.INT_SIZE;
+        options = LittleEndian.getShort(bytes, offset);
+        offset += LittleEndian.SHORT_SIZE;
+        cTxbx = LittleEndian.getInt(bytes, offset);
+    }
+    
+    public int getSpid()
+    {
+        return spid;
+    }
+    
+    public int getXaLeft()
+    {
+        return xaLeft;
+    }
+    
+    public int getYaTop()
+    {
+        return yaTop;
+    }
+    
+    public int getXaRight()
+    {
+        return xaRight;
+    }
+    
+    public int getYaBottom()
+    {
+        return yaBottom;
+    }
+    
+    public boolean isFHdr()
+    {
+        return fHdr.isSet(options);
+    }
+    
+    public short getBx()
+    {
+        return bx.getShortValue(options);
+    }
+    
+    public short getBy()
+    {
+        return by.getShortValue(options);
+    }
+    
+    public short getWr()
+    {
+        return wr.getShortValue(options);
+    }
+    
+    public short getWrk()
+    {
+        return wrk.getShortValue(options);
+    }
+    
+    public boolean isFRcaSimple()
+    {
+        return fRcaSimple.isSet(options);
+    }
+    
+    public boolean isFBelowText()
+    {
+        return fBelowText.isSet(options);
+    }
+    
+    public boolean isFAnchorLock()
+    {
+        return fAnchorLock.isSet(options);
+    }
+    
+    public int getCTxbx()
+    {
+        return cTxbx;
+    }
+    
+    public byte[] toByteArray()
+    {
+        int offset = 0;
+        byte[] buf = new byte[FSPA_SIZE];
+
+        LittleEndian.putInt(buf, offset, spid);
+        offset += LittleEndian.INT_SIZE;
+        LittleEndian.putInt(buf, offset, xaLeft);
+        offset += LittleEndian.INT_SIZE;
+        LittleEndian.putInt(buf, offset, yaTop);
+        offset += LittleEndian.INT_SIZE;
+        LittleEndian.putInt(buf, offset, xaRight);
+        offset += LittleEndian.INT_SIZE;
+        LittleEndian.putInt(buf, offset, yaBottom);
+        offset += LittleEndian.INT_SIZE;
+        LittleEndian.putShort(buf, offset, options);
+        offset += LittleEndian.SHORT_SIZE;
+        LittleEndian.putInt(buf, offset, cTxbx);
+        offset += LittleEndian.INT_SIZE;
+
+        return buf;
+    }
+    
+    public String toString()
+    {
+        StringBuffer buf = new StringBuffer();
+        buf.append("spid: ").append(spid);
+        buf.append(", xaLeft: ").append(xaLeft);
+        buf.append(", yaTop: ").append(yaTop);
+        buf.append(", xaRight: ").append(xaRight);
+        buf.append(", yaBottom: ").append(yaBottom);
+        buf.append(", options: ").append(options);
+            buf.append(" (fHdr: ").append(isFHdr());
+            buf.append(", bx: ").append(getBx());
+            buf.append(", by: ").append(getBy());
+            buf.append(", wr: ").append(getWr());
+            buf.append(", wrk: ").append(getWrk());
+            buf.append(", fRcaSimple: ").append(isFRcaSimple());
+            buf.append(", fBelowText: ").append(isFBelowText());
+            buf.append(", fAnchorLock: ").append(isFAnchorLock());
+        buf.append("), cTxbx: ").append(cTxbx);
+        return buf.toString();
+    }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/FSPATable.java b/src/scratchpad/src/org/apache/poi/hwpf/model/FSPATable.java
new file mode 100644 (file)
index 0000000..58c69ff
--- /dev/null
@@ -0,0 +1,82 @@
+/* ====================================================================
+   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.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This class holds all the FSPA (File Shape Address) structures.
+ * 
+ * @author Squeeself
+ */
+public class FSPATable 
+{
+    protected ArrayList shapes = new ArrayList();
+    protected HashMap cps = new HashMap();
+    protected List _text;
+    
+    public FSPATable(byte[] tableStream, int fcPlcspa, int lcbPlcspa, List tpt)
+    {
+        _text = tpt;
+        // Will be 0 if no drawing objects in document
+        if (fcPlcspa == 0)
+            return;
+        
+        PlexOfCps plex = new PlexOfCps(tableStream, fcPlcspa, lcbPlcspa, FSPA.FSPA_SIZE);
+        for (int i=0; i < plex.length(); i++)
+        {
+            GenericPropertyNode property = plex.getProperty(i);
+            FSPA fspa = new FSPA(property.getBytes(), 0);
+            
+            shapes.add(fspa);
+            cps.put(Integer.valueOf(property.getStart()), Integer.valueOf(i));
+        }
+    }
+    
+    public FSPA getFspaFromCp(int cp)
+    {
+        Integer idx = (Integer)cps.get(Integer.valueOf(cp));
+        if (idx == null)
+            return null;
+        return (FSPA)shapes.get(idx.intValue());
+    }
+    
+    public List getShapes()
+    {
+        return shapes;
+    }
+    
+    public String toString()
+    {
+        StringBuffer buf = new StringBuffer();
+        buf.append("[FPSA PLC size=").append(shapes.size()).append("]\n");
+        for (Iterator it = cps.keySet().iterator(); it.hasNext(); )
+        {
+            Integer i = (Integer) it.next();
+            FSPA fspa = (FSPA) shapes.get(((Integer)cps.get(i)).intValue());
+            buf.append("  [FC: ").append(i.toString()).append("] ");
+            buf.append(fspa.toString());
+            buf.append("\n");
+        }
+        buf.append("[/FSPA PLC]");
+        return buf.toString();
+    }
+}
index ee8f9724e9fcd4977b3ba0adbd3d714faf7a5dda..48e6d78b3a9852b7a654ccc8432daa6f8d44eb00 100644 (file)
@@ -308,6 +308,26 @@ public class FileInformationBlock extends FIBAbstractType
     {
       return _fieldHandler.getFieldSize(FIBFieldHandler.PLCFFLDMOM);
     }
+    
+    public int getFcPlcspaMom()
+    {
+        return _fieldHandler.getFieldOffset(FIBFieldHandler.PLCSPAMOM);
+    }
+    
+    public int getLcbPlcspaMom()
+    {
+        return _fieldHandler.getFieldSize(FIBFieldHandler.PLCSPAMOM);
+    }
+    
+    public int getFcDggInfo()
+    {
+        return _fieldHandler.getFieldOffset(FIBFieldHandler.DGGINFO);
+    }
+    
+    public int getLcbDggInfo()
+    {
+        return _fieldHandler.getFieldSize(FIBFieldHandler.DGGINFO);
+    }
 
     public void writeTo (byte[] mainStream, HWPFOutputStream tableStream)
       throws IOException
index d9598b1061cefad7b934deaf5fe0cff0c1b8a0b3..9681741d94256ad2ffd9bec1344a6a89c83e6fcc 100644 (file)
@@ -26,7 +26,12 @@ import org.apache.poi.hwpf.usermodel.Range;
 
 import java.util.List;
 import java.util.ArrayList;
-
+import java.util.Iterator;
+import org.apache.poi.ddf.DefaultEscherRecordFactory;
+import org.apache.poi.ddf.EscherBSERecord;
+import org.apache.poi.ddf.EscherBlipRecord;
+import org.apache.poi.ddf.EscherRecord;
+import org.apache.poi.ddf.EscherRecordFactory;
 
 /**
  * Holds information about all pictures embedded in Word Document either via "Insert -> Picture -> From File" or via
@@ -57,6 +62,9 @@ public class PicturesTable
 
   private HWPFDocument _document;
   private byte[] _dataStream;
+  private byte[] _mainStream;
+  private FSPATable _fspa;
+  private EscherRecordHolder _dgg;
 
   /** @link dependency
    * @stereotype instantiate*/
@@ -67,10 +75,13 @@ public class PicturesTable
    * @param document 
    * @param _dataStream
    */
-  public PicturesTable(HWPFDocument _document, byte[] _dataStream)
+  public PicturesTable(HWPFDocument _document, byte[] _dataStream, byte[] _mainStream, FSPATable fspa, EscherRecordHolder dgg)
   {
-       this._document = _document;
+    this._document = _document;
     this._dataStream = _dataStream;
+    this._mainStream = _mainStream;
+    this._fspa = fspa;
+    this._dgg = dgg;
   }
 
   /**
@@ -83,6 +94,13 @@ public class PicturesTable
     }
     return false;
   }
+  
+  public boolean hasEscherPicture(CharacterRun run) {
+    if (run.isSpecialCharacter() && !run.isObj() && !run.isOle2() && !run.isData() && run.text().startsWith("\u0008")) {
+      return true;
+    }
+    return false;
+  }
 
   /**
    * determines whether specified CharacterRun contains reference to a picture
@@ -122,6 +140,46 @@ public class PicturesTable
     }
     return null;
   }
+  
+  /**
+     * Performs a recursive search for pictures in the given list of escher records.
+     *
+     * @param escherRecords the escher records.
+     * @param pictures the list to populate with the pictures.
+     */
+    private void searchForPictures(List escherRecords, List pictures)
+    {
+        Iterator recordIter = escherRecords.iterator();
+        while (recordIter.hasNext())
+        {
+            Object obj = recordIter.next();
+            if (obj instanceof EscherRecord)
+            {
+                EscherRecord escherRecord = (EscherRecord) obj;
+
+                if (escherRecord instanceof EscherBSERecord)
+                {
+                    EscherBSERecord bse = (EscherBSERecord) escherRecord;
+                    EscherBlipRecord blip = bse.getBlipRecord();
+                    if (blip != null)
+                    {
+                        pictures.add(new Picture(blip.getPicturedata()));
+                    }
+                    else if (bse.getOffset() > 0)
+                    {
+                        // Blip stored in delay stream, which in a word doc, is the main stream
+                        EscherRecordFactory recordFactory = new DefaultEscherRecordFactory();
+                        blip = (EscherBlipRecord) recordFactory.createRecord(_mainStream, bse.getOffset());
+                        blip.fillFields(_mainStream, bse.getOffset(), recordFactory);
+                        pictures.add(new Picture(blip.getPicturedata()));
+                    }
+                }
+
+                // Recursive call.
+                searchForPictures(escherRecord.getChildRecords(), pictures);
+            }
+        }
+    }
 
   /**
    * Not all documents have all the images concatenated in the data stream
@@ -136,12 +194,13 @@ public class PicturesTable
     for (int i = 0; i < range.numCharacterRuns(); i++) {
        CharacterRun run = range.getCharacterRun(i);
        String text = run.text();
-       int j = text.charAt(0);
        Picture picture = extractPicture(run, false);
        if (picture != null) {
                pictures.add(picture);
        }
        }
+    
+    searchForPictures(_dgg.getEscherRecords(), pictures);
 
     return pictures;
   }
index 473a9331bf3d8b4906799c6224e7d19a85b1e459..8a3737865bbf408e7f8f2ff0b1a96df36be0c3cf 100644 (file)
@@ -98,6 +98,15 @@ public class Picture
       fillImageContent();
     }
   }
+  
+  public Picture(byte[] _dataStream)
+  {
+      this._dataStream = _dataStream;
+      this.dataBlockStartOfsset = 0;
+      this.dataBlockSize = _dataStream.length;
+      this.pictureBytesStartOffset = 0;
+      this.size = _dataStream.length;
+  }
 
   private void fillWidthHeight()
   {
index bf867c40d410cb389fa607120da028e1aebd3650..bcf02a8a1da3c6b3f74ac686fc53f4e932bef3de 100644 (file)
@@ -35,10 +35,12 @@ public class TestHWPFPictures extends TestCase {
        private String docAFile;
        private String docBFile;
        private String docCFile;
+    private String docDFile;
        
        private String imgAFile;
        private String imgBFile;
        private String imgCFile;
+    private String imgDFile;
        
        protected void setUp() throws Exception {
                String dirname = System.getProperty("HWPF.testdata.path");
@@ -46,10 +48,12 @@ public class TestHWPFPictures extends TestCase {
                docAFile = dirname + "/testPictures.doc";
                docBFile = dirname + "/two_images.doc";
                docCFile = dirname + "/vector_image.doc";
+        docDFile = dirname + "/GaiaTest.doc";
                
                imgAFile = dirname + "/simple_image.jpg";
                imgBFile = dirname + "/simple_image.png";
                imgCFile = dirname + "/vector_image.emf";
+        imgDFile = dirname + "/GaiaTestImg.png";
        }
        
        /**
@@ -126,7 +130,26 @@ public class TestHWPFPictures extends TestCase {
                assertEquals(picBytes.length, pic.getContent().length);
                assertBytesSame(picBytes, pic.getContent());
        }
-       
+    
+       /**
+        * Pending the missing files being uploaded to
+        *  bug #44937
+        */
+    public void BROKENtestEscherDrawing() throws Exception
+    {
+        HWPFDocument docD = new HWPFDocument(new FileInputStream(docDFile));
+        List allPictures = docD.getPicturesTable().getAllPictures();
+        
+        assertEquals(1, allPictures.size());
+        
+        Picture pic = (Picture) allPictures.get(0);
+        assertNotNull(pic);
+        byte[] picD = readFile(imgDFile);
+        
+        assertEquals(picD.length, pic.getContent().length);
+        
+        assertBytesSame(picD, pic.getContent());
+    }
        
        private void assertBytesSame(byte[] a, byte[] b) {
                assertEquals(a.length, b.length);