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.hssf.record.RecordFormatException;
021: import org.apache.poi.util.HexDump;
022: import org.apache.poi.util.LittleEndian;
023:
024: import java.util.*;
025:
026: /**
027: * This record defines the drawing groups used for a particular sheet.
028: */
029: public class EscherDggRecord extends EscherRecord {
030: public static final short RECORD_ID = (short) 0xF006;
031: public static final String RECORD_DESCRIPTION = "MsofbtDgg";
032:
033: private int field_1_shapeIdMax;
034: // private int field_2_numIdClusters; // for some reason the number of clusters is actually the real number + 1
035: private int field_3_numShapesSaved;
036: private int field_4_drawingsSaved;
037: private FileIdCluster[] field_5_fileIdClusters;
038:
039: public static class FileIdCluster {
040: public FileIdCluster(int drawingGroupId, int numShapeIdsUsed) {
041: this .field_1_drawingGroupId = drawingGroupId;
042: this .field_2_numShapeIdsUsed = numShapeIdsUsed;
043: }
044:
045: private int field_1_drawingGroupId;
046: private int field_2_numShapeIdsUsed;
047:
048: public int getDrawingGroupId() {
049: return field_1_drawingGroupId;
050: }
051:
052: public int getNumShapeIdsUsed() {
053: return field_2_numShapeIdsUsed;
054: }
055:
056: public void incrementShapeId() {
057: this .field_2_numShapeIdsUsed++;
058: }
059: }
060:
061: /**
062: * This method deserializes the record from a byte array.
063: *
064: * @param data The byte array containing the escher record information
065: * @param offset The starting offset into <code>data</code>.
066: * @param recordFactory May be null since this is not a container record.
067: * @return The number of bytes read from the byte array.
068: */
069: public int fillFields(byte[] data, int offset,
070: EscherRecordFactory recordFactory) {
071: int bytesRemaining = readHeader(data, offset);
072: int pos = offset + 8;
073: int size = 0;
074: field_1_shapeIdMax = LittleEndian.getInt(data, pos + size);
075: size += 4;
076: int field_2_numIdClusters = LittleEndian.getInt(data, pos
077: + size);
078: size += 4;
079: field_3_numShapesSaved = LittleEndian.getInt(data, pos + size);
080: size += 4;
081: field_4_drawingsSaved = LittleEndian.getInt(data, pos + size);
082: size += 4;
083: field_5_fileIdClusters = new FileIdCluster[(bytesRemaining - size) / 8]; // Can't rely on field_2_numIdClusters
084: for (int i = 0; i < field_5_fileIdClusters.length; i++) {
085: field_5_fileIdClusters[i] = new FileIdCluster(LittleEndian
086: .getInt(data, pos + size), LittleEndian.getInt(
087: data, pos + size + 4));
088: size += 8;
089: }
090: bytesRemaining -= size;
091: if (bytesRemaining != 0)
092: throw new RecordFormatException(
093: "Expecting no remaining data but got "
094: + bytesRemaining + " byte(s).");
095: return 8 + size + bytesRemaining;
096: }
097:
098: /**
099: * This method serializes this escher record into a byte array.
100: *
101: * @param offset The offset into <code>data</code> to start writing the record data to.
102: * @param data The byte array to serialize to.
103: * @param listener A listener to retrieve start and end callbacks. Use a <code>NullEscherSerailizationListener</code> to ignore these events.
104: * @return The number of bytes written.
105: *
106: * @see NullEscherSerializationListener
107: */
108: public int serialize(int offset, byte[] data,
109: EscherSerializationListener listener) {
110: listener.beforeRecordSerialize(offset, getRecordId(), this );
111:
112: int pos = offset;
113: LittleEndian.putShort(data, pos, getOptions());
114: pos += 2;
115: LittleEndian.putShort(data, pos, getRecordId());
116: pos += 2;
117: int remainingBytes = getRecordSize() - 8;
118: LittleEndian.putInt(data, pos, remainingBytes);
119: pos += 4;
120:
121: LittleEndian.putInt(data, pos, field_1_shapeIdMax);
122: pos += 4;
123: LittleEndian.putInt(data, pos, getNumIdClusters());
124: pos += 4;
125: LittleEndian.putInt(data, pos, field_3_numShapesSaved);
126: pos += 4;
127: LittleEndian.putInt(data, pos, field_4_drawingsSaved);
128: pos += 4;
129: for (int i = 0; i < field_5_fileIdClusters.length; i++) {
130: LittleEndian.putInt(data, pos,
131: field_5_fileIdClusters[i].field_1_drawingGroupId);
132: pos += 4;
133: LittleEndian.putInt(data, pos,
134: field_5_fileIdClusters[i].field_2_numShapeIdsUsed);
135: pos += 4;
136: }
137:
138: listener.afterRecordSerialize(pos, getRecordId(),
139: getRecordSize(), this );
140: return getRecordSize();
141: }
142:
143: /**
144: * Returns the number of bytes that are required to serialize this record.
145: *
146: * @return Number of bytes
147: */
148: public int getRecordSize() {
149: return 8 + 16 + (8 * field_5_fileIdClusters.length);
150: }
151:
152: public short getRecordId() {
153: return RECORD_ID;
154: }
155:
156: /**
157: * The short name for this record
158: */
159: public String getRecordName() {
160: return "Dgg";
161: }
162:
163: public String toString() {
164: String nl = System.getProperty("line.separator");
165:
166: // String extraData;
167: // ByteArrayOutputStream b = new ByteArrayOutputStream();
168: // try
169: // {
170: // HexDump.dump(this.remainingData, 0, b, 0);
171: // extraData = b.toString();
172: // }
173: // catch ( Exception e )
174: // {
175: // extraData = "error";
176: // }
177: StringBuffer field_5_string = new StringBuffer();
178: for (int i = 0; i < field_5_fileIdClusters.length; i++) {
179: field_5_string.append(" DrawingGroupId").append(i + 1)
180: .append(": ");
181: field_5_string
182: .append(field_5_fileIdClusters[i].field_1_drawingGroupId);
183: field_5_string.append(nl);
184: field_5_string.append(" NumShapeIdsUsed").append(i + 1)
185: .append(": ");
186: field_5_string
187: .append(field_5_fileIdClusters[i].field_2_numShapeIdsUsed);
188: field_5_string.append(nl);
189: }
190: return getClass().getName() + ":" + nl + " RecordId: 0x"
191: + HexDump.toHex(RECORD_ID) + nl + " Options: 0x"
192: + HexDump.toHex(getOptions()) + nl + " ShapeIdMax: "
193: + field_1_shapeIdMax + nl + " NumIdClusters: "
194: + getNumIdClusters() + nl + " NumShapesSaved: "
195: + field_3_numShapesSaved + nl + " DrawingsSaved: "
196: + field_4_drawingsSaved + nl + ""
197: + field_5_string.toString();
198:
199: }
200:
201: public int getShapeIdMax() {
202: return field_1_shapeIdMax;
203: }
204:
205: /**
206: * The maximum is actually the next available. shape id.
207: */
208: public void setShapeIdMax(int field_1_shapeIdMax) {
209: this .field_1_shapeIdMax = field_1_shapeIdMax;
210: }
211:
212: /**
213: * Number of id clusters + 1
214: */
215: public int getNumIdClusters() {
216: return field_5_fileIdClusters.length + 1;
217: }
218:
219: public int getNumShapesSaved() {
220: return field_3_numShapesSaved;
221: }
222:
223: public void setNumShapesSaved(int field_3_numShapesSaved) {
224: this .field_3_numShapesSaved = field_3_numShapesSaved;
225: }
226:
227: public int getDrawingsSaved() {
228: return field_4_drawingsSaved;
229: }
230:
231: public void setDrawingsSaved(int field_4_drawingsSaved) {
232: this .field_4_drawingsSaved = field_4_drawingsSaved;
233: }
234:
235: public FileIdCluster[] getFileIdClusters() {
236: return field_5_fileIdClusters;
237: }
238:
239: public void setFileIdClusters(FileIdCluster[] field_5_fileIdClusters) {
240: this .field_5_fileIdClusters = field_5_fileIdClusters;
241: }
242:
243: public void addCluster(int dgId, int numShapedUsed) {
244: List clusters = new ArrayList(Arrays
245: .asList(field_5_fileIdClusters));
246: clusters.add(new FileIdCluster(dgId, numShapedUsed));
247: Collections.sort(clusters, new Comparator() {
248: public int compare(Object o1, Object o2) {
249: FileIdCluster f1 = (FileIdCluster) o1;
250: FileIdCluster f2 = (FileIdCluster) o2;
251: if (f1.getDrawingGroupId() == f2.getDrawingGroupId())
252: return 0;
253: if (f1.getDrawingGroupId() < f2.getDrawingGroupId())
254: return -1;
255: else
256: return +1;
257: }
258: });
259: field_5_fileIdClusters = (FileIdCluster[]) clusters
260: .toArray(new FileIdCluster[clusters.size()]);
261: }
262: }
|