Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

TestDrawingAggregate.java 54KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920
  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. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.hssf.model;
  16. import static org.apache.poi.poifs.storage.RawDataUtil.decompress;
  17. import static org.junit.jupiter.api.Assertions.assertArrayEquals;
  18. import static org.junit.jupiter.api.Assertions.assertEquals;
  19. import static org.junit.jupiter.api.Assertions.assertNotNull;
  20. import static org.junit.jupiter.api.Assertions.assertSame;
  21. import static org.junit.jupiter.api.Assertions.assertThrows;
  22. import static org.junit.jupiter.api.Assertions.assertTrue;
  23. import java.io.ByteArrayInputStream;
  24. import java.io.File;
  25. import java.io.IOException;
  26. import java.util.ArrayList;
  27. import java.util.HashMap;
  28. import java.util.List;
  29. import java.util.Map;
  30. import java.util.stream.Stream;
  31. import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream;
  32. import org.apache.poi.POIDataSamples;
  33. import org.apache.poi.ddf.DefaultEscherRecordFactory;
  34. import org.apache.poi.ddf.EscherContainerRecord;
  35. import org.apache.poi.ddf.EscherDggRecord;
  36. import org.apache.poi.ddf.EscherRecord;
  37. import org.apache.poi.ddf.EscherRecordFactory;
  38. import org.apache.poi.hssf.HSSFTestDataSamples;
  39. import org.apache.poi.hssf.record.ContinueRecord;
  40. import org.apache.poi.hssf.record.DrawingRecord;
  41. import org.apache.poi.hssf.record.EOFRecord;
  42. import org.apache.poi.hssf.record.EscherAggregate;
  43. import org.apache.poi.hssf.record.NoteRecord;
  44. import org.apache.poi.hssf.record.ObjRecord;
  45. import org.apache.poi.hssf.record.Record;
  46. import org.apache.poi.hssf.record.RecordBase;
  47. import org.apache.poi.hssf.record.RecordFactory;
  48. import org.apache.poi.hssf.record.TextObjectRecord;
  49. import org.apache.poi.hssf.record.WindowTwoRecord;
  50. import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
  51. import org.apache.poi.hssf.usermodel.HSSFPatriarch;
  52. import org.apache.poi.hssf.usermodel.HSSFSheet;
  53. import org.apache.poi.hssf.usermodel.HSSFTestHelper;
  54. import org.apache.poi.hssf.usermodel.HSSFWorkbook;
  55. import org.junit.jupiter.api.Test;
  56. import org.junit.jupiter.params.ParameterizedTest;
  57. import org.junit.jupiter.params.provider.Arguments;
  58. import org.junit.jupiter.params.provider.MethodSource;
  59. class TestDrawingAggregate {
  60. /**
  61. * information about drawing aggregate in a worksheet
  62. */
  63. private static class DrawingAggregateInfo {
  64. /**
  65. * start and end indices of the aggregate in the worksheet stream
  66. */
  67. private int startRecordIndex, endRecordIndex;
  68. /**
  69. * the records being aggregated
  70. */
  71. private List<RecordBase> aggRecords;
  72. /**
  73. * @return aggregate info or null if the sheet does not contain drawing objects
  74. */
  75. static DrawingAggregateInfo get(HSSFSheet sheet){
  76. DrawingAggregateInfo info = null;
  77. InternalSheet isheet = HSSFTestHelper.getSheetForTest(sheet);
  78. List<RecordBase> records = isheet.getRecords();
  79. for(int i = 0; i < records.size(); i++){
  80. RecordBase rb = records.get(i);
  81. if((rb instanceof DrawingRecord) && info == null) {
  82. info = new DrawingAggregateInfo();
  83. info.startRecordIndex = i;
  84. info.endRecordIndex = i;
  85. } else if (info != null && (
  86. rb instanceof DrawingRecord
  87. || rb instanceof ObjRecord
  88. || rb instanceof TextObjectRecord
  89. || rb instanceof ContinueRecord
  90. || rb instanceof NoteRecord
  91. )){
  92. info.endRecordIndex = i;
  93. } else {
  94. if(rb instanceof EscherAggregate)
  95. throw new IllegalStateException("Drawing data already aggregated. " +
  96. "You should cal this method before the first invocation of HSSFSheet#getDrawingPatriarch()");
  97. if (info != null) break;
  98. }
  99. }
  100. if(info != null){
  101. info.aggRecords = new ArrayList<>(
  102. records.subList(info.startRecordIndex, info.endRecordIndex + 1));
  103. }
  104. return info;
  105. }
  106. /**
  107. * @return the raw data being aggregated
  108. */
  109. byte[] getRawBytes(){
  110. UnsynchronizedByteArrayOutputStream out = UnsynchronizedByteArrayOutputStream.builder().get();
  111. for (RecordBase rb : aggRecords) {
  112. Record r = (org.apache.poi.hssf.record.Record) rb;
  113. try {
  114. out.write(r.serialize());
  115. } catch (IOException e) {
  116. throw new RuntimeException(e);
  117. }
  118. }
  119. return out.toByteArray();
  120. }
  121. }
  122. public static Stream<Arguments> samples() {
  123. String property = System.getProperty(POIDataSamples.TEST_PROPERTY, "test-data");
  124. File testData = new File(property, "spreadsheet");
  125. if (!testData.exists()) {
  126. testData = new File("../" + property, "spreadsheet");
  127. }
  128. File[] files = testData.listFiles((dir, name) -> name.endsWith(".xls"));
  129. assertNotNull(files, "Need to find files in test-data path, had path: " + testData);
  130. return Stream.of(files).
  131. filter(file -> !file.getName().equals("clusterfuzz-testcase-minimized-POIHSSFFuzzer-5285517825277952.xls")).
  132. map(Arguments::of);
  133. }
  134. /**
  135. * test that we correctly read and write drawing aggregates in all .xls files in POI test samples.
  136. * iterate over all sheets, aggregate drawing records (if there are any)
  137. * and remember information about the aggregated data.
  138. * Then serialize the workbook, read back and assert that the aggregated data is preserved.
  139. *
  140. * The assertion is strict meaning that the drawing data before and after save must be equal.
  141. */
  142. @ParameterizedTest
  143. @MethodSource("samples")
  144. void testAllTestSamples(File file) throws IOException {
  145. boolean ignoreParse = true;
  146. try (HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook(file.getName())) {
  147. ignoreParse = false;
  148. // map aggregate info by sheet index
  149. Map<Integer, DrawingAggregateInfo> aggs = new HashMap<>();
  150. for (int i = 0; i < wb.getNumberOfSheets(); i++){
  151. HSSFSheet sheet = wb.getSheetAt(i);
  152. DrawingAggregateInfo info = DrawingAggregateInfo.get(sheet);
  153. if(info != null) {
  154. aggs.put(i, info);
  155. if (file.getName().equals("clusterfuzz-testcase-minimized-POIHSSFFuzzer-5436547081830400.xls")) {
  156. assertThrows(IllegalArgumentException.class,
  157. sheet::getDrawingPatriarch);
  158. return;
  159. }
  160. HSSFPatriarch p = sheet.getDrawingPatriarch();
  161. // compare aggregate.serialize() with raw bytes from the record stream
  162. EscherAggregate agg = HSSFTestHelper.getEscherAggregate(p);
  163. byte[] dgBytes1 = info.getRawBytes();
  164. byte[] dgBytes2 = agg.serialize();
  165. assertEquals(dgBytes1.length, dgBytes2.length, "different size of raw data ande aggregate.serialize()");
  166. assertArrayEquals(dgBytes1, dgBytes2,
  167. "raw drawing data (" + dgBytes1.length + " bytes) and aggregate.serialize() are different.");
  168. }
  169. }
  170. if(aggs.size() != 0){
  171. try (HSSFWorkbook wb2 = HSSFTestDataSamples.writeOutAndReadBack(wb)) {
  172. for (int i = 0; i < wb2.getNumberOfSheets(); i++) {
  173. DrawingAggregateInfo info1 = aggs.get(i);
  174. if (info1 != null) {
  175. HSSFSheet sheet2 = wb2.getSheetAt(i);
  176. DrawingAggregateInfo info2 = DrawingAggregateInfo.get(sheet2);
  177. byte[] dgBytes1 = info1.getRawBytes();
  178. byte[] dgBytes2 = info2.getRawBytes();
  179. assertEquals(dgBytes1.length, dgBytes2.length, "different size of drawing data before and after save");
  180. assertArrayEquals(dgBytes1, dgBytes2, "drawing data (" + dgBytes1.length + " bytes) before and after save is different.");
  181. }
  182. }
  183. }
  184. }
  185. } catch (Throwable e) {
  186. // don't bother about files we cannot read - they are different bugs
  187. if (!ignoreParse) {
  188. throw e;
  189. }
  190. }
  191. }
  192. /**
  193. * when reading incomplete data ensure that the serialized bytes match the source
  194. */
  195. @Test
  196. void testIncompleteData() throws IOException {
  197. //EscherDgContainer and EscherSpgrContainer length exceeds the actual length of the data
  198. String data =
  199. "H4sIAAAAAAAAAGWOOw7CQAxE32YTsSRIWSgQJSUloqSm5g4ICURBg+iBK3APGi6wBWeh9xGYbEps2WON"+
  200. "P+OWwpYeIsECMFC8S2jxNvMdlrYQ5xha5N8K6ryHdir6+avwOer5l3hq2NPYWuWN0n1dIsgfbgshuSj1"+
  201. "+2eqbvLdxQ0ndhy5KJ/lc1ZZK9okY5X/gSbrHZTH1vE/ozagTcwAAAA=";
  202. byte[] dgBytes = decompress(data);
  203. List<EscherRecord> records = new ArrayList<>();
  204. EscherRecordFactory recordFactory = new DefaultEscherRecordFactory();
  205. int pos = 0;
  206. while (pos < dgBytes.length) {
  207. EscherRecord r = recordFactory.createRecord(dgBytes, pos);
  208. int bytesRead = r.fillFields(dgBytes, pos, recordFactory);
  209. records.add(r);
  210. pos += bytesRead;
  211. }
  212. assertEquals(dgBytes.length, pos, "data was not fully read");
  213. // serialize to byte array
  214. UnsynchronizedByteArrayOutputStream out = UnsynchronizedByteArrayOutputStream.builder().get();
  215. for(EscherRecord r : records) {
  216. out.write(r.serialize());
  217. }
  218. assertArrayEquals(dgBytes, out.toByteArray());
  219. }
  220. /**
  221. * TODO: figure out why it fails with "RecordFormatException: 0 bytes written but getRecordSize() reports 80"
  222. */
  223. @Test
  224. void testFailing() throws IOException {
  225. try (HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("15573.xls")) {
  226. HSSFSheet sh = wb.getSheetAt(0);
  227. HSSFPatriarch dp = sh.getDrawingPatriarch();
  228. assertNotNull(dp);
  229. try (HSSFWorkbook wb2 = HSSFTestDataSamples.writeOutAndReadBack(wb)) {
  230. HSSFSheet sh2 = wb2.getSheetAt(0);
  231. HSSFPatriarch dp2 = sh2.getDrawingPatriarch();
  232. assertNotNull(dp2);
  233. }
  234. }
  235. }
  236. private static byte[] toByteArray(List<RecordBase> records) {
  237. UnsynchronizedByteArrayOutputStream out = UnsynchronizedByteArrayOutputStream.builder().get();
  238. for (RecordBase rb : records) {
  239. Record r = (org.apache.poi.hssf.record.Record) rb;
  240. try {
  241. out.write(r.serialize());
  242. } catch (IOException e) {
  243. throw new RuntimeException(e);
  244. }
  245. }
  246. return out.toByteArray();
  247. }
  248. @Test
  249. void testSolverContainerMustBeSavedDuringSerialization() throws IOException{
  250. try (HSSFWorkbook wb1 = HSSFTestDataSamples.openSampleWorkbook("SolverContainerAfterSPGR.xls")) {
  251. HSSFSheet sh = wb1.getSheetAt(0);
  252. InternalSheet ish = HSSFTestHelper.getSheetForTest(sh);
  253. List<RecordBase> records = ish.getRecords();
  254. // records to be aggregated
  255. List<RecordBase> dgRecords = records.subList(19, 22);
  256. byte[] dgBytes = toByteArray(dgRecords);
  257. sh.getDrawingPatriarch();
  258. EscherAggregate agg = (EscherAggregate) ish.findFirstRecordBySid(EscherAggregate.sid);
  259. assertNotNull(agg);
  260. assertEquals(3, agg.getEscherRecords().get(0).getChildRecords().size());
  261. assertEquals(EscherContainerRecord.SOLVER_CONTAINER, agg.getEscherRecords().get(0).getChild(2).getRecordId());
  262. try (HSSFWorkbook wb2 = HSSFTestDataSamples.writeOutAndReadBack(wb1)) {
  263. sh = wb2.getSheetAt(0);
  264. sh.getDrawingPatriarch();
  265. ish = HSSFTestHelper.getSheetForTest(sh);
  266. agg = (EscherAggregate) ish.findFirstRecordBySid(EscherAggregate.sid);
  267. assertNotNull(agg);
  268. assertEquals(3, agg.getEscherRecords().get(0).getChildRecords().size());
  269. assertEquals(EscherContainerRecord.SOLVER_CONTAINER, agg.getEscherRecords().get(0).getChild(2).getRecordId());
  270. // collect drawing records into a byte buffer.
  271. agg = (EscherAggregate) ish.findFirstRecordBySid(EscherAggregate.sid);
  272. assertNotNull(agg);
  273. byte[] dgBytesAfterSave = agg.serialize();
  274. assertEquals(dgBytes.length, dgBytesAfterSave.length, "different size of drawing data before and after save");
  275. assertArrayEquals(dgBytes, dgBytesAfterSave, "drawing data before and after save is different");
  276. }
  277. }
  278. }
  279. @Test
  280. void testFileWithTextbox() throws IOException{
  281. try (HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("text.xls")) {
  282. HSSFSheet sh = wb.getSheetAt(0);
  283. InternalSheet ish = HSSFTestHelper.getSheetForTest(sh);
  284. List<RecordBase> records = ish.getRecords();
  285. // records to be aggregated
  286. List<RecordBase> dgRecords = records.subList(19, 23);
  287. byte[] dgBytes = toByteArray(dgRecords);
  288. sh.getDrawingPatriarch();
  289. // collect drawing records into a byte buffer.
  290. EscherAggregate agg = (EscherAggregate) ish.findFirstRecordBySid(EscherAggregate.sid);
  291. assertNotNull(agg);
  292. byte[] dgBytesAfterSave = agg.serialize();
  293. assertEquals(dgBytes.length, dgBytesAfterSave.length, "different size of drawing data before and after save");
  294. assertArrayEquals(dgBytes, dgBytesAfterSave, "drawing data before and after save is different");
  295. }
  296. }
  297. @Test
  298. void testFileWithCharts() throws IOException {
  299. try (HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("49581.xls")) {
  300. HSSFSheet sh = wb.getSheetAt(0);
  301. InternalSheet ish = HSSFTestHelper.getSheetForTest(sh);
  302. List<RecordBase> records = ish.getRecords();
  303. // records to be aggregated
  304. List<RecordBase> dgRecords = records.subList(19, 21);
  305. byte[] dgBytes = toByteArray(dgRecords);
  306. sh.getDrawingPatriarch();
  307. // collect drawing records into a byte buffer.
  308. EscherAggregate agg = (EscherAggregate) ish.findFirstRecordBySid(EscherAggregate.sid);
  309. assertNotNull(agg);
  310. byte[] dgBytesAfterSave = agg.serialize();
  311. assertEquals(dgBytes.length, dgBytesAfterSave.length, "different size of drawing data before and after save");
  312. for (int i = 0; i < dgBytes.length; i++) {
  313. if (dgBytes[i] != dgBytesAfterSave[i]) {
  314. System.out.println("pos = " + i);
  315. }
  316. }
  317. assertArrayEquals(dgBytes, dgBytesAfterSave, "drawing data before and after save is different");
  318. }
  319. }
  320. /**
  321. * test reading drawing aggregate from a test file from Bugzilla 45129
  322. */
  323. @Test
  324. void test45129() throws IOException {
  325. try (HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("45129.xls")) {
  326. HSSFSheet sh = wb.getSheetAt(0);
  327. InternalWorkbook iworkbook = HSSFTestHelper.getWorkbookForTest(wb);
  328. InternalSheet isheet = HSSFTestHelper.getSheetForTest(sh);
  329. List<RecordBase> records = isheet.getRecords();
  330. // the sheet's drawing is not aggregated
  331. assertEquals(394, records.size(), "wrong size of sheet records stream");
  332. // the last record before the drawing block
  333. assertTrue(records.get(18) instanceof RowRecordsAggregate,
  334. "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass().getSimpleName());
  335. // records to be aggregated
  336. List<RecordBase> dgRecords = records.subList(19, 389);
  337. // collect drawing records into a byte buffer.
  338. byte[] dgBytes = toByteArray(dgRecords);
  339. for (RecordBase rb : dgRecords) {
  340. Record r = (org.apache.poi.hssf.record.Record) rb;
  341. short sid = r.getSid();
  342. // we expect that drawing block consists of either
  343. // DrawingRecord or ContinueRecord or ObjRecord or TextObjectRecord
  344. assertTrue(
  345. sid == DrawingRecord.sid ||
  346. sid == ContinueRecord.sid ||
  347. sid == ObjRecord.sid ||
  348. sid == TextObjectRecord.sid);
  349. }
  350. // the first record after the drawing block
  351. assertTrue(records.get(389) instanceof WindowTwoRecord, "records.get(389) is expected to be Window2");
  352. // aggregate drawing records.
  353. // The subrange [19, 388] is expected to be replaced with a EscherAggregate object
  354. DrawingManager2 drawingManager = iworkbook.findDrawingGroup();
  355. int loc = isheet.aggregateDrawingRecords(drawingManager, false);
  356. EscherAggregate agg = (EscherAggregate) records.get(loc);
  357. assertEquals(25, records.size(), "wrong size of the aggregated sheet records stream");
  358. assertTrue(records.get(18) instanceof RowRecordsAggregate,
  359. "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass().getSimpleName());
  360. assertTrue(records.get(19) instanceof EscherAggregate,
  361. "records.get(19) is expected to be EscherAggregate but was " + records.get(19).getClass().getSimpleName());
  362. assertTrue(records.get(20) instanceof WindowTwoRecord,
  363. "records.get(20) is expected to be Window2 but was " + records.get(20).getClass().getSimpleName());
  364. byte[] dgBytesAfterSave = agg.serialize();
  365. assertEquals(dgBytes.length, dgBytesAfterSave.length, "different size of drawing data before and after save");
  366. assertArrayEquals(dgBytes, dgBytesAfterSave, "drawing data before and after save is different");
  367. }
  368. }
  369. /**
  370. * Try to check file with such record sequence
  371. * ...
  372. * DrawingRecord
  373. * ContinueRecord
  374. * ObjRecord | TextObjRecord
  375. * ...
  376. */
  377. @Test
  378. void testSerializeDrawingBigger8k() throws IOException {
  379. try (HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("DrawingContinue.xls")) {
  380. InternalWorkbook iworkbook = HSSFTestHelper.getWorkbookForTest(wb);
  381. HSSFSheet sh = wb.getSheetAt(0);
  382. InternalSheet isheet = HSSFTestHelper.getSheetForTest(sh);
  383. List<RecordBase> records = isheet.getRecords();
  384. // the sheet's drawing is not aggregated
  385. assertEquals(32, records.size(), "wrong size of sheet records stream");
  386. // the last record before the drawing block
  387. assertTrue(records.get(18) instanceof RowRecordsAggregate,
  388. "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass().getSimpleName());
  389. // records to be aggregated
  390. List<RecordBase> dgRecords = records.subList(19, 26);
  391. for (RecordBase rb : dgRecords) {
  392. Record r = (org.apache.poi.hssf.record.Record) rb;
  393. short sid = r.getSid();
  394. // we expect that drawing block consists of either
  395. // DrawingRecord or ContinueRecord or ObjRecord or TextObjectRecord
  396. assertTrue(
  397. sid == DrawingRecord.sid ||
  398. sid == ContinueRecord.sid ||
  399. sid == ObjRecord.sid ||
  400. sid == NoteRecord.sid ||
  401. sid == TextObjectRecord.sid);
  402. }
  403. // collect drawing records into a byte buffer.
  404. byte[] dgBytes = toByteArray(dgRecords);
  405. // the first record after the drawing block
  406. assertTrue(records.get(26) instanceof WindowTwoRecord, "records.get(26) is expected to be Window2");
  407. // aggregate drawing records.
  408. // The subrange [19, 38] is expected to be replaced with a EscherAggregate object
  409. DrawingManager2 drawingManager = iworkbook.findDrawingGroup();
  410. int loc = isheet.aggregateDrawingRecords(drawingManager, false);
  411. EscherAggregate agg = (EscherAggregate) records.get(loc);
  412. assertEquals(26, records.size(), "wrong size of the aggregated sheet records stream");
  413. assertTrue(records.get(18) instanceof RowRecordsAggregate,
  414. "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass().getSimpleName());
  415. assertTrue(records.get(19) instanceof EscherAggregate,
  416. "records.get(19) is expected to be EscherAggregate but was " + records.get(19).getClass().getSimpleName());
  417. assertTrue(records.get(20) instanceof WindowTwoRecord,
  418. "records.get(20) is expected to be Window2 but was " + records.get(20).getClass().getSimpleName());
  419. byte[] dgBytesAfterSave = agg.serialize();
  420. assertEquals(dgBytes.length, dgBytesAfterSave.length, "different size of drawing data before and after save");
  421. assertArrayEquals(dgBytes, dgBytesAfterSave, "drawing data before and after save is different");
  422. }
  423. }
  424. @Test
  425. void testSerializeDrawingBigger8k_noAggregation() throws IOException {
  426. try (HSSFWorkbook wb1 = HSSFTestDataSamples.openSampleWorkbook("DrawingContinue.xls")) {
  427. InternalSheet isheet = HSSFTestHelper.getSheetForTest(wb1.getSheetAt(0));
  428. List<RecordBase> records = isheet.getRecords();
  429. try (HSSFWorkbook wb2 = HSSFTestDataSamples.writeOutAndReadBack(wb1)) {
  430. InternalSheet isheet2 = HSSFTestHelper.getSheetForTest(wb2.getSheetAt(0));
  431. List<RecordBase> records2 = isheet2.getRecords();
  432. assertEquals(records.size(), records2.size());
  433. for (int i = 0; i < records.size(); i++) {
  434. RecordBase r1 = records.get(i);
  435. RecordBase r2 = records2.get(i);
  436. assertSame(r1.getClass(), r2.getClass());
  437. assertEquals(r1.getRecordSize(), r2.getRecordSize());
  438. if (r1 instanceof Record) {
  439. assertEquals(((org.apache.poi.hssf.record.Record) r1).getSid(), ((org.apache.poi.hssf.record.Record) r2).getSid());
  440. assertArrayEquals(((org.apache.poi.hssf.record.Record) r1).serialize(), ((org.apache.poi.hssf.record.Record) r2).serialize());
  441. }
  442. }
  443. }
  444. }
  445. }
  446. @Test
  447. void testSerializeDrawingWithComments() throws IOException {
  448. try (HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("DrawingAndComments.xls")) {
  449. HSSFSheet sh = wb.getSheetAt(0);
  450. InternalWorkbook iworkbook = HSSFTestHelper.getWorkbookForTest(wb);
  451. InternalSheet isheet = HSSFTestHelper.getSheetForTest(sh);
  452. List<RecordBase> records = isheet.getRecords();
  453. // the sheet's drawing is not aggregated
  454. assertEquals(46, records.size(), "wrong size of sheet records stream");
  455. // the last record before the drawing block
  456. assertTrue(records.get(18) instanceof RowRecordsAggregate,
  457. "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass().getSimpleName());
  458. // records to be aggregated
  459. List<RecordBase> dgRecords = records.subList(19, 39);
  460. for (RecordBase rb : dgRecords) {
  461. Record r = (org.apache.poi.hssf.record.Record) rb;
  462. short sid = r.getSid();
  463. // we expect that drawing block consists of either
  464. // DrawingRecord or ContinueRecord or ObjRecord or TextObjectRecord
  465. assertTrue(
  466. sid == DrawingRecord.sid ||
  467. sid == ContinueRecord.sid ||
  468. sid == ObjRecord.sid ||
  469. sid == NoteRecord.sid ||
  470. sid == TextObjectRecord.sid);
  471. }
  472. // collect drawing records into a byte buffer.
  473. byte[] dgBytes = toByteArray(dgRecords);
  474. // the first record after the drawing block
  475. assertTrue(records.get(39) instanceof WindowTwoRecord, "records.get(39) is expected to be Window2");
  476. // aggregate drawing records.
  477. // The subrange [19, 38] is expected to be replaced with a EscherAggregate object
  478. DrawingManager2 drawingManager = iworkbook.findDrawingGroup();
  479. int loc = isheet.aggregateDrawingRecords(drawingManager, false);
  480. EscherAggregate agg = (EscherAggregate) records.get(loc);
  481. assertEquals(27, records.size(), "wrong size of the aggregated sheet records stream");
  482. assertTrue(records.get(18) instanceof RowRecordsAggregate,
  483. "records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass().getSimpleName());
  484. assertTrue(records.get(19) instanceof EscherAggregate,
  485. "records.get(19) is expected to be EscherAggregate but was " + records.get(19).getClass().getSimpleName());
  486. assertTrue(records.get(20) instanceof WindowTwoRecord,
  487. "records.get(20) is expected to be Window2 but was " + records.get(20).getClass().getSimpleName());
  488. byte[] dgBytesAfterSave = agg.serialize();
  489. assertEquals(dgBytes.length, dgBytesAfterSave.length, "different size of drawing data before and after save");
  490. assertArrayEquals(dgBytes, dgBytesAfterSave, "drawing data before and after save is different");
  491. }
  492. }
  493. @Test
  494. void testFileWithPictures() throws IOException {
  495. try (HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("ContinueRecordProblem.xls")) {
  496. HSSFSheet sh = wb.getSheetAt(0);
  497. InternalWorkbook iworkbook = HSSFTestHelper.getWorkbookForTest(wb);
  498. InternalSheet isheet = HSSFTestHelper.getSheetForTest(sh);
  499. List<RecordBase> records = isheet.getRecords();
  500. // the sheet's drawing is not aggregated
  501. assertEquals(315, records.size(), "wrong size of sheet records stream");
  502. // the last record before the drawing block
  503. assertTrue(records.get(21) instanceof RowRecordsAggregate,
  504. "records.get(21) is expected to be RowRecordsAggregate but was " + records.get(21).getClass().getSimpleName());
  505. // records to be aggregated
  506. List<RecordBase> dgRecords = records.subList(22, 300);
  507. for (RecordBase rb : dgRecords) {
  508. Record r = (org.apache.poi.hssf.record.Record) rb;
  509. short sid = r.getSid();
  510. // we expect that drawing block consists of either
  511. // DrawingRecord or ContinueRecord or ObjRecord or TextObjectRecord
  512. assertTrue(
  513. sid == DrawingRecord.sid ||
  514. sid == ContinueRecord.sid ||
  515. sid == ObjRecord.sid ||
  516. sid == TextObjectRecord.sid);
  517. }
  518. // collect drawing records into a byte buffer.
  519. byte[] dgBytes = toByteArray(dgRecords);
  520. // the first record after the drawing block
  521. assertTrue(records.get(300) instanceof WindowTwoRecord, "records.get(300) is expected to be Window2");
  522. // aggregate drawing records.
  523. // The subrange [19, 299] is expected to be replaced with a EscherAggregate object
  524. DrawingManager2 drawingManager = iworkbook.findDrawingGroup();
  525. int loc = isheet.aggregateDrawingRecords(drawingManager, false);
  526. EscherAggregate agg = (EscherAggregate) records.get(loc);
  527. assertEquals(38, records.size(), "wrong size of the aggregated sheet records stream");
  528. assertTrue(records.get(21) instanceof RowRecordsAggregate,
  529. "records.get(21) is expected to be RowRecordsAggregate but was " + records.get(21).getClass().getSimpleName());
  530. assertTrue(records.get(22) instanceof EscherAggregate,
  531. "records.get(22) is expected to be EscherAggregate but was " + records.get(22).getClass().getSimpleName());
  532. assertTrue(records.get(23) instanceof WindowTwoRecord,
  533. "records.get(23) is expected to be Window2 but was " + records.get(23).getClass().getSimpleName());
  534. byte[] dgBytesAfterSave = agg.serialize();
  535. assertEquals(dgBytes.length, dgBytesAfterSave.length, "different size of drawing data before and after save");
  536. assertArrayEquals(dgBytes, dgBytesAfterSave, "drawing data before and after save is different");
  537. }
  538. }
  539. @Test
  540. void testUnhandledContinue() throws IOException {
  541. String data =
  542. "H4sIAAAAAAAAAO3adVRU2/4A8EPHAEOnlEooNaSUdCNIg4CUDCEtQ6gwlITSjYiSkoKA0ikg0i1IyCjS"+
  543. "QwpSEr8B73v3PS6+9+67vz/eH+615pyz9tn71PqevT/rfGcJOIcLBtDXrNgAgBjAXcMFAAAb9SPDBAAw"+
  544. "gLGmzna8xlxjR9WhAXhrxMAfCzqAf9IPQPXBAn6078IBgAyCH/VgVD2ADwCxAGhNBbXpc9LUF2h8n4we"+
  545. "iOoNAKEnywaAFmAEGtDQABLgCA0AcAHfZvLjeozjc+gAUMATgAEygBNqzQTwHl8lcH5dGHWmvGY+1FJD"+
  546. "FQOTHHX1x+dkBta2H9UcoLam0I7bAYCRrJMjDOoIM9W56wx1vcnt6WAfF92t0gIhfrfqv0o8e9khH4fE"+
  547. "thqnQJHiJqOZUrbDByG8xwYeiEmYJPcUPoP17NH6hTz9cVtyfvnyyUuV3BzE06+vDH/Dlxi+/pYeV32e"+
  548. "IGIy2p+e90VyZ+i9OlDL+Rp6Dmot/G2tUgYbGW5vpkSep5Fk2eKtJthDdEvKkzrvC4cmWe7kKaliC7ip"+
  549. "0sMjlMUdN/akSG0ticE4nweeA7LUha1xyjNLXZEJUx80rOZMmgMIveJ5pQ7Hio17qM558+zaZgheNOHN"+
  550. "tk7hCxKIZgFTs9t1NGhTdj0EIdz0tEcV4KZebLmun1t9qpQ2fF6N29/P3I3j3pYc8kI9zaMjjFNPi/ej"+
  551. "qfkAaisS9bRAqLXpHai9Kw/38TIr6s3tZghB0GpAXUB/ncuYLE2mulOgiSpODb6R8rVbnQasDoj6bIiB"+
  552. "gpPYItWexPrqVgUk73GpZwT2sBroUQZ07ovZJ6SXgbdvjH//55ZoggllM0Rdw7K6gHmeIt/exXytDGpq"+
  553. "VeVUw1D6S2kCKezDar0iZnm3GGAy99/4bWY7VIgeWUlVmOVn8kdFOmIsel1/vx9MX9vNOZHYeqdvYnuy"+
  554. "PuP2uxHPjCotCFiHoJKzFzI4MTQn1bBVdLQQT0LmrX8os3+t4Nu7F1SC7mDgrFsvKsHS80DFHx3O8SsA"+
  555. "AJZ3XHlcbcydoagIOY6SWl1Vp3EIQT34gw8x7PqBwdNgkpp5LViiOWHMLE5uaQp1LIusFllOAzxrOusm"+
  556. "WExAlgdfVmW/LRLc67SnF1MHKe/PT2vXvfZQw1g/fIwStuEpmaxlQa9NEWv40J8h8PmVmRGejXo+EW2v"+
  557. "HEI0qo7ZNPb5niruyPOdHhnQLRUPGb+y4Wwo0WGygw6NOzBXGDYgzKBYzu+v6872oAZEaXgP4VtOrDV5"+
  558. "LyQtP9wxoKWMM/buA960eUbfNY0RKG1vKafEuMZMtwJjh5N0+JRy8JYlbS/r6OhsqifipW+Gx4NtrO4B"+
  559. "znA/UjinjWh9TytvuD/PeHSCSyZI5WEAslSzQZpIoczUQ5XM8tCuQSArrxGN5VGZ1OKFiaOi+zEpKW/o"+
  560. "vaSMwbfZQYveck70N1ZjZrwdxtKxlzAobG5kMl1LQFazAkJqVsrYDgCNeunmvRhm4c6jbinypsbQpyUr"+
  561. "wX1UwXJ9mtLhn3qC321JFsoymDATqy98V+hQ3ZBcpxN+W1+6wo6FrlRGKhW2ug7eAH3Dvn0rNWTG6vvr"+
  562. "qKDGWqAXYu0s8ZmmdMM3xFjWIjXsqtT56ly7tMPY9d40CZ/CQ0b4OLsD9qG5CB5n47N2/2qJMKo1+rUg"+
  563. "TTpa4D7au2JRC6XrayDXu7ZXGpvcwM5DWoz4HdBBTfQnmzN1K2YG+hpYNVGkX6ZlZGv7OM1XZeaZU1e2"+
  564. "Rt+QEzSTyLSYPXezW5pSbf62gbi5iHWB7xBAZ2leDdXI7Kat5+Epnor5sC3ZefMh0hUTSQ8VP+BIz2fh"+
  565. "t3eD2z9TLOhGRLoIErwXi+9yUgMZHhVGhWusRIi4J297mNL4iBUbHaKdFaRyobYMnKg9BWjH4+uPILV0"+
  566. "8nC8A3U/jlFjjX71Jgi595V1xmS7qScwAiEcrTYLmRbMfuaHL6EOo1NjPeWNa8hlBYLWd64rInOTrmyv"+
  567. "FPTmG8O5ys73rWL5VnYIcryPaJz1hicCpRGXFTgKhf3IKiBPTEzV5pMWMjt2zJfd24LZxbIx8ecWeVuF"+
  568. "eCqzynPsivav2VzI2+hbgvBvzjdDA5uZQkqynn+lwzfceOc/l4qsu1hsOTVzy6AnNW9HhaqZ8yHRS87z"+
  569. "01vZyoyAyGRlaOVkgW6lsSNCaOFlWqgRBJ2ZaR02lhwDHRJ1xN2B1xc64WubpudpxVONMUW7GMG/w61N"+
  570. "qLmi+xXRMaSqigzr33Iwc3owsLyZl1hUaNChDstgByZaRb2FUik+0vh0uZw72thqliZVKKQydVxsnHk3"+
  571. "yPj3tx8NnQv4+UTxz+WMaeP0AU6Pnb8XbrR/GklPdzw98vxeLqH/cRw63ft0SPxeejD/ECAaqljYP6Zo"+
  572. "TOAbas2G/aMp8RrpyQyOBpihYQAbqK0+1BxuiKojWTvefxM1J1MApKiTggESs9MPZ+nkUghPWpajkQKk"+
  573. "6H/bg/3bDYkDqHuDQT1hXLziJ1WUv+3+2wE6cY650PkPXCD+CRcAqPZf4ALfb1y4csIF3l9c+MWF/44L"+
  574. "j9ungt3+JRe6HacgxPUvhzyKvXJ2F/yZmvIM81egZfIaDI0XieSQH6KXZeYHV8Oe9jmC77MXmJyzbuVH"+
  575. "7Dxh7HWqUYgJgJQPP+qfFs2Wy5VJLBvjrb4LP6d2qSSiIEa1EDOTzXzBAf7NYTKe9Uv+BzvZxsBSGlzq"+
  576. "j2IjVpqWoXU2lXXDhRppha9tKwNMX4WqNEd+qo3WpH0X21ausDawEugMlpZ1XaXro5TpEAOTyMX3q32g"+
  577. "MJxtF2+idkYSmm3o6N6l7W39svNCNlqfzruLTTpsXDpob1SYnlNqhqsWeUW8X0QLFtb0RgBb4RFZ5sL0"+
  578. "d0/SQfbKUi5bT3OBzDhhYW67b3Rb0nlESHfbpvodNwNarcSwSY0MT4wUiebd+x+jYc7Y1n2+lUQtURRx"+
  579. "30MmxUonWXqrOwS88XfYSPvWDKWTxAd15QH75K4YXh20CYiyU3YjQcbGEoJcjplI/AMtEo7r7XINk573"+
  580. "ttxnL6/9tUHRi1OE6J/j4C+e18b5+n2Sujwc78Z2iVgqPx6w8gr3STZTEnam+x76oWmpHGSLuwkiJvTG"+
  581. "RlKOOIuBQ9oojJdCS+4ryVHpYg358B7SDCFMC46CEUMqT575UKujkzl/itEcCTxEr8cwQdh5o5lxmTEm"+
  582. "sBHYgkxtulQL0LCL7vs/j9lrs2FGJpAmZb1khCo2GylQdMmohMWCCNdlSh5UgdKDv7/24CGqTnOKID6P"+
  583. "zVFodIvClLZo9WhLi4c6eh1EzC5SzyMTLmTnaWpiPnzRRdLGOGLDNc4iUwyxMqmSe6ed0PRpeHenTdnu"+
  584. "OLWibGodMxRubxi1VyEzLFOFs7LTt8poQuMjWvzk6Ews6D2wxOX6F1iIMr2OwsJbhNo+Ubfgulo5Ravk"+
  585. "JUteZgv/qaiWkdJy++ryV4WQnU13JuY9z566hsH7oslDpXJGjvbpFH65FOhTlwdfaNChF1Qs3GSMctPh"+
  586. "Nbz9Fm+pKrB9Z++2XPC1VZ2OCtUKaQm5UWaWKDF9woBGK5HEoXLY2/hUPIeLbibJao0EH3edb2ALE9T4"+
  587. "ZQV+5Zl+PQUW6ZVIRMQ0pjyc21bn9c6Y4njsNgCvvVmcFDX+RLQKZ9pzmbtT97CkcWN3zy0+hSrChV8h"+
  588. "jVBJfGUk2+xSWQQden2qE/JJ0wf93E45aJWQUtYEJQ5idRqUycJ3TzENxD4I/XJlTx63k95POuxW6jSb"+
  589. "NU5wwAcj6djFzYfLB6U7YLpvGT2Swk3LEhF0wpUTMPJESYaj/zktnB54/pwWTsfE76Xr32uB9QwtYKOm"+
  590. "5GMt4ACzZ2iB+C9qge8/1QLJz7TQ/1e0wP9LC7+08P+hBWVCae5j4tP+VAtqruNMxHUe2Ud+n1fmLyTQ"+
  591. "2YXx5fEvPB/0XNrBMcMbTT7fB5TM7O+t+C9liWwSe9yRtqHauspQ07lU7sQyCrpFV0itVmSh8uCy2/tc"+
  592. "rkxkTnA/Icuwi65LXrzZJjtnHVc9/PG3+Paqyx5jxLjp9kTYCh49bnfJR++wGTq+hLGRe9o5GK58GrHP"+
  593. "7FjDwHSCxrWuXyx9SlJbKsY84b3W1/QO+3VV1NceWUxtBxid1fMEeb7QKAz1A+wk8WG36NZBztBeCYG7"+
  594. "Ff3BFrRdwldH+yS7B5aW1um8pvWF+8W0tsKaqgWwpTsuZC5YpqhZ0AYqlV/g4gm3iiPF6YRmwpvFhd/D"+
  595. "33NdS0ps2ALJJj/q52V5VMG0QPbiqOj+HW98bDtnDJerSZ+1+lZo6ggtvZWebZfZBtN9YuxrmAlHTxYf"+
  596. "cVMDllgfs9JcREuB7CZEfBGQhT07MvJnX2sM/PFxwfU8dYjmBZW53fWD60iNEH3cB9p76dFftdDU0XE0"+
  597. "eQtfiKn4AVpcWOxftPeb0ZsDA8pLJEO4ut35E4Okqnz7NKwgjs4EOccfF5rfSNDc95WDaY4wHbB9SZU+"+
  598. "2C3b89lxyHxNsxk8eXENfcuYb3FPwzTNo5HutoMS0IX1onkxJE5oLbCpVoAuDVGtSH07DxyWULrA7qew"+
  599. "93XSHVJ7S0eaI6tFWGSkkSqG5fXNNIaewY9XxXL904XR5S+itGBOaaoyMuLjYUtuabkPoKtE9IZqZH7D"+
  600. "f5ZINS+ovLSROlfUeChS3SrjUT9xwJ2ej3XF6+6k/TPFzm+IJyWCBBUe1XwIIS6DA21muvSJqx77Oqur"+
  601. "DDQNorlG+2d64a68eyEHak/+z7ygeeyFQJQXwMdeEGV970demkTM+/g3L7g4WBuZ7yC5LjyY/yKyDZ/b"+
  602. "gok76IaXN1V32OAfmGAqzTetqTixv5i0voLHNPd49oWQocYHEM5g+8zbpPDK0QVj+0R4gEyI+wWF9M16"+
  603. "GvOlR1rss/eySUS7skoe7TItY7t2ujMbvxeOyBB7YfC8OTBGcKqE/O3cVyPNtkqvXWqdV9asDQO7TNfb"+
  604. "3N/gPR/Rd9gD2kKHUxPpOKhcEgoRegu26aFPXPExpL7aNpRT9D7eaNLCPZAZ7yNnTZcxyqlmD5fnoyra"+
  605. "wzuIqH+twGznTh7ki6/NuB8Ajx/AYzQmjXV05puyUVLC3CFe7CZZDjaipzsyJ7tzBF55V6FcjB7We32x"+
  606. "ZTeUreF/TgunB54/p4XTEfF7+Q++LZylBTyA8EQL+IDrGVog+Yta4D9bC104p1MRpD/TgtBfSUUIAL9S"+
  607. "Eb+08P+gBSMhtMnjl5b+51rQHoecaEE6837xU9bHUW+s2AnqYPixjWDi8hTPy6oMyheJGuqdWNg0iK5G"+
  608. "EVHdMLHdXq4/6HsLRVwujx8WVJgTF1MVia0W0M0cEfHxqqTvFnE1mVdhz4T2bA+sd04hE0PrS0HpneEl"+
  609. "BKyvjaSiNsK3P55XNq6KLnS2zo6lzSkrKVzbKUNmlVrgfClUabUVVTW2fp47oaDiQ3bdk8QeY9nwshsF"+
  610. "U0ZueXZ4zUDu+RqlNpwxbCz7lcVq6py5Qdt74hc0hcut9C0DiJbBMtVR0FinhbSAV2lkYQ3nOyZflfbu"+
  611. "wsTpcz5lTcx5iT+5Zn3pegbXSIle3PB0Cn8kMr+/oSQy+F7N4orDRGJD+XaCIEWYS7Y8SI/R+ahmYXTa"+
  612. "jMBDyW+XwWI6cPpNZkWQMeQSpbfDODPeFMYlG/nMz9kGSdVWwBPruVFyNykS/+67tDLkoT7aUXKSberW"+
  613. "T4+Yu9slePniXDlUGffJxlN7yEheEmPmdDtkDuVhnsONyNKCijToxwBxJioQsvz9ZswLnz8JEfpVDhSl"+
  614. "FsVD56mJw9Wb9+TswrgB0jvhjcdeuAi7MXKcjIhMY4ZnHjHCx21u4RzyPrvIYsah0+PN+B3kpVibPhKE"+
  615. "nmaYJvFia3qArN6mS7sA7cIIwjwvfnSmVkftHY3VQuf90Z5H3HO0g1H8yPdlfg3sCcJ3P98Ly6m5tzXv"+
  616. "ny6SETr94g5cXtcrv4ZddXMiT68thBCEq+NvQp2nGMlRC+FJchk179vxn52zkQlfka3B4coruG/+9muu"+
  617. "fapi57uGeFsBglGxLM4wNRxbTy6dC2UNJCbn9g4+ipE5KrqHSp4ZpOM9XLvH352LfpaKuHn9RypCUmCk"+
  618. "5coC9RBwkoqwhBMoe3HZdVKOuJe7EfjU0ctAJD6muK6ILFcN3i24PISLVMm8tHmfhCndtVm17nkx3Ggi"+
  619. "DBDpFbCO7/dvMhFO6uXmybZv6la3zrixy4XPPKZGHdj0/Z5/SScoPQn52HA+TfkWxQbaGNdswrJMZb7z"+
  620. "OfkKgxKtYCp8vdDvMtOMBTzyzDNfF7wNuBke719LaLaXS6ZSZ6+rvx0rJmXy+rDW+IpQ+CBso1pdHRRc"+
  621. "yZIjBbQHH7QmiN/qAakyb4IcZLWTAvEd4udrIZTt1yq/im1+n3kuiH/jFagSzH5Flw3W8ipOfSeCgSgj"+
  622. "iiKLjELxlsz5xptFVxQ9vGDBuyNXI9okPSQZwiwGqtZ3jXCcJTaWcP7XuHB65PlzXDgdEn+KC2elIkBA"+
  623. "8gkXCI7/dfAHLpD+RS4InMUFcaDthAtt/8AFsp9wwZf/r3BB8DcuCJxwgfsXF35x4b/jQouTZIA7Kv7O"+
  624. "/YtUxI9/LojhVueUB4iqhbfJJ2bUENhFCYDT2u5YXEsgUFZLkThQaleuYHC3CTKxTCbd1WT0EahBGslv"+
  625. "DVS32ii8KogjzQvMo62Dwg72hZO1psRHKPQVVBUiB/prviITb5iO+tuV8Cf4gpbxNSDVG/UcMS0Pn9pX"+
  626. "1fA9HSo2ohu/A25wf6KTwNh4tyDGJVmddORGO0dF7IBkC70hNsJXKFHlI05Ibn6hbebFsMuvbvjzplET"+
  627. "SHnmI++kTM7evTcpq/uhfFbDakQz8qsyjX32rhp8Ep/1zTZd2tJVkquZu8KMOVIPhflEnxnPxcax9scj"+
  628. "lToDBcO0pj5X3t7kifqSPfmyOjC8dKfK1GBAJ0ydvb8WSyv18/6Vwdj9aYKeNLT1q7nMXLlgkoOFNqzE"+
  629. "2nm7cSKRT4xtUp10hOZfm4YE0Ypt3Z/MaGB/DmqcUQt5RHWUzfTQJS21R/ToZnLorfPzIZocgeD19QPw"+
  630. "XHTIFdwHg7Mlmota6OqYilolxSmSlx8CKjwsELJHKCrINvmNCxi34NV87Ipn6YNICQjQvqAz/rKMznR+"+
  631. "xLnkeisDE8nNYUGNo/Yd6z5nn79bwVxU+VrjMw6FYyvsRHjKviTE8i3z9Tag580i9Ern5SnETqo8xEsw"+
  632. "fIyRKSNIzwJRMUUgiRI8wm5TB8UZvJzFngq0eBhAJRO5vbBiKg5703eOV45AT6Sh6XK9gDG76nyVal0a"+
  633. "GR0lk4aLl1kWQ6H+WmNtU1jngMZR7RpLTy8JgWWcC6Gelj7Icfervb2pQuc3RKswbdDSUy3K1mwMB09O"+
  634. "lBZ8Pj1LRWmBn0xd0b0TcWaMvhRwTruEejUL/yMtjCZxXMuKevsgpH2fOmbNcDiBq2jZnuNYC7lyjL3W"+
  635. "qwueYx20DlUl8XqYe3XExPqBVvFjxAb1PUWkUsOab20KKdiK5yizYzde8dLz1mmLILgnsHdJoYpxUgvG"+
  636. "/PjoRnHGWuODhPomZGNKi+ICT3xpqjdmSokyIOcwY/Q6GjQGghDxtZ5GXkroNGSRBZXJVzXWn/V8EX8z"+
  637. "bh2EV1VrM2gkFVGxYum4qEsJHd2DPj6kJnJzVTADlCZWR7ItRI7zEPBUU2RiU8t1G6QOxXMhpekJvVQ4"+
  638. "IppKQdVys+cLtUY6Un0+hI2Z0wMzAxO8Lr0LbaILk8WtNsxpaFYMrTjC22723OH5GFkUi+ux8An2Hi0F"+
  639. "fvcr1v8aFU6POn+OCqfj4ffS/e+pcOEMKhABrCdUAAPhwB+pQHYGFcT/BBUEz6LC/wGpc+eRNSkAAA==";
  640. byte[] dgBytes = decompress(data);
  641. List<org.apache.poi.hssf.record.Record> dgRecords = RecordFactory.createRecords(new ByteArrayInputStream(dgBytes));
  642. assertEquals(20, dgRecords.size());
  643. int[] expectedSids = {
  644. DrawingRecord.sid, ObjRecord.sid,
  645. DrawingRecord.sid, TextObjectRecord.sid,
  646. DrawingRecord.sid, ObjRecord.sid,
  647. DrawingRecord.sid, TextObjectRecord.sid,
  648. DrawingRecord.sid, ObjRecord.sid,
  649. DrawingRecord.sid, TextObjectRecord.sid,
  650. DrawingRecord.sid, ObjRecord.sid,
  651. DrawingRecord.sid, TextObjectRecord.sid,
  652. ContinueRecord.sid, ObjRecord.sid,
  653. ContinueRecord.sid, TextObjectRecord.sid
  654. };
  655. int[] actualSids = dgRecords.stream().mapToInt(Record::getSid).toArray();
  656. assertArrayEquals(expectedSids, actualSids, "unexpected record.sid");
  657. DrawingManager2 drawingManager = new DrawingManager2(new EscherDggRecord());
  658. // create a dummy sheet consisting of our test data
  659. InternalSheet sheet = InternalSheet.createSheet();
  660. List<RecordBase> records = sheet.getRecords();
  661. records.clear();
  662. records.addAll(dgRecords);
  663. records.add(EOFRecord.instance);
  664. sheet.aggregateDrawingRecords(drawingManager, false);
  665. assertEquals(2, records.size(), "drawing was not fully aggregated");
  666. assertTrue(records.get(0) instanceof EscherAggregate, "expected EscherAggregate");
  667. assertTrue(records.get(1) instanceof EOFRecord, "expected EOFRecord");
  668. EscherAggregate agg = (EscherAggregate) records.get(0);
  669. byte[] dgBytesAfterSave = agg.serialize();
  670. assertEquals(dgBytes.length, dgBytesAfterSave.length, "different size of drawing data before and after save");
  671. assertArrayEquals(dgBytes, dgBytesAfterSave, "drawing data before and after save is different");
  672. }
  673. @Test
  674. void testUnhandledContinue2() throws IOException {
  675. String data =
  676. "H4sIAAAAAAAAAO3bdVRUW9sA8AGGrqFHSlpAhSEcQAkJ6UYQyaFBmiEFpCVEOiREGikJSekGlRJQuiQl"+
  677. "FQFB4ptBvxvIvd+97/fete4f7rWYc9aZc4aZw7P3/s3zbFYB/FiEANTNeD4AAATA2sQCAADIH0wgAEAI"+
  678. "QNv04kNugZusiGMoAOxNEODHhgrAObkOgLgGHfDt/GlMAID4+3EUxHEADgDgB8DdVEbsNgDAgPMAHxQl"+
  679. "nzpAAwoI8XsbUfh1QwCvUPiNAIBjFCzEO/BuoUOeiYZ89fPA60AloCBQGCgO5EE8XgPKA4WA/MCrQDoA"+
  680. "F+IsRgDDR0VM5JUAwHVAbosYYl9ZDg1ICsA4+Sz0gM3dkJpDxN4s4gwSxFZb3NbG0cTGUf+mm50JXJfD"+
  681. "1doqJrJbthUC6tjw3QAtsFvnYRJZvMDMlyLTPQ+TzrYehmInaLpMTTqKcMzi0JotHH9kzL01ZkHKc6Ni"+
  682. "kq2K4yJorozv7TaO8FulNhosxSW8sMlIXxqugsRXD+7W4bYy1NBcBKvi7KqW0pqLcXjSxXM+DifJFmzX"+
  683. "wxikWpWZvDlUODjJ7JArLYfB6yRHcy9MRtBma/86sYUxiBBz5k0WQBxc2B4jM7/6OjxudljZdFGvxQ/f"+
  684. "I5br+tFosU4PBbUn555F+hUmPa5ss2Tu+7yRzIRgVsuXDWrkr4Nxp5w01EYk7+l7XHgKn2n3qpbe8no+"+
  685. "ZuWesRfDsSsy6IG4v8fHaKfuFteEvsEbxF444m7hIrb6DiZWcE4O5GNmRNOdFgje/Q2/Or/+OvtR8XMZ"+
  686. "irYBenKYNTjaMvJGrzRZrKfqsyGakrbXPlDsC3/c2KmE5CaUuoZhvFXADUk3WXwPm17x0PT0jvLtn2mN"+
  687. "xBuXgU3VNawp8hrkSnHvM+WppoPBcjJPtB7QsKXyJrO+VegVgOUa0TqKuTf5fM62rrx6bHq9EpaXwRMR"+
  688. "boP2wUNp6CCQprb70nh8u0Pf+O5kffqdjneu6dWqEMKbeFWXeiED44OL1xt2nh0vxxKReN46EjuQz9/u"+
  689. "KKC44kwIOOujl5871I5HBQAOMJDdAQAwdoBzws0N7EwQEYKMkgJ1GZsxCOkExRIN1joJfgWxVDFpGcGo"+
  690. "Qj9YEQ7QSLdKI2WLKLhspp46hiokRtiv0E9vFmE7qKSqOuqo2bojlj1JcezuxZCzqNDWlyirjpMyPT3c"+
  691. "EfRJfo5Zn+XL/tDzDGxJWZIUEhZ+hc04do8U4Xu81g7nSFIK/SWmffPB3sCismdGvWojIRoSNA8SHYrJ"+
  692. "xTQkWvJ17lYzUdnpcXF+PiRRGoqK0ilkHaLo8VVb0bZtDeXeaVXlfxqR7pAvX8ybfFfS7/YofnHVpRBH"+
  693. "0lApA95hPONuVas3kX7dpR2hQkHNJRuE0Jq2/XrGQUM6mQ6/LRQe7XSZ6eMH/Eutk2bCD/ZpYNXv10Zu"+
  694. "PmSPkomEhfJa817co9K8plVfn7dYGr3pIBT/9DUJtWGrDHrAHZG1yTXhiqmxsYmvO3D3sXtjnuZeZfqj"+
  695. "RayNk8XdX7z5qNaLaGO3FWazI9RvwT55f9LInEuNb01nVUbDJ38oCeKRHAM+uZ/BM8WnJY3XlPZ6uCO6"+
  696. "05vVj9B3iZffJ/yhcE6rh5Zc1hO1kkp2Y2pmzTfy2gHGh2IWUkNqjm721ZDu7M9xKoy+H9EDvK3ei/Bz"+
  697. "KkOwBMpWnQ2XQmXKWC41Mb1ifefDUyitSEO9t7nyiWu1eKTEN7Q03XgVNnoVxTTxeHDBYejjCAM5OtMW"+
  698. "bO7omPh9p0WvOSPFgd2celfAQRIAQ32ZwcXDM7rqLUQ3PSmHYYpSpmjmPAZ8Sthn67Z+cwbMMHo6NPaK"+
  699. "pN3m5HhHpikPygTa1vuwBaAln7788kVGO302kID8dL1eAUknroFcleOjaGk34QtRlwBmrePCn9b6Zylt"+
  700. "nlDxY/umra1wTHlGrXVlAcrjUS4aWHEEsWRLVJA36DOSw6tlvFDPCuKXAuvz1Ii+G4aCHIu/BbGxrYuN"+
  701. "g4kzMoblI14ptkBAN3alD/yuSFuBnFJYY66qi4qZqEmMlsLMiBfpDa+VKkQfCUXH5U3s9Yzz8Lx7vken"+
  702. "XUrSDtXi2rxAC0pz0OXNMyyeqJ28cL3gfd50oYZvk57mo5x3t3iELzsWcZdo14RMg0xykkXXdPiyBhfK"+
  703. "I8YVHS+Q7shaM7mwKtzAbXGn5tCmdJ1Ei61VqUpbeOyae+Po+VFs1Zz4PZtt+KfydJcxYW2bKBYCknYb"+
  704. "2/ttJKALGC7Q4wFbdD+AdPW4V1J2Z5VTM6SRH0zgJxpCQbgmNl8OfV/Dq0Wc4Y5BH6FTiUm57X5bayYi"+
  705. "yK9TnFo7R3VJygCERmOfE14cfo3QEWg0Y+wZ2u/a1R68QXP7rhtmyBZfttcvowEK6mXAH08cv29nTCOn"+
  706. "X+D0WPpr40D53ch6+sLTI9GvjQ31x3Hp9NWnQ+DXtg78ISCU5dAxvk3fQMA2YsuH8e1U0Cbx9/kdhIoG"+
  707. "6EY824eGB8BHHCHaRB7XBVACyBCzPCpCBkSw0zdnFbCEeVoCqP+gBLh/SuCnBP57ErjpXBiC7H9HfyiB"+
  708. "7rABCKie8SNB3EbNnkXSZZVoMkd0ilYN3R0U+dkyojCakWwRd7HZkLLwRnE70YNVnkzb1mFFVZhPS4VQ"+
  709. "Zo+84BTf1Ovh6C0EBUK+UWDwOwWYvuxvb0VznabAyBw3i6A2TjAd8BYXmLh28EWYkJKJnBaRE/udl03a"+
  710. "WLeJ8IscZuajCuhd22r7dhlPKHCZDUEBPzUq7aK2GO6dQTF+Nfob8xoJMAv+j3iYz8uoYPa3SZchIT3N"+
  711. "Khs8LCtxho8JHo9cupb0EbPJbvprXa9NScmut9ZnumVhV9vnKs1NX/QbReV2aB1IBZd3vG3Dx2dyKdWZ"+
  712. "ohmawBYv+gvmbA3WvPc+5KV0xbXmD8mncyttAhgV2VnVtyx277mMediuO59P7O3W3bLeLdnr97CoTwe5"+
  713. "H0JJ0Catmhskb0KhwXwBBaPE0ZikVQzMmPVM5Dd8oH2G/a5AAaMyhc0vl1Bn8CmIxR1YeY7ovzQFcX+h"+
  714. "Az9GJ/Kw+iLAsjCgxX7oG+J3m56EtSnKdJSbKT9e9tpTgvShNguDUYXlyxn3ge/hONgjb72KOZQh0gJl"+
  715. "S86mSzEyZQzfJQC/LKP42G2upWgoY8pgqMQf7zlCAubjWqimKRtwuFa5a0XQDRRDWvzx4ycQgmTnICi8"+
  716. "KRxTL1ans4EIphwLhQe+uxJsiT/AfHdLfk5bfBn/oAVGO3rBTmxFzpVUvoAkuaS0HStsMknEWvV5rve6"+
  717. "z559INy3PIkz+3MsvSsrWSc1y2YfKxRrSWwY9RnNAqtqSm8QE7yYx3D9/N668T383V78ZKDo1I5TvsuF"+
  718. "UqFqUs01p0ZZcBJuejBbZGHbBkVwuYD1mydnBnFQfewychqIOFsCNyMUlE76sPRBYKe0DkhO5K3qy1IL"+
  719. "ujR7lJJC6qoAFt2LiZmyzaOH7oIYo1V75YfD94QS8POYtS10jXj97EgBkS940/upMNr2P15FmxV851sp"+
  720. "KYdxbRkGFRJJ2tR5pMc57zzPBww0j4djlO/qKuZetMytokpQvFOg3s6+rjKKTxa3y69TzovjG8M+aT6u"+
  721. "vKUoPFh6oOPJpvMpbxIH/qROZCA/XZ/j7e3o1nNG8RQtBwRB8X4i0OM3Sr6ieJlaq8JWjHHjbhbnUml4"+
  722. "A9thSAnoxJeXfK0qlSSyvIthRJdlcU6i+B2n+nymFAN1B8qs5r7cw4HPLLLe6/a2BHZBg4SPD3IGNsm1"+
  723. "lRA94DmaghKnqL3H3Geqf5sETo9Ef08Cp0Pg/ysBNCAgEfEtvw+ABxg9QwKoZ0rg/YkExn4jAbR/UAI8"+
  724. "3yUg8xsJCP2UwE8J/GcSKAnuIYz+05yAnM0YBPQ9J+BJPRICYzOnKUtK50peABRIjIixqdLd9ipl77P2"+
  725. "oU0LXMpeuoDMCdCzVT/8ert1p5m2126hbi/y/QOn7r4oWXXslNkTCOiQkj3J+bIw9DwazJiFzYlFkpzt"+
  726. "Kk5W30krQlmEmwBK4fSXAPnmA0nZ9MwnmFJyPqEXBl8lw5+HXQ4oCL7f4LBOFlVA59qNgEBgyh0m5gAt"+
  727. "5TzOx+hm0Aq9YGyT1eAAuzzVkFGZatgIbPUcgWQZAZ1OrIkzbUB/jyHpW9Y29pVByVWndmFKVKJFFJYV"+
  728. "A7RjsQHDwD7MESl8+pcNdn5hy8J2IILZyUVah/AcypvROiGkRpnLWs9DGlBGImderZiyXzPkjFcLzmNo"+
  729. "MwPbq4o/GVUacxkLX9vdsflafzg+WT5VcX70/Fr8zkVKmO2iqWEjYr7YIIp9qBDlxLbyrGEOZaJQps2H"+
  730. "U0bidvqV17cEgzAN/PsxjEVCpeptOyOApeLVAnbkUoupEtUCRA996ZOhQBoyeFmkrEjOLEyrEyhbklld"+
  731. "Qdr1KeANQV7gEs77EIP7Csv4SATw4JwbafKyM0g1inAw719r78OONpfRDJFJUXuGZqYV4XvVaa4lJ7+j"+
  732. "p0Wjg5j79cuQkgz7FaxH1kfRSfnqgWZJmnHKrzN8vh5fDEXLEUrv1tl87/OOjOKTLRDsmPVqfGZbfFay"+
  733. "RT5YT4SsrV35Ln5DcUJgD/Z47z5OvSyLBlvP7SEYkGJjrV7xDpQIIlQssn5HscT5a1tMPRRImIWa0IJB"+
  734. "S9mG4fMCBA2UChQIiaFQY+jC+xz66J1UvVDCROMKHJdPtJjqa3a+i76xuxNb32iHt3oxNF6CZIBh7MHX"+
  735. "3qCh6lFjEZSzAlh6X2qcCvHMw7+YD4iKIhZ7nEeXVooSCb00nNDqFjQcZjWQ6dWbmXXHpb4evi648EC0"+
  736. "wvhiqHWZ4bSSIJ3Y/Avzm210Y7Xjkr/kAxQ1NZniKeC0FC9u5Q4/070BkRh5xPP08YqhrLUebteahItY"+
  737. "2q07jNXiFuxa4EmjKiuLaTcedreMYvHuax91HhyYHV4s6Qo8eP1Z7fO2pG2psK51OkuyZKiuPv4rKTpF"+
  738. "vPWbB0oN5Hjr3jH5E5UWITHaF/DQdDDjW9romoIDnXM/aSV91KW8HNwv5AeSfqaNoQY+SQiAx3vt6uvg"+
  739. "B25YfqClzquedJ4SO6ySyWn3IA+LHcvCrLztMRNTwn1mHdvmCP9tCDg9CP09BJyOgF/bh/8bAdynEICG"+
  740. "eAPoAFMkAlDwAdlnIADtL6YDgP8gAngBP9MBPxHwX0PA6+aBzkeInnb4lxAgEzbf6ZuV6tRnE9Jul4hW"+
  741. "TGyCmyXtY3zYlXe9Ev2uP216UvqTZNF6lcBMJr7Dy4buBgM8c7V8tqadXW3ZhuY3stjRlezsPhhJuLF8"+
  742. "iuIk9tj6MCLjH/nGf9EfW5GkNgtHPzP8vAK0OhS7N06MAatJHe8+kLP8pDIQpSHxOCTRYfOkMqBfvekg"+
  743. "8xZUazjZuCuVksfMXK2lilAAZg5CAQ/YThSQLRbyspC76c3zYDP+R1lCgAf56dJ+KhBa/7reRwXaIU5X"+
  744. "HUyfr1q1e5Gj10/VrGJT3Q3PuREeuW60C4Ub8wdJHjfj3/f87N6o4jpJg6LoPk2gOPSUIYEUu1164KEp"+
  745. "sxeaJYVf0bOVBCuBWp1uJvYtYCACA6JpiUo1LjXh3bsLNrv1e+PjV6aczyee745fuEhpWCRygoGNIiQG"+
  746. "ZhXo8ysa51DmC6W7fDiDb6ik4vMOu66K94CtDWgkULAQFgCXiieMQEKbucAqps7+iyhBd5xdw0JGTkoD"+
  747. "9pDLxqgnpYEQ420xC8wh0bJmfi75SrY6k8EImIciPePYHiE5BjsGG+GlFzTnrpoQF2LJQbq4XzpN68hF"+
  748. "qZkReH4pu/v5QsHVuAgDjZhQmofaco2hW0/GkzUup1w2VPF+JIW2e3wBQQGabxS4xXxCgZtZ3eMzTgqz"+
  749. "Wi2OwZOCZHtvkRSAJATuYOv0ISiAw/IWu0fzthGQb2NtA5o7cvP6buNBVY1A02g3hdr+KEgwBseYgMTV"+
  750. "nJQK6EhvhVJEACdl6zWTiBIYPsfVG+7hzt3gs7j4dpzMc+xd4eTjzp0PqrDyopPKQPBJZWB3isgSPpp5"+
  751. "tgRy7xoJUP1ZZaAbKQH/Delav3JpHZDTG2iT/wt1UbE1dIlRu2lT4kWpVmeTJBZPd+gdFfct192xkZGR"+
  752. "9FuXR+RWKDME/DMAQYPVbJS69p0VRbt4QVtiFOlXtBz4pTEf7G0PyTMFLDuy71LpE1Gn6zLwD05uEMvq"+
  753. "6skxj3euZrZrWRQQ02YVmhvcCGxRl+sQBakxUz4kKB/uitdaEEnSD2A5/4GHp3d15eGkie6L0VKWREiP"+
  754. "re3+PAmI093LRrh/xVccmKlDU2+tltnsZiEAo8YLbIKFUe2uqS6Wl7TUlEkSWV4l4IoYL6NmgSztljq+"+
  755. "yTA08ObVOPJq5veglrqOOZrESKWoBNHSb7x0t7FHzvWq6Uei7Hj3VP4n9keY/zYJnB6J/p4ETkfAr23j"+
  756. "76cDEBJAwUB83UZIAJUAAD9DAsAzJCAImD+RwMRvJID+D0rgyncJyP1GAiI/JfBTAv+ZBPoZnjfFIXra"+
  757. "3l+TQNx81R9KwOF3EqhcNiNyN1LjSXYLR0pg7ywJHO7vdSHzAb3YJMksrnJkwkrnRRKtkGsELgdIRPjm"+
  758. "g/Gw9e7odqTklDIXBl0luzI/fdm/IOi+0okEIk5JIBkhgcoTCeT+KgG72XMEphZoyMKABRivRXTwa2jX"+
  759. "iyzNHLMeq7jH3V8OJ61cxsrcL13eP1gWtrXloe/n3zwOOFfGtSsaaJbBAdT5AQG4loGvbt3alq+g1is0"+
  760. "JY5185VCIiASgYDdmrEFd3jl1z4Pm/VEW4QIwhfktshuDK+0yBN8KV08vJJRWi1Ty2Y8RB4vmFpGxiaw"+
  761. "yVzCilMmswlgJ8FjCK3oMzcASyIzAmDFQO5hEF5HPwkk/fVqUA+qcufqJjXZ8/I42YZUZEqASbY4M6GC"+
  762. "tOtD1huCPD/zAHvDR4pqd189pW/6ktwcbPVORBP89FF/a/qYfZoaS39IMTD6UoYOZk85k4CTad8rNoy7"+
  763. "n4k0aOQ6IRdl28PaC5lhkntKNor55L3kJazXTzICJO0+AwT9Kb9jgFB1y0pia/n9ZeI6xF+vMO0zxpEB"+
  764. "N+EaSVXyNvPBL3UBm4mkr78wwP07A14iGZCMrAtcgmIj6wJ61G/1UASfEMkswMxaBYU+TXQdUKakUFVh"+
  765. "+9avrWhsKCIzAsWj8d6xECiFBIkag/aDqSnQHzvgA+7DVErEMyF/5AB9pWYIaduUwgFB95WPbdJ87bAE"+
  766. "R6ACXr05cMHP1mnlqLVcd/Rle+WiIt3mYMrY12u7KT0UdVadimBty7bG827X/V866uVHib7w9Az11uxQ"+
  767. "76EqBPrVFRdL29guCPY45bw1rLRnFiUxMepJdXj2kK38NjNTJeMEToBtADTqWkx2ZvUMTeKr+2FCtrLM"+
  768. "RWSKT10v6rFHHtocMRHsxejn3gurn1oWHy28NfaUwC+o5GvNvT1ga/CkbqLSZ+0eGE6m5pqX/OOi6l+W"+
  769. "CPhS7XarmsRCW+ogWsQZ1zB46BJswEDIUnh6cfNhtKZQfuMT4HvQ0vWrnnMHm8BZN3RFU7VV6ku9duC9"+
  770. "SaLsd9dSqzwMHAD/NgacHob+HgNOB8Cvbe3/ZgDvjwxAxURO4oA+NELE9PojA9DPZMDiCQOmfsMAjH+Q"+
  771. "AdDvDFD4DQNEfzLgJwP+MwY8biPYj/s7CYHwM6oC2j0/JAQyyxAMGMNNSqFfrHPjEe/pWYlKw4/NAwm2"+
  772. "N+WGE83nduLUh3zczje7QBIawyLIKG9H+Z5G/Yug24G5hhk3g6AuLnJ9ABHYsPbtixBBpSxLLWIndvaX"+
  773. "TUm4t4nxveZfvmIaEduMckObOu+WFxVjfEcht96ONnl4+O7FhZiSC+TNCQ5sspWy6HI9pikzsLgdwCWO"+
  774. "LcFzYZLvRYdPHDDMYmQGfdVjeiDKD96/t/Fcymr12vXLdyOMBzE3rKEvp60+cU6nCsHPu1E6X2iEB46l"+
  775. "5eLEMsUytIMttCw1NvmKnYs94OqXjeVm5k3pVSLbXEOJLjCT5u2VeVUeD3vY2uxuJPV2W29ZH6d9WyBA"+
  776. "tLNvxIJx8Hz5iFJlZJgpD367Ap2FkNVWBofAQ4bpE/UQFy1eNv1caD9BojU/dg7SAlil4mxWS6GsV641"+
  777. "20N8J+6nZhhWaKguL96klsdNuM4VxzsUxzBSqzwq6gQqhCjiDVjLboCvMIH1VTs7nY/8AnxCzimcZAPM"+
  778. "iK2xHnDJqCGzAZZRKr/LBsRRnM4GpPidzgbEo/+QDXj2JMTKjLXuvv6j1+JfgRzmntj6AiRj4JyCpxDf"+
  779. "pN2FeoU7UIo+IbsHNTUC7b8y4DfZAPRv2QByiSjm79mA0tr7i4sYNr6ptl/zhmpIRvR0cQp2rsDQQ7vR"+
  780. "+1tjOt/O7rq0jiZDu5TOjOGMJL/0P10oeCodkMhrgeWU5+s/ihtUMdPYzdQTHrT2Eqqwv2OlrQwv7bg2"+
  781. "tR5mtqVXYcyJrAxAaJEMcOp/GiJa4Vkd7oNgQJM2ggF+xRCloiJTQTZHBAMa7MmaWF6yJIuujXOknawU"+
  782. "DPusyFoQOyq9rpwYQn7fZVinYnC3Nkh2kjVZeeux67MbR3V7kfxzuveM99mOPLJcblfq2bxnwTNst7Hd"+
  783. "b2MEXbjrwnXcn+/bRCpdLeiRkK0JX/E38LaHUGP4kfKtjwW8tLQO231jLhO6rnjzmTYGCvW2NnKlINZh"+
  784. "cCB/3NETFhXebfFUqfFlHsEwRXIMV4KlQNBDcedVzI8JWS1Cyjr1XIfo/zYInB6I/h4ETofA34IA9EcI"+
  785. "oGECuhEv3od4K2ctFMQ4EwI/VgYw/0EI8AF+VgZ+QuC/BgGe5ra+P68M/HahoMwL61FJBY0+Mh2QttMI"+
  786. "JiR4QJLf2TgJOkFCfIuJ1idw2vfLiJn0VFDJY2MfdIKxnb4XPDseUx48Rr3/FAQIhdRlZLnLs2/q8xMq"+
  787. "WlnVkcFfDpPgzshXk2ZpZ/kytyR8rwy8ElTKzmh6ugv2c5ItUWD5lg7wg7kufK3rpS2J3JguW6KPKiac"+
  788. "HHsd2cRPfYDLb947Lk7gZ+GC4eHSSZOSpyyjymYYGpldboruhWaJ+Zrv1pBYBZOeDTkx2e3QNJ3kGOWn"+
  789. "CwNHE0dGW3XVEw22wnyV3ZWHgQtSW1l7Ie3DK+EJ4M1elgNLCROj6Kc9JiPkjwRTa5nZ+DeZIzvhNztc"+
  790. "IdRh9Gahzn1WMyPAGD5jaeBIGikU2NJljiMZk0iTYQ9qthHvU+HSvpj7Gc5OkB0gnwqWS7wjF2mlx7qW"+
  791. "ejVIA3zh/jI0yyWUkjiUk83Y+NpxU/P1tlAW8okwvMc8wVD/tkeZbPNX7Z5d6XrKE+5xlgU8v6UEuHpF"+
  792. "f5MSMOX48rHxlS/uHh8qXt4b0/XNFyz2hQYvJN4p3ajgidFr4ZRfSPNEpSir9y9KDrYOVdO4CW7qdt/K"+
  793. "+WYBiMi6TViJ81ZbTD33t0UCQOQiARRdLO2m/BbqGy+fo0caYztLvt5inEq5VDSzV+2TRLc0Vn9ne12i"+
  794. "4lY8ar4nviaKEVyUl4u5tPzLIU0JNEfhE8lZUWw72xT81yoD4mVICkRB6fG/U6DsfynQeUIBLWX30o6a"+
  795. "qfVQileiZT0plgOsMk1JVdN2CfnpkWQBVrsO532MLkWjW8bOkRKMN3JX12sVVynXye/ds7yIGShNwoNT"+
  796. "Xq4rH9RlyfEo4WmYXEGsLK6pyocQ0sRtfp2yVpeJCKy30uPKz8NE3gkeTx5h6XziEObeJvWsj6opUHpX"+
  797. "8xQ7myirkq/lAxH1K0x3m6MMPnT0z1rPCPVfsKmaXnpHCiG43wKLSH2fpttVq3G3Nl4LWyr/SHo+Lwvi"+
  798. "p9IQmzVDjm0LdSLqeHM8ILiJRsdoNYS93WyEhi7IOdKXZLTCvCLifxTMEi+snNzAtfevk8DpkejvSeB0"+
  799. "BPza/oPKABD5z4SARKQEELP1WQsFMc+QwP8ATkmhK404AAA=";
  800. byte[] dgBytes = decompress(data);
  801. List<org.apache.poi.hssf.record.Record> dgRecords = RecordFactory.createRecords(new ByteArrayInputStream(dgBytes));
  802. assertEquals(14, dgRecords.size());
  803. int[] expectedSids = {
  804. DrawingRecord.sid, ObjRecord.sid,
  805. DrawingRecord.sid, ObjRecord.sid,
  806. DrawingRecord.sid, ObjRecord.sid,
  807. DrawingRecord.sid, ObjRecord.sid,
  808. ContinueRecord.sid, ObjRecord.sid,
  809. ContinueRecord.sid, ObjRecord.sid,
  810. ContinueRecord.sid, ObjRecord.sid
  811. };
  812. int[] actualSids = dgRecords.stream().mapToInt(Record::getSid).toArray();
  813. assertArrayEquals(expectedSids, actualSids, "unexpected record.sid");
  814. DrawingManager2 drawingManager = new DrawingManager2(new EscherDggRecord());
  815. // create a dummy sheet consisting of our test data
  816. InternalSheet sheet = InternalSheet.createSheet();
  817. List<RecordBase> records = sheet.getRecords();
  818. records.clear();
  819. records.addAll(dgRecords);
  820. records.add(EOFRecord.instance);
  821. sheet.aggregateDrawingRecords(drawingManager, false);
  822. assertEquals(2, records.size(), "drawing was not fully aggregated");
  823. assertTrue(records.get(0) instanceof EscherAggregate, "expected EscherAggregate");
  824. assertTrue(records.get(1) instanceof EOFRecord, "expected EOFRecord");
  825. EscherAggregate agg = (EscherAggregate) records.get(0);
  826. byte[] dgBytesAfterSave = agg.serialize();
  827. assertEquals(dgBytes.length, dgBytesAfterSave.length, "different size of drawing data before and after save");
  828. assertArrayEquals(dgBytes, dgBytesAfterSave, "drawing data brefpore and after save is different");
  829. }
  830. }