diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml
index 421404a94..8dd956c16 100644
--- a/src/documentation/content/xdocs/changes.xml
+++ b/src/documentation/content/xdocs/changes.xml
@@ -37,6 +37,7 @@
+ 44937 - Partial support for extracting Escher images from HWPF files
44824 - Avoid an infinite loop when reading some HWPF pictures
44898 - Correctly handle short last blocks in POIFS
diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml
index da781461e..796e2e203 100644
--- a/src/documentation/content/xdocs/status.xml
+++ b/src/documentation/content/xdocs/status.xml
@@ -34,6 +34,7 @@
+ 44937 - Partial support for extracting Escher images from HWPF files
44824 - Avoid an infinite loop when reading some HWPF pictures
44898 - Correctly handle short last blocks in POIFS
diff --git a/src/java/org/apache/poi/ddf/EscherClientAnchorRecord.java b/src/java/org/apache/poi/ddf/EscherClientAnchorRecord.java
index f3d90c715..ec3354c59 100644
--- a/src/java/org/apache/poi/ddf/EscherClientAnchorRecord.java
+++ b/src/java/org/apache/poi/ddf/EscherClientAnchorRecord.java
@@ -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 );
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java b/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java
index a54e50de4..a43357f02 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java
@@ -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
index 000000000..4242dd4df
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/EscherRecordHolder.java
@@ -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
index 000000000..bb3d5def1
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/FSPA.java
@@ -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
index 000000000..58c69ff4b
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/FSPATable.java
@@ -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();
+ }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java b/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java
index ee8f9724e..48e6d78b3 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java
@@ -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
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/PicturesTable.java b/src/scratchpad/src/org/apache/poi/hwpf/model/PicturesTable.java
index d9598b106..9681741d9 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/PicturesTable.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/PicturesTable.java
@@ -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;
}
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java
index 473a9331b..8a3737865 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java
@@ -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()
{
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/TestHWPFPictures.java b/src/scratchpad/testcases/org/apache/poi/hwpf/TestHWPFPictures.java
index bf867c40d..bcf02a8a1 100644
--- a/src/scratchpad/testcases/org/apache/poi/hwpf/TestHWPFPictures.java
+++ b/src/scratchpad/testcases/org/apache/poi/hwpf/TestHWPFPictures.java
@@ -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);