View | Details | Raw Unified | Return to bug 53010
Collapse All | Expand All

(-)src/testcases/org/apache/poi/hssf/model/TestDrawingAggregate.java (-121 / +147 lines)
Lines 17-27 Link Here
17
package org.apache.poi.hssf.model;
17
package org.apache.poi.hssf.model;
18
18
19
import junit.framework.TestCase;
19
import junit.framework.TestCase;
20
import org.apache.poi.ddf.EscherClientDataRecord;
21
import org.apache.poi.ddf.EscherContainerRecord;
22
import org.apache.poi.ddf.EscherDggRecord;
20
import org.apache.poi.ddf.EscherDggRecord;
23
import org.apache.poi.ddf.EscherRecord;
24
import org.apache.poi.ddf.EscherSpRecord;
25
import org.apache.poi.hssf.HSSFTestDataSamples;
21
import org.apache.poi.hssf.HSSFTestDataSamples;
26
import org.apache.poi.hssf.record.*;
22
import org.apache.poi.hssf.record.*;
27
import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
23
import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
Lines 30-176 Link Here
30
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
26
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
31
import org.apache.poi.util.HexRead;
27
import org.apache.poi.util.HexRead;
32
28
33
import java.io.ByteArrayInputStream;
29
import java.io.*;
34
import java.util.ArrayList;
30
import java.util.Arrays;
35
import java.util.LinkedHashMap;
36
import java.util.List;
31
import java.util.List;
37
import java.util.Map;
38
32
39
/**
33
/**
40
 * @author Yegor Kozlov
34
 * @author Yegor Kozlov
41
 * @author Evgeniy Berlog
35
 * @author Evgeniy Berlog
42
 */
36
 */
43
public class TestDrawingAggregate extends TestCase {
37
public class TestDrawingAggregate extends TestCase {
38
    private static byte[] toByteArray(List<RecordBase> records){
39
            ByteArrayOutputStream out = new ByteArrayOutputStream();
40
            for(RecordBase rb : records) {
41
                    Record r = (Record)rb;
42
                    try {
43
                            out.write(r.serialize());
44
                        } catch (IOException e){
45
                            throw new RuntimeException(e);
46
                        }
47
                }
48
            return out.toByteArray();
49
        }
50
44
    /**
51
    /**
45
     * Serialize escher aggregate, read back and assert that the drawing data is preserved.
52
     * test reading drawing aggregate from a test file from Bugzilla 45129
46
     *
47
     * @param agg the aggregate to test
48
     * @return verified aggregate (serialized and read back)
49
     */
53
     */
50
    public static EscherAggregate assertWriteAndReadBack(EscherAggregate agg) {
54
    public void test45129() {
51
        byte[] dgBytes = agg.serialize();
55
        HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("45129.xls");
56
        HSSFSheet sh = wb.getSheetAt(0);
52
57
58
        InternalWorkbook iworkbook = HSSFTestHelper.getWorkbookForTest(wb);
59
        InternalSheet isheet = HSSFTestHelper.getSheetForTest(sh);
53
60
54
        List<Record> dgRecords = RecordFactory.createRecords(new ByteArrayInputStream(dgBytes));
61
        List<RecordBase> records = isheet.getRecords();
55
62
56
        DrawingManager2 drawingManager = new DrawingManager2(new EscherDggRecord());
63
        // the sheet's drawing is not aggregated
64
        assertEquals("wrong size of sheet records stream", 394, records.size());
65
        // the last record before the drawing block
66
        assertTrue(
67
                "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass().getSimpleName(),
68
                records.get(18) instanceof RowRecordsAggregate);
57
69
58
        // create a dummy sheet consisting of our test data
70
        // records to be aggregated
59
        InternalSheet sheet = InternalSheet.createSheet();
71
        List<RecordBase> dgRecords = records.subList(19, 389);
60
        List<RecordBase> records = sheet.getRecords();
72
        // collect drawing records into a byte buffer.
61
        records.clear();
73
        byte[] dgBytes = toByteArray(dgRecords);
62
        records.addAll(dgRecords);
63
        records.add(EOFRecord.instance);
64
74
75
        for (RecordBase rb : dgRecords) {
76
            Record r = (Record) rb;
77
            short sid = r.getSid();
78
            // we expect that drawing block consists of either
79
            // DrawingRecord or ContinueRecord or ObjRecord or TextObjectRecord
80
            assertTrue(
81
                    sid == DrawingRecord.sid ||
82
                            sid == ContinueRecord.sid ||
83
                            sid == ObjRecord.sid ||
84
                            sid == TextObjectRecord.sid);
85
        }
65
86
66
        sheet.aggregateDrawingRecords(drawingManager, false);
87
        // the first record after the drawing block
67
        assertEquals("drawing was not fully aggregated", 2, records.size());
88
        assertTrue(
68
        assertTrue("expected EscherAggregate", records.get(0) instanceof EscherAggregate);
89
                "records.get(389) is expected to be Window2",
69
        assertTrue("expected EOFRecord", records.get(1) instanceof EOFRecord);
90
                records.get(389) instanceof WindowTwoRecord);
70
        EscherAggregate agg2 = (EscherAggregate) records.get(0);
71
91
72
        assertEquals(agg.getEscherRecords().size(), agg2.getEscherRecords().size());
92
        // aggregate drawing records.
93
        // The subrange [19, 388] is expected to be replaced with a EscherAggregate object
94
        DrawingManager2 drawingManager = iworkbook.findDrawingGroup();
95
        int loc = isheet.aggregateDrawingRecords(drawingManager, false);
96
        EscherAggregate agg = (EscherAggregate) records.get(loc);
73
97
74
        // assert that both pre- and after- serialize aggregates have the same xml representation
98
        assertEquals("wrong size of the aggregated sheet records stream", 25, records.size());
75
        for (int i = 0; i < agg.getEscherRecords().size(); i++) {
99
        assertTrue(
76
            EscherRecord r1 = agg.getEscherRecords().get(i);
100
                "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass().getSimpleName(),
77
            EscherRecord r2 = agg2.getEscherRecords().get(i);
101
                records.get(18) instanceof RowRecordsAggregate);
102
        assertTrue("records.get(19) is expected to be EscherAggregate but was " + records.get(19).getClass().getSimpleName(),
103
                records.get(19) instanceof EscherAggregate);
104
        assertTrue("records.get(20) is expected to be Window2 but was " + records.get(20).getClass().getSimpleName(),
105
                records.get(20) instanceof WindowTwoRecord);
78
106
79
            assertEquals(r1.toXml(), r2.toXml());
107
        byte[] dgBytesAfterSave = agg.serialize();
108
        assertEquals("different size of drawing data before and after save", dgBytes.length, dgBytesAfterSave.length);
109
        assertTrue("drawing data brefpore and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));
80
        }
110
    }
81
111
82
        return agg2;
83
    }
84
85
    /**
112
    /**
86
     * assert that mapping of Obj records to escher shape containers is the same in both aggregates
113
     * Try to check file with such record sequence
114
     * ...
115
     * DrawingRecord
116
     * ContinueRecord
117
     * ObjRecord | TextObjRecord
118
     * ...
87
     */
119
     */
88
    public static void assertObjectMappingSame(EscherAggregate agg1, EscherAggregate agg2) {
120
    public void testSerializeDrawingBigger8k() {
121
        HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("DrawingContinue.xls");
122
        InternalWorkbook iworkbook = HSSFTestHelper.getWorkbookForTest(wb);
123
        HSSFSheet sh = wb.getSheetAt(0);
124
        InternalSheet isheet = HSSFTestHelper.getSheetForTest(sh);
89
125
90
        // map EscherClientDataRecord and EscherTextboxRecord to their parents
126
        List<RecordBase> records = isheet.getRecords();
91
        Map<EscherRecord, EscherContainerRecord> map1 = new LinkedHashMap<EscherRecord, EscherContainerRecord>();
92
        for (EscherRecord r : agg1.getEscherRecords()) mapShapeContainers(r, map1);
93
127
94
        Map<EscherRecord, EscherContainerRecord> map2 = new LinkedHashMap<EscherRecord, EscherContainerRecord>();
128
        // the sheet's drawing is not aggregated
95
        for (EscherRecord r : agg2.getEscherRecords()) mapShapeContainers(r, map2);
129
        assertEquals("wrong size of sheet records stream", 32, records.size());
130
        // the last record before the drawing block
131
        assertTrue(
132
                "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass().getSimpleName(),
133
                records.get(18) instanceof RowRecordsAggregate);
96
134
97
        assertEquals("aggregates have different number of shapes", map1.size(), map2.size());
135
        // records to be aggregated
136
        List<RecordBase> dgRecords = records.subList(19, 26);
137
        for (RecordBase rb : dgRecords) {
138
            Record r = (Record) rb;
139
            short sid = r.getSid();
140
            // we expect that drawing block consists of either
141
            // DrawingRecord or ContinueRecord or ObjRecord or TextObjectRecord
142
            assertTrue(
143
                    sid == DrawingRecord.sid ||
144
                            sid == ContinueRecord.sid ||
145
                            sid == ObjRecord.sid ||
146
                            sid == NoteRecord.sid ||
147
                            sid == TextObjectRecord.sid);
148
        }
149
        // collect drawing records into a byte buffer.
150
        byte[] dgBytes = toByteArray(dgRecords);
98
151
99
        // for each EscherClientDataRecord get parent SP_CONTAINER and corresponding ObjRecord
152
        // the first record after the drawing block
100
        // verify that ObjRecord to
153
        assertTrue(
101
        List<EscherRecord> l1 = new ArrayList<EscherRecord>(map1.keySet());
154
                "records.get(26) is expected to be Window2",
102
        List<EscherRecord> l2 = new ArrayList<EscherRecord>(map2.keySet());
155
                records.get(26) instanceof WindowTwoRecord);
103
        for (int i = 0; i < l1.size(); i++) {
104
            EscherRecord e1 = l1.get(i);
105
            EscherRecord e2 = l2.get(i);
106
            ObjRecord obj1 = (ObjRecord) HSSFRecordTestHelper.getShapeToObjForTest(agg1).get(e1);
107
            ObjRecord obj2 = (ObjRecord) HSSFRecordTestHelper.getShapeToObjForTest(agg2).get(e2);
108
156
109
            CommonObjectDataSubRecord cmo1 = (CommonObjectDataSubRecord) obj1.getSubRecords().get(0);
157
        // aggregate drawing records.
110
            CommonObjectDataSubRecord cmo2 = (CommonObjectDataSubRecord) obj2.getSubRecords().get(0);
158
        // The subrange [19, 38] is expected to be replaced with a EscherAggregate object
159
        DrawingManager2 drawingManager = iworkbook.findDrawingGroup();
160
        int loc = isheet.aggregateDrawingRecords(drawingManager, false);
161
        EscherAggregate agg = (EscherAggregate) records.get(loc);
111
162
112
            assertEquals(cmo1.getObjectId(), cmo2.getObjectId());
163
        assertEquals("wrong size of the aggregated sheet records stream", 26, records.size());
113
            assertEquals(obj1.toString(), obj2.toString());
164
        assertTrue(
165
                "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass().getSimpleName(),
166
                records.get(18) instanceof RowRecordsAggregate);
167
        assertTrue("records.get(19) is expected to be EscherAggregate but was " + records.get(19).getClass().getSimpleName(),
168
                records.get(19) instanceof EscherAggregate);
169
        assertTrue("records.get(20) is expected to be Window2 but was " + records.get(20).getClass().getSimpleName(),
170
                records.get(20) instanceof WindowTwoRecord);
114
171
115
            // test that obj parents have the same shapeId, that is, that shape is the same
172
        byte[] dgBytesAfterSave = agg.serialize();
116
            EscherContainerRecord p1 = map1.get(e1);
173
        assertEquals("different size of drawing data before and after save", dgBytes.length, dgBytesAfterSave.length);
117
            EscherContainerRecord p2 = map2.get(e2);
174
        assertTrue("drawing data before and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));
118
            EscherSpRecord sp1 = (EscherSpRecord) p1.getChildById(EscherSpRecord.RECORD_ID);
119
            EscherSpRecord sp2 = (EscherSpRecord) p2.getChildById(EscherSpRecord.RECORD_ID);
120
            assertEquals(sp1.getShapeId(), sp2.getShapeId());
121
122
            assertEquals("wrong shape2obj mapping", sp1.getShapeId() % 1024, cmo1.getObjectId());
123
            assertEquals(p1.toXml(), p2.toXml());
124
        }
175
    }
125
    }
126
176
127
    /**
128
     * recursively map EscherClientDataRecords  to their parent shape containers:
129
     * <p/>
130
     * EscherClientDataRecord1 --> EscherContainerRecord1
131
     * EscherClientDataRecord2 --> EscherContainerRecord2
132
     * ...
133
     * <p/>
134
     * TODO: YK: this method can be avoided if we have EscherRecord.getParent()
135
     */
136
    private static void mapShapeContainers(EscherRecord parent, Map<EscherRecord, EscherContainerRecord> map) {
137
        if (parent.isContainerRecord()) {
138
            if (parent.getRecordId() == EscherContainerRecord.SP_CONTAINER) {
139
                // iterate over shape's children and search for EscherClientDataRecord
140
                for (EscherRecord r : parent.getChildRecords()) {
141
                    if (r.getRecordId() == EscherClientDataRecord.RECORD_ID) {
142
                        map.put(r, (EscherContainerRecord) parent);
143
                    }
144
                }
145
            } else {
146
                for (EscherRecord ch : parent.getChildRecords()) {
147
                    mapShapeContainers(ch, map);
148
                }
149
            }
150
        }
151
    }
152
177
153
    /**
178
    public void testSerializeDrawingWithComments() throws IOException {
154
     * test reading drawing aggregate from a test file from Bugzilla 45129
179
        HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("DrawingAndComments.xls");
155
     */
156
    public void test45129() {
157
        HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("45129.xls");
158
        HSSFSheet sh = wb.getSheetAt(0);
180
        HSSFSheet sh = wb.getSheetAt(0);
159
160
        InternalWorkbook iworkbook = HSSFTestHelper.getWorkbookForTest(wb);
181
        InternalWorkbook iworkbook = HSSFTestHelper.getWorkbookForTest(wb);
161
        InternalSheet isheet = HSSFTestHelper.getSheetForTest(sh);
182
        InternalSheet isheet = HSSFTestHelper.getSheetForTest(sh);
162
183
163
        List<RecordBase> records = isheet.getRecords();
184
        List<RecordBase> records = isheet.getRecords();
164
185
165
        // the sheet's drawing is not aggregated
186
        // the sheet's drawing is not aggregated
166
        assertEquals("wrong size of sheet records stream", 394, records.size());
187
        assertEquals("wrong size of sheet records stream", 46, records.size());
167
        // the last record before the drawing block
188
        // the last record before the drawing block
168
        assertTrue(
189
        assertTrue(
169
                "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass().getSimpleName(),
190
                "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass().getSimpleName(),
170
                records.get(18) instanceof RowRecordsAggregate);
191
                records.get(18) instanceof RowRecordsAggregate);
171
192
172
        // records to be aggregated
193
        // records to be aggregated
173
        List<RecordBase> dgRecords = records.subList(19, 388);
194
        List<RecordBase> dgRecords = records.subList(19, 39);
174
        for (RecordBase rb : dgRecords) {
195
        for (RecordBase rb : dgRecords) {
175
            Record r = (Record) rb;
196
            Record r = (Record) rb;
176
            short sid = r.getSid();
197
            short sid = r.getSid();
Lines 180-200 Link Here
180
                    sid == DrawingRecord.sid ||
201
                    sid == DrawingRecord.sid ||
181
                            sid == ContinueRecord.sid ||
202
                            sid == ContinueRecord.sid ||
182
                            sid == ObjRecord.sid ||
203
                            sid == ObjRecord.sid ||
204
                            sid == NoteRecord.sid ||
183
                            sid == TextObjectRecord.sid);
205
                            sid == TextObjectRecord.sid);
184
        }
206
        }
207
        // collect drawing records into a byte buffer.
208
        byte[] dgBytes = toByteArray(dgRecords);
185
209
186
        // the first record after the drawing block
210
        // the first record after the drawing block
187
        assertTrue(
211
        assertTrue(
188
                "records.get(389) is expected to be Window2",
212
                "records.get(39) is expected to be Window2",
189
                records.get(389) instanceof WindowTwoRecord);
213
                records.get(39) instanceof WindowTwoRecord);
190
214
191
        // aggregate drawing records.
215
        // aggregate drawing records.
192
        // The subrange [19, 388] is expected to be replaced with a EscherAggregate object
216
        // The subrange [19, 38] is expected to be replaced with a EscherAggregate object
193
        DrawingManager2 drawingManager = iworkbook.findDrawingGroup();
217
        DrawingManager2 drawingManager = iworkbook.findDrawingGroup();
194
        int loc = isheet.aggregateDrawingRecords(drawingManager, false);
218
        int loc = isheet.aggregateDrawingRecords(drawingManager, false);
195
        EscherAggregate agg = (EscherAggregate) records.get(loc);
219
        EscherAggregate agg = (EscherAggregate) records.get(loc);
196
220
197
        assertEquals("wrong size of the aggregated sheet records stream", 25, records.size());
221
        assertEquals("wrong size of the aggregated sheet records stream", 27, records.size());
198
        assertTrue(
222
        assertTrue(
199
                "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass().getSimpleName(),
223
                "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass().getSimpleName(),
200
                records.get(18) instanceof RowRecordsAggregate);
224
                records.get(18) instanceof RowRecordsAggregate);
Lines 203-213 Link Here
203
        assertTrue("records.get(20) is expected to be Window2 but was " + records.get(20).getClass().getSimpleName(),
227
        assertTrue("records.get(20) is expected to be Window2 but was " + records.get(20).getClass().getSimpleName(),
204
                records.get(20) instanceof WindowTwoRecord);
228
                records.get(20) instanceof WindowTwoRecord);
205
229
206
        EscherAggregate agg2 = assertWriteAndReadBack(agg);
230
        byte[] dgBytesAfterSave = agg.serialize();
207
231
        assertEquals("different size of drawing data before and after save", dgBytes.length, dgBytesAfterSave.length);
208
        assertObjectMappingSame(agg, agg2);
232
        assertTrue("drawing data before and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));
209
    }
233
    }
210
234
235
211
    public void testFileWithPictures() {
236
    public void testFileWithPictures() {
212
        HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("ContinueRecordProblem.xls");
237
        HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("ContinueRecordProblem.xls");
213
        HSSFSheet sh = wb.getSheetAt(0);
238
        HSSFSheet sh = wb.getSheetAt(0);
Lines 225-231 Link Here
225
                records.get(21) instanceof RowRecordsAggregate);
250
                records.get(21) instanceof RowRecordsAggregate);
226
251
227
        // records to be aggregated
252
        // records to be aggregated
228
        List<RecordBase> dgRecords = records.subList(22, 299);
253
        List<RecordBase> dgRecords = records.subList(22, 300);
229
        for (RecordBase rb : dgRecords) {
254
        for (RecordBase rb : dgRecords) {
230
            Record r = (Record) rb;
255
            Record r = (Record) rb;
231
            short sid = r.getSid();
256
            short sid = r.getSid();
Lines 237-242 Link Here
237
                            sid == ObjRecord.sid ||
262
                            sid == ObjRecord.sid ||
238
                            sid == TextObjectRecord.sid);
263
                            sid == TextObjectRecord.sid);
239
        }
264
        }
265
        // collect drawing records into a byte buffer.
266
        byte[] dgBytes = toByteArray(dgRecords);
240
267
241
        // the first record after the drawing block
268
        // the first record after the drawing block
242
        assertTrue(
269
        assertTrue(
Lines 244-250 Link Here
244
                records.get(300) instanceof WindowTwoRecord);
271
                records.get(300) instanceof WindowTwoRecord);
245
272
246
        // aggregate drawing records.
273
        // aggregate drawing records.
247
        // The subrange [19, 388] is expected to be replaced with a EscherAggregate object
274
        // The subrange [19, 299] is expected to be replaced with a EscherAggregate object
248
        DrawingManager2 drawingManager = iworkbook.findDrawingGroup();
275
        DrawingManager2 drawingManager = iworkbook.findDrawingGroup();
249
        int loc = isheet.aggregateDrawingRecords(drawingManager, false);
276
        int loc = isheet.aggregateDrawingRecords(drawingManager, false);
250
        EscherAggregate agg = (EscherAggregate) records.get(loc);
277
        EscherAggregate agg = (EscherAggregate) records.get(loc);
Lines 258-266 Link Here
258
        assertTrue("records.get(23) is expected to be Window2 but was " + records.get(23).getClass().getSimpleName(),
285
        assertTrue("records.get(23) is expected to be Window2 but was " + records.get(23).getClass().getSimpleName(),
259
                records.get(23) instanceof WindowTwoRecord);
286
                records.get(23) instanceof WindowTwoRecord);
260
287
261
        EscherAggregate agg2 = assertWriteAndReadBack(agg);
288
        byte[] dgBytesAfterSave = agg.serialize();
262
289
        assertEquals("different size of drawing data before and after save", dgBytes.length, dgBytesAfterSave.length);
263
        assertObjectMappingSame(agg, agg2);
290
        assertTrue("drawing data brefpore and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));
264
    }
291
    }
265
292
266
    public void testUnhandledContinue() {
293
    public void testUnhandledContinue() {
Lines 972-981 Link Here
972
        assertTrue("expected EOFRecord", records.get(1) instanceof EOFRecord);
999
        assertTrue("expected EOFRecord", records.get(1) instanceof EOFRecord);
973
        EscherAggregate agg = (EscherAggregate) records.get(0);
1000
        EscherAggregate agg = (EscherAggregate) records.get(0);
974
1001
975
        // serialize, read back and assert that the drawing data is preserved
1002
        byte[] dgBytesAfterSave = agg.serialize();
976
        EscherAggregate agg2 = assertWriteAndReadBack(agg);
1003
        assertEquals("different size of drawing data before and after save", dgBytes.length, dgBytesAfterSave.length);
977
1004
        assertTrue("drawing data before and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));
978
        assertObjectMappingSame(agg, agg2);
979
    }
1005
    }
980
1006
981
    public void testUnhandledContinue2() {
1007
    public void testUnhandledContinue2() {
Lines 1926-1933 Link Here
1926
1952
1927
        EscherAggregate agg = (EscherAggregate) records.get(0);
1953
        EscherAggregate agg = (EscherAggregate) records.get(0);
1928
1954
1929
        EscherAggregate agg2 = assertWriteAndReadBack(agg);
1955
        byte[] dgBytesAfterSave = agg.serialize();
1930
1956
        assertEquals("different size of drawing data before and after save", dgBytes.length, dgBytesAfterSave.length);
1931
        assertObjectMappingSame(agg, agg2);
1957
        assertTrue("drawing data brefpore and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));
1932
    }
1958
    }
1933
}
1959
}
(-)src/java/org/apache/poi/hssf/record/RecordFactoryInputStream.java (-2 / +2 lines)
Lines 341-348 Link Here
341
				return null;
341
				return null;
342
			}
342
			}
343
			if (_lastRecord instanceof DrawingRecord) {
343
			if (_lastRecord instanceof DrawingRecord) {
344
				((DrawingRecord) _lastRecord).processContinueRecord(contRec.getData());
344
//				((DrawingRecord) _lastRecord).appendContinueRecord(contRec.getData());
345
				return null;
345
				return contRec;
346
			}
346
			}
347
			if (_lastRecord instanceof UnknownRecord) {
347
			if (_lastRecord instanceof UnknownRecord) {
348
				//Gracefully handle records that we don't know about,
348
				//Gracefully handle records that we don't know about,
(-)src/java/org/apache/poi/hssf/model/InternalSheet.java (-23 / +2 lines)
Lines 1508-1538 Link Here
1508
            return loc;
1508
            return loc;
1509
        }
1509
        }
1510
        List<RecordBase> records = getRecords();
1510
        List<RecordBase> records = getRecords();
1511
        EscherAggregate r = EscherAggregate.createAggregate( records, loc, drawingManager );
1512
        int startloc = loc;
1513
        while ( loc + 1 < records.size()
1514
                && records.get( loc ) instanceof DrawingRecord
1515
                && (records.get( loc + 1 ) instanceof ObjRecord ||
1516
                    records.get( loc + 1 ) instanceof TextObjectRecord) )
1517
        {
1518
            loc += 2;
1519
            if (records.get( loc ) instanceof NoteRecord) loc ++;
1520
            while ( loc + 1 < records.size()
1521
                    && records.get( loc ) instanceof ContinueRecord
1522
                    && (records.get( loc + 1 ) instanceof ObjRecord ||
1523
                    records.get( loc + 1 ) instanceof TextObjectRecord) )
1524
            {
1525
                loc += 2;
1526
                if (records.get( loc ) instanceof NoteRecord) loc ++;
1527
            }
1528
        }
1529
1511
1530
        int endloc = loc-1;
1512
        EscherAggregate.createAggregate( records, loc, drawingManager );
1531
        for(int i = 0; i < (endloc - startloc + 1); i++)
1532
            records.remove(startloc);
1533
        records.add(startloc, r);
1534
1513
1535
        return startloc;
1514
        return loc;
1536
    }
1515
    }
1537
1516
1538
    /**
1517
    /**
(-)src/java/org/apache/poi/hssf/record/EscherAggregate.java (-867 / +888 lines)
Lines 17-27 Link Here
17
17
18
package org.apache.poi.hssf.record;
18
package org.apache.poi.hssf.record;
19
19
20
import java.util.ArrayList;
20
import java.io.ByteArrayOutputStream;
21
import java.util.HashMap;
21
import java.io.IOException;
22
import java.util.Iterator;
22
import java.util.*;
23
import java.util.List;
24
import java.util.Map;
25
23
26
import org.apache.poi.ddf.DefaultEscherRecordFactory;
24
import org.apache.poi.ddf.DefaultEscherRecordFactory;
27
import org.apache.poi.ddf.EscherBoolProperty;
25
import org.apache.poi.ddf.EscherBoolProperty;
Lines 65-948 Link Here
65
 * combination of MSODRAWING -> OBJ -> MSODRAWING -> OBJ records
63
 * combination of MSODRAWING -> OBJ -> MSODRAWING -> OBJ records
66
 * but the escher records are serialized _across_ the MSODRAWING
64
 * but the escher records are serialized _across_ the MSODRAWING
67
 * records.
65
 * records.
68
 * <p>
66
 * <p/>
69
 * It gets even worse when you start looking at TXO records.
67
 * It gets even worse when you start looking at TXO records.
70
 * <p>
68
 * <p/>
71
 * So what we do with this class is aggregate lazily.  That is
69
 * So what we do with this class is aggregate lazily.  That is
72
 * we don't aggregate the MSODRAWING -> OBJ records unless we
70
 * we don't aggregate the MSODRAWING -> OBJ records unless we
73
 * need to modify them.
71
 * need to modify them.
72
 * <p/>
73
 * At first document contains 4 types of records which belong to drawing layer.
74
 * There are can be such sequence of record:
75
 * <p/>
76
 * DrawingRecord
77
 * ContinueRecord
78
 * ...
79
 * ContinueRecord
80
 * ObjRecord | TextObjectRecord
81
 * .....
82
 * ContinueRecord
83
 * ...
84
 * ContinueRecord
85
 * ObjRecord | TextObjectRecord
86
 * NoteRecord
87
 * ...
88
 * NoteRecord
89
 * <p/>
90
 * To work with shapes we have to read data from Drawing and Continue records into single array of bytes and
91
 * build escher(office art) records tree from this array.
92
 * Each shape in drawing layer matches corresponding ObjRecord
93
 * Each textbox matches corresponding TextObjectRecord
74
 *
94
 *
95
 * ObjRecord contains information about shape. Thus each ObjRecord corresponds EscherContainerRecord(SPGR)
75
 *
96
 *
97
 * EscherAggrefate contains also NoteRecords
98
 * NoteRecords must be serial
99
 *
76
 * @author Glen Stampoultzis (glens at apache.org)
100
 * @author Glen Stampoultzis (glens at apache.org)
77
 */
101
 */
102
78
public final class EscherAggregate extends AbstractEscherHolderRecord {
103
public final class EscherAggregate extends AbstractEscherHolderRecord {
79
	public static final short sid = 9876; // not a real sid - dummy value
104
    public static final short sid = 9876; // not a real sid - dummy value
80
	private static POILogger log = POILogFactory.getLogger(EscherAggregate.class);
105
    private static POILogger log = POILogFactory.getLogger(EscherAggregate.class);
81
106
82
	public static final short ST_MIN = (short) 0;
107
    public static final short ST_MIN = (short) 0;
83
	public static final short ST_NOT_PRIMATIVE = ST_MIN;
108
    public static final short ST_NOT_PRIMATIVE = ST_MIN;
84
	public static final short ST_RECTANGLE = (short) 1;
109
    public static final short ST_RECTANGLE = (short) 1;
85
	public static final short ST_ROUNDRECTANGLE = (short) 2;
110
    public static final short ST_ROUNDRECTANGLE = (short) 2;
86
	public static final short ST_ELLIPSE = (short) 3;
111
    public static final short ST_ELLIPSE = (short) 3;
87
	public static final short ST_DIAMOND = (short) 4;
112
    public static final short ST_DIAMOND = (short) 4;
88
	public static final short ST_ISOCELESTRIANGLE = (short) 5;
113
    public static final short ST_ISOCELESTRIANGLE = (short) 5;
89
	public static final short ST_RIGHTTRIANGLE = (short) 6;
114
    public static final short ST_RIGHTTRIANGLE = (short) 6;
90
	public static final short ST_PARALLELOGRAM = (short) 7;
115
    public static final short ST_PARALLELOGRAM = (short) 7;
91
	public static final short ST_TRAPEZOID = (short) 8;
116
    public static final short ST_TRAPEZOID = (short) 8;
92
	public static final short ST_HEXAGON = (short) 9;
117
    public static final short ST_HEXAGON = (short) 9;
93
	public static final short ST_OCTAGON = (short) 10;
118
    public static final short ST_OCTAGON = (short) 10;
94
	public static final short ST_PLUS = (short) 11;
119
    public static final short ST_PLUS = (short) 11;
95
	public static final short ST_STAR = (short) 12;
120
    public static final short ST_STAR = (short) 12;
96
	public static final short ST_ARROW = (short) 13;
121
    public static final short ST_ARROW = (short) 13;
97
	public static final short ST_THICKARROW = (short) 14;
122
    public static final short ST_THICKARROW = (short) 14;
98
	public static final short ST_HOMEPLATE = (short) 15;
123
    public static final short ST_HOMEPLATE = (short) 15;
99
	public static final short ST_CUBE = (short) 16;
124
    public static final short ST_CUBE = (short) 16;
100
	public static final short ST_BALLOON = (short) 17;
125
    public static final short ST_BALLOON = (short) 17;
101
	public static final short ST_SEAL = (short) 18;
126
    public static final short ST_SEAL = (short) 18;
102
	public static final short ST_ARC = (short) 19;
127
    public static final short ST_ARC = (short) 19;
103
	public static final short ST_LINE = (short) 20;
128
    public static final short ST_LINE = (short) 20;
104
	public static final short ST_PLAQUE = (short) 21;
129
    public static final short ST_PLAQUE = (short) 21;
105
	public static final short ST_CAN = (short) 22;
130
    public static final short ST_CAN = (short) 22;
106
	public static final short ST_DONUT = (short) 23;
131
    public static final short ST_DONUT = (short) 23;
107
	public static final short ST_TEXTSIMPLE = (short) 24;
132
    public static final short ST_TEXTSIMPLE = (short) 24;
108
	public static final short ST_TEXTOCTAGON = (short) 25;
133
    public static final short ST_TEXTOCTAGON = (short) 25;
109
	public static final short ST_TEXTHEXAGON = (short) 26;
134
    public static final short ST_TEXTHEXAGON = (short) 26;
110
	public static final short ST_TEXTCURVE = (short) 27;
135
    public static final short ST_TEXTCURVE = (short) 27;
111
	public static final short ST_TEXTWAVE = (short) 28;
136
    public static final short ST_TEXTWAVE = (short) 28;
112
	public static final short ST_TEXTRING = (short) 29;
137
    public static final short ST_TEXTRING = (short) 29;
113
	public static final short ST_TEXTONCURVE = (short) 30;
138
    public static final short ST_TEXTONCURVE = (short) 30;
114
	public static final short ST_TEXTONRING = (short) 31;
139
    public static final short ST_TEXTONRING = (short) 31;
115
	public static final short ST_STRAIGHTCONNECTOR1 = (short) 32;
140
    public static final short ST_STRAIGHTCONNECTOR1 = (short) 32;
116
	public static final short ST_BENTCONNECTOR2 = (short) 33;
141
    public static final short ST_BENTCONNECTOR2 = (short) 33;
117
	public static final short ST_BENTCONNECTOR3 = (short) 34;
142
    public static final short ST_BENTCONNECTOR3 = (short) 34;
118
	public static final short ST_BENTCONNECTOR4 = (short) 35;
143
    public static final short ST_BENTCONNECTOR4 = (short) 35;
119
	public static final short ST_BENTCONNECTOR5 = (short) 36;
144
    public static final short ST_BENTCONNECTOR5 = (short) 36;
120
	public static final short ST_CURVEDCONNECTOR2 = (short) 37;
145
    public static final short ST_CURVEDCONNECTOR2 = (short) 37;
121
	public static final short ST_CURVEDCONNECTOR3 = (short) 38;
146
    public static final short ST_CURVEDCONNECTOR3 = (short) 38;
122
	public static final short ST_CURVEDCONNECTOR4 = (short) 39;
147
    public static final short ST_CURVEDCONNECTOR4 = (short) 39;
123
	public static final short ST_CURVEDCONNECTOR5 = (short) 40;
148
    public static final short ST_CURVEDCONNECTOR5 = (short) 40;
124
	public static final short ST_CALLOUT1 = (short) 41;
149
    public static final short ST_CALLOUT1 = (short) 41;
125
	public static final short ST_CALLOUT2 = (short) 42;
150
    public static final short ST_CALLOUT2 = (short) 42;
126
	public static final short ST_CALLOUT3 = (short) 43;
151
    public static final short ST_CALLOUT3 = (short) 43;
127
	public static final short ST_ACCENTCALLOUT1 = (short) 44;
152
    public static final short ST_ACCENTCALLOUT1 = (short) 44;
128
	public static final short ST_ACCENTCALLOUT2 = (short) 45;
153
    public static final short ST_ACCENTCALLOUT2 = (short) 45;
129
	public static final short ST_ACCENTCALLOUT3 = (short) 46;
154
    public static final short ST_ACCENTCALLOUT3 = (short) 46;
130
	public static final short ST_BORDERCALLOUT1 = (short) 47;
155
    public static final short ST_BORDERCALLOUT1 = (short) 47;
131
	public static final short ST_BORDERCALLOUT2 = (short) 48;
156
    public static final short ST_BORDERCALLOUT2 = (short) 48;
132
	public static final short ST_BORDERCALLOUT3 = (short) 49;
157
    public static final short ST_BORDERCALLOUT3 = (short) 49;
133
	public static final short ST_ACCENTBORDERCALLOUT1 = (short) 50;
158
    public static final short ST_ACCENTBORDERCALLOUT1 = (short) 50;
134
	public static final short ST_ACCENTBORDERCALLOUT2 = (short) 51;
159
    public static final short ST_ACCENTBORDERCALLOUT2 = (short) 51;
135
	public static final short ST_ACCENTBORDERCALLOUT3 = (short) 52;
160
    public static final short ST_ACCENTBORDERCALLOUT3 = (short) 52;
136
	public static final short ST_RIBBON = (short) 53;
161
    public static final short ST_RIBBON = (short) 53;
137
	public static final short ST_RIBBON2 = (short) 54;
162
    public static final short ST_RIBBON2 = (short) 54;
138
	public static final short ST_CHEVRON = (short) 55;
163
    public static final short ST_CHEVRON = (short) 55;
139
	public static final short ST_PENTAGON = (short) 56;
164
    public static final short ST_PENTAGON = (short) 56;
140
	public static final short ST_NOSMOKING = (short) 57;
165
    public static final short ST_NOSMOKING = (short) 57;
141
	public static final short ST_SEAL8 = (short) 58;
166
    public static final short ST_SEAL8 = (short) 58;
142
	public static final short ST_SEAL16 = (short) 59;
167
    public static final short ST_SEAL16 = (short) 59;
143
	public static final short ST_SEAL32 = (short) 60;
168
    public static final short ST_SEAL32 = (short) 60;
144
	public static final short ST_WEDGERECTCALLOUT = (short) 61;
169
    public static final short ST_WEDGERECTCALLOUT = (short) 61;
145
	public static final short ST_WEDGERRECTCALLOUT = (short) 62;
170
    public static final short ST_WEDGERRECTCALLOUT = (short) 62;
146
	public static final short ST_WEDGEELLIPSECALLOUT = (short) 63;
171
    public static final short ST_WEDGEELLIPSECALLOUT = (short) 63;
147
	public static final short ST_WAVE = (short) 64;
172
    public static final short ST_WAVE = (short) 64;
148
	public static final short ST_FOLDEDCORNER = (short) 65;
173
    public static final short ST_FOLDEDCORNER = (short) 65;
149
	public static final short ST_LEFTARROW = (short) 66;
174
    public static final short ST_LEFTARROW = (short) 66;
150
	public static final short ST_DOWNARROW = (short) 67;
175
    public static final short ST_DOWNARROW = (short) 67;
151
	public static final short ST_UPARROW = (short) 68;
176
    public static final short ST_UPARROW = (short) 68;
152
	public static final short ST_LEFTRIGHTARROW = (short) 69;
177
    public static final short ST_LEFTRIGHTARROW = (short) 69;
153
	public static final short ST_UPDOWNARROW = (short) 70;
178
    public static final short ST_UPDOWNARROW = (short) 70;
154
	public static final short ST_IRREGULARSEAL1 = (short) 71;
179
    public static final short ST_IRREGULARSEAL1 = (short) 71;
155
	public static final short ST_IRREGULARSEAL2 = (short) 72;
180
    public static final short ST_IRREGULARSEAL2 = (short) 72;
156
	public static final short ST_LIGHTNINGBOLT = (short) 73;
181
    public static final short ST_LIGHTNINGBOLT = (short) 73;
157
	public static final short ST_HEART = (short) 74;
182
    public static final short ST_HEART = (short) 74;
158
	public static final short ST_PICTUREFRAME = (short) 75;
183
    public static final short ST_PICTUREFRAME = (short) 75;
159
	public static final short ST_QUADARROW = (short) 76;
184
    public static final short ST_QUADARROW = (short) 76;
160
	public static final short ST_LEFTARROWCALLOUT = (short) 77;
185
    public static final short ST_LEFTARROWCALLOUT = (short) 77;
161
	public static final short ST_RIGHTARROWCALLOUT = (short) 78;
186
    public static final short ST_RIGHTARROWCALLOUT = (short) 78;
162
	public static final short ST_UPARROWCALLOUT = (short) 79;
187
    public static final short ST_UPARROWCALLOUT = (short) 79;
163
	public static final short ST_DOWNARROWCALLOUT = (short) 80;
188
    public static final short ST_DOWNARROWCALLOUT = (short) 80;
164
	public static final short ST_LEFTRIGHTARROWCALLOUT = (short) 81;
189
    public static final short ST_LEFTRIGHTARROWCALLOUT = (short) 81;
165
	public static final short ST_UPDOWNARROWCALLOUT = (short) 82;
190
    public static final short ST_UPDOWNARROWCALLOUT = (short) 82;
166
	public static final short ST_QUADARROWCALLOUT = (short) 83;
191
    public static final short ST_QUADARROWCALLOUT = (short) 83;
167
	public static final short ST_BEVEL = (short) 84;
192
    public static final short ST_BEVEL = (short) 84;
168
	public static final short ST_LEFTBRACKET = (short) 85;
193
    public static final short ST_LEFTBRACKET = (short) 85;
169
	public static final short ST_RIGHTBRACKET = (short) 86;
194
    public static final short ST_RIGHTBRACKET = (short) 86;
170
	public static final short ST_LEFTBRACE = (short) 87;
195
    public static final short ST_LEFTBRACE = (short) 87;
171
	public static final short ST_RIGHTBRACE = (short) 88;
196
    public static final short ST_RIGHTBRACE = (short) 88;
172
	public static final short ST_LEFTUPARROW = (short) 89;
197
    public static final short ST_LEFTUPARROW = (short) 89;
173
	public static final short ST_BENTUPARROW = (short) 90;
198
    public static final short ST_BENTUPARROW = (short) 90;
174
	public static final short ST_BENTARROW = (short) 91;
199
    public static final short ST_BENTARROW = (short) 91;
175
	public static final short ST_SEAL24 = (short) 92;
200
    public static final short ST_SEAL24 = (short) 92;
176
	public static final short ST_STRIPEDRIGHTARROW = (short) 93;
201
    public static final short ST_STRIPEDRIGHTARROW = (short) 93;
177
	public static final short ST_NOTCHEDRIGHTARROW = (short) 94;
202
    public static final short ST_NOTCHEDRIGHTARROW = (short) 94;
178
	public static final short ST_BLOCKARC = (short) 95;
203
    public static final short ST_BLOCKARC = (short) 95;
179
	public static final short ST_SMILEYFACE = (short) 96;
204
    public static final short ST_SMILEYFACE = (short) 96;
180
	public static final short ST_VERTICALSCROLL = (short) 97;
205
    public static final short ST_VERTICALSCROLL = (short) 97;
181
	public static final short ST_HORIZONTALSCROLL = (short) 98;
206
    public static final short ST_HORIZONTALSCROLL = (short) 98;
182
	public static final short ST_CIRCULARARROW = (short) 99;
207
    public static final short ST_CIRCULARARROW = (short) 99;
183
	public static final short ST_NOTCHEDCIRCULARARROW = (short) 100;
208
    public static final short ST_NOTCHEDCIRCULARARROW = (short) 100;
184
	public static final short ST_UTURNARROW = (short) 101;
209
    public static final short ST_UTURNARROW = (short) 101;
185
	public static final short ST_CURVEDRIGHTARROW = (short) 102;
210
    public static final short ST_CURVEDRIGHTARROW = (short) 102;
186
	public static final short ST_CURVEDLEFTARROW = (short) 103;
211
    public static final short ST_CURVEDLEFTARROW = (short) 103;
187
	public static final short ST_CURVEDUPARROW = (short) 104;
212
    public static final short ST_CURVEDUPARROW = (short) 104;
188
	public static final short ST_CURVEDDOWNARROW = (short) 105;
213
    public static final short ST_CURVEDDOWNARROW = (short) 105;
189
	public static final short ST_CLOUDCALLOUT = (short) 106;
214
    public static final short ST_CLOUDCALLOUT = (short) 106;
190
	public static final short ST_ELLIPSERIBBON = (short) 107;
215
    public static final short ST_ELLIPSERIBBON = (short) 107;
191
	public static final short ST_ELLIPSERIBBON2 = (short) 108;
216
    public static final short ST_ELLIPSERIBBON2 = (short) 108;
192
	public static final short ST_FLOWCHARTPROCESS = (short) 109;
217
    public static final short ST_FLOWCHARTPROCESS = (short) 109;
193
	public static final short ST_FLOWCHARTDECISION = (short) 110;
218
    public static final short ST_FLOWCHARTDECISION = (short) 110;
194
	public static final short ST_FLOWCHARTINPUTOUTPUT = (short) 111;
219
    public static final short ST_FLOWCHARTINPUTOUTPUT = (short) 111;
195
	public static final short ST_FLOWCHARTPREDEFINEDPROCESS = (short) 112;
220
    public static final short ST_FLOWCHARTPREDEFINEDPROCESS = (short) 112;
196
	public static final short ST_FLOWCHARTINTERNALSTORAGE = (short) 113;
221
    public static final short ST_FLOWCHARTINTERNALSTORAGE = (short) 113;
197
	public static final short ST_FLOWCHARTDOCUMENT = (short) 114;
222
    public static final short ST_FLOWCHARTDOCUMENT = (short) 114;
198
	public static final short ST_FLOWCHARTMULTIDOCUMENT = (short) 115;
223
    public static final short ST_FLOWCHARTMULTIDOCUMENT = (short) 115;
199
	public static final short ST_FLOWCHARTTERMINATOR = (short) 116;
224
    public static final short ST_FLOWCHARTTERMINATOR = (short) 116;
200
	public static final short ST_FLOWCHARTPREPARATION = (short) 117;
225
    public static final short ST_FLOWCHARTPREPARATION = (short) 117;
201
	public static final short ST_FLOWCHARTMANUALINPUT = (short) 118;
226
    public static final short ST_FLOWCHARTMANUALINPUT = (short) 118;
202
	public static final short ST_FLOWCHARTMANUALOPERATION = (short) 119;
227
    public static final short ST_FLOWCHARTMANUALOPERATION = (short) 119;
203
	public static final short ST_FLOWCHARTCONNECTOR = (short) 120;
228
    public static final short ST_FLOWCHARTCONNECTOR = (short) 120;
204
	public static final short ST_FLOWCHARTPUNCHEDCARD = (short) 121;
229
    public static final short ST_FLOWCHARTPUNCHEDCARD = (short) 121;
205
	public static final short ST_FLOWCHARTPUNCHEDTAPE = (short) 122;
230
    public static final short ST_FLOWCHARTPUNCHEDTAPE = (short) 122;
206
	public static final short ST_FLOWCHARTSUMMINGJUNCTION = (short) 123;
231
    public static final short ST_FLOWCHARTSUMMINGJUNCTION = (short) 123;
207
	public static final short ST_FLOWCHARTOR = (short) 124;
232
    public static final short ST_FLOWCHARTOR = (short) 124;
208
	public static final short ST_FLOWCHARTCOLLATE = (short) 125;
233
    public static final short ST_FLOWCHARTCOLLATE = (short) 125;
209
	public static final short ST_FLOWCHARTSORT = (short) 126;
234
    public static final short ST_FLOWCHARTSORT = (short) 126;
210
	public static final short ST_FLOWCHARTEXTRACT = (short) 127;
235
    public static final short ST_FLOWCHARTEXTRACT = (short) 127;
211
	public static final short ST_FLOWCHARTMERGE = (short) 128;
236
    public static final short ST_FLOWCHARTMERGE = (short) 128;
212
	public static final short ST_FLOWCHARTOFFLINESTORAGE = (short) 129;
237
    public static final short ST_FLOWCHARTOFFLINESTORAGE = (short) 129;
213
	public static final short ST_FLOWCHARTONLINESTORAGE = (short) 130;
238
    public static final short ST_FLOWCHARTONLINESTORAGE = (short) 130;
214
	public static final short ST_FLOWCHARTMAGNETICTAPE = (short) 131;
239
    public static final short ST_FLOWCHARTMAGNETICTAPE = (short) 131;
215
	public static final short ST_FLOWCHARTMAGNETICDISK = (short) 132;
240
    public static final short ST_FLOWCHARTMAGNETICDISK = (short) 132;
216
	public static final short ST_FLOWCHARTMAGNETICDRUM = (short) 133;
241
    public static final short ST_FLOWCHARTMAGNETICDRUM = (short) 133;
217
	public static final short ST_FLOWCHARTDISPLAY = (short) 134;
242
    public static final short ST_FLOWCHARTDISPLAY = (short) 134;
218
	public static final short ST_FLOWCHARTDELAY = (short) 135;
243
    public static final short ST_FLOWCHARTDELAY = (short) 135;
219
	public static final short ST_TEXTPLAINTEXT = (short) 136;
244
    public static final short ST_TEXTPLAINTEXT = (short) 136;
220
	public static final short ST_TEXTSTOP = (short) 137;
245
    public static final short ST_TEXTSTOP = (short) 137;
221
	public static final short ST_TEXTTRIANGLE = (short) 138;
246
    public static final short ST_TEXTTRIANGLE = (short) 138;
222
	public static final short ST_TEXTTRIANGLEINVERTED = (short) 139;
247
    public static final short ST_TEXTTRIANGLEINVERTED = (short) 139;
223
	public static final short ST_TEXTCHEVRON = (short) 140;
248
    public static final short ST_TEXTCHEVRON = (short) 140;
224
	public static final short ST_TEXTCHEVRONINVERTED = (short) 141;
249
    public static final short ST_TEXTCHEVRONINVERTED = (short) 141;
225
	public static final short ST_TEXTRINGINSIDE = (short) 142;
250
    public static final short ST_TEXTRINGINSIDE = (short) 142;
226
	public static final short ST_TEXTRINGOUTSIDE = (short) 143;
251
    public static final short ST_TEXTRINGOUTSIDE = (short) 143;
227
	public static final short ST_TEXTARCHUPCURVE = (short) 144;
252
    public static final short ST_TEXTARCHUPCURVE = (short) 144;
228
	public static final short ST_TEXTARCHDOWNCURVE = (short) 145;
253
    public static final short ST_TEXTARCHDOWNCURVE = (short) 145;
229
	public static final short ST_TEXTCIRCLECURVE = (short) 146;
254
    public static final short ST_TEXTCIRCLECURVE = (short) 146;
230
	public static final short ST_TEXTBUTTONCURVE = (short) 147;
255
    public static final short ST_TEXTBUTTONCURVE = (short) 147;
231
	public static final short ST_TEXTARCHUPPOUR = (short) 148;
256
    public static final short ST_TEXTARCHUPPOUR = (short) 148;
232
	public static final short ST_TEXTARCHDOWNPOUR = (short) 149;
257
    public static final short ST_TEXTARCHDOWNPOUR = (short) 149;
233
	public static final short ST_TEXTCIRCLEPOUR = (short) 150;
258
    public static final short ST_TEXTCIRCLEPOUR = (short) 150;
234
	public static final short ST_TEXTBUTTONPOUR = (short) 151;
259
    public static final short ST_TEXTBUTTONPOUR = (short) 151;
235
	public static final short ST_TEXTCURVEUP = (short) 152;
260
    public static final short ST_TEXTCURVEUP = (short) 152;
236
	public static final short ST_TEXTCURVEDOWN = (short) 153;
261
    public static final short ST_TEXTCURVEDOWN = (short) 153;
237
	public static final short ST_TEXTCASCADEUP = (short) 154;
262
    public static final short ST_TEXTCASCADEUP = (short) 154;
238
	public static final short ST_TEXTCASCADEDOWN = (short) 155;
263
    public static final short ST_TEXTCASCADEDOWN = (short) 155;
239
	public static final short ST_TEXTWAVE1 = (short) 156;
264
    public static final short ST_TEXTWAVE1 = (short) 156;
240
	public static final short ST_TEXTWAVE2 = (short) 157;
265
    public static final short ST_TEXTWAVE2 = (short) 157;
241
	public static final short ST_TEXTWAVE3 = (short) 158;
266
    public static final short ST_TEXTWAVE3 = (short) 158;
242
	public static final short ST_TEXTWAVE4 = (short) 159;
267
    public static final short ST_TEXTWAVE4 = (short) 159;
243
	public static final short ST_TEXTINFLATE = (short) 160;
268
    public static final short ST_TEXTINFLATE = (short) 160;
244
	public static final short ST_TEXTDEFLATE = (short) 161;
269
    public static final short ST_TEXTDEFLATE = (short) 161;
245
	public static final short ST_TEXTINFLATEBOTTOM = (short) 162;
270
    public static final short ST_TEXTINFLATEBOTTOM = (short) 162;
246
	public static final short ST_TEXTDEFLATEBOTTOM = (short) 163;
271
    public static final short ST_TEXTDEFLATEBOTTOM = (short) 163;
247
	public static final short ST_TEXTINFLATETOP = (short) 164;
272
    public static final short ST_TEXTINFLATETOP = (short) 164;
248
	public static final short ST_TEXTDEFLATETOP = (short) 165;
273
    public static final short ST_TEXTDEFLATETOP = (short) 165;
249
	public static final short ST_TEXTDEFLATEINFLATE = (short) 166;
274
    public static final short ST_TEXTDEFLATEINFLATE = (short) 166;
250
	public static final short ST_TEXTDEFLATEINFLATEDEFLATE = (short) 167;
275
    public static final short ST_TEXTDEFLATEINFLATEDEFLATE = (short) 167;
251
	public static final short ST_TEXTFADERIGHT = (short) 168;
276
    public static final short ST_TEXTFADERIGHT = (short) 168;
252
	public static final short ST_TEXTFADELEFT = (short) 169;
277
    public static final short ST_TEXTFADELEFT = (short) 169;
253
	public static final short ST_TEXTFADEUP = (short) 170;
278
    public static final short ST_TEXTFADEUP = (short) 170;
254
	public static final short ST_TEXTFADEDOWN = (short) 171;
279
    public static final short ST_TEXTFADEDOWN = (short) 171;
255
	public static final short ST_TEXTSLANTUP = (short) 172;
280
    public static final short ST_TEXTSLANTUP = (short) 172;
256
	public static final short ST_TEXTSLANTDOWN = (short) 173;
281
    public static final short ST_TEXTSLANTDOWN = (short) 173;
257
	public static final short ST_TEXTCANUP = (short) 174;
282
    public static final short ST_TEXTCANUP = (short) 174;
258
	public static final short ST_TEXTCANDOWN = (short) 175;
283
    public static final short ST_TEXTCANDOWN = (short) 175;
259
	public static final short ST_FLOWCHARTALTERNATEPROCESS = (short) 176;
284
    public static final short ST_FLOWCHARTALTERNATEPROCESS = (short) 176;
260
	public static final short ST_FLOWCHARTOFFPAGECONNECTOR = (short) 177;
285
    public static final short ST_FLOWCHARTOFFPAGECONNECTOR = (short) 177;
261
	public static final short ST_CALLOUT90 = (short) 178;
286
    public static final short ST_CALLOUT90 = (short) 178;
262
	public static final short ST_ACCENTCALLOUT90 = (short) 179;
287
    public static final short ST_ACCENTCALLOUT90 = (short) 179;
263
	public static final short ST_BORDERCALLOUT90 = (short) 180;
288
    public static final short ST_BORDERCALLOUT90 = (short) 180;
264
	public static final short ST_ACCENTBORDERCALLOUT90 = (short) 181;
289
    public static final short ST_ACCENTBORDERCALLOUT90 = (short) 181;
265
	public static final short ST_LEFTRIGHTUPARROW = (short) 182;
290
    public static final short ST_LEFTRIGHTUPARROW = (short) 182;
266
	public static final short ST_SUN = (short) 183;
291
    public static final short ST_SUN = (short) 183;
267
	public static final short ST_MOON = (short) 184;
292
    public static final short ST_MOON = (short) 184;
268
	public static final short ST_BRACKETPAIR = (short) 185;
293
    public static final short ST_BRACKETPAIR = (short) 185;
269
	public static final short ST_BRACEPAIR = (short) 186;
294
    public static final short ST_BRACEPAIR = (short) 186;
270
	public static final short ST_SEAL4 = (short) 187;
295
    public static final short ST_SEAL4 = (short) 187;
271
	public static final short ST_DOUBLEWAVE = (short) 188;
296
    public static final short ST_DOUBLEWAVE = (short) 188;
272
	public static final short ST_ACTIONBUTTONBLANK = (short) 189;
297
    public static final short ST_ACTIONBUTTONBLANK = (short) 189;
273
	public static final short ST_ACTIONBUTTONHOME = (short) 190;
298
    public static final short ST_ACTIONBUTTONHOME = (short) 190;
274
	public static final short ST_ACTIONBUTTONHELP = (short) 191;
299
    public static final short ST_ACTIONBUTTONHELP = (short) 191;
275
	public static final short ST_ACTIONBUTTONINFORMATION = (short) 192;
300
    public static final short ST_ACTIONBUTTONINFORMATION = (short) 192;
276
	public static final short ST_ACTIONBUTTONFORWARDNEXT = (short) 193;
301
    public static final short ST_ACTIONBUTTONFORWARDNEXT = (short) 193;
277
	public static final short ST_ACTIONBUTTONBACKPREVIOUS = (short) 194;
302
    public static final short ST_ACTIONBUTTONBACKPREVIOUS = (short) 194;
278
	public static final short ST_ACTIONBUTTONEND = (short) 195;
303
    public static final short ST_ACTIONBUTTONEND = (short) 195;
279
	public static final short ST_ACTIONBUTTONBEGINNING = (short) 196;
304
    public static final short ST_ACTIONBUTTONBEGINNING = (short) 196;
280
	public static final short ST_ACTIONBUTTONRETURN = (short) 197;
305
    public static final short ST_ACTIONBUTTONRETURN = (short) 197;
281
	public static final short ST_ACTIONBUTTONDOCUMENT = (short) 198;
306
    public static final short ST_ACTIONBUTTONDOCUMENT = (short) 198;
282
	public static final short ST_ACTIONBUTTONSOUND = (short) 199;
307
    public static final short ST_ACTIONBUTTONSOUND = (short) 199;
283
	public static final short ST_ACTIONBUTTONMOVIE = (short) 200;
308
    public static final short ST_ACTIONBUTTONMOVIE = (short) 200;
284
	public static final short ST_HOSTCONTROL = (short) 201;
309
    public static final short ST_HOSTCONTROL = (short) 201;
285
	public static final short ST_TEXTBOX = (short) 202;
310
    public static final short ST_TEXTBOX = (short) 202;
286
	public static final short ST_NIL = (short) 0x0FFF;
311
    public static final short ST_NIL = (short) 0x0FFF;
287
312
288
	protected HSSFPatriarch patriarch;
313
    protected HSSFPatriarch patriarch;
289
314
290
	/** Maps shape container objects to their {@link TextObjectRecord} or {@link ObjRecord} */
315
    /**
291
	Map<EscherRecord, Record> shapeToObj = new HashMap<EscherRecord, Record>();
316
     * Maps shape container objects to their {@link TextObjectRecord} or {@link ObjRecord}
317
     */
318
    private final Map<EscherRecord, Record> shapeToObj = new HashMap<EscherRecord, Record>();
292
	private DrawingManager2 drawingManager;
319
    private DrawingManager2 drawingManager;
293
	private short drawingGroupId;
320
    private short drawingGroupId;
294
321
295
	/**
322
    /**
296
	 * list of "tail" records that need to be serialized after all drawing group records
323
     * list of "tail" records that need to be serialized after all drawing group records
297
	 */
324
     */
298
	private List tailRec = new ArrayList();
325
    private List tailRec = new ArrayList();
299
326
300
	public EscherAggregate( DrawingManager2 drawingManager )
327
    public EscherAggregate(DrawingManager2 drawingManager) {
301
	{
302
		this.drawingManager = drawingManager;
328
        this.drawingManager = drawingManager;
303
	}
329
    }
304
330
305
	/**
331
    /**
306
	 * @return  Returns the current sid.
332
     * @return Returns the current sid.
307
	 */
333
     */
308
	public short getSid()
334
    public short getSid() {
309
	{
310
		return sid;
335
        return sid;
311
	}
336
    }
312
337
313
	/**
338
    /**
314
	 * Calculates the string representation of this record.  This is
339
     * Calculates the string representation of this record.  This is
315
	 * simply a dump of all the records.
340
     * simply a dump of all the records.
316
	 */
341
     */
317
	public String toString()
342
    public String toString() {
318
	{
319
		String nl = System.getProperty( "line.separtor" );
343
        String nl = System.getProperty("line.separtor");
320
344
321
		StringBuffer result = new StringBuffer();
345
        StringBuffer result = new StringBuffer();
322
		result.append( '[' ).append( getRecordName() ).append( ']' + nl );
346
        result.append('[').append(getRecordName()).append(']' + nl);
323
		for ( Iterator iterator = getEscherRecords().iterator(); iterator.hasNext(); )
347
        for (Iterator iterator = getEscherRecords().iterator(); iterator.hasNext(); ) {
324
		{
325
			EscherRecord escherRecord = (EscherRecord) iterator.next();
348
            EscherRecord escherRecord = (EscherRecord) iterator.next();
326
			result.append( escherRecord.toString() );
349
            result.append(escherRecord.toString());
327
		}
350
        }
328
		result.append( "[/" ).append( getRecordName() ).append( ']' + nl );
351
        result.append("[/").append(getRecordName()).append(']' + nl);
329
352
330
		return result.toString();
353
        return result.toString();
331
	}
354
    }
332
    
355
333
    public String toXml(String tab){
356
    public String toXml(String tab) {
334
        StringBuilder builder = new StringBuilder();
357
        StringBuilder builder = new StringBuilder();
335
        builder.append(tab).append("<").append(getRecordName()).append(">\n");
358
        builder.append(tab).append("<").append(getRecordName()).append(">\n");
336
        for ( Iterator iterator = getEscherRecords().iterator(); iterator.hasNext(); )
359
        for (Iterator iterator = getEscherRecords().iterator(); iterator.hasNext(); ) {
337
        {
338
            EscherRecord escherRecord = (EscherRecord) iterator.next();
360
            EscherRecord escherRecord = (EscherRecord) iterator.next();
339
            builder.append( escherRecord.toXml(tab+"\t") );
361
            builder.append(escherRecord.toXml(tab + "\t"));
340
        }
362
        }
341
        builder.append(tab).append("</").append(getRecordName()).append(">\n");
363
        builder.append(tab).append("</").append(getRecordName()).append(">\n");
342
        return builder.toString();
364
        return builder.toString();
343
    }
365
    }
344
366
345
	/**
367
    private static boolean isDrawingLayerRecord(final short sid) {
346
	 * Collapses the drawing records into an aggregate.
368
        return sid == DrawingRecord.sid ||
369
                sid == ContinueRecord.sid ||
370
                sid == ObjRecord.sid ||
371
                sid == TextObjectRecord.sid;
372
    }
373
347
	 */
374
    /**
375
     * Collapses the drawing records into an aggregate.
376
     * read Drawing and Continue records into single byte array, create Escher tree from byte array, create map <EscherRecord, Record>
348
	public static EscherAggregate createAggregate( List records, int locFirstDrawingRecord, DrawingManager2 drawingManager )
377
     */
349
	{
350
		// Keep track of any shape records created so we can match them back to the object id's.
378
    public static EscherAggregate createAggregate(List records, int locFirstDrawingRecord, DrawingManager2 drawingManager) {
351
		// Textbox objects are also treated as shape objects.
352
		final List<EscherRecord> shapeRecords = new ArrayList<EscherRecord>();
353
		EscherRecordFactory recordFactory = new DefaultEscherRecordFactory()
379
        // Keep track of any shape records created so we can match them back to the object id's.
354
		{
380
        // Textbox objects are also treated as shape objects.
355
			public EscherRecord createRecord( byte[] data, int offset )
381
        final List<EscherRecord> shapeRecords = new ArrayList<EscherRecord>();
356
			{
357
				EscherRecord r = super.createRecord( data, offset );
382
        EscherRecordFactory recordFactory = new DefaultEscherRecordFactory() {
383
            public EscherRecord createRecord(byte[] data, int offset) {
358
				if ( r.getRecordId() == EscherClientDataRecord.RECORD_ID || r.getRecordId() == EscherTextboxRecord.RECORD_ID )
384
                EscherRecord r = super.createRecord(data, offset);
359
				{
360
					shapeRecords.add( r );
385
                if (r.getRecordId() == EscherClientDataRecord.RECORD_ID || r.getRecordId() == EscherTextboxRecord.RECORD_ID) {
361
				}
386
                    shapeRecords.add(r);
362
				return r;
363
			}
364
		};
387
                }
388
                return r;
389
            }
390
        };
365
391
366
		// Calculate the size of the buffer
392
        // Create one big buffer
393
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
394
367
		EscherAggregate agg = new EscherAggregate(drawingManager);
395
        EscherAggregate agg = new EscherAggregate(drawingManager);
368
		int loc = locFirstDrawingRecord;
396
        int loc = locFirstDrawingRecord;
369
		int dataSize = 0;
397
        while (loc + 1 < records.size()
370
		while ( loc + 1 < records.size()
371
				&& sid( records, loc ) == DrawingRecord.sid
398
                && (isDrawingLayerRecord(sid(records, loc)))) {
372
				&& isObjectRecord( records, loc + 1 ) )
399
            try {
373
		{
400
                if (!(sid(records, loc) == DrawingRecord.sid || sid(records, loc) == ContinueRecord.sid)) {
374
			dataSize += ( (DrawingRecord) records.get( loc ) ).getRecordData().length;
401
                    loc++;
375
			loc += 2;
402
                    continue;
376
            while ( loc + 1 < records.size()
377
                    && sid( records, loc ) == ContinueRecord.sid
378
                    && isObjectRecord( records, loc + 1 ) )
379
            {
380
                dataSize += ( (ContinueRecord) records.get( loc ) ).getData().length;
381
                loc += 2;
382
            }
403
                }
404
                if (sid(records, loc) == DrawingRecord.sid) {
405
                    buffer.write(((DrawingRecord) records.get(loc)).getRecordData());
406
                } else {
407
                    buffer.write(((ContinueRecord) records.get(loc)).getData());
383
		}
408
                }
384
409
            } catch (IOException e) {
385
		// Create one big buffer
410
                throw new RuntimeException("Couldn't get data from drawing/continue records", e);
386
		byte buffer[] = new byte[dataSize];
387
		int offset = 0;
388
		loc = locFirstDrawingRecord;
389
		while ( loc + 1 < records.size()
390
				&& sid( records, loc ) == DrawingRecord.sid
391
				&& isObjectRecord( records, loc + 1 ) )
392
		{
393
			DrawingRecord drawingRecord = (DrawingRecord) records.get( loc );
394
			System.arraycopy( drawingRecord.getRecordData(), 0, buffer, offset, drawingRecord.getRecordData().length );
395
			offset += drawingRecord.getRecordData().length;
396
			loc += 2;
397
            while ( loc + 1 < records.size()
398
                    && sid( records, loc ) == ContinueRecord.sid
399
                    && isObjectRecord( records, loc + 1 ) )
400
            {
401
                ContinueRecord continueRecord = (ContinueRecord) records.get( loc );
402
                System.arraycopy( continueRecord.getData(), 0, buffer, offset, continueRecord.getData().length );
403
                offset += continueRecord.getData().length;
404
                loc += 2;
405
            }
411
            }
406
		}
412
            loc++;
413
        }
407
414
408
		// Decode the shapes
415
        // Decode the shapes
409
		//		agg.escherRecords = new ArrayList();
416
        //		agg.escherRecords = new ArrayList();
410
		int pos = 0;
417
        int pos = 0;
411
		while ( pos < dataSize )
418
        while (pos < buffer.size()) {
412
		{
419
            EscherRecord r = recordFactory.createRecord(buffer.toByteArray(), pos);
413
			EscherRecord r = recordFactory.createRecord( buffer, pos );
420
            int bytesRead = r.fillFields(buffer.toByteArray(), pos, recordFactory);
414
			int bytesRead = r.fillFields( buffer, pos, recordFactory );
415
			agg.addEscherRecord( r );
421
            agg.addEscherRecord(r);
416
			pos += bytesRead;
422
            pos += bytesRead;
417
		}
423
        }
418
424
419
		// Associate the object records with the shapes
425
        // Associate the object records with the shapes
420
		loc = locFirstDrawingRecord;
426
        loc = locFirstDrawingRecord + 1;
421
		int shapeIndex = 0;
427
        int shapeIndex = 0;
422
		agg.shapeToObj = new HashMap<EscherRecord, Record>();
428
        while (loc < records.size()
423
		while ( loc + 1 < records.size()
429
                && (isDrawingLayerRecord(sid(records, loc)))) {
424
				&& sid( records, loc ) == DrawingRecord.sid
430
            if (!isObjectRecord(records, loc)) {
425
				&& isObjectRecord( records, loc + 1 ) )
431
                loc++;
426
		{
432
                continue;
427
			Record objRecord = (Record) records.get( loc + 1 );
433
            }
434
            Record objRecord = (Record) records.get(loc);
428
			agg.shapeToObj.put( shapeRecords.get( shapeIndex++ ), objRecord );
435
            agg.shapeToObj.put(shapeRecords.get(shapeIndex++), objRecord);
429
			loc += 2;
436
            loc++;
430
            while ( loc + 1 < records.size()
431
                    && sid( records, loc ) == ContinueRecord.sid
432
                    && isObjectRecord( records, loc + 1 ) )
433
            {
434
                objRecord = (Record) records.get( loc + 1 );
435
                agg.shapeToObj.put( shapeRecords.get( shapeIndex++ ), objRecord );
436
                loc += 2;
437
            }
437
        }
438
439
        // any NoteRecords that follow the drawing block must be aggregated and and saved in the tailRec collection
440
        // TODO remove this logic. 'tail' records should be inserted in the main record stream
441
        while (loc < records.size()) {
442
            if (sid(records, loc) == NoteRecord.sid) {
443
                NoteRecord r = (NoteRecord) records.get(loc);
444
                agg.tailRec.add(r);
445
            } else {
446
                break;
438
		}
447
            }
448
            loc++;
449
        }
439
450
440
		return agg;
451
        int locLastDrawingRecord = loc;
452
        // replace drawing block with the created EscherAggregate
453
        records.subList(locFirstDrawingRecord, locLastDrawingRecord).clear();
454
        records.add(locFirstDrawingRecord, agg);
441
455
442
	}
456
457
        return agg;
458
    }
443
459
444
	/**
460
    /**
445
	 * Serializes this aggregate to a byte array.  Since this is an aggregate
461
     * Serializes this aggregate to a byte array.  Since this is an aggregate
446
	 * record it will effectively serialize the aggregated records.
462
     * record it will effectively serialize the aggregated records.
447
	 *
463
     *
448
	 * @param offset	The offset into the start of the array.
464
     * @param offset The offset into the start of the array.
449
	 * @param data	  The byte array to serialize to.
465
     * @param data   The byte array to serialize to.
450
	 * @return		  The number of bytes serialized.
466
     * @return The number of bytes serialized.
451
	 */
467
     */
452
	public int serialize( int offset, byte[] data )
468
    public int serialize(int offset, byte[] data) {
453
	{
454
		convertUserModelToRecords();
469
        convertUserModelToRecords();
455
470
456
		// Determine buffer size
471
        // Determine buffer size
457
		List records = getEscherRecords();
472
        List records = getEscherRecords();
458
		int size = getEscherRecordSize( records );
473
        int size = getEscherRecordSize(records);
459
		byte[] buffer = new byte[size];
474
        byte[] buffer = new byte[size];
460
475
461
476
462
		// Serialize escher records into one big data structure and keep note of ending offsets.
477
        // Serialize escher records into one big data structure and keep note of ending offsets.
463
		final List spEndingOffsets = new ArrayList();
478
        final List spEndingOffsets = new ArrayList();
464
		final List shapes = new ArrayList();
479
        final List shapes = new ArrayList();
465
		int pos = 0;
480
        int pos = 0;
466
		for ( Iterator iterator = records.iterator(); iterator.hasNext(); )
481
        for (Iterator iterator = records.iterator(); iterator.hasNext(); ) {
467
		{
468
			EscherRecord e = (EscherRecord) iterator.next();
482
            EscherRecord e = (EscherRecord) iterator.next();
469
			pos += e.serialize( pos, buffer, new EscherSerializationListener()
483
            pos += e.serialize(pos, buffer, new EscherSerializationListener() {
470
			{
484
                public void beforeRecordSerialize(int offset, short recordId, EscherRecord record) {
471
				public void beforeRecordSerialize( int offset, short recordId, EscherRecord record )
472
				{
473
				}
485
                }
474
486
475
				public void afterRecordSerialize( int offset, short recordId, int size, EscherRecord record )
487
                public void afterRecordSerialize(int offset, short recordId, int size, EscherRecord record) {
476
				{
488
                    if (recordId == EscherClientDataRecord.RECORD_ID || recordId == EscherTextboxRecord.RECORD_ID) {
477
					if ( recordId == EscherClientDataRecord.RECORD_ID || recordId == EscherTextboxRecord.RECORD_ID )
478
					{
479
						spEndingOffsets.add( Integer.valueOf( offset ) );
489
                        spEndingOffsets.add(Integer.valueOf(offset));
480
						shapes.add( record );
490
                        shapes.add(record);
481
					}
491
                    }
482
				}
492
                }
483
			} );
493
            });
484
		}
494
        }
485
		// todo: fix this
495
        // todo: fix this
486
		shapes.add( 0, null );
496
        shapes.add(0, null);
487
		spEndingOffsets.add( 0, null );
497
        spEndingOffsets.add(0, null);
488
498
489
		// Split escher records into separate MSODRAWING and OBJ, TXO records.  (We don't break on
499
        // Split escher records into separate MSODRAWING and OBJ, TXO records.  (We don't break on
490
		// the first one because it's the patriach).
500
        // the first one because it's the patriach).
491
		pos = offset;
501
        pos = offset;
492
		for ( int i = 1; i < shapes.size(); i++ )
502
        int writtenEscherBytes = 0;
493
		{
503
        for (int i = 1; i < shapes.size(); i++) {
494
			int endOffset = ( (Integer) spEndingOffsets.get( i ) ).intValue() - 1;
504
            int endOffset = ((Integer) spEndingOffsets.get(i)).intValue() - 1;
495
			int startOffset;
505
            int startOffset;
496
			if ( i == 1 )
506
            if (i == 1)
497
				startOffset = 0;
507
                startOffset = 0;
498
			else
508
            else
499
				startOffset = ( (Integer) spEndingOffsets.get( i - 1 ) ).intValue();
509
                startOffset = ((Integer) spEndingOffsets.get(i - 1)).intValue();
500
510
501
			// Create and write a new MSODRAWING record
511
502
			DrawingRecord drawing = new DrawingRecord();
503
			byte[] drawingData = new byte[endOffset - startOffset + 1];
512
            byte[] drawingData = new byte[endOffset - startOffset + 1];
504
			System.arraycopy( buffer, startOffset, drawingData, 0, drawingData.length );
513
            System.arraycopy(buffer, startOffset, drawingData, 0, drawingData.length);
505
			drawing.setData( drawingData );
514
            int temp = 0;
506
			int temp = drawing.serialize( pos, data );
515
516
            //First record in drawing layer MUST be DrawingRecord
517
            if (writtenEscherBytes + drawingData.length > RecordInputStream.MAX_RECORD_DATA_SIZE && i != 1) {
518
                for (int j = 0; j < drawingData.length; j += RecordInputStream.MAX_RECORD_DATA_SIZE) {
519
                    ContinueRecord drawing = new ContinueRecord(Arrays.copyOfRange(drawingData, j, Math.min(j + RecordInputStream.MAX_RECORD_DATA_SIZE, drawingData.length)));
520
                    temp += drawing.serialize(pos + temp, data);
521
                }
522
            } else {
523
                for (int j = 0; j < drawingData.length; j += RecordInputStream.MAX_RECORD_DATA_SIZE) {
524
                    if (j == 0) {
525
                        DrawingRecord drawing = new DrawingRecord();
526
                        drawing.setData(Arrays.copyOfRange(drawingData, j, Math.min(j + RecordInputStream.MAX_RECORD_DATA_SIZE, drawingData.length)));
527
                        temp += drawing.serialize(pos + temp, data);
528
                    } else {
529
                        ContinueRecord drawing = new ContinueRecord(Arrays.copyOfRange(drawingData, j, Math.min(j + RecordInputStream.MAX_RECORD_DATA_SIZE, drawingData.length)));
530
                        temp += drawing.serialize(pos + temp, data);
531
                    }
532
                }
533
534
            }
535
507
			pos += temp;
536
            pos += temp;
537
            writtenEscherBytes += drawingData.length;
508
538
509
			// Write the matching OBJ record
539
            // Write the matching OBJ record
510
			Record obj = shapeToObj.get( shapes.get( i ) );
540
            Record obj = shapeToObj.get(shapes.get(i));
511
			temp = obj.serialize( pos, data );
541
            temp = obj.serialize(pos, data);
512
			pos += temp;
542
            pos += temp;
513
543
514
		}
544
        }
515
545
516
		// write records that need to be serialized after all drawing group records
546
        // write records that need to be serialized after all drawing group records
517
		for ( int i = 0; i < tailRec.size(); i++ )
547
        for (int i = 0; i < tailRec.size(); i++) {
518
		{
519
			Record rec = (Record)tailRec.get(i);
548
            Record rec = (Record) tailRec.get(i);
520
			pos += rec.serialize( pos, data );
549
            pos += rec.serialize(pos, data);
521
		}
550
        }
522
551
523
		int bytesWritten = pos - offset;
552
        int bytesWritten = pos - offset;
524
		if ( bytesWritten != getRecordSize() )
553
        if (bytesWritten != getRecordSize())
525
			throw new RecordFormatException( bytesWritten + " bytes written but getRecordSize() reports " + getRecordSize() );
554
            throw new RecordFormatException(bytesWritten + " bytes written but getRecordSize() reports " + getRecordSize());
526
		return bytesWritten;
555
        return bytesWritten;
527
	}
556
    }
528
557
529
	/**
558
    /**
530
	 * How many bytes do the raw escher records contain.
559
     * How many bytes do the raw escher records contain.
560
     *
531
	 * @param records   List of escher records
561
     * @param records List of escher records
532
	 * @return  the number of bytes
562
     * @return the number of bytes
533
	 */
563
     */
534
	private int getEscherRecordSize( List records )
564
    private int getEscherRecordSize(List records) {
535
	{
536
		int size = 0;
565
        int size = 0;
537
		for ( Iterator iterator = records.iterator(); iterator.hasNext(); )
566
        for (Iterator iterator = records.iterator(); iterator.hasNext(); )
538
			size += ( (EscherRecord) iterator.next() ).getRecordSize();
567
            size += ((EscherRecord) iterator.next()).getRecordSize();
539
		return size;
568
        return size;
540
	}
569
    }
541
570
542
	public int getRecordSize() {
571
    public int getRecordSize() {
543
		// TODO - convert this to RecordAggregate
572
        // TODO - convert this to RecordAggregate
544
		convertUserModelToRecords();
573
        convertUserModelToRecords();
545
		List records = getEscherRecords();
574
        // To determine size of aggregate record we have to know size of each DrawingRecord because if DrawingRecord
575
        // is split into several continue records we have to add header size to total EscherAggregate size
576
        int continueRecordsHeadersSize = 0;
577
        // Determine buffer size
578
        List<EscherRecord> records = getEscherRecords();
546
		int rawEscherSize = getEscherRecordSize( records );
579
        int rawEscherSize = getEscherRecordSize(records);
580
        byte[] buffer = new byte[rawEscherSize];
581
        final List<Integer> spEndingOffsets = new ArrayList<Integer>();
582
        int pos = 0;
583
        for (EscherRecord e : records) {
584
            pos += e.serialize(pos, buffer, new EscherSerializationListener() {
585
                public void beforeRecordSerialize(int offset, short recordId, EscherRecord record) {
586
                }
587
588
                public void afterRecordSerialize(int offset, short recordId, int size, EscherRecord record) {
589
                    if (recordId == EscherClientDataRecord.RECORD_ID || recordId == EscherTextboxRecord.RECORD_ID) {
590
                        spEndingOffsets.add(offset);
591
                    }
592
                }
593
            });
594
        }
595
        spEndingOffsets.add(0, 0);
596
597
        for (int i = 1; i < spEndingOffsets.size(); i++) {
598
            if (spEndingOffsets.get(i) - spEndingOffsets.get(i - 1) <= RecordInputStream.MAX_RECORD_DATA_SIZE){
599
                continue;
600
            }
601
            continueRecordsHeadersSize += ((spEndingOffsets.get(i) - spEndingOffsets.get(i - 1)) / RecordInputStream.MAX_RECORD_DATA_SIZE)*4;
602
        }
603
547
		int drawingRecordSize = rawEscherSize + ( shapeToObj.size() ) * 4;
604
        int drawingRecordSize = rawEscherSize + (shapeToObj.size()) * 4;
548
		int objRecordSize = 0;
605
        int objRecordSize = 0;
549
		for ( Iterator iterator = shapeToObj.values().iterator(); iterator.hasNext(); )
606
        for (Iterator iterator = shapeToObj.values().iterator(); iterator.hasNext(); ) {
550
		{
551
			Record r = (Record) iterator.next();
607
            Record r = (Record) iterator.next();
552
			objRecordSize += r.getRecordSize();
608
            objRecordSize += r.getRecordSize();
553
		}
609
        }
554
		int tailRecordSize = 0;
610
        int tailRecordSize = 0;
555
		for ( Iterator iterator = tailRec.iterator(); iterator.hasNext(); )
611
        for (Iterator iterator = tailRec.iterator(); iterator.hasNext(); ) {
556
		{
557
			Record r = (Record) iterator.next();
612
            Record r = (Record) iterator.next();
558
			tailRecordSize += r.getRecordSize();
613
            tailRecordSize += r.getRecordSize();
559
		}
614
        }
560
		return drawingRecordSize + objRecordSize + tailRecordSize;
615
        return drawingRecordSize + objRecordSize + tailRecordSize +continueRecordsHeadersSize;
561
	}
616
    }
562
617
563
	/**
618
    /**
564
	 * Associates an escher record to an OBJ record or a TXO record.
619
     * Associates an escher record to an OBJ record or a TXO record.
565
	 */
620
     */
566
	Object associateShapeToObjRecord( EscherRecord r, ObjRecord objRecord )
621
    Object associateShapeToObjRecord(EscherRecord r, ObjRecord objRecord) {
567
	{
568
		return shapeToObj.put( r, objRecord );
622
        return shapeToObj.put(r, objRecord);
569
	}
623
    }
570
624
571
	public HSSFPatriarch getPatriarch()
625
    public HSSFPatriarch getPatriarch() {
572
	{
573
		return patriarch;
626
        return patriarch;
574
	}
627
    }
575
628
576
	public void setPatriarch( HSSFPatriarch patriarch )
629
    public void setPatriarch(HSSFPatriarch patriarch) {
577
	{
578
		this.patriarch = patriarch;
630
        this.patriarch = patriarch;
579
	}
631
    }
580
632
581
	/**
633
    /**
582
	 * Converts the Records into UserModel
634
     * Converts the Records into UserModel
583
	 *  objects on the bound HSSFPatriarch
635
     * objects on the bound HSSFPatriarch
584
	 */
636
     */
585
	public void convertRecordsToUserModel() {
637
    public void convertRecordsToUserModel() {
586
		if(patriarch == null) {
638
        if (patriarch == null) {
587
			throw new IllegalStateException("Must call setPatriarch() first");
639
            throw new IllegalStateException("Must call setPatriarch() first");
588
		}
640
        }
589
641
590
		// The top level container ought to have
642
        // The top level container ought to have
591
		//  the DgRecord and the container of one container
643
        //  the DgRecord and the container of one container
592
		//  per shape group (patriach overall first)
644
        //  per shape group (patriach overall first)
593
		EscherContainerRecord topContainer = getEscherContainer();
645
        EscherContainerRecord topContainer = getEscherContainer();
594
		if(topContainer == null) {
646
        if (topContainer == null) {
595
			return;
647
            return;
596
		}
648
        }
597
		topContainer = topContainer.getChildContainers().get(0);
649
        topContainer = topContainer.getChildContainers().get(0);
598
650
599
		List tcc = topContainer.getChildContainers();
651
        List tcc = topContainer.getChildContainers();
600
		if(tcc.size() == 0) {
652
        if (tcc.size() == 0) {
601
			throw new IllegalStateException("No child escher containers at the point that should hold the patriach data, and one container per top level shape!");
653
            throw new IllegalStateException("No child escher containers at the point that should hold the patriach data, and one container per top level shape!");
602
		}
654
        }
603
655
604
		// First up, get the patriach position
656
        // First up, get the patriach position
605
		// This is in the first EscherSpgrRecord, in
657
        // This is in the first EscherSpgrRecord, in
606
		//  the first container, with a EscherSRecord too
658
        //  the first container, with a EscherSRecord too
607
		EscherContainerRecord patriachContainer =
659
        EscherContainerRecord patriachContainer =
608
			(EscherContainerRecord)tcc.get(0);
660
                (EscherContainerRecord) tcc.get(0);
609
		EscherSpgrRecord spgr = null;
661
        EscherSpgrRecord spgr = null;
610
		for(Iterator<EscherRecord> it = patriachContainer.getChildIterator(); it.hasNext();) {
662
        for (Iterator<EscherRecord> it = patriachContainer.getChildIterator(); it.hasNext(); ) {
611
			EscherRecord r = it.next();
663
            EscherRecord r = it.next();
612
			if(r instanceof EscherSpgrRecord) {
664
            if (r instanceof EscherSpgrRecord) {
613
				spgr = (EscherSpgrRecord)r;
665
                spgr = (EscherSpgrRecord) r;
614
				break;
666
                break;
615
			}
667
            }
616
		}
668
        }
617
		if(spgr != null) {
669
        if (spgr != null) {
618
			patriarch.setCoordinates(
670
            patriarch.setCoordinates(
619
					spgr.getRectX1(), spgr.getRectY1(),
671
                    spgr.getRectX1(), spgr.getRectY1(),
620
					spgr.getRectX2(), spgr.getRectY2()
672
                    spgr.getRectX2(), spgr.getRectY2()
621
			);
673
            );
622
		}
674
        }
623
675
624
		convertRecordsToUserModelRecursive(tcc, patriarch, null);
676
        convertRecordsToUserModelRecursive(tcc, patriarch, null);
625
677
626
		// Now, clear any trace of what records make up
678
        // Now, clear any trace of what records make up
627
		//  the patriarch
679
        //  the patriarch
628
		// Otherwise, everything will go horribly wrong
680
        // Otherwise, everything will go horribly wrong
629
		//  when we try to write out again....
681
        //  when we try to write out again....
630
//		clearEscherRecords();
682
//		clearEscherRecords();
631
		drawingManager.getDgg().setFileIdClusters(new EscherDggRecord.FileIdCluster[0]);
683
        drawingManager.getDgg().setFileIdClusters(new EscherDggRecord.FileIdCluster[0]);
632
684
633
		// TODO: Support converting our records
685
        // TODO: Support converting our records
634
		// back into shapes
686
        // back into shapes
635
		// log.log(POILogger.WARN, "Not processing objects into Patriarch!");
687
        // log.log(POILogger.WARN, "Not processing objects into Patriarch!");
636
	}
688
    }
637
689
638
	private static void convertRecordsToUserModelRecursive(List tcc, HSSFShapeContainer container, HSSFShape parent) {
690
    private static void convertRecordsToUserModelRecursive(List tcc, HSSFShapeContainer container, HSSFShape parent) {
639
		// Now process the containers for each group
691
        // Now process the containers for each group
640
		//  and objects
692
        //  and objects
641
		for(int i=1; i<tcc.size(); i++) {
693
        for (int i = 1; i < tcc.size(); i++) {
642
			EscherContainerRecord shapeContainer = (EscherContainerRecord)tcc.get(i);
694
            EscherContainerRecord shapeContainer = (EscherContainerRecord) tcc.get(i);
643
695
644
			// Could be a group, or a base object
696
            // Could be a group, or a base object
645
			if (shapeContainer.getRecordId() == EscherContainerRecord.SPGR_CONTAINER)
697
            if (shapeContainer.getRecordId() == EscherContainerRecord.SPGR_CONTAINER) {
646
			{
647
				// Group
698
                // Group
648
				final int shapeChildren = shapeContainer.getChildRecords().size();
699
                final int shapeChildren = shapeContainer.getChildRecords().size();
649
				if (shapeChildren > 0)
700
                if (shapeChildren > 0) {
650
				{
651
					HSSFShapeGroup group = new HSSFShapeGroup( parent, new HSSFClientAnchor() );
701
                    HSSFShapeGroup group = new HSSFShapeGroup(parent, new HSSFClientAnchor());
652
					addToParentOrContainer(group, container, parent);
702
                    addToParentOrContainer(group, container, parent);
653
703
654
					EscherContainerRecord groupContainer = (EscherContainerRecord) shapeContainer.getChild( 0 );
704
                    EscherContainerRecord groupContainer = (EscherContainerRecord) shapeContainer.getChild(0);
655
					convertRecordsToUserModel( groupContainer, group );
705
                    convertRecordsToUserModel(groupContainer, group);
656
					
706
657
					if (shapeChildren>1){
707
                    if (shapeChildren > 1) {
658
						convertRecordsToUserModelRecursive(shapeContainer.getChildRecords(), container, group);
708
                        convertRecordsToUserModelRecursive(shapeContainer.getChildRecords(), container, group);
659
					}
709
                    }
660
				} else
710
                } else {
661
				{
662
					log.log( POILogger.WARN,
711
                    log.log(POILogger.WARN,
663
							"Found drawing group without children." );
712
                            "Found drawing group without children.");
664
				}
713
                }
665
714
666
			} else if (shapeContainer.getRecordId() == EscherContainerRecord.SP_CONTAINER)
715
            } else if (shapeContainer.getRecordId() == EscherContainerRecord.SP_CONTAINER) {
667
			{
668
				EscherSpRecord spRecord = shapeContainer
716
                EscherSpRecord spRecord = shapeContainer
669
						.getChildById( EscherSpRecord.RECORD_ID );
717
                        .getChildById(EscherSpRecord.RECORD_ID);
670
				int type = spRecord.getShapeType();
718
                int type = spRecord.getShapeType();
671
719
672
				switch (type)
720
                switch (type) {
673
				{
674
				case ST_TEXTBOX:
721
                    case ST_TEXTBOX:
675
					HSSFTextbox box = new HSSFTextbox( parent,
722
                        HSSFTextbox box = new HSSFTextbox(parent,
676
							new HSSFClientAnchor() );
723
                                new HSSFClientAnchor());
677
					addToParentOrContainer(box, container, parent);
724
                        addToParentOrContainer(box, container, parent);
678
725
679
					convertRecordsToUserModel( shapeContainer, box );
726
                        convertRecordsToUserModel(shapeContainer, box);
680
					break;
727
                        break;
681
				case ST_PICTUREFRAME:
728
                    case ST_PICTUREFRAME:
682
					// Duplicated from
729
                        // Duplicated from
683
					// org.apache.poi.hslf.model.Picture.getPictureIndex()
730
                        // org.apache.poi.hslf.model.Picture.getPictureIndex()
684
					EscherOptRecord opt = (EscherOptRecord) getEscherChild(
731
                        EscherOptRecord opt = (EscherOptRecord) getEscherChild(
685
							shapeContainer, EscherOptRecord.RECORD_ID );
732
                                shapeContainer, EscherOptRecord.RECORD_ID);
686
					EscherSimpleProperty prop = (EscherSimpleProperty)opt.lookup(
733
                        EscherSimpleProperty prop = (EscherSimpleProperty) opt.lookup(
687
							EscherProperties.BLIP__BLIPTODISPLAY );
734
                                EscherProperties.BLIP__BLIPTODISPLAY);
688
					if (prop == null)
735
                        if (prop == null) {
689
					{
690
						log.log( POILogger.WARN,
736
                            log.log(POILogger.WARN,
691
								"Picture index for picture shape not found." );
737
                                    "Picture index for picture shape not found.");
692
					} else
738
                        } else {
693
					{
694
						int pictureIndex = prop.getPropertyValue();
739
                            int pictureIndex = prop.getPropertyValue();
695
740
696
						EscherClientAnchorRecord anchorRecord = (EscherClientAnchorRecord) getEscherChild(
741
                            EscherClientAnchorRecord anchorRecord = (EscherClientAnchorRecord) getEscherChild(
697
								shapeContainer,
742
                                    shapeContainer,
698
								EscherClientAnchorRecord.RECORD_ID );
743
                                    EscherClientAnchorRecord.RECORD_ID);
699
744
700
						EscherChildAnchorRecord childRecord = (EscherChildAnchorRecord) getEscherChild(
745
                            EscherChildAnchorRecord childRecord = (EscherChildAnchorRecord) getEscherChild(
701
								shapeContainer,
746
                                    shapeContainer,
702
								EscherChildAnchorRecord.RECORD_ID );
747
                                    EscherChildAnchorRecord.RECORD_ID);
703
748
704
						if (anchorRecord!=null && childRecord!=null){
749
                            if (anchorRecord != null && childRecord != null) {
705
							log.log( POILogger.WARN, "Picture with both CLIENT and CHILD anchor: "+ type );
750
                                log.log(POILogger.WARN, "Picture with both CLIENT and CHILD anchor: " + type);
706
						}
751
                            }
707
					
752
708
						HSSFAnchor anchor;
753
                            HSSFAnchor anchor;
709
						if (anchorRecord!=null){
754
                            if (anchorRecord != null) {
710
							anchor = toClientAnchor(anchorRecord);
755
                                anchor = toClientAnchor(anchorRecord);
711
						}else{
756
                            } else {
712
							anchor = toChildAnchor(childRecord);
757
                                anchor = toChildAnchor(childRecord);
713
						}
758
                            }
714
759
715
						HSSFPicture picture = new HSSFPicture( parent, anchor );
760
                            HSSFPicture picture = new HSSFPicture(parent, anchor);
716
						picture.setPictureIndex( pictureIndex );
761
                            picture.setPictureIndex(pictureIndex);
717
762
718
						addToParentOrContainer(picture, container, parent);
763
                            addToParentOrContainer(picture, container, parent);
719
					}
764
                        }
720
					break;
765
                        break;
721
				default:
766
                    default:
722
					final HSSFSimpleShape shape = new HSSFSimpleShape( parent,
767
                        final HSSFSimpleShape shape = new HSSFSimpleShape(parent,
723
							new HSSFClientAnchor() );
768
                                new HSSFClientAnchor());
724
					addToParentOrContainer(shape, container, parent);
769
                        addToParentOrContainer(shape, container, parent);
725
					convertRecordsToUserModel( shapeContainer, shape);
770
                        convertRecordsToUserModel(shapeContainer, shape);
726
					
771
727
					log.log( POILogger.WARN, "Unhandled shape type: "
772
                        log.log(POILogger.WARN, "Unhandled shape type: "
728
							+ type );
773
                                + type);
729
					break;
774
                        break;
730
				}
775
                }
731
			} else
776
            } else {
732
			{
733
				log.log( POILogger.WARN, "Unexpected record id of shape group." );
777
                log.log(POILogger.WARN, "Unexpected record id of shape group.");
734
			}
778
            }
735
779
736
		}
780
        }
737
	}
781
    }
738
782
739
    private static void addToParentOrContainer(HSSFShape shape, HSSFShapeContainer container, HSSFShape parent) {
783
    private static void addToParentOrContainer(HSSFShape shape, HSSFShapeContainer container, HSSFShape parent) {
740
784
741
    	if (parent instanceof HSSFShapeGroup)
785
        if (parent instanceof HSSFShapeGroup)
742
    		((HSSFShapeGroup) parent).addShape(shape);
786
            ((HSSFShapeGroup) parent).addShape(shape);
743
    	else if (container instanceof HSSFPatriarch)
787
        else if (container instanceof HSSFPatriarch)
744
    		((HSSFPatriarch) container).addShape(shape);
788
            ((HSSFPatriarch) container).addShape(shape);
745
    	else
789
        else
746
    		container.getChildren().add(shape);
790
            container.getChildren().add(shape);
747
	}
791
    }
748
792
749
	private static HSSFClientAnchor toClientAnchor(EscherClientAnchorRecord anchorRecord){
793
    private static HSSFClientAnchor toClientAnchor(EscherClientAnchorRecord anchorRecord) {
750
        HSSFClientAnchor anchor = new HSSFClientAnchor();
794
        HSSFClientAnchor anchor = new HSSFClientAnchor();
751
        anchor.setAnchorType(anchorRecord.getFlag());
795
        anchor.setAnchorType(anchorRecord.getFlag());
752
        anchor.setCol1( anchorRecord.getCol1() );
796
        anchor.setCol1(anchorRecord.getCol1());
753
        anchor.setCol2( anchorRecord.getCol2() );
797
        anchor.setCol2(anchorRecord.getCol2());
754
        anchor.setDx1( anchorRecord.getDx1() );
798
        anchor.setDx1(anchorRecord.getDx1());
755
        anchor.setDx2( anchorRecord.getDx2() );
799
        anchor.setDx2(anchorRecord.getDx2());
756
        anchor.setDy1( anchorRecord.getDy1() );
800
        anchor.setDy1(anchorRecord.getDy1());
757
        anchor.setDy2( anchorRecord.getDy2() );
801
        anchor.setDy2(anchorRecord.getDy2());
758
        anchor.setRow1( anchorRecord.getRow1() );
802
        anchor.setRow1(anchorRecord.getRow1());
759
        anchor.setRow2( anchorRecord.getRow2() );
803
        anchor.setRow2(anchorRecord.getRow2());
760
        return anchor;
804
        return anchor;
761
    }
805
    }
762
806
763
    private static HSSFChildAnchor toChildAnchor(EscherChildAnchorRecord anchorRecord){
807
    private static HSSFChildAnchor toChildAnchor(EscherChildAnchorRecord anchorRecord) {
764
        HSSFChildAnchor anchor = new HSSFChildAnchor();
808
        HSSFChildAnchor anchor = new HSSFChildAnchor();
765
//        anchor.setAnchorType(anchorRecord.getFlag());
809
//        anchor.setAnchorType(anchorRecord.getFlag());
766
//        anchor.setCol1( anchorRecord.getCol1() );
810
//        anchor.setCol1( anchorRecord.getCol1() );
767
//        anchor.setCol2( anchorRecord.getCol2() );
811
//        anchor.setCol2( anchorRecord.getCol2() );
768
        anchor.setDx1( anchorRecord.getDx1() );
812
        anchor.setDx1(anchorRecord.getDx1());
769
        anchor.setDx2( anchorRecord.getDx2() );
813
        anchor.setDx2(anchorRecord.getDx2());
770
        anchor.setDy1( anchorRecord.getDy1() );
814
        anchor.setDy1(anchorRecord.getDy1());
771
        anchor.setDy2( anchorRecord.getDy2() );
815
        anchor.setDy2(anchorRecord.getDy2());
772
//        anchor.setRow1( anchorRecord.getRow1() );
816
//        anchor.setRow1( anchorRecord.getRow1() );
773
//        anchor.setRow2( anchorRecord.getRow2() );
817
//        anchor.setRow2( anchorRecord.getRow2() );
774
        return anchor;
818
        return anchor;
775
    }
819
    }
776
820
777
	private static void convertRecordsToUserModel(EscherContainerRecord shapeContainer, Object model) {
821
    private static void convertRecordsToUserModel(EscherContainerRecord shapeContainer, Object model) {
778
		for(Iterator<EscherRecord> it = shapeContainer.getChildIterator(); it.hasNext();) {
822
        for (Iterator<EscherRecord> it = shapeContainer.getChildIterator(); it.hasNext(); ) {
779
			EscherRecord r = it.next();
823
            EscherRecord r = it.next();
780
			if(r instanceof EscherSpgrRecord) {
824
            if (r instanceof EscherSpgrRecord) {
781
				// This may be overriden by a later EscherClientAnchorRecord
825
                // This may be overriden by a later EscherClientAnchorRecord
782
				EscherSpgrRecord spgr = (EscherSpgrRecord)r;
826
                EscherSpgrRecord spgr = (EscherSpgrRecord) r;
783
827
784
				if(model instanceof HSSFShapeGroup) {
828
                if (model instanceof HSSFShapeGroup) {
785
					HSSFShapeGroup g = (HSSFShapeGroup)model;
829
                    HSSFShapeGroup g = (HSSFShapeGroup) model;
786
					g.setCoordinates(
830
                    g.setCoordinates(
787
							spgr.getRectX1(), spgr.getRectY1(),
831
                            spgr.getRectX1(), spgr.getRectY1(),
788
							spgr.getRectX2(), spgr.getRectY2()
832
                            spgr.getRectX2(), spgr.getRectY2()
789
					);
833
                    );
790
				} else {
834
                } else {
791
					throw new IllegalStateException("Got top level anchor but not processing a group");
835
                    throw new IllegalStateException("Got top level anchor but not processing a group");
792
				}
836
                }
793
			}
837
            } else if (r instanceof EscherClientAnchorRecord) {
794
			else if(r instanceof EscherClientAnchorRecord) {
795
				EscherClientAnchorRecord car = (EscherClientAnchorRecord)r;
838
                EscherClientAnchorRecord car = (EscherClientAnchorRecord) r;
796
839
797
				if(model instanceof HSSFShape) {
840
                if (model instanceof HSSFShape) {
798
					HSSFShape g = (HSSFShape)model;
841
                    HSSFShape g = (HSSFShape) model;
799
					g.getAnchor().setDx1(car.getDx1());
842
                    g.getAnchor().setDx1(car.getDx1());
800
					g.getAnchor().setDx2(car.getDx2());
843
                    g.getAnchor().setDx2(car.getDx2());
801
					g.getAnchor().setDy1(car.getDy1());
844
                    g.getAnchor().setDy1(car.getDy1());
802
					g.getAnchor().setDy2(car.getDy2());
845
                    g.getAnchor().setDy2(car.getDy2());
803
				} else {
846
                } else {
804
					throw new IllegalStateException("Got top level anchor but not processing a group or shape");
847
                    throw new IllegalStateException("Got top level anchor but not processing a group or shape");
805
				}
848
                }
806
			}
849
            } else if (r instanceof EscherTextboxRecord) {
807
			else if(r instanceof EscherTextboxRecord) {
808
				EscherTextboxRecord tbr = (EscherTextboxRecord)r;
850
                EscherTextboxRecord tbr = (EscherTextboxRecord) r;
809
851
810
				// Also need to find the TextObjectRecord too
852
                // Also need to find the TextObjectRecord too
811
				// TODO
853
                // TODO
812
			}
854
            } else if (r instanceof EscherSpRecord) {
813
			else if(r instanceof EscherSpRecord) {
814
				// Use flags if needed
855
                // Use flags if needed
815
				final EscherSpRecord spr = (EscherSpRecord) r;
856
                final EscherSpRecord spr = (EscherSpRecord) r;
816
				if (model instanceof HSSFShape){
857
                if (model instanceof HSSFShape) {
817
					final HSSFShape s = (HSSFShape) model;
858
                    final HSSFShape s = (HSSFShape) model;
818
				}
859
                }
819
			}
860
            } else if (r instanceof EscherOptRecord) {
820
			else if(r instanceof EscherOptRecord) {
821
				// Use properties if needed
861
                // Use properties if needed
822
			}
862
            } else {
823
			else {
824
				//System.err.println(r);
863
                //System.err.println(r);
825
			}
864
            }
826
		}
865
        }
827
	}
866
    }
828
867
829
	public void clear()
868
    public void clear() {
830
	{
831
		clearEscherRecords();
869
        clearEscherRecords();
832
		shapeToObj.clear();
870
        shapeToObj.clear();
833
//		lastShapeId = 1024;
871
//		lastShapeId = 1024;
834
	}
872
    }
835
873
836
	protected String getRecordName()
874
    protected String getRecordName() {
837
	{
838
		return "ESCHERAGGREGATE";
875
        return "ESCHERAGGREGATE";
839
	}
876
    }
840
877
841
	// =============== Private methods ========================
878
    // =============== Private methods ========================
842
879
843
	private static boolean isObjectRecord( List records, int loc )
880
    private static boolean isObjectRecord(List records, int loc) {
844
	{
845
		return sid( records, loc ) == ObjRecord.sid || sid( records, loc ) == TextObjectRecord.sid;
881
        return sid(records, loc) == ObjRecord.sid || sid(records, loc) == TextObjectRecord.sid;
846
	}
882
    }
847
883
848
	private void convertUserModelToRecords()
884
    private void convertUserModelToRecords() {
849
	{
885
        if (patriarch != null) {
850
		if ( patriarch != null )
851
		{
852
			shapeToObj.clear();
886
            shapeToObj.clear();
853
			tailRec.clear();
887
            tailRec.clear();
854
			clearEscherRecords();
888
            clearEscherRecords();
855
			if ( patriarch.getChildren().size() != 0 )
889
            if (patriarch.getChildren().size() != 0) {
856
			{
857
				convertPatriarch( patriarch );
890
                convertPatriarch(patriarch);
858
				EscherContainerRecord dgContainer = (EscherContainerRecord) getEscherRecord( 0 );
891
                EscherContainerRecord dgContainer = (EscherContainerRecord) getEscherRecord(0);
859
				EscherContainerRecord spgrContainer = null;
892
                EscherContainerRecord spgrContainer = null;
860
				Iterator<EscherRecord> iter = dgContainer.getChildIterator();
893
                Iterator<EscherRecord> iter = dgContainer.getChildIterator();
861
				while (iter.hasNext()) {
894
                while (iter.hasNext()) {
862
					EscherRecord child = iter.next();
895
                    EscherRecord child = iter.next();
863
					if (child.getRecordId() == EscherContainerRecord.SPGR_CONTAINER) {
896
                    if (child.getRecordId() == EscherContainerRecord.SPGR_CONTAINER) {
864
						spgrContainer = (EscherContainerRecord) child;
897
                        spgrContainer = (EscherContainerRecord) child;
865
					}
898
                    }
866
				}
899
                }
867
				convertShapes( patriarch, spgrContainer, shapeToObj );
900
                convertShapes(patriarch, spgrContainer, shapeToObj);
868
901
869
				patriarch = null;
902
                patriarch = null;
870
			}
903
            }
871
		}
904
        }
872
	}
905
    }
873
906
874
	private void convertShapes( HSSFShapeContainer parent, EscherContainerRecord escherParent, Map shapeToObj )
907
    private void convertShapes(HSSFShapeContainer parent, EscherContainerRecord escherParent, Map shapeToObj) {
875
	{
876
		if ( escherParent == null ) throw new IllegalArgumentException( "Parent record required" );
908
        if (escherParent == null) throw new IllegalArgumentException("Parent record required");
877
909
878
		List shapes = parent.getChildren();
910
        List shapes = parent.getChildren();
879
		for ( Iterator iterator = shapes.iterator(); iterator.hasNext(); )
911
        for (Iterator iterator = shapes.iterator(); iterator.hasNext(); ) {
880
		{
881
			HSSFShape shape = (HSSFShape) iterator.next();
912
            HSSFShape shape = (HSSFShape) iterator.next();
882
			if ( shape instanceof HSSFShapeGroup )
913
            if (shape instanceof HSSFShapeGroup) {
883
			{
884
				convertGroup( (HSSFShapeGroup) shape, escherParent, shapeToObj );
914
                convertGroup((HSSFShapeGroup) shape, escherParent, shapeToObj);
885
			}
915
            } else {
886
			else
887
			{
888
				AbstractShape shapeModel = AbstractShape.createShape(
916
                AbstractShape shapeModel = AbstractShape.createShape(
889
						shape,
917
                        shape,
890
						drawingManager.allocateShapeId(drawingGroupId) );
918
                        drawingManager.allocateShapeId(drawingGroupId));
891
				shapeToObj.put( findClientData( shapeModel.getSpContainer() ), shapeModel.getObjRecord() );
919
                shapeToObj.put(findClientData(shapeModel.getSpContainer()), shapeModel.getObjRecord());
892
				if ( shapeModel instanceof TextboxShape )
920
                if (shapeModel instanceof TextboxShape) {
893
				{
894
					EscherRecord escherTextbox = ( (TextboxShape) shapeModel ).getEscherTextbox();
921
                    EscherRecord escherTextbox = ((TextboxShape) shapeModel).getEscherTextbox();
895
					shapeToObj.put( escherTextbox, ( (TextboxShape) shapeModel ).getTextObjectRecord() );
922
                    shapeToObj.put(escherTextbox, ((TextboxShape) shapeModel).getTextObjectRecord());
896
					//					escherParent.addChildRecord(escherTextbox);
923
                    //					escherParent.addChildRecord(escherTextbox);
897
924
898
					if ( shapeModel instanceof CommentShape ){
925
                    if (shapeModel instanceof CommentShape) {
899
						CommentShape comment = (CommentShape)shapeModel;
926
                        CommentShape comment = (CommentShape) shapeModel;
900
						tailRec.add(comment.getNoteRecord());
927
                        tailRec.add(comment.getNoteRecord());
901
					}
928
                    }
902
929
903
				}
930
                }
904
				escherParent.addChildRecord( shapeModel.getSpContainer() );
931
                escherParent.addChildRecord(shapeModel.getSpContainer());
905
			}
932
            }
906
		}
933
        }
907
//		drawingManager.newCluster( (short)1 );
934
//		drawingManager.newCluster( (short)1 );
908
//		drawingManager.newCluster( (short)2 );
935
//		drawingManager.newCluster( (short)2 );
909
936
910
	}
937
    }
911
938
912
	private void convertGroup( HSSFShapeGroup shape, EscherContainerRecord escherParent, Map shapeToObj )
939
    private void convertGroup(HSSFShapeGroup shape, EscherContainerRecord escherParent, Map shapeToObj) {
913
	{
914
		EscherContainerRecord spgrContainer = new EscherContainerRecord();
940
        EscherContainerRecord spgrContainer = new EscherContainerRecord();
915
		EscherContainerRecord spContainer = new EscherContainerRecord();
941
        EscherContainerRecord spContainer = new EscherContainerRecord();
916
		EscherSpgrRecord spgr = new EscherSpgrRecord();
942
        EscherSpgrRecord spgr = new EscherSpgrRecord();
917
		EscherSpRecord sp = new EscherSpRecord();
943
        EscherSpRecord sp = new EscherSpRecord();
918
		EscherOptRecord opt = new EscherOptRecord();
944
        EscherOptRecord opt = new EscherOptRecord();
919
		EscherRecord anchor;
945
        EscherRecord anchor;
920
		EscherClientDataRecord clientData = new EscherClientDataRecord();
946
        EscherClientDataRecord clientData = new EscherClientDataRecord();
921
947
922
		spgrContainer.setRecordId( EscherContainerRecord.SPGR_CONTAINER );
948
        spgrContainer.setRecordId(EscherContainerRecord.SPGR_CONTAINER);
923
		spgrContainer.setOptions( (short) 0x000F );
949
        spgrContainer.setOptions((short) 0x000F);
924
		spContainer.setRecordId( EscherContainerRecord.SP_CONTAINER );
950
        spContainer.setRecordId(EscherContainerRecord.SP_CONTAINER);
925
		spContainer.setOptions( (short) 0x000F );
951
        spContainer.setOptions((short) 0x000F);
926
		spgr.setRecordId( EscherSpgrRecord.RECORD_ID );
952
        spgr.setRecordId(EscherSpgrRecord.RECORD_ID);
927
		spgr.setOptions( (short) 0x0001 );
953
        spgr.setOptions((short) 0x0001);
928
		spgr.setRectX1( shape.getX1() );
954
        spgr.setRectX1(shape.getX1());
929
		spgr.setRectY1( shape.getY1() );
955
        spgr.setRectY1(shape.getY1());
930
		spgr.setRectX2( shape.getX2() );
956
        spgr.setRectX2(shape.getX2());
931
		spgr.setRectY2( shape.getY2() );
957
        spgr.setRectY2(shape.getY2());
932
		sp.setRecordId( EscherSpRecord.RECORD_ID );
958
        sp.setRecordId(EscherSpRecord.RECORD_ID);
933
		sp.setOptions( (short) 0x0002 );
959
        sp.setOptions((short) 0x0002);
934
		int shapeId = drawingManager.allocateShapeId(drawingGroupId);
960
        int shapeId = drawingManager.allocateShapeId(drawingGroupId);
935
		sp.setShapeId( shapeId );
961
        sp.setShapeId(shapeId);
936
		if (shape.getAnchor() instanceof HSSFClientAnchor)
962
        if (shape.getAnchor() instanceof HSSFClientAnchor)
937
			sp.setFlags( EscherSpRecord.FLAG_GROUP | EscherSpRecord.FLAG_HAVEANCHOR );
963
            sp.setFlags(EscherSpRecord.FLAG_GROUP | EscherSpRecord.FLAG_HAVEANCHOR);
938
		else
964
        else
939
			sp.setFlags( EscherSpRecord.FLAG_GROUP | EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_CHILD );
965
            sp.setFlags(EscherSpRecord.FLAG_GROUP | EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_CHILD);
940
		opt.setRecordId( EscherOptRecord.RECORD_ID );
966
        opt.setRecordId(EscherOptRecord.RECORD_ID);
941
		opt.setOptions( (short) 0x0023 );
967
        opt.setOptions((short) 0x0023);
942
		opt.addEscherProperty( new EscherBoolProperty( EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x00040004 ) );
968
        opt.addEscherProperty(new EscherBoolProperty(EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x00040004));
943
		opt.addEscherProperty( new EscherBoolProperty( EscherProperties.GROUPSHAPE__PRINT, 0x00080000 ) );
969
        opt.addEscherProperty(new EscherBoolProperty(EscherProperties.GROUPSHAPE__PRINT, 0x00080000));
944
970
945
		anchor = ConvertAnchor.createAnchor( shape.getAnchor() );
971
        anchor = ConvertAnchor.createAnchor(shape.getAnchor());
946
//		clientAnchor.setCol1( ( (HSSFClientAnchor) shape.getAnchor() ).getCol1() );
972
//		clientAnchor.setCol1( ( (HSSFClientAnchor) shape.getAnchor() ).getCol1() );
947
//		clientAnchor.setRow1( (short) ( (HSSFClientAnchor) shape.getAnchor() ).getRow1() );
973
//		clientAnchor.setRow1( (short) ( (HSSFClientAnchor) shape.getAnchor() ).getRow1() );
948
//		clientAnchor.setDx1( (short) shape.getAnchor().getDx1() );
974
//		clientAnchor.setDx1( (short) shape.getAnchor().getDx1() );
Lines 951-1063 Link Here
951
//		clientAnchor.setRow2( (short) ( (HSSFClientAnchor) shape.getAnchor() ).getRow2() );
977
//		clientAnchor.setRow2( (short) ( (HSSFClientAnchor) shape.getAnchor() ).getRow2() );
952
//		clientAnchor.setDx2( (short) shape.getAnchor().getDx2() );
978
//		clientAnchor.setDx2( (short) shape.getAnchor().getDx2() );
953
//		clientAnchor.setDy2( (short) shape.getAnchor().getDy2() );
979
//		clientAnchor.setDy2( (short) shape.getAnchor().getDy2() );
954
		clientData.setRecordId( EscherClientDataRecord.RECORD_ID );
980
        clientData.setRecordId(EscherClientDataRecord.RECORD_ID);
955
		clientData.setOptions( (short) 0x0000 );
981
        clientData.setOptions((short) 0x0000);
956
982
957
		spgrContainer.addChildRecord( spContainer );
983
        spgrContainer.addChildRecord(spContainer);
958
		spContainer.addChildRecord( spgr );
984
        spContainer.addChildRecord(spgr);
959
		spContainer.addChildRecord( sp );
985
        spContainer.addChildRecord(sp);
960
		spContainer.addChildRecord( opt );
986
        spContainer.addChildRecord(opt);
961
		spContainer.addChildRecord( anchor );
987
        spContainer.addChildRecord(anchor);
962
		spContainer.addChildRecord( clientData );
988
        spContainer.addChildRecord(clientData);
963
989
964
		ObjRecord obj = new ObjRecord();
990
        ObjRecord obj = new ObjRecord();
965
		CommonObjectDataSubRecord cmo = new CommonObjectDataSubRecord();
991
        CommonObjectDataSubRecord cmo = new CommonObjectDataSubRecord();
966
		cmo.setObjectType( CommonObjectDataSubRecord.OBJECT_TYPE_GROUP );
992
        cmo.setObjectType(CommonObjectDataSubRecord.OBJECT_TYPE_GROUP);
967
		cmo.setObjectId( shapeId );
993
        cmo.setObjectId(shapeId);
968
		cmo.setLocked( true );
994
        cmo.setLocked(true);
969
		cmo.setPrintable( true );
995
        cmo.setPrintable(true);
970
		cmo.setAutofill( true );
996
        cmo.setAutofill(true);
971
		cmo.setAutoline( true );
997
        cmo.setAutoline(true);
972
		GroupMarkerSubRecord gmo = new GroupMarkerSubRecord();
998
        GroupMarkerSubRecord gmo = new GroupMarkerSubRecord();
973
		EndSubRecord end = new EndSubRecord();
999
        EndSubRecord end = new EndSubRecord();
974
		obj.addSubRecord( cmo );
1000
        obj.addSubRecord(cmo);
975
		obj.addSubRecord( gmo );
1001
        obj.addSubRecord(gmo);
976
		obj.addSubRecord( end );
1002
        obj.addSubRecord(end);
977
		shapeToObj.put( clientData, obj );
1003
        shapeToObj.put(clientData, obj);
978
1004
979
		escherParent.addChildRecord( spgrContainer );
1005
        escherParent.addChildRecord(spgrContainer);
980
1006
981
		convertShapes( shape, spgrContainer, shapeToObj );
1007
        convertShapes(shape, spgrContainer, shapeToObj);
982
1008
983
	}
1009
    }
984
1010
985
	private EscherRecord findClientData( EscherContainerRecord spContainer )
1011
    private EscherRecord findClientData(EscherContainerRecord spContainer) {
986
	{
987
		for (Iterator<EscherRecord> iterator = spContainer.getChildIterator(); iterator.hasNext();) {
1012
        for (Iterator<EscherRecord> iterator = spContainer.getChildIterator(); iterator.hasNext(); ) {
988
			EscherRecord r = iterator.next();
1013
            EscherRecord r = iterator.next();
989
			if (r.getRecordId() == EscherClientDataRecord.RECORD_ID) {
1014
            if (r.getRecordId() == EscherClientDataRecord.RECORD_ID) {
990
				return r;
1015
                return r;
991
			}
1016
            }
992
		}
1017
        }
993
		throw new IllegalArgumentException( "Can not find client data record" );
1018
        throw new IllegalArgumentException("Can not find client data record");
994
	}
1019
    }
995
1020
996
	private void convertPatriarch( HSSFPatriarch patriarch )
1021
    private void convertPatriarch(HSSFPatriarch patriarch) {
997
	{
998
		EscherContainerRecord dgContainer = new EscherContainerRecord();
1022
        EscherContainerRecord dgContainer = new EscherContainerRecord();
999
		EscherDgRecord dg;
1023
        EscherDgRecord dg;
1000
		EscherContainerRecord spgrContainer = new EscherContainerRecord();
1024
        EscherContainerRecord spgrContainer = new EscherContainerRecord();
1001
		EscherContainerRecord spContainer1 = new EscherContainerRecord();
1025
        EscherContainerRecord spContainer1 = new EscherContainerRecord();
1002
		EscherSpgrRecord spgr = new EscherSpgrRecord();
1026
        EscherSpgrRecord spgr = new EscherSpgrRecord();
1003
		EscherSpRecord sp1 = new EscherSpRecord();
1027
        EscherSpRecord sp1 = new EscherSpRecord();
1004
1028
1005
		dgContainer.setRecordId( EscherContainerRecord.DG_CONTAINER );
1029
        dgContainer.setRecordId(EscherContainerRecord.DG_CONTAINER);
1006
		dgContainer.setOptions( (short) 0x000F );
1030
        dgContainer.setOptions((short) 0x000F);
1007
		dg = drawingManager.createDgRecord();
1031
        dg = drawingManager.createDgRecord();
1008
		drawingGroupId = dg.getDrawingGroupId();
1032
        drawingGroupId = dg.getDrawingGroupId();
1009
//		dg.setOptions( (short) ( drawingId << 4 ) );
1033
//		dg.setOptions( (short) ( drawingId << 4 ) );
1010
//		dg.setNumShapes( getNumberOfShapes( patriarch ) );
1034
//		dg.setNumShapes( getNumberOfShapes( patriarch ) );
1011
//		dg.setLastMSOSPID( 0 );  // populated after all shape id's are assigned.
1035
//		dg.setLastMSOSPID( 0 );  // populated after all shape id's are assigned.
1012
		spgrContainer.setRecordId( EscherContainerRecord.SPGR_CONTAINER );
1036
        spgrContainer.setRecordId(EscherContainerRecord.SPGR_CONTAINER);
1013
		spgrContainer.setOptions( (short) 0x000F );
1037
        spgrContainer.setOptions((short) 0x000F);
1014
		spContainer1.setRecordId( EscherContainerRecord.SP_CONTAINER );
1038
        spContainer1.setRecordId(EscherContainerRecord.SP_CONTAINER);
1015
		spContainer1.setOptions( (short) 0x000F );
1039
        spContainer1.setOptions((short) 0x000F);
1016
		spgr.setRecordId( EscherSpgrRecord.RECORD_ID );
1040
        spgr.setRecordId(EscherSpgrRecord.RECORD_ID);
1017
		spgr.setOptions( (short) 0x0001 );	// version
1041
        spgr.setOptions((short) 0x0001);    // version
1018
		spgr.setRectX1( patriarch.getX1() );
1042
        spgr.setRectX1(patriarch.getX1());
1019
		spgr.setRectY1( patriarch.getY1() );
1043
        spgr.setRectY1(patriarch.getY1());
1020
		spgr.setRectX2( patriarch.getX2() );
1044
        spgr.setRectX2(patriarch.getX2());
1021
		spgr.setRectY2( patriarch.getY2() );
1045
        spgr.setRectY2(patriarch.getY2());
1022
		sp1.setRecordId( EscherSpRecord.RECORD_ID );
1046
        sp1.setRecordId(EscherSpRecord.RECORD_ID);
1023
		sp1.setOptions( (short) 0x0002 );
1047
        sp1.setOptions((short) 0x0002);
1024
		sp1.setShapeId( drawingManager.allocateShapeId(dg.getDrawingGroupId()) );
1048
        sp1.setShapeId(drawingManager.allocateShapeId(dg.getDrawingGroupId()));
1025
		sp1.setFlags( EscherSpRecord.FLAG_GROUP | EscherSpRecord.FLAG_PATRIARCH );
1049
        sp1.setFlags(EscherSpRecord.FLAG_GROUP | EscherSpRecord.FLAG_PATRIARCH);
1026
1050
1027
		dgContainer.addChildRecord( dg );
1051
        dgContainer.addChildRecord(dg);
1028
		dgContainer.addChildRecord( spgrContainer );
1052
        dgContainer.addChildRecord(spgrContainer);
1029
		spgrContainer.addChildRecord( spContainer1 );
1053
        spgrContainer.addChildRecord(spContainer1);
1030
		spContainer1.addChildRecord( spgr );
1054
        spContainer1.addChildRecord(spgr);
1031
		spContainer1.addChildRecord( sp1 );
1055
        spContainer1.addChildRecord(sp1);
1032
1056
1033
		addEscherRecord( dgContainer );
1057
        addEscherRecord(dgContainer);
1034
	}
1058
    }
1035
1059
1036
1060
1037
	private static short sid( List records, int loc )
1061
    private static short sid(List records, int loc) {
1038
	{
1039
		return ( (Record) records.get( loc ) ).getSid();
1062
        return ((Record) records.get(loc)).getSid();
1040
	}
1063
    }
1041
1064
1042
1065
1043
	// Duplicated from org.apache.poi.hslf.model.Shape
1066
    // Duplicated from org.apache.poi.hslf.model.Shape
1044
1067
1045
	/**
1068
    /**
1046
	 * Helper method to return escher child by record ID
1069
     * Helper method to return escher child by record ID
1047
	 * 
1070
     *
1048
	 * @return escher record or <code>null</code> if not found.
1071
     * @return escher record or <code>null</code> if not found.
1049
	 */
1072
     */
1050
	private static EscherRecord getEscherChild(EscherContainerRecord owner,
1073
    private static EscherRecord getEscherChild(EscherContainerRecord owner,
1051
			int recordId)
1074
                                               int recordId) {
1052
	{
1053
		for (Iterator iterator = owner.getChildRecords().iterator(); iterator
1075
        for (Iterator iterator = owner.getChildRecords().iterator(); iterator
1054
				.hasNext();)
1076
                .hasNext(); ) {
1055
		{
1056
			EscherRecord escherRecord = (EscherRecord) iterator.next();
1077
            EscherRecord escherRecord = (EscherRecord) iterator.next();
1057
			if (escherRecord.getRecordId() == recordId)
1078
            if (escherRecord.getRecordId() == recordId)
1058
				return escherRecord;
1079
                return escherRecord;
1059
		}
1080
        }
1060
		return null;
1081
        return null;
1061
	}
1082
    }
1062
1083
1063
}
1084
}
(-)src/java/org/apache/poi/hssf/record/DrawingRecord.java (-22 / +21 lines)
Lines 20-41 Link Here
20
import org.apache.poi.util.LittleEndianOutput;
20
import org.apache.poi.util.LittleEndianOutput;
21
/**
21
/**
22
 * DrawingRecord (0x00EC)<p/>
22
 * DrawingRecord (0x00EC)<p/>
23
 *
24
 */
23
 */
25
public final class DrawingRecord extends StandardRecord {
24
public final class DrawingRecord extends StandardRecord {
26
    public static final short sid = 0x00EC;
25
    public static final short sid = 0x00EC;
27
26
28
	private static final byte[] EMPTY_BYTE_ARRAY = { };
27
    private static final byte[] EMPTY_BYTE_ARRAY = {};
29
28
30
    private byte[] recordData;
29
    private byte[] recordData;
31
    private byte[] contd;
30
    private byte[] contd;
32
31
33
    public DrawingRecord() {
32
    public DrawingRecord() {
34
    	recordData = EMPTY_BYTE_ARRAY;
33
        recordData = EMPTY_BYTE_ARRAY;
35
    }
34
    }
36
35
37
    public DrawingRecord(RecordInputStream in) {
36
    public DrawingRecord(RecordInputStream in) {
38
      recordData = in.readRemainder();
37
        recordData = in.readRemainder();
39
    }
38
    }
40
39
41
    public void processContinueRecord(byte[] record) {
40
    public void processContinueRecord(byte[] record) {
Lines 46-51 Link Here
46
    public void serialize(LittleEndianOutput out) {
45
    public void serialize(LittleEndianOutput out) {
47
        out.write(recordData);
46
        out.write(recordData);
48
    }
47
    }
48
49
    protected int getDataSize() {
49
    protected int getDataSize() {
50
        return recordData.length;
50
        return recordData.length;
51
    }
51
    }
Lines 55-66 Link Here
55
    }
55
    }
56
56
57
    public byte[] getData() {
57
    public byte[] getData() {
58
        if(contd != null) {
58
//        if (continueData.size() != 0) {
59
            byte[] newBuffer = new byte[ recordData.length + contd.length ];
59
//            byte[] newBuffer = new byte[recordData.length + continueData.size()];
60
            System.arraycopy( recordData, 0, newBuffer, 0, recordData.length );
60
//            System.arraycopy(recordData, 0, newBuffer, 0, recordData.length);
61
            System.arraycopy( contd, 0, newBuffer, recordData.length, contd.length);
61
//            System.arraycopy(continueData.toByteArray(), 0, newBuffer, recordData.length, continueData.size());
62
            return newBuffer;
62
//            return newBuffer;
63
        }
63
//        }
64
        return recordData;
64
        return recordData;
65
    }
65
    }
66
66
Lines 69-89 Link Here
69
    }
69
    }
70
70
71
    public void setData(byte[] thedata) {
71
    public void setData(byte[] thedata) {
72
    	if (thedata == null) {
72
        if (thedata == null) {
73
    		throw new IllegalArgumentException("data must not be null");
73
            throw new IllegalArgumentException("data must not be null");
74
    	}
74
        }
75
        recordData = thedata;
75
        recordData = thedata;
76
    }
76
    }
77
77
78
    public Object clone() {
78
    public Object clone() {
79
    	DrawingRecord rec = new DrawingRecord();
79
        DrawingRecord rec = new DrawingRecord();
80
    	
80
        rec.recordData = recordData.clone();
81
    	rec.recordData = recordData.clone();
81
        if (contd != null) {
82
    	if (contd != null) {
82
            // TODO - this code probably never executes
83
	    	// TODO - this code probably never executes
83
            rec.contd = contd.clone();
84
	    	rec.contd = contd.clone();
84
        }
85
    	}
85
86
    	
86
        return rec;
87
    	return rec;
88
    }
87
    }
89
}
88
}
(-)src/testcases/org/apache/poi/hssf/record/HSSFRecordTestHelper.java (-34 lines)
Lines 1-34 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 *    contributor license agreements.  See the NOTICE file distributed with
4
 *    this work for additional information regarding copyright ownership.
5
 *    The ASF licenses this file to You under the Apache License, Version 2.0
6
 *    (the "License"); you may not use this file except in compliance with
7
 *    the License.  You may obtain a copy of the License at
8
 *
9
 *        http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 *    Unless required by applicable law or agreed to in writing, software
12
 *    distributed under the License is distributed on an "AS IS" BASIS,
13
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 *    See the License for the specific language governing permissions and
15
 *    limitations under the License.
16
 */
17
18
package org.apache.poi.hssf.record;
19
20
import org.apache.poi.ddf.EscherRecord;
21
22
import java.util.Map;
23
24
/**
25
 * @author Evgeniy Berlog
26
 * date: 30.05.12
27
 */
28
public class HSSFRecordTestHelper {
29
30
    public static Map<EscherRecord, Record> getShapeToObjForTest(EscherAggregate agg){
31
        return agg.shapeToObj;
32
    }
33
34
}

Return to bug 53010