You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ni...@apache.org on 2008/05/20 18:01:54 UTC

svn commit: r658302 - in /poi/trunk/src: documentation/content/xdocs/ java/org/apache/poi/ddf/ scratchpad/src/org/apache/poi/hwpf/ scratchpad/src/org/apache/poi/hwpf/model/ scratchpad/src/org/apache/poi/hwpf/usermodel/ scratchpad/testcases/org/apache/p...

Author: nick
Date: Tue May 20 09:01:53 2008
New Revision: 658302

URL: http://svn.apache.org/viewvc?rev=658302&view=rev
Log:
Patch from bug #44937 from Squeeself- Partial support for extracting Escher images from HWPF files

Added:
    poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/EscherRecordHolder.java   (with props)
    poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FSPA.java   (with props)
    poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FSPATable.java   (with props)
Modified:
    poi/trunk/src/documentation/content/xdocs/changes.xml
    poi/trunk/src/documentation/content/xdocs/status.xml
    poi/trunk/src/java/org/apache/poi/ddf/EscherClientAnchorRecord.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/PicturesTable.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hwpf/TestHWPFPictures.java

Modified: poi/trunk/src/documentation/content/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/poi/trunk/src/documentation/content/xdocs/changes.xml?rev=658302&r1=658301&r2=658302&view=diff
==============================================================================
--- poi/trunk/src/documentation/content/xdocs/changes.xml (original)
+++ poi/trunk/src/documentation/content/xdocs/changes.xml Tue May 20 09:01:53 2008
@@ -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>  

Modified: poi/trunk/src/documentation/content/xdocs/status.xml
URL: http://svn.apache.org/viewvc/poi/trunk/src/documentation/content/xdocs/status.xml?rev=658302&r1=658301&r2=658302&view=diff
==============================================================================
--- poi/trunk/src/documentation/content/xdocs/status.xml (original)
+++ poi/trunk/src/documentation/content/xdocs/status.xml Tue May 20 09:01:53 2008
@@ -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>  

Modified: poi/trunk/src/java/org/apache/poi/ddf/EscherClientAnchorRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ddf/EscherClientAnchorRecord.java?rev=658302&r1=658301&r2=658302&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ddf/EscherClientAnchorRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/ddf/EscherClientAnchorRecord.java Tue May 20 09:01:53 2008
@@ -65,20 +65,27 @@
         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 );

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java?rev=658302&r1=658301&r2=658302&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java Tue May 20 09:01:53 2008
@@ -53,10 +53,10 @@
   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 @@
   
   /** 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 @@
     {
         _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 @@
       _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());

Added: poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/EscherRecordHolder.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/EscherRecordHolder.java?rev=658302&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/EscherRecordHolder.java (added)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/EscherRecordHolder.java Tue May 20 09:01:53 2008
@@ -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;
+    }
+}

Propchange: poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/EscherRecordHolder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FSPA.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FSPA.java?rev=658302&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FSPA.java (added)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FSPA.java Tue May 20 09:01:53 2008
@@ -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();
+    }
+}

Propchange: poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FSPA.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FSPATable.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FSPATable.java?rev=658302&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FSPATable.java (added)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FSPATable.java Tue May 20 09:01:53 2008
@@ -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();
+    }
+}

Propchange: poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FSPATable.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java?rev=658302&r1=658301&r2=658302&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java Tue May 20 09:01:53 2008
@@ -308,6 +308,26 @@
     {
       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

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/PicturesTable.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/PicturesTable.java?rev=658302&r1=658301&r2=658302&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/PicturesTable.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/PicturesTable.java Tue May 20 09:01:53 2008
@@ -26,7 +26,12 @@
 
 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 @@
 
   private HWPFDocument _document;
   private byte[] _dataStream;
+  private byte[] _mainStream;
+  private FSPATable _fspa;
+  private EscherRecordHolder _dgg;
 
   /** @link dependency
    * @stereotype instantiate*/
@@ -67,10 +75,13 @@
    * @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 @@
     }
     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 @@
     }
     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 @@
     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;
   }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java?rev=658302&r1=658301&r2=658302&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java Tue May 20 09:01:53 2008
@@ -98,6 +98,15 @@
       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()
   {

Modified: poi/trunk/src/scratchpad/testcases/org/apache/poi/hwpf/TestHWPFPictures.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/testcases/org/apache/poi/hwpf/TestHWPFPictures.java?rev=658302&r1=658301&r2=658302&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/testcases/org/apache/poi/hwpf/TestHWPFPictures.java (original)
+++ poi/trunk/src/scratchpad/testcases/org/apache/poi/hwpf/TestHWPFPictures.java Tue May 20 09:01:53 2008
@@ -35,10 +35,12 @@
 	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 @@
 		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 @@
 		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);



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org