<!-- Don't forget to update status.xml too! -->
<release version="3.1-final" date="2008-06-??">
+ <action dev="POI-DEVELOPERS" type="add">44840 - Improved handling of HSSFObjectData, especially for entries with data held not in POIFS</action>
<action dev="POI-DEVELOPERS" type="add">45043 - Support for getting excel cell comments when extracting text</action>
<action dev="POI-DEVELOPERS" type="add">Extend the support for specifying a policy to HSSF on missing / blank cells when fetching, to be able to specify the policy at the HSSFWorkbook level</action>
<action dev="POI-DEVELOPERS" type="fix">45025 - improved FormulaParser parse error messages</action>
<!-- Don't forget to update changes.xml too! -->
<changes>
<release version="3.1-final" date="2008-06-??">
+ <action dev="POI-DEVELOPERS" type="add">44840 - Improved handling of HSSFObjectData, especially for entries with data held not in POIFS</action>
<action dev="POI-DEVELOPERS" type="add">45043 - Support for getting excel cell comments when extracting text</action>
<action dev="POI-DEVELOPERS" type="add">Extend the support for specifying a policy to HSSF on missing / blank cells when fetching, to be able to specify the policy at the HSSFWorkbook level</action>
<action dev="POI-DEVELOPERS" type="fix">45025 - improved FormulaParser parse error messages</action>
in.readByte(); // discard
}
- field_6_stream_id = in.readInt();
+ // Fetch the stream ID
+ field_6_stream_id = in.readInt();
+
+ // Store what's left
remainingBytes = in.readRemainder();
}
this.record = record;
this.poifs = poifs;
}
+
+ /**
+ * Returns the OLE2 Class Name of the object
+ */
+ public String getOLE2ClassName() {
+ EmbeddedObjectRefSubRecord subRecord = findObjectRecord();
+ return subRecord.field_5_ole_classname;
+ }
/**
- * Gets the object data.
+ * Gets the object data. Only call for ones that have
+ * data though. See {@link #hasDirectoryEntry()}
*
* @return the object data as an OLE2 directory.
* @throws IOException if there was an error reading the data.
*/
- public DirectoryEntry getDirectory() throws IOException
- {
+ public DirectoryEntry getDirectory() throws IOException {
+ EmbeddedObjectRefSubRecord subRecord = findObjectRecord();
+
+ int streamId = ((EmbeddedObjectRefSubRecord) subRecord).getStreamId();
+ String streamName = "MBD" + HexDump.toHex(streamId);
+
+ Entry entry = poifs.getRoot().getEntry(streamName);
+ if (entry instanceof DirectoryEntry) {
+ return (DirectoryEntry) entry;
+ } else {
+ throw new IOException("Stream " + streamName + " was not an OLE2 directory");
+ }
+ }
+
+ /**
+ * Returns the data portion, for an ObjectData
+ * that doesn't have an associated POIFS Directory
+ * Entry
+ */
+ public byte[] getObjectData() {
+ EmbeddedObjectRefSubRecord subRecord = findObjectRecord();
+ return subRecord.remainingBytes;
+ }
+
+ /**
+ * Does this ObjectData have an associated POIFS
+ * Directory Entry?
+ * (Not all do, those that don't have a data portion)
+ */
+ public boolean hasDirectoryEntry() {
+ EmbeddedObjectRefSubRecord subRecord = findObjectRecord();
+
+ // Field 6 tells you
+ return (subRecord.field_6_stream_id != 0);
+ }
+
+ /**
+ * Finds the EmbeddedObjectRefSubRecord, or throws an
+ * Exception if there wasn't one
+ */
+ protected EmbeddedObjectRefSubRecord findObjectRecord() {
Iterator subRecordIter = record.getSubRecords().iterator();
- while (subRecordIter.hasNext())
- {
+
+ while (subRecordIter.hasNext()) {
Object subRecord = subRecordIter.next();
- if (subRecord instanceof EmbeddedObjectRefSubRecord)
- {
- int streamId = ((EmbeddedObjectRefSubRecord) subRecord).getStreamId();
- String streamName = "MBD" + HexDump.toHex(streamId);
-
- Entry entry = poifs.getRoot().getEntry(streamName);
- if (entry instanceof DirectoryEntry)
- {
- return (DirectoryEntry) entry;
- }
- else
- {
- throw new IOException("Stream " + streamName + " was not an OLE2 directory");
- }
+ if (subRecord instanceof EmbeddedObjectRefSubRecord) {
+ return (EmbeddedObjectRefSubRecord)subRecord;
}
}
-
+
throw new IllegalStateException("Object data does not contain a reference to an embedded object OLE2 directory");
}
}
package org.apache.poi.hssf.usermodel;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
+import java.util.List;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.record.EmbeddedObjectRefSubRecord;
import org.apache.poi.hssf.util.Region;
import org.apache.poi.util.TempFile;
writeOutAndReadBack(wb);
assertTrue("no errors writing sample xls", true);
}
+
+ /**
+ * Problems with extracting check boxes from
+ * HSSFObjectData
+ * @throws Exception
+ */
+ public void test44840() throws Exception {
+ HSSFWorkbook wb = openSample("WithCheckBoxes.xls");
+
+ // Take a look at the embeded objects
+ List objects = wb.getAllEmbeddedObjects();
+ assertEquals(1, objects.size());
+
+ HSSFObjectData obj = (HSSFObjectData)objects.get(0);
+ assertNotNull(obj);
+
+ // Peek inside the underlying record
+ EmbeddedObjectRefSubRecord rec = obj.findObjectRecord();
+ assertNotNull(rec);
+
+ assertEquals(32, rec.field_1_stream_id_offset);
+ assertEquals(0, rec.field_6_stream_id); // WRONG!
+ assertEquals("Forms.CheckBox.1", rec.field_5_ole_classname);
+ assertEquals(12, rec.remainingBytes.length);
+
+ // Doesn't have a directory
+ assertFalse(obj.hasDirectoryEntry());
+ assertNotNull(obj.getObjectData());
+ assertEquals(12, obj.getObjectData().length);
+ assertEquals("Forms.CheckBox.1", obj.getOLE2ClassName());
+
+ try {
+ obj.getDirectory();
+ fail();
+ } catch(FileNotFoundException e) {}
+ }
}