001: /* ====================================================================
002: Licensed to the Apache Software Foundation (ASF) under one or more
003: contributor license agreements. See the NOTICE file distributed with
004: this work for additional information regarding copyright ownership.
005: The ASF licenses this file to You under the Apache License, Version 2.0
006: (the "License"); you may not use this file except in compliance with
007: the License. You may obtain a copy of the License at
008:
009: http://www.apache.org/licenses/LICENSE-2.0
010:
011: Unless required by applicable law or agreed to in writing, software
012: distributed under the License is distributed on an "AS IS" BASIS,
013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: See the License for the specific language governing permissions and
015: limitations under the License.
016: ==================================================================== */
017:
018: package org.apache.poi.ddf;
019:
020: import junit.framework.TestCase;
021: import org.apache.poi.util.HexRead;
022: import org.apache.poi.util.HexDump;
023:
024: import java.io.IOException;
025: import java.util.Arrays;
026: import java.util.List;
027: import java.util.Iterator;
028:
029: public class TestEscherOptRecord extends TestCase {
030:
031: public void testFillFields() throws Exception {
032: checkFillFieldsSimple();
033: checkFillFieldsComplex();
034: }
035:
036: private void checkFillFieldsComplex() throws IOException {
037: String dataStr = "33 00 " + "0B F0 " + "14 00 00 00 "
038: + "BF 00 01 00 00 00 " + "01 80 02 00 00 00 "
039: + "BF 00 01 00 00 00 " + "01 02";
040:
041: EscherOptRecord r = new EscherOptRecord();
042: r.fillFields(HexRead.readFromString(dataStr),
043: new DefaultEscherRecordFactory());
044: assertEquals((short) 0x0033, r.getOptions());
045: assertEquals((short) 0xF00B, r.getRecordId());
046: assertEquals(3, r.getEscherProperties().size());
047: EscherBoolProperty prop1 = new EscherBoolProperty(
048: EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 1);
049: EscherComplexProperty prop2 = new EscherComplexProperty(
050: (short) 1, false, new byte[] { 0x01, 0x02 });
051: EscherBoolProperty prop3 = new EscherBoolProperty(
052: EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 1);
053: assertEquals(prop1, r.getEscherProperty(0));
054: assertEquals(prop2, r.getEscherProperty(1));
055: assertEquals(prop3, r.getEscherProperty(2));
056:
057: }
058:
059: private void checkFillFieldsSimple() throws IOException {
060: String dataStr = "33 00 "
061: + // options
062: "0B F0 "
063: + // recordid
064: "12 00 00 00 "
065: + // remaining bytes
066: "BF 00 08 00 08 00 " + "81 01 09 00 00 08 "
067: + "C0 01 40 00 00 08";
068:
069: EscherOptRecord r = new EscherOptRecord();
070: r.fillFields(HexRead.readFromString(dataStr),
071: new DefaultEscherRecordFactory());
072: assertEquals((short) 0x0033, r.getOptions());
073: assertEquals((short) 0xF00B, r.getRecordId());
074: assertEquals(3, r.getEscherProperties().size());
075: EscherBoolProperty prop1 = new EscherBoolProperty(
076: EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 524296);
077: EscherRGBProperty prop2 = new EscherRGBProperty(
078: EscherProperties.FILL__FILLCOLOR, 0x08000009);
079: EscherRGBProperty prop3 = new EscherRGBProperty(
080: EscherProperties.LINESTYLE__COLOR, 0x08000040);
081: assertEquals(prop1, r.getEscherProperty(0));
082: assertEquals(prop2, r.getEscherProperty(1));
083: assertEquals(prop3, r.getEscherProperty(2));
084: }
085:
086: public void testSerialize() throws Exception {
087: checkSerializeSimple();
088: checkSerializeComplex();
089: }
090:
091: private void checkSerializeComplex() {
092: //Complex escher record
093: EscherOptRecord r = new EscherOptRecord();
094: r.setOptions((short) 0x0033);
095: r.setRecordId((short) 0xF00B);
096: EscherBoolProperty prop1 = new EscherBoolProperty(
097: EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 1);
098: EscherComplexProperty prop2 = new EscherComplexProperty(
099: (short) 1, false, new byte[] { 0x01, 0x02 });
100: EscherBoolProperty prop3 = new EscherBoolProperty(
101: EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 1);
102: r.addEscherProperty(prop1);
103: r.addEscherProperty(prop2);
104: r.addEscherProperty(prop3);
105:
106: byte[] data = new byte[28];
107: int bytesWritten = r.serialize(0, data,
108: new NullEscherSerializationListener());
109: assertEquals(28, bytesWritten);
110: String dataStr = "[33, 00, " + "0B, F0, " + "14, 00, 00, 00, "
111: + "BF, 00, 01, 00, 00, 00, "
112: + "01, 80, 02, 00, 00, 00, "
113: + "BF, 00, 01, 00, 00, 00, " + "01, 02, ]";
114: assertEquals(dataStr, HexDump.toHex(data));
115:
116: }
117:
118: private void checkSerializeSimple() {
119: EscherOptRecord r = new EscherOptRecord();
120: r.setOptions((short) 0x0033);
121: r.setRecordId((short) 0xF00B);
122: EscherBoolProperty prop1 = new EscherBoolProperty(
123: EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 1);
124: EscherRGBProperty prop2 = new EscherRGBProperty(
125: EscherProperties.FILL__FILLCOLOR, 0x08000009);
126: EscherRGBProperty prop3 = new EscherRGBProperty(
127: EscherProperties.LINESTYLE__COLOR, 0x08000040);
128: r.addEscherProperty(prop1);
129: r.addEscherProperty(prop2);
130: r.addEscherProperty(prop3);
131:
132: byte[] data = new byte[26];
133: int bytesWritten = r.serialize(0, data,
134: new NullEscherSerializationListener());
135: String dataStr = "[33, 00, " + "0B, F0, " + "12, 00, 00, 00, "
136: + "BF, 00, 01, 00, 00, 00, "
137: + "81, 01, 09, 00, 00, 08, "
138: + "C0, 01, 40, 00, 00, 08, ]";
139: assertEquals(dataStr, HexDump.toHex(data));
140: assertEquals(26, bytesWritten);
141: }
142:
143: public void testToString() throws Exception {
144: String nl = System.getProperty("line.separator");
145: EscherOptRecord r = new EscherOptRecord();
146: r.setOptions((short) 0x000F);
147: r.setRecordId(EscherOptRecord.RECORD_ID);
148: EscherProperty prop1 = new EscherBoolProperty((short) 1, 1);
149: r.addEscherProperty(prop1);
150: String expected = "org.apache.poi.ddf.EscherOptRecord:"
151: + nl
152: + " isContainer: true"
153: + nl
154: + " options: 0x0013"
155: + nl
156: + " recordId: 0x"
157: + HexDump.toHex(EscherOptRecord.RECORD_ID)
158: + nl
159: + " numchildren: 0"
160: + nl
161: + " properties:"
162: + nl
163: + " propNum: 1, RAW: 0x0001, propName: unknown, complex: false, blipId: false, value: 1 (0x00000001)"
164: + nl;
165: assertEquals(expected, r.toString());
166: }
167:
168: /**
169: * Test serialisation of a particually complex example
170: * This test is currently broken!
171: */
172: public void testComplexSerialise() throws Exception {
173: byte[] data = new byte[] {
174: 0x53,
175: 0x01,
176: 0x0B,
177: 0xF0 - 256,
178: 0x9C - 256,
179: 0x01,
180: 0x00,
181: 0x00,
182: // Simple data follows
183: 0x42,
184: 0x01,
185: 0x49,
186: 0x00,
187: 0x00,
188: 0x00, // SP @ 8
189: 0x43,
190: 0x01,
191: 0x85 - 256,
192: 0x00,
193: 0x00,
194: 0x00, // SP @ 14
195: 0x44,
196: 0x01,
197: 0x04,
198: 0x00,
199: 0x00,
200: 0x00, // SP @ 20
201: 0x45,
202: 0xC1 - 256,
203: 0x88 - 256,
204: 0x00,
205: 0x00,
206: 0x00, // SP @ 26
207: 0x46,
208: 0xC1 - 256,
209: 0x90 - 256,
210: 0x00,
211: 0x00,
212: 0x00, // SP @ 32
213: 0x7F,
214: 0x01,
215: 0x01,
216: 0x00,
217: 0x01,
218: 0x00,
219: 0x80 - 256,
220: 0x01,
221: 0x00,
222: 0x00,
223: 0x00,
224: 0x00,
225: 0x81 - 256,
226: 0x01,
227: 0x02,
228: 0x00,
229: 0x00,
230: 0x08,
231: 0xBF - 256,
232: 0x01,
233: 0x10,
234: 0x00,
235: 0x10,
236: 0x00,
237: 0xC0 - 256,
238: 0x01,
239: 0x01,
240: 0x00,
241: 0x00,
242: 0x08, // SP 10
243: 0xC1 - 256,
244: 0x01,
245: 0x00,
246: 0x00,
247: 0x01,
248: 0x00,
249: 0xC4 - 256,
250: 0x01,
251: 0x00,
252: 0x00,
253: 0x00,
254: 0x00,
255: 0xCB - 256,
256: 0x01,
257: 0x38,
258: 0x63,
259: 0x00,
260: 0x00,
261: 0xCD - 256,
262: 0x01,
263: 0x00,
264: 0x00,
265: 0x00,
266: 0x00,
267: 0xCE - 256,
268: 0x01,
269: 0x00,
270: 0x00,
271: 0x00,
272: 0x00, // SP 15
273: 0xD0 - 256,
274: 0x01,
275: 0x00,
276: 0x00,
277: 0x00,
278: 0x00,
279: 0xD1 - 256,
280: 0x01,
281: 0x00,
282: 0x00,
283: 0x00,
284: 0x00,
285: 0xD7 - 256,
286: 0x01,
287: 0x00,
288: 0x00,
289: 0x00,
290: 0x00,
291: 0xFF - 256,
292: 0x01,
293: 0x18,
294: 0x00,
295: 0x18,
296: 0x00,
297: 0x01,
298: 0x02,
299: 0x02,
300: 0x00,
301: 0x00,
302: 0x08,
303: 0x3F,
304: 0x02,
305: 0x00,
306: 0x00,
307: 0x02,
308: 0x00, // SP 21
309:
310: // Complex data follows
311:
312: // Complex data for Array #325
313: // Array header
314: 0x22,
315: 0x00,
316: 0x22,
317: 0x00,
318: 0xF0 - 256,
319: 0xFF - 256,
320: // Array data
321: 0x18, 0x00, 0x28, 0x00, 0x04, 0x00, 0x34, 0x00, 0x04,
322: 0x00, 0x28, 0x00, 0x04, 0x00, 0x1C, 0x00, 0x04, 0x00,
323: 0x10, 0x00, 0x04, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00,
324: 0x00, 0x1C, 0x00, 0x04, 0x00, 0x28, 0x00, 0x10, 0x00,
325: 0x34, 0x00, 0x18, 0x00, 0x3C, 0x00, 0x24, 0x00, 0x44,
326: 0x00, 0x30, 0x00, 0x48, 0x00, 0x3C, 0x00, 0x44, 0x00,
327: 0x48, 0x00, 0x3C, 0x00, 0x54, 0x00, 0x38, 0x00, 0x60,
328: 0x00, 0x2C, 0x00, 0x70, 0x00, 0x20, 0x00, 0x78, 0x00,
329: 0x14, 0x00, 0x80 - 256, 0x00, 0x08, 0x00, 0x84 - 256,
330: 0x00,
331: 0x04,
332: 0x00,
333: 0x78,
334: 0x00,
335: 0x04,
336: 0x00,
337: 0x6C,
338: 0x00,
339: 0x04,
340: 0x00,
341: 0x60,
342: 0x00,
343: 0x04,
344: 0x00,
345: 0x54,
346: 0x00,
347: 0x08,
348: 0x00,
349: 0x48,
350: 0x00,
351: 0x0C,
352: 0x00,
353: 0x3C,
354: 0x00,
355: 0x0C,
356: 0x00,
357: 0x30,
358: 0x00,
359: 0x08,
360: 0x00,
361: 0x3C,
362: 0x00,
363: 0x08,
364: 0x00,
365: 0x48,
366: 0x00,
367: 0x08,
368: 0x00,
369: 0x54,
370: 0x00,
371: 0x00,
372: 0x00,
373: 0x48,
374: 0x00,
375: 0x00,
376: 0x00,
377: 0x3C,
378: 0x00,
379: 0x00,
380: 0x00,
381: 0x30,
382: 0x00,
383: 0x04,
384: 0x00,
385: 0x24,
386: 0x00,
387: // Complex data for Array #326
388: // Array header
389: 0x45,
390: 0x00,
391: 0x48,
392: 0x00,
393: 0x02,
394: 0x00,
395: // Array data
396: 0x00, 0x40, 0x00, 0xB0 - 256, 0x01, 0x00, 0x00,
397: 0xB0 - 256, 0x01, 0x00, 0x00, 0xB0 - 256, 0x01, 0x00,
398: 0x00, 0xB0 - 256, 0x01, 0x00, 0x00, 0xB0 - 256, 0x01,
399: 0x00, 0x00, 0xB0 - 256, 0x01, 0x00, 0x00, 0xB0 - 256,
400: 0x01, 0x00, 0x00, 0xB0 - 256, 0x01, 0x00, 0x00,
401: 0xB0 - 256, 0x01, 0x00, 0x00, 0xB0 - 256, 0x01, 0x00,
402: 0x00, 0xB0 - 256, 0x01, 0x00, 0x00, 0xB0 - 256, 0x01,
403: 0x00, 0x00, 0xB0 - 256, 0x01, 0x00, 0x00, 0xB0 - 256,
404: 0x01, 0x00, 0x00, 0xB0 - 256, 0x01, 0x00, 0x00,
405: 0xB0 - 256, 0x01, 0x00, 0x00, 0xB0 - 256, 0x01, 0x00,
406: 0x00, 0xB0 - 256, 0x01, 0x00, 0x00, 0xB0 - 256, 0x01,
407: 0x00, 0x00, 0xB0 - 256, 0x01, 0x00, 0x00, 0xB0 - 256,
408: 0x01, 0x00, 0x00, 0xB0 - 256, 0x01, 0x00, 0x00,
409: 0xB0 - 256, 0x01, 0x00, 0x00, 0xB0 - 256, 0x01, 0x00,
410: 0x00, 0xB0 - 256, 0x01, 0x00, 0x00, 0xB0 - 256, 0x01,
411: 0x00, 0x00, 0xB0 - 256, 0x01, 0x00, 0x00, 0xB0 - 256,
412: 0x01, 0x00, 0x00, 0xB0 - 256, 0x01, 0x00, 0x00,
413: 0xB0 - 256, 0x01, 0x00, 0x00, 0xB0 - 256, 0x01, 0x00,
414: 0x00, 0xB0 - 256, 0x01, 0x00, 0x00, 0xB0 - 256, 0x01,
415: 0x00, 0x00, 0xB0 - 256, 0x00, 0x80 - 256 };
416:
417: // Create the record
418: EscherOptRecord r = new EscherOptRecord();
419: int filled = r.fillFields(data,
420: new DefaultEscherRecordFactory());
421:
422: // Check it's the right length
423: assertEquals(data.length, filled);
424: assertEquals(data.length, r.getRecordSize());
425:
426: // Serialise it
427: byte[] dest = new byte[data.length];
428: int written = r.serialize(0, dest);
429:
430: // Check it serialised it back to the same data
431: assertEquals(data.length, written);
432: for (int i = 0; i < data.length; i++) {
433: assertEquals(data[i], dest[i]);
434: }
435: }
436:
437: /**
438: * Test read/write against an OPT record from a real ppt file.
439: * In PowerPoint is is legal to have array properties with empty complex part.
440: * In Glen's original implementation complex part is always 6 bytes which resulted
441: * in +6 extra bytes when writing back out. As the result the ppt becomes unreadable.
442: *
443: * Make sure we write back the original empty complex part.
444: *
445: * See Bug 41946 for details.
446: */
447: public void test41946() throws IOException {
448: String dataStr1 = "03 08 0B F0 00 03 00 00 81 00 30 65 01 00 82 00 98 B2 00 00 83 00 30 65 01 "
449: + "00 84 00 98 B2 00 00 85 00 00 00 00 00 87 00 01 00 00 00 88 00 00 00 00 00 "
450: + "89 00 00 00 00 00 BF 00 00 00 0F 00 0C 01 F4 00 00 10 0D 01 00 00 00 20 0E "
451: + "01 00 00 00 20 80 01 00 00 00 00 81 01 04 00 00 08 82 01 00 00 01 00 83 01 "
452: + "00 00 00 08 84 01 00 00 01 00 85 01 00 00 00 20 86 41 00 00 00 00 87 C1 00 "
453: + "00 00 00 88 01 00 00 00 00 89 01 00 00 00 00 8A 01 00 00 00 00 8B 01 00 00 "
454: + "00 00 8C 01 00 00 00 00 8D 01 00 00 00 00 8E 01 00 00 00 00 8F 01 00 00 00 "
455: + "00 90 01 00 00 00 00 91 01 00 00 00 00 92 01 00 00 00 00 93 01 00 00 00 00 "
456: + "94 01 00 00 00 00 95 01 00 00 00 00 96 01 00 00 00 00 97 C1 00 00 00 00 98 "
457: + "01 00 00 00 00 99 01 00 00 00 00 9A 01 00 00 00 00 9B 01 00 00 00 00 9C 01 "
458: + "03 00 00 40 BF 01 0C 00 1E 00 C0 01 01 00 00 08 C1 01 00 00 01 00 C2 01 FF "
459: + "FF FF 00 C3 01 00 00 00 20 C4 01 00 00 00 00 C5 41 00 00 00 00 C6 C1 00 00 "
460: + "00 00 C7 01 00 00 00 00 C8 01 00 00 00 00 C9 01 00 00 00 00 CA 01 00 00 00 "
461: + "00 CB 01 35 25 00 00 CC 01 00 00 08 00 CD 01 00 00 00 00 CE 01 00 00 00 00 "
462: + "CF C1 00 00 00 00 D7 01 02 00 00 00 FF 01 06 00 0E 00 00 02 00 00 00 00 01 "
463: + "02 02 00 00 08 02 02 CB CB CB 00 03 02 00 00 00 20 04 02 00 00 01 00 05 02 "
464: + "38 63 00 00 06 02 38 63 00 00 07 02 00 00 00 00 08 02 00 00 00 00 09 02 00 "
465: + "00 01 00 0A 02 00 00 00 00 0B 02 00 00 00 00 0C 02 00 00 01 00 0D 02 00 00 "
466: + "00 00 0E 02 00 00 00 00 0F 02 00 01 00 00 10 02 00 00 00 00 11 02 00 00 00 "
467: + "00 3F 02 00 00 03 00 80 02 00 00 00 00 81 02 00 00 01 00 82 02 05 00 00 00 "
468: + "83 02 9C 31 00 00 84 02 00 00 00 00 85 02 F0 F9 06 00 86 02 00 00 00 00 87 "
469: + "02 F7 00 00 10 88 02 00 00 00 20 BF 02 01 00 0F 00 C0 02 00 00 00 00 C1 02 "
470: + "00 00 00 00 C2 02 64 00 00 00 C3 02 00 00 00 00 C4 02 00 00 00 00 C5 02 00 "
471: + "00 00 00 C6 02 00 00 00 00 C7 02 00 00 00 00 C8 02 00 00 00 00 C9 02 00 00 "
472: + "00 00 CA 02 30 75 00 00 CB 02 D0 12 13 00 CC 02 30 ED EC FF CD 02 40 54 89 "
473: + "00 CE 02 00 80 00 00 CF 02 00 80 FF FF D0 02 00 00 79 FF D1 02 32 00 00 00 "
474: + "D2 02 20 4E 00 00 D3 02 50 C3 00 00 D4 02 00 00 00 00 D5 02 10 27 00 00 D6 "
475: + "02 70 94 00 00 D7 02 B0 3C FF FF D8 02 00 00 00 00 D9 02 10 27 00 00 DA 02 "
476: + "70 94 00 00 FF 02 16 00 1F 00 04 03 01 00 00 00 41 03 A8 29 01 00 42 03 00 "
477: + "00 00 00 43 03 03 00 00 00 44 03 7C BE 01 00 45 03 00 00 00 00 7F 03 00 00 "
478: + "0F 00 84 03 7C BE 01 00 85 03 00 00 00 00 86 03 7C BE 01 00 87 03 00 00 00 "
479: + "00";
480:
481: EscherOptRecord r = new EscherOptRecord();
482: byte[] data = HexRead.readFromString(dataStr1);
483: r.fillFields(data, 0, new DefaultEscherRecordFactory());
484: assertEquals((short) 0xF00B, r.getRecordId());
485:
486: byte[] data1 = r.serialize();
487: EscherOptRecord opt2 = new EscherOptRecord();
488: opt2.fillFields(data1, new DefaultEscherRecordFactory());
489:
490: byte[] data2 = opt2.serialize();
491: assertTrue(Arrays.equals(data1, data2));
492: }
493:
494: /**
495: * Test that EscherOptRecord can properly read/write array properties
496: * with empty complex part.
497: */
498: public void testEmptyArrayProperty() throws IOException {
499: EscherOptRecord r = new EscherOptRecord();
500: EscherArrayProperty p = new EscherArrayProperty(
501: (short) (EscherProperties.FILL__SHADECOLORS + 0x8000),
502: new byte[0]);
503: assertEquals(0, p.getNumberOfElementsInArray());
504: r.addEscherProperty(p);
505:
506: byte[] data1 = r.serialize();
507: EscherOptRecord opt2 = new EscherOptRecord();
508: opt2.fillFields(data1, new DefaultEscherRecordFactory());
509: p = (EscherArrayProperty) opt2.getEscherProperties().get(0);
510: assertEquals(0, p.getNumberOfElementsInArray());
511:
512: byte[] data2 = opt2.serialize();
513: assertTrue(Arrays.equals(data1, data2));
514: }
515: }
|