You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TestDrawingAggregate.java 54KB

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