diff --git a/src/java/org/apache/poi/hssf/record/DrawingRecord.java b/src/java/org/apache/poi/hssf/record/DrawingRecord.java index 4dbc53015..d73702b6a 100644 --- a/src/java/org/apache/poi/hssf/record/DrawingRecord.java +++ b/src/java/org/apache/poi/hssf/record/DrawingRecord.java @@ -23,6 +23,7 @@ public class DrawingRecord extends Record public static final short sid = 0xEC; private byte[] recordData; + private byte[] contd; public DrawingRecord() { @@ -53,10 +54,8 @@ public class DrawingRecord extends Record public void processContinueRecord( byte[] record ) { - byte[] newBuffer = new byte[ recordData.length + record.length ]; - System.arraycopy( recordData, 0, newBuffer, 0, recordData.length ); - System.arraycopy( record, 0, newBuffer, recordData.length, record.length); - recordData = newBuffer; + //don't merge continue record with the drawing record, it must be serialized separately + contd = record; } public int serialize( int offset, byte[] data ) @@ -92,7 +91,14 @@ public class DrawingRecord extends Record public byte[] getData() { - return recordData; + if(contd != null) { + byte[] newBuffer = new byte[ recordData.length + contd.length ]; + System.arraycopy( recordData, 0, newBuffer, 0, recordData.length ); + System.arraycopy( contd, 0, newBuffer, recordData.length, contd.length); + return newBuffer; + } else { + return recordData; + } } public void setData( byte[] thedata ) diff --git a/src/java/org/apache/poi/hssf/record/RecordFactory.java b/src/java/org/apache/poi/hssf/record/RecordFactory.java index 398576dc7..927d5f08b 100644 --- a/src/java/org/apache/poi/hssf/record/RecordFactory.java +++ b/src/java/org/apache/poi/hssf/record/RecordFactory.java @@ -140,6 +140,9 @@ public class RecordFactory // Drawing records have a very strange continue behaviour. //There can actually be OBJ records mixed between the continues. lastDrawingRecord.processContinueRecord( ((ContinueRecord)record).getData() ); + //we must rememeber the position of the continue record. + //in the serialization procedure the original structure of records must be preserved + records.add(record); } else if (record.getSid() == ContinueRecord.sid && (lastRecord instanceof DrawingGroupRecord)) { ((DrawingGroupRecord)lastRecord).processContinueRecord(((ContinueRecord)record).getData()); diff --git a/src/testcases/org/apache/poi/hssf/data/39512.xls b/src/testcases/org/apache/poi/hssf/data/39512.xls new file mode 100644 index 000000000..44cf5718e Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/39512.xls differ diff --git a/src/testcases/org/apache/poi/hssf/record/TestRecordFactory.java b/src/testcases/org/apache/poi/hssf/record/TestRecordFactory.java index 4dbb2a5b0..4f721a798 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestRecordFactory.java +++ b/src/testcases/org/apache/poi/hssf/record/TestRecordFactory.java @@ -20,8 +20,13 @@ package org.apache.poi.hssf.record; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.List; +import java.util.Iterator; +import java.util.Arrays; import junit.framework.TestCase; +import org.apache.poi.util.HexRead; /** * Tests the record factory @@ -166,6 +171,63 @@ public class TestRecordFactory assertEquals("4th data byte", 4, record.getData()[ 0 ]); } + /** + * Drawing records have a very strange continue behaviour. + * There can actually be OBJ records mixed between the continues. + * Record factory must preserve this structure when reading records. + */ + public void testMixedContinue() throws Exception { + /** + * Taken from a real file $HSSF.testdata.path/39512.xls. See Bug 39512 for details. + */ + String dump = + //OBJ + "5D, 00, 48, 00, 15, 00, 12, 00, 0C, 00, 3C, 00, 11, 00, A0, 2E, 03, 01, CC, 42, " + + "CF, 00, 00, 00, 00, 00, 0A, 00, 0C, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, " + + "03, 00, 0B, 00, 06, 00, 28, 01, 03, 01, 00, 00, 12, 00, 08, 00, 00, 00, 00, 00, " + + "00, 00, 03, 00, 11, 00, 04, 00, 3D, 00, 00, 00, 00, 00, 00, 00, " + + //MSODRAWING + "EC, 00, 08, 00, 00, 00, 0D, F0, 00, 00, 00, 00, " + + //TXO + "B6, 01, 12, 00, 22, 02, 00, 00, 00, 00, 00, 00, 00, 00, 10, 00, 10, 00, 00, 00, " + + "00, 00, 3C, 00, 21, 00, 01, 4F, 00, 70, 00, 74, 00, 69, 00, 6F, 00, 6E, 00, 20, " + + "00, 42, 00, 75, 00, 74, 00, 74, 00, 6F, 00, 6E, 00, 20, 00, 33, 00, 39, 00, 3C, " + + "00, 10, 00, 00, 00, 05, 00, 00, 00, 00, 00, 10, 00, 00, 00, 00, 00, 00, 00, " + + //CONTINUE + "3C, 00, 7E, 00, 0F, 00, 04, F0, 7E, 00, 00, 00, 92, 0C, 0A, F0, 08, 00, 00, 00, " + + "3D, 04, 00, 00, 00, 0A, 00, 00, A3, 00, 0B, F0, 3C, 00, 00, 00, 7F, 00, 00, 01, " + + "00, 01, 80, 00, 8C, 01, 03, 01, 85, 00, 01, 00, 00, 00, 8B, 00, 02, 00, 00, 00, " + + "BF, 00, 08, 00, 1A, 00, 7F, 01, 29, 00, 29, 00, 81, 01, 41, 00, 00, 08, BF, 01, " + + "00, 00, 10, 00, C0, 01, 40, 00, 00, 08, FF, 01, 00, 00, 08, 00, 00, 00, 10, F0, " + + "12, 00, 00, 00, 02, 00, 02, 00, A0, 03, 18, 00, B5, 00, 04, 00, 30, 02, 1A, 00, " + + "00, 00, 00, 00, 11, F0, 00, 00, 00, 00, " + + //OBJ + "5D, 00, 48, 00, 15, 00, 12, 00, 0C, 00, 3D, 00, 11, 00, 8C, 01, 03, 01, C8, 59, CF, 00, 00, " + + "00, 00, 00, 0A, 00, 0C, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 03, 00, 0B, 00, 06, 00, " + + "7C, 16, 03, 01, 00, 00, 12, 00, 08, 00, 00, 00, 00, 00, 00, 00, 03, 00, 11, 00, 04, 00, 01, " + + "00, 00, 00, 00, 00, 00, 00"; + byte[] data = HexRead.readFromString(dump); + + List records = RecordFactory.createRecords(new ByteArrayInputStream(data)); + assertEquals(5, records.size()); + assertTrue(records.get(0) instanceof ObjRecord); + assertTrue(records.get(1) instanceof DrawingRecord); + assertTrue(records.get(2) instanceof TextObjectRecord); + assertTrue(records.get(3) instanceof ContinueRecord); + assertTrue(records.get(4) instanceof ObjRecord); + + //serialize and verify that the serialized data is the same as the original + ByteArrayOutputStream out = new ByteArrayOutputStream(); + for(Iterator it = records.iterator(); it.hasNext(); ){ + Record rec = (Record)it.next(); + out.write(rec.serialize()); + } + + byte[] ser = out.toByteArray(); + assertEquals(data.length, ser.length); + assertTrue(Arrays.equals(data, ser)); + } + public static void main(String [] ignored_args) { System.out