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 org.apache.poi.util.LittleEndian;
021: import org.apache.poi.util.HexDump;
022:
023: import java.util.*;
024: import java.io.IOException;
025:
026: /**
027: * The opt record is used to store property values for a shape. It is the key to determining
028: * the attributes of a shape. Properties can be of two types: simple or complex. Simple types
029: * are fixed length. Complex properties are variable length.
030: *
031: * @author Glen Stampoultzis
032: */
033: public class EscherOptRecord extends EscherRecord {
034: public static final short RECORD_ID = (short) 0xF00B;
035: public static final String RECORD_DESCRIPTION = "msofbtOPT";
036:
037: private List properties = new ArrayList();
038:
039: /**
040: * This method deserializes the record from a byte array.
041: *
042: * @param data The byte array containing the escher record information
043: * @param offset The starting offset into <code>data</code>.
044: * @param recordFactory May be null since this is not a container record.
045: * @return The number of bytes read from the byte array.
046: */
047: public int fillFields(byte[] data, int offset,
048: EscherRecordFactory recordFactory) {
049: int bytesRemaining = readHeader(data, offset);
050: int pos = offset + 8;
051:
052: EscherPropertyFactory f = new EscherPropertyFactory();
053: properties = f.createProperties(data, pos, getInstance());
054: return bytesRemaining + 8;
055: }
056:
057: /**
058: * This method serializes this escher record into a byte array.
059: *
060: * @param offset The offset into <code>data</code> to start writing the record data to.
061: * @param data The byte array to serialize to.
062: * @param listener A listener to retrieve start and end callbacks. Use a <code>NullEscherSerailizationListener</code> to ignore these events.
063: *
064: * @return The number of bytes written.
065: * @see NullEscherSerializationListener
066: */
067: public int serialize(int offset, byte[] data,
068: EscherSerializationListener listener) {
069: listener.beforeRecordSerialize(offset, getRecordId(), this );
070:
071: LittleEndian.putShort(data, offset, getOptions());
072: LittleEndian.putShort(data, offset + 2, getRecordId());
073: LittleEndian.putInt(data, offset + 4, getPropertiesSize());
074: int pos = offset + 8;
075: for (Iterator iterator = properties.iterator(); iterator
076: .hasNext();) {
077: EscherProperty escherProperty = (EscherProperty) iterator
078: .next();
079: pos += escherProperty.serializeSimplePart(data, pos);
080: }
081: for (Iterator iterator = properties.iterator(); iterator
082: .hasNext();) {
083: EscherProperty escherProperty = (EscherProperty) iterator
084: .next();
085: pos += escherProperty.serializeComplexPart(data, pos);
086: }
087: listener.afterRecordSerialize(pos, getRecordId(), pos - offset,
088: this );
089: return pos - offset;
090: }
091:
092: /**
093: * Returns the number of bytes that are required to serialize this record.
094: *
095: * @return Number of bytes
096: */
097: public int getRecordSize() {
098: return 8 + getPropertiesSize();
099: }
100:
101: /**
102: * Automatically recalculate the correct option
103: */
104: public short getOptions() {
105: setOptions((short) ((properties.size() << 4) | 0x3));
106: return super .getOptions();
107: }
108:
109: /**
110: * The short name for this record
111: */
112: public String getRecordName() {
113: return "Opt";
114: }
115:
116: private int getPropertiesSize() {
117: int totalSize = 0;
118: for (Iterator iterator = properties.iterator(); iterator
119: .hasNext();) {
120: EscherProperty escherProperty = (EscherProperty) iterator
121: .next();
122: totalSize += escherProperty.getPropertySize();
123: }
124: return totalSize;
125: }
126:
127: /**
128: * Retrieve the string representation of this record.
129: */
130: public String toString() {
131: String nl = System.getProperty("line.separator");
132: StringBuffer propertiesBuf = new StringBuffer();
133: for (Iterator iterator = properties.iterator(); iterator
134: .hasNext();)
135: propertiesBuf.append(" " + iterator.next().toString()
136: + nl);
137:
138: return "org.apache.poi.ddf.EscherOptRecord:" + nl
139: + " isContainer: " + isContainerRecord() + nl
140: + " options: 0x" + HexDump.toHex(getOptions()) + nl
141: + " recordId: 0x" + HexDump.toHex(getRecordId()) + nl
142: + " numchildren: " + getChildRecords().size() + nl
143: + " properties:" + nl + propertiesBuf.toString();
144: }
145:
146: /**
147: * The list of properties stored by this record.
148: */
149: public List getEscherProperties() {
150: return properties;
151: }
152:
153: /**
154: * The list of properties stored by this record.
155: */
156: public EscherProperty getEscherProperty(int index) {
157: return (EscherProperty) properties.get(index);
158: }
159:
160: /**
161: * Add a property to this record.
162: */
163: public void addEscherProperty(EscherProperty prop) {
164: properties.add(prop);
165: }
166:
167: /**
168: * Records should be sorted by property number before being stored.
169: */
170: public void sortProperties() {
171: Collections.sort(properties, new Comparator() {
172: public int compare(Object o1, Object o2) {
173: EscherProperty p1 = (EscherProperty) o1;
174: EscherProperty p2 = (EscherProperty) o2;
175: return new Short(p1.getPropertyNumber())
176: .compareTo(new Short(p2.getPropertyNumber()));
177: }
178: });
179: }
180:
181: }
|