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.HexDump;
021: import org.apache.poi.util.LittleEndian;
022:
023: import java.io.ByteArrayOutputStream;
024:
025: /**
026: * The escher client anchor specifies which rows and cells the shape is bound to as well as
027: * the offsets within those cells. Each cell is 1024 units wide by 256 units long regardless
028: * of the actual size of the cell. The EscherClientAnchorRecord only applies to the top-most
029: * shapes. Shapes contained in groups are bound using the EscherChildAnchorRecords.
030: *
031: * @author Glen Stampoultzis
032: * @see EscherChildAnchorRecord
033: */
034: public class EscherClientAnchorRecord extends EscherRecord {
035: public static final short RECORD_ID = (short) 0xF010;
036: public static final String RECORD_DESCRIPTION = "MsofbtClientAnchor";
037:
038: private short field_1_flag;
039: private short field_2_col1;
040: private short field_3_dx1;
041: private short field_4_row1;
042: private short field_5_dy1;
043: private short field_6_col2;
044: private short field_7_dx2;
045: private short field_8_row2;
046: private short field_9_dy2;
047: private byte[] remainingData;
048: private boolean shortRecord = false;
049:
050: /**
051: * This method deserializes the record from a byte array.
052: *
053: * @param data The byte array containing the escher record information
054: * @param offset The starting offset into <code>data</code>.
055: * @param recordFactory May be null since this is not a container record.
056: * @return The number of bytes read from the byte array.
057: */
058: public int fillFields(byte[] data, int offset,
059: EscherRecordFactory recordFactory) {
060: int bytesRemaining = readHeader(data, offset);
061: int pos = offset + 8;
062: int size = 0;
063:
064: // Always find 4 two byte entries. Sometimes find 9
065: field_1_flag = LittleEndian.getShort(data, pos + size);
066: size += 2;
067: field_2_col1 = LittleEndian.getShort(data, pos + size);
068: size += 2;
069: field_3_dx1 = LittleEndian.getShort(data, pos + size);
070: size += 2;
071: field_4_row1 = LittleEndian.getShort(data, pos + size);
072: size += 2;
073: if (bytesRemaining >= 18) {
074: field_5_dy1 = LittleEndian.getShort(data, pos + size);
075: size += 2;
076: field_6_col2 = LittleEndian.getShort(data, pos + size);
077: size += 2;
078: field_7_dx2 = LittleEndian.getShort(data, pos + size);
079: size += 2;
080: field_8_row2 = LittleEndian.getShort(data, pos + size);
081: size += 2;
082: field_9_dy2 = LittleEndian.getShort(data, pos + size);
083: size += 2;
084: shortRecord = false;
085: } else {
086: shortRecord = true;
087: }
088: bytesRemaining -= size;
089: remainingData = new byte[bytesRemaining];
090: System.arraycopy(data, pos + size, remainingData, 0,
091: bytesRemaining);
092: return 8 + size + bytesRemaining;
093: }
094:
095: /**
096: * This method serializes this escher record into a byte array.
097: *
098: * @param offset The offset into <code>data</code> to start writing the record data to.
099: * @param data The byte array to serialize to.
100: * @param listener A listener to retrieve start and end callbacks. Use a <code>NullEscherSerailizationListener</code> to ignore these events.
101: * @return The number of bytes written.
102: * @see NullEscherSerializationListener
103: */
104: public int serialize(int offset, byte[] data,
105: EscherSerializationListener listener) {
106: listener.beforeRecordSerialize(offset, getRecordId(), this );
107:
108: if (remainingData == null)
109: remainingData = new byte[0];
110: LittleEndian.putShort(data, offset, getOptions());
111: LittleEndian.putShort(data, offset + 2, getRecordId());
112: int remainingBytes = remainingData.length
113: + (shortRecord ? 8 : 18);
114: LittleEndian.putInt(data, offset + 4, remainingBytes);
115: LittleEndian.putShort(data, offset + 8, field_1_flag);
116: LittleEndian.putShort(data, offset + 10, field_2_col1);
117: LittleEndian.putShort(data, offset + 12, field_3_dx1);
118: LittleEndian.putShort(data, offset + 14, field_4_row1);
119: if (!shortRecord) {
120: LittleEndian.putShort(data, offset + 16, field_5_dy1);
121: LittleEndian.putShort(data, offset + 18, field_6_col2);
122: LittleEndian.putShort(data, offset + 20, field_7_dx2);
123: LittleEndian.putShort(data, offset + 22, field_8_row2);
124: LittleEndian.putShort(data, offset + 24, field_9_dy2);
125: }
126: System.arraycopy(remainingData, 0, data, offset
127: + (shortRecord ? 16 : 26), remainingData.length);
128: int pos = offset + 8 + (shortRecord ? 8 : 18)
129: + remainingData.length;
130:
131: listener.afterRecordSerialize(pos, getRecordId(), pos - offset,
132: this );
133: return pos - offset;
134: }
135:
136: /**
137: * Returns the number of bytes that are required to serialize this record.
138: *
139: * @return Number of bytes
140: */
141: public int getRecordSize() {
142: return 8 + (shortRecord ? 8 : 18)
143: + (remainingData == null ? 0 : remainingData.length);
144: }
145:
146: /**
147: * The record id for this record.
148: */
149: public short getRecordId() {
150: return RECORD_ID;
151: }
152:
153: /**
154: * The short name for this record
155: */
156: public String getRecordName() {
157: return "ClientAnchor";
158: }
159:
160: /**
161: * Returns the string representation for this record.
162: *
163: * @return A string
164: */
165: public String toString() {
166: String nl = System.getProperty("line.separator");
167:
168: String extraData;
169: ByteArrayOutputStream b = new ByteArrayOutputStream();
170: try {
171: HexDump.dump(this .remainingData, 0, b, 0);
172: extraData = b.toString();
173: } catch (Exception e) {
174: extraData = "error\n";
175: }
176: return getClass().getName() + ":" + nl + " RecordId: 0x"
177: + HexDump.toHex(RECORD_ID) + nl + " Options: 0x"
178: + HexDump.toHex(getOptions()) + nl + " Flag: "
179: + field_1_flag + nl + " Col1: " + field_2_col1 + nl
180: + " DX1: " + field_3_dx1 + nl + " Row1: "
181: + field_4_row1 + nl + " DY1: " + field_5_dy1 + nl
182: + " Col2: " + field_6_col2 + nl + " DX2: "
183: + field_7_dx2 + nl + " Row2: " + field_8_row2 + nl
184: + " DY2: " + field_9_dy2 + nl + " Extra Data:" + nl
185: + extraData;
186:
187: }
188:
189: /**
190: * 0 = Move and size with Cells, 2 = Move but don't size with cells, 3 = Don't move or size with cells.
191: */
192: public short getFlag() {
193: return field_1_flag;
194: }
195:
196: /**
197: * 0 = Move and size with Cells, 2 = Move but don't size with cells, 3 = Don't move or size with cells.
198: */
199: public void setFlag(short field_1_flag) {
200: this .field_1_flag = field_1_flag;
201: }
202:
203: /**
204: * The column number for the top-left position. 0 based.
205: */
206: public short getCol1() {
207: return field_2_col1;
208: }
209:
210: /**
211: * The column number for the top-left position. 0 based.
212: */
213: public void setCol1(short field_2_col1) {
214: this .field_2_col1 = field_2_col1;
215: }
216:
217: /**
218: * The x offset within the top-left cell. Range is from 0 to 1023.
219: */
220: public short getDx1() {
221: return field_3_dx1;
222: }
223:
224: /**
225: * The x offset within the top-left cell. Range is from 0 to 1023.
226: */
227: public void setDx1(short field_3_dx1) {
228: this .field_3_dx1 = field_3_dx1;
229: }
230:
231: /**
232: * The row number for the top-left corner of the shape.
233: */
234: public short getRow1() {
235: return field_4_row1;
236: }
237:
238: /**
239: * The row number for the top-left corner of the shape.
240: */
241: public void setRow1(short field_4_row1) {
242: this .field_4_row1 = field_4_row1;
243: }
244:
245: /**
246: * The y offset within the top-left corner of the current shape.
247: */
248: public short getDy1() {
249: return field_5_dy1;
250: }
251:
252: /**
253: * The y offset within the top-left corner of the current shape.
254: */
255: public void setDy1(short field_5_dy1) {
256: shortRecord = false;
257: this .field_5_dy1 = field_5_dy1;
258: }
259:
260: /**
261: * The column of the bottom right corner of this shape.
262: */
263: public short getCol2() {
264: return field_6_col2;
265: }
266:
267: /**
268: * The column of the bottom right corner of this shape.
269: */
270: public void setCol2(short field_6_col2) {
271: shortRecord = false;
272: this .field_6_col2 = field_6_col2;
273: }
274:
275: /**
276: * The x offset withing the cell for the bottom-right corner of this shape.
277: */
278: public short getDx2() {
279: return field_7_dx2;
280: }
281:
282: /**
283: * The x offset withing the cell for the bottom-right corner of this shape.
284: */
285: public void setDx2(short field_7_dx2) {
286: shortRecord = false;
287: this .field_7_dx2 = field_7_dx2;
288: }
289:
290: /**
291: * The row number for the bottom-right corner of the current shape.
292: */
293: public short getRow2() {
294: return field_8_row2;
295: }
296:
297: /**
298: * The row number for the bottom-right corner of the current shape.
299: */
300: public void setRow2(short field_8_row2) {
301: shortRecord = false;
302: this .field_8_row2 = field_8_row2;
303: }
304:
305: /**
306: * The y offset withing the cell for the bottom-right corner of this shape.
307: */
308: public short getDy2() {
309: return field_9_dy2;
310: }
311:
312: /**
313: * The y offset withing the cell for the bottom-right corner of this shape.
314: */
315: public void setDy2(short field_9_dy2) {
316: shortRecord = false;
317: this .field_9_dy2 = field_9_dy2;
318: }
319:
320: /**
321: * Any remaining data in the record
322: */
323: public byte[] getRemainingData() {
324: return remainingData;
325: }
326:
327: /**
328: * Any remaining data in the record
329: */
330: public void setRemainingData(byte[] remainingData) {
331: this.remainingData = remainingData;
332: }
333: }
|