From 104093d45ebfdc5f58d1226324b3a95136495ec9 Mon Sep 17 00:00:00 2001 From: Glen Stampoultzis Date: Tue, 10 Feb 2004 21:58:00 +0000 Subject: [PATCH] Escher records for drawing format support git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/branches/REL_2_BRANCH@353495 13f79535-47bb-0310-9956-ffa450edef68 --- .../record/AbstractEscherHolderRecord.java | 266 +++++++ .../record/CommonObjectDataSubRecord.java | 498 +++++++++++++ .../poi/hssf/record/DrawingGroupRecord.java | 30 + .../apache/poi/hssf/record/DrawingRecord.java | 97 +++ .../record/DrawingRecordForBiffViewer.java | 35 + .../hssf/record/DrawingSelectionRecord.java | 30 + .../apache/poi/hssf/record/EndSubRecord.java | 176 +++++ .../poi/hssf/record/EscherAggregate.java | 696 ++++++++++++++++++ .../poi/hssf/record/GroupMarkerSubRecord.java | 176 +++++ .../org/apache/poi/hssf/record/ObjRecord.java | 227 ++++++ .../apache/poi/hssf/record/RecordFactory.java | 17 +- .../org/apache/poi/hssf/record/SubRecord.java | 98 +++ .../poi/hssf/record/TextObjectBaseRecord.java | 519 +++++++++++++ .../poi/hssf/record/TextObjectRecord.java | 216 ++++++ .../apache/poi/hssf/record/UnknownRecord.java | 13 +- 15 files changed, 3083 insertions(+), 11 deletions(-) create mode 100644 src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java create mode 100644 src/java/org/apache/poi/hssf/record/CommonObjectDataSubRecord.java create mode 100644 src/java/org/apache/poi/hssf/record/DrawingGroupRecord.java create mode 100644 src/java/org/apache/poi/hssf/record/DrawingRecord.java create mode 100644 src/java/org/apache/poi/hssf/record/DrawingRecordForBiffViewer.java create mode 100644 src/java/org/apache/poi/hssf/record/DrawingSelectionRecord.java create mode 100644 src/java/org/apache/poi/hssf/record/EndSubRecord.java create mode 100644 src/java/org/apache/poi/hssf/record/EscherAggregate.java create mode 100644 src/java/org/apache/poi/hssf/record/GroupMarkerSubRecord.java create mode 100644 src/java/org/apache/poi/hssf/record/ObjRecord.java create mode 100644 src/java/org/apache/poi/hssf/record/SubRecord.java create mode 100644 src/java/org/apache/poi/hssf/record/TextObjectBaseRecord.java create mode 100644 src/java/org/apache/poi/hssf/record/TextObjectRecord.java diff --git a/src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java b/src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java new file mode 100644 index 000000000..59d85acff --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java @@ -0,0 +1,266 @@ + +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" and + * "Apache POI" must not be used to endorse or promote products + * derived from this software without prior written permission. For + * written permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * "Apache POI", nor may "Apache" appear in their name, without + * prior written permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ + + +package org.apache.poi.hssf.record; + + + +import org.apache.poi.ddf.DefaultEscherRecordFactory; +import org.apache.poi.ddf.EscherRecord; +import org.apache.poi.ddf.EscherRecordFactory; +import org.apache.poi.ddf.NullEscherSerializationListener; +import org.apache.poi.util.LittleEndian; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * The escher container record is used to hold escher records. It is abstract and + * must be subclassed for maximum benefit. + * + * @author Glen Stampoultzis (glens at apache.org) + */ +public abstract class AbstractEscherHolderRecord + extends Record +{ + private static final boolean DESERIALISE = System.getProperty("poi.deserialize.escher") != null; + + private List escherRecords; + private byte[] rawData; + + + public AbstractEscherHolderRecord() + { + escherRecords = new ArrayList(); + } + + /** + * Constructs a Bar record and sets its fields appropriately. + * + * @param id id must be 0x1017 or an exception + * will be throw upon validation + * @param size size the size of the data area of the record + * @param data data of the record (should not contain sid/len) + */ + + public AbstractEscherHolderRecord(short id, short size, byte [] data) + { + super(id, size, data); + + } + + /** + * Constructs a Bar record and sets its fields appropriately. + * + * @param id id must be 0x1017 or an exception + * will be throw upon validation + * @param size size the size of the data area of the record + * @param data data of the record (should not contain sid/len) + * @param offset of the record's data + */ + + public AbstractEscherHolderRecord(short id, short size, byte [] data, int offset) + { + super(id, size, data, offset); + + } + + /** + * Checks the sid matches the expected side for this record + * + * @param id the expected sid. + */ + protected void validateSid(short id) + { + if (id != getSid()) + { + throw new RecordFormatException("Not a Bar record"); + } + } + + protected void fillFields(byte [] data, short size, int offset) + { + escherRecords = new ArrayList(); + if (! DESERIALISE ) + { + rawData = new byte[size]; + System.arraycopy(data, offset, rawData, 0, size); + } + else + { + EscherRecordFactory recordFactory = new DefaultEscherRecordFactory(); + int pos = offset; + while ( pos < offset + size ) + { + EscherRecord r = recordFactory.createRecord(data, pos); + int bytesRead = r.fillFields(data, pos, recordFactory ); + escherRecords.add(r); + pos += bytesRead; + } + } + } + + public String toString() + { + StringBuffer buffer = new StringBuffer(); + + final String nl = System.getProperty("line.separator"); + buffer.append("[" + getRecordName() + "]" + nl); + for ( Iterator iterator = escherRecords.iterator(); iterator.hasNext(); ) + { + EscherRecord r = (EscherRecord) iterator.next(); + buffer.append(r.toString()); + } + buffer.append("[/" + getRecordName() + "]" + nl); + + return buffer.toString(); + } + + protected abstract String getRecordName(); + + public int serialize(int offset, byte[] data) + { + if (escherRecords.size() == 0 && rawData != null) + { + System.arraycopy( rawData, 0, data, offset, rawData.length); + return rawData.length; + } + else + { + collapseShapeInformation(); + + LittleEndian.putShort(data, 0 + offset, getSid()); + LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize() - 4)); + + int pos = offset + 4; + for ( Iterator iterator = escherRecords.iterator(); iterator.hasNext(); ) + { + EscherRecord r = (EscherRecord) iterator.next(); + pos += r.serialize(pos, data, new NullEscherSerializationListener() ); + } + + return getRecordSize(); + } + } + + /** + * Size of record (including 4 byte header) + */ + public int getRecordSize() + { + if (escherRecords.size() == 0 && rawData != null) + { + return rawData.length; + } + else + { + collapseShapeInformation(); + + int size = 4; + for ( Iterator iterator = escherRecords.iterator(); iterator.hasNext(); ) + { + EscherRecord r = (EscherRecord) iterator.next(); + size += r.getRecordSize(); + } + return size; + } + } + + private void collapseShapeInformation() + { + + } + + public abstract short getSid(); + + public Object clone() + { + throw new IllegalStateException("Not implemented yet."); + } + + public void addEscherRecord(int index, EscherRecord element) + { + escherRecords.add( index, element ); + } + + public boolean addEscherRecord(EscherRecord element) + { + return escherRecords.add( element ); + } + + public List getEscherRecords() + { + return escherRecords; + } + + public void clearEscherRecords() + { + escherRecords.clear(); + } + + + public EscherRecord getEscherRecord(int index) + { + return (EscherRecord) escherRecords.get(index); + } + + +} // END OF CLASS + + + + diff --git a/src/java/org/apache/poi/hssf/record/CommonObjectDataSubRecord.java b/src/java/org/apache/poi/hssf/record/CommonObjectDataSubRecord.java new file mode 100644 index 000000000..65c76d604 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/CommonObjectDataSubRecord.java @@ -0,0 +1,498 @@ + +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" and + * "Apache POI" must not be used to endorse or promote products + * derived from this software without prior written permission. For + * written permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * "Apache POI", nor may "Apache" appear in their name, without + * prior written permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ + + +package org.apache.poi.hssf.record; + + + +import org.apache.poi.util.*; + +/** + * The common object data record is used to store all common preferences for an excel object. + * NOTE: This source is automatically generated please do not modify this file. Either subclass or + * remove the record in src/records/definitions. + + * @author Glen Stampoultzis (glens at apache.org) + */ +public class CommonObjectDataSubRecord + extends SubRecord +{ + public final static short sid = 0x15; + private short field_1_objectType; + public final static short OBJECT_TYPE_GROUP = 0; + public final static short OBJECT_TYPE_LINE = 1; + public final static short OBJECT_TYPE_RECTANGLE = 2; + public final static short OBJECT_TYPE_OVAL = 3; + public final static short OBJECT_TYPE_ARC = 4; + public final static short OBJECT_TYPE_CHART = 5; + public final static short OBJECT_TYPE_TEXT = 6; + public final static short OBJECT_TYPE_BUTTON = 7; + public final static short OBJECT_TYPE_PICTURE = 8; + public final static short OBJECT_TYPE_POLYGON = 9; + public final static short OBJECT_TYPE_RESERVED1 = 10; + public final static short OBJECT_TYPE_CHECKBOX = 11; + public final static short OBJECT_TYPE_OPTION_BUTTON = 12; + public final static short OBJECT_TYPE_EDIT_BOX = 13; + public final static short OBJECT_TYPE_LABEL = 14; + public final static short OBJECT_TYPE_DIALOG_BOX = 15; + public final static short OBJECT_TYPE_SPINNER = 16; + public final static short OBJECT_TYPE_SCROLL_BAR = 17; + public final static short OBJECT_TYPE_LIST_BOX = 18; + public final static short OBJECT_TYPE_GROUP_BOX = 19; + public final static short OBJECT_TYPE_COMBO_BOX = 20; + public final static short OBJECT_TYPE_RESERVED2 = 21; + public final static short OBJECT_TYPE_RESERVED3 = 22; + public final static short OBJECT_TYPE_RESERVED4 = 23; + public final static short OBJECT_TYPE_RESERVED5 = 24; + public final static short OBJECT_TYPE_COMMENT = 25; + public final static short OBJECT_TYPE_RESERVED6 = 26; + public final static short OBJECT_TYPE_RESERVED7 = 27; + public final static short OBJECT_TYPE_RESERVED8 = 28; + public final static short OBJECT_TYPE_RESERVED9 = 29; + public final static short OBJECT_TYPE_MICROSOFT_OFFICE_DRAWING = 30; + private short field_2_objectId; + private short field_3_option; + private BitField locked = new BitField(0x1); + private BitField printable = new BitField(0x10); + private BitField autofill = new BitField(0x2000); + private BitField autoline = new BitField(0x4000); + private int field_4_reserved1; + private int field_5_reserved2; + private int field_6_reserved3; + + + public CommonObjectDataSubRecord() + { + + } + + /** + * Constructs a CommonObjectData record and sets its fields appropriately. + * + * @param id id must be 0x15 or an exception + * will be throw upon validation + * @param size size the size of the data area of the record + * @param data data of the record (should not contain sid/len) + */ + + public CommonObjectDataSubRecord(short id, short size, byte [] data) + { + super(id, size, data); + + } + + /** + * Constructs a CommonObjectData record and sets its fields appropriately. + * + * @param id id must be 0x15 or an exception + * will be throw upon validation + * @param size size the size of the data area of the record + * @param data data of the record (should not contain sid/len) + * @param offset of the record's data + */ + + public CommonObjectDataSubRecord(short id, short size, byte [] data, int offset) + { + super(id, size, data, offset); + + } + + /** + * Checks the sid matches the expected side for this record + * + * @param id the expected sid. + */ + protected void validateSid(short id) + { + if (id != sid) + { + throw new RecordFormatException("Not a CommonObjectData record"); + } + } + + protected void fillFields(byte [] data, short size, int offset) + { + + int pos = 0; + field_1_objectType = LittleEndian.getShort(data, pos + 0x0 + offset); + field_2_objectId = LittleEndian.getShort(data, pos + 0x2 + offset); + field_3_option = LittleEndian.getShort(data, pos + 0x4 + offset); + field_4_reserved1 = LittleEndian.getInt(data, pos + 0x6 + offset); + field_5_reserved2 = LittleEndian.getInt(data, pos + 0xa + offset); + field_6_reserved3 = LittleEndian.getInt(data, pos + 0xe + offset); + + } + + public String toString() + { + StringBuffer buffer = new StringBuffer(); + + buffer.append("[ftCmo]\n"); + buffer.append(" .objectType = ") + .append("0x").append(HexDump.toHex( getObjectType ())) + .append(" (").append( getObjectType() ).append(" )"); + buffer.append(System.getProperty("line.separator")); + buffer.append(" .objectId = ") + .append("0x").append(HexDump.toHex( getObjectId ())) + .append(" (").append( getObjectId() ).append(" )"); + buffer.append(System.getProperty("line.separator")); + buffer.append(" .option = ") + .append("0x").append(HexDump.toHex( getOption ())) + .append(" (").append( getOption() ).append(" )"); + buffer.append(System.getProperty("line.separator")); + buffer.append(" .locked = ").append(isLocked()).append('\n'); + buffer.append(" .printable = ").append(isPrintable()).append('\n'); + buffer.append(" .autofill = ").append(isAutofill()).append('\n'); + buffer.append(" .autoline = ").append(isAutoline()).append('\n'); + buffer.append(" .reserved1 = ") + .append("0x").append(HexDump.toHex( getReserved1 ())) + .append(" (").append( getReserved1() ).append(" )"); + buffer.append(System.getProperty("line.separator")); + buffer.append(" .reserved2 = ") + .append("0x").append(HexDump.toHex( getReserved2 ())) + .append(" (").append( getReserved2() ).append(" )"); + buffer.append(System.getProperty("line.separator")); + buffer.append(" .reserved3 = ") + .append("0x").append(HexDump.toHex( getReserved3 ())) + .append(" (").append( getReserved3() ).append(" )"); + buffer.append(System.getProperty("line.separator")); + + buffer.append("[/ftCmo]\n"); + return buffer.toString(); + } + + public int serialize(int offset, byte[] data) + { + int pos = 0; + + LittleEndian.putShort(data, 0 + offset, sid); + LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize() - 4)); + + LittleEndian.putShort(data, 4 + offset + pos, field_1_objectType); + LittleEndian.putShort(data, 6 + offset + pos, field_2_objectId); + LittleEndian.putShort(data, 8 + offset + pos, field_3_option); + LittleEndian.putInt(data, 10 + offset + pos, field_4_reserved1); + LittleEndian.putInt(data, 14 + offset + pos, field_5_reserved2); + LittleEndian.putInt(data, 18 + offset + pos, field_6_reserved3); + + return getRecordSize(); + } + + /** + * Size of record (exluding 4 byte header) + */ + public int getRecordSize() + { + return 4 + 2 + 2 + 2 + 4 + 4 + 4; + } + + public short getSid() + { + return this.sid; + } + + public Object clone() { + CommonObjectDataSubRecord rec = new CommonObjectDataSubRecord(); + + rec.field_1_objectType = field_1_objectType; + rec.field_2_objectId = field_2_objectId; + rec.field_3_option = field_3_option; + rec.field_4_reserved1 = field_4_reserved1; + rec.field_5_reserved2 = field_5_reserved2; + rec.field_6_reserved3 = field_6_reserved3; + return rec; + } + + + /** + * Get the object type field for the CommonObjectData record. + * + * @return One of + * OBJECT_TYPE_GROUP + * OBJECT_TYPE_LINE + * OBJECT_TYPE_RECTANGLE + * OBJECT_TYPE_OVAL + * OBJECT_TYPE_ARC + * OBJECT_TYPE_CHART + * OBJECT_TYPE_TEXT + * OBJECT_TYPE_BUTTON + * OBJECT_TYPE_PICTURE + * OBJECT_TYPE_POLYGON + * OBJECT_TYPE_RESERVED1 + * OBJECT_TYPE_CHECKBOX + * OBJECT_TYPE_OPTION_BUTTON + * OBJECT_TYPE_EDIT_BOX + * OBJECT_TYPE_LABEL + * OBJECT_TYPE_DIALOG_BOX + * OBJECT_TYPE_SPINNER + * OBJECT_TYPE_SCROLL_BAR + * OBJECT_TYPE_LIST_BOX + * OBJECT_TYPE_GROUP_BOX + * OBJECT_TYPE_COMBO_BOX + * OBJECT_TYPE_RESERVED2 + * OBJECT_TYPE_RESERVED3 + * OBJECT_TYPE_RESERVED4 + * OBJECT_TYPE_RESERVED5 + * OBJECT_TYPE_COMMENT + * OBJECT_TYPE_RESERVED6 + * OBJECT_TYPE_RESERVED7 + * OBJECT_TYPE_RESERVED8 + * OBJECT_TYPE_RESERVED9 + * OBJECT_TYPE_MICROSOFT_OFFICE_DRAWING + */ + public short getObjectType() + { + return field_1_objectType; + } + + /** + * Set the object type field for the CommonObjectData record. + * + * @param field_1_objectType + * One of + * OBJECT_TYPE_GROUP + * OBJECT_TYPE_LINE + * OBJECT_TYPE_RECTANGLE + * OBJECT_TYPE_OVAL + * OBJECT_TYPE_ARC + * OBJECT_TYPE_CHART + * OBJECT_TYPE_TEXT + * OBJECT_TYPE_BUTTON + * OBJECT_TYPE_PICTURE + * OBJECT_TYPE_POLYGON + * OBJECT_TYPE_RESERVED1 + * OBJECT_TYPE_CHECKBOX + * OBJECT_TYPE_OPTION_BUTTON + * OBJECT_TYPE_EDIT_BOX + * OBJECT_TYPE_LABEL + * OBJECT_TYPE_DIALOG_BOX + * OBJECT_TYPE_SPINNER + * OBJECT_TYPE_SCROLL_BAR + * OBJECT_TYPE_LIST_BOX + * OBJECT_TYPE_GROUP_BOX + * OBJECT_TYPE_COMBO_BOX + * OBJECT_TYPE_RESERVED2 + * OBJECT_TYPE_RESERVED3 + * OBJECT_TYPE_RESERVED4 + * OBJECT_TYPE_RESERVED5 + * OBJECT_TYPE_COMMENT + * OBJECT_TYPE_RESERVED6 + * OBJECT_TYPE_RESERVED7 + * OBJECT_TYPE_RESERVED8 + * OBJECT_TYPE_RESERVED9 + * OBJECT_TYPE_MICROSOFT_OFFICE_DRAWING + */ + public void setObjectType(short field_1_objectType) + { + this.field_1_objectType = field_1_objectType; + } + + /** + * Get the object id field for the CommonObjectData record. + */ + public short getObjectId() + { + return field_2_objectId; + } + + /** + * Set the object id field for the CommonObjectData record. + */ + public void setObjectId(short field_2_objectId) + { + this.field_2_objectId = field_2_objectId; + } + + /** + * Get the option field for the CommonObjectData record. + */ + public short getOption() + { + return field_3_option; + } + + /** + * Set the option field for the CommonObjectData record. + */ + public void setOption(short field_3_option) + { + this.field_3_option = field_3_option; + } + + /** + * Get the reserved1 field for the CommonObjectData record. + */ + public int getReserved1() + { + return field_4_reserved1; + } + + /** + * Set the reserved1 field for the CommonObjectData record. + */ + public void setReserved1(int field_4_reserved1) + { + this.field_4_reserved1 = field_4_reserved1; + } + + /** + * Get the reserved2 field for the CommonObjectData record. + */ + public int getReserved2() + { + return field_5_reserved2; + } + + /** + * Set the reserved2 field for the CommonObjectData record. + */ + public void setReserved2(int field_5_reserved2) + { + this.field_5_reserved2 = field_5_reserved2; + } + + /** + * Get the reserved3 field for the CommonObjectData record. + */ + public int getReserved3() + { + return field_6_reserved3; + } + + /** + * Set the reserved3 field for the CommonObjectData record. + */ + public void setReserved3(int field_6_reserved3) + { + this.field_6_reserved3 = field_6_reserved3; + } + + /** + * Sets the locked field value. + * true if object is locked when sheet has been protected + */ + public void setLocked(boolean value) + { + field_3_option = locked.setShortBoolean(field_3_option, value); + } + + /** + * true if object is locked when sheet has been protected + * @return the locked field value. + */ + public boolean isLocked() + { + return locked.isSet(field_3_option); + } + + /** + * Sets the printable field value. + * object appears when printed + */ + public void setPrintable(boolean value) + { + field_3_option = printable.setShortBoolean(field_3_option, value); + } + + /** + * object appears when printed + * @return the printable field value. + */ + public boolean isPrintable() + { + return printable.isSet(field_3_option); + } + + /** + * Sets the autofill field value. + * whether object uses an automatic fill style + */ + public void setAutofill(boolean value) + { + field_3_option = autofill.setShortBoolean(field_3_option, value); + } + + /** + * whether object uses an automatic fill style + * @return the autofill field value. + */ + public boolean isAutofill() + { + return autofill.isSet(field_3_option); + } + + /** + * Sets the autoline field value. + * whether object uses an automatic line style + */ + public void setAutoline(boolean value) + { + field_3_option = autoline.setShortBoolean(field_3_option, value); + } + + /** + * whether object uses an automatic line style + * @return the autoline field value. + */ + public boolean isAutoline() + { + return autoline.isSet(field_3_option); + } + + +} // END OF CLASS + + diff --git a/src/java/org/apache/poi/hssf/record/DrawingGroupRecord.java b/src/java/org/apache/poi/hssf/record/DrawingGroupRecord.java new file mode 100644 index 000000000..9d3ab19ce --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/DrawingGroupRecord.java @@ -0,0 +1,30 @@ +package org.apache.poi.hssf.record; + +public class DrawingGroupRecord extends AbstractEscherHolderRecord +{ + public static final short sid = 0xEB; + + public DrawingGroupRecord() + { + } + + public DrawingGroupRecord( short id, short size, byte[] data ) + { + super( id, size, data ); + } + + public DrawingGroupRecord( short id, short size, byte[] data, int offset ) + { + super( id, size, data, offset ); + } + + protected String getRecordName() + { + return "MSODRAWINGGROUP"; + } + + public short getSid() + { + return sid; + } +} diff --git a/src/java/org/apache/poi/hssf/record/DrawingRecord.java b/src/java/org/apache/poi/hssf/record/DrawingRecord.java new file mode 100644 index 000000000..cb847afeb --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/DrawingRecord.java @@ -0,0 +1,97 @@ +package org.apache.poi.hssf.record; + +import org.apache.poi.util.LittleEndian; + +public class DrawingRecord extends Record +{ + public static final short sid = 0xEC; + + private byte[] recordData; + + public DrawingRecord() + { + } + + public DrawingRecord( short id, short size, byte[] data ) + { + super( id, size, data ); + } + + public DrawingRecord( short id, short size, byte[] data, int offset ) + { + super( id, size, data, offset ); + } + + /** + * Checks the sid matches the expected side for this record + * + * @param id the expected sid. + */ + protected void validateSid(short id) + { + if (id != sid) + { + throw new RecordFormatException("Not a MSODRAWING record"); + } + } + + protected void fillFields( byte[] data, short size, int offset ) + { + if (offset == 0 && size == data.length) + { + recordData = data; + } + else + { + recordData = new byte[size]; + System.arraycopy(data, offset, recordData, 0, size); + } + } + + protected void fillFields( byte[] data, short size ) + { + recordData = data; + } + + public int serialize( int offset, byte[] data ) + { + if (recordData == null) + { + recordData = new byte[ 0 ]; + } + LittleEndian.putShort(data, 0 + offset, sid); + LittleEndian.putShort(data, 2 + offset, ( short ) (recordData.length)); + if (recordData.length > 0) + { + System.arraycopy(recordData, 0, data, 4 + offset, recordData.length); + } + return getRecordSize(); + } + + public int getRecordSize() + { + int retval = 4; + + if (recordData != null) + { + retval += recordData.length; + } + return retval; + } + + public short getSid() + { + return sid; + } + + public byte[] getData() + { + return recordData; + } + + public void setData( byte[] thedata ) + { + this.recordData = thedata; + } + +} diff --git a/src/java/org/apache/poi/hssf/record/DrawingRecordForBiffViewer.java b/src/java/org/apache/poi/hssf/record/DrawingRecordForBiffViewer.java new file mode 100644 index 000000000..2dbd71418 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/DrawingRecordForBiffViewer.java @@ -0,0 +1,35 @@ +package org.apache.poi.hssf.record; + +/** + * This is purely for the biff viewer. During normal operations we don't want + * to be seeing this. + */ +public class DrawingRecordForBiffViewer + extends AbstractEscherHolderRecord +{ + public static final short sid = 0xEC; + + public DrawingRecordForBiffViewer() + { + } + + public DrawingRecordForBiffViewer( short id, short size, byte[] data ) + { + super( id, size, data ); + } + + public DrawingRecordForBiffViewer( short id, short size, byte[] data, int offset ) + { + super( id, size, data, offset ); + } + + protected String getRecordName() + { + return "MSODRAWING"; + } + + public short getSid() + { + return sid; + } +} diff --git a/src/java/org/apache/poi/hssf/record/DrawingSelectionRecord.java b/src/java/org/apache/poi/hssf/record/DrawingSelectionRecord.java new file mode 100644 index 000000000..2ae8660fc --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/DrawingSelectionRecord.java @@ -0,0 +1,30 @@ +package org.apache.poi.hssf.record; + +public class DrawingSelectionRecord extends AbstractEscherHolderRecord +{ + public static final short sid = 0xED; + + public DrawingSelectionRecord() + { + } + + public DrawingSelectionRecord( short id, short size, byte[] data ) + { + super( id, size, data ); + } + + public DrawingSelectionRecord( short id, short size, byte[] data, int offset ) + { + super( id, size, data, offset ); + } + + protected String getRecordName() + { + return "MSODRAWINGSELECTION"; + } + + public short getSid() + { + return sid; + } +} diff --git a/src/java/org/apache/poi/hssf/record/EndSubRecord.java b/src/java/org/apache/poi/hssf/record/EndSubRecord.java new file mode 100644 index 000000000..22ac23462 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/EndSubRecord.java @@ -0,0 +1,176 @@ + +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" and + * "Apache POI" must not be used to endorse or promote products + * derived from this software without prior written permission. For + * written permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * "Apache POI", nor may "Apache" appear in their name, without + * prior written permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ + + +package org.apache.poi.hssf.record; + + + +import org.apache.poi.util.*; + +/** + * The end data record is used to denote the end of the subrecords. + * NOTE: This source is automatically generated please do not modify this file. Either subclass or + * remove the record in src/records/definitions. + + * @author Glen Stampoultzis (glens at apache.org) + */ +public class EndSubRecord + extends SubRecord +{ + public final static short sid = 0x00; + + + public EndSubRecord() + { + + } + + /** + * Constructs a End record and sets its fields appropriately. + * + * @param id id must be 0x00 or an exception + * will be throw upon validation + * @param size size the size of the data area of the record + * @param data data of the record (should not contain sid/len) + */ + + public EndSubRecord(short id, short size, byte [] data) + { + super(id, size, data); + + } + + /** + * Constructs a End record and sets its fields appropriately. + * + * @param id id must be 0x00 or an exception + * will be throw upon validation + * @param size size the size of the data area of the record + * @param data data of the record (should not contain sid/len) + * @param offset of the record's data + */ + + public EndSubRecord(short id, short size, byte [] data, int offset) + { + super(id, size, data, offset); + + } + + /** + * Checks the sid matches the expected side for this record + * + * @param id the expected sid. + */ + protected void validateSid(short id) + { + if (id != sid) + { + throw new RecordFormatException("Not a End record"); + } + } + + protected void fillFields(byte [] data, short size, int offset) + { + + int pos = 0; + + } + + public String toString() + { + StringBuffer buffer = new StringBuffer(); + + buffer.append("[ftEnd]\n"); + + buffer.append("[/ftEnd]\n"); + return buffer.toString(); + } + + public int serialize(int offset, byte[] data) + { + int pos = 0; + + LittleEndian.putShort(data, 0 + offset, sid); + LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize() - 4)); + + + return getRecordSize(); + } + + /** + * Size of record (exluding 4 byte header) + */ + public int getRecordSize() + { + return 4 ; + } + + public short getSid() + { + return this.sid; + } + + public Object clone() { + EndSubRecord rec = new EndSubRecord(); + + return rec; + } + + + +} // END OF CLASS + + diff --git a/src/java/org/apache/poi/hssf/record/EscherAggregate.java b/src/java/org/apache/poi/hssf/record/EscherAggregate.java new file mode 100644 index 000000000..a45621927 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/EscherAggregate.java @@ -0,0 +1,696 @@ +package org.apache.poi.hssf.record; + +import org.apache.poi.ddf.*; +import org.apache.poi.hssf.usermodel.*; +import org.apache.poi.hssf.model.AbstractShape; +import org.apache.poi.hssf.model.TextboxShape; +import org.apache.poi.hssf.model.DrawingManager; +import org.apache.poi.hssf.model.ConvertAnchor; + +import java.util.*; + +/** + * This class is used to aggregate the MSODRAWING and OBJ record + * combinations. This is necessary due to the bizare way in which + * these records are serialized. What happens is that you get a + * combination of MSODRAWING -> OBJ -> MSODRAWING -> OBJ records + * but the escher records are serialized _across_ the MSODRAWING + * records. + *

+ * It gets even worse when you start looking at TXO records. + *

+ * So what we do with this class is aggregate lazily. That is + * we don't aggregate the MSODRAWING -> OBJ records unless we + * need to modify them. + * + * + * @author Glen Stampoultzis (glens at apache.org) + */ +public class EscherAggregate extends AbstractEscherHolderRecord +{ + public static final short sid = 9876; + + public static final short ST_MIN = (short) 0; + public static final short ST_NOT_PRIMATIVE = ST_MIN; + public static final short ST_RECTANGLE = (short) 1; + public static final short ST_ROUNDRECTANGLE = (short) 2; + public static final short ST_ELLIPSE = (short) 3; + public static final short ST_DIAMOND = (short) 4; + public static final short ST_ISOCELESTRIANGLE = (short) 5; + public static final short ST_RIGHTTRIANGLE = (short) 6; + public static final short ST_PARALLELOGRAM = (short) 7; + public static final short ST_TRAPEZOID = (short) 8; + public static final short ST_HEXAGON = (short) 9; + public static final short ST_OCTAGON = (short) 10; + public static final short ST_PLUS = (short) 11; + public static final short ST_STAR = (short) 12; + public static final short ST_ARROW = (short) 13; + public static final short ST_THICKARROW = (short) 14; + public static final short ST_HOMEPLATE = (short) 15; + public static final short ST_CUBE = (short) 16; + public static final short ST_BALLOON = (short) 17; + public static final short ST_SEAL = (short) 18; + public static final short ST_ARC = (short) 19; + public static final short ST_LINE = (short) 20; + public static final short ST_PLAQUE = (short) 21; + public static final short ST_CAN = (short) 22; + public static final short ST_DONUT = (short) 23; + public static final short ST_TEXTSIMPLE = (short) 24; + public static final short ST_TEXTOCTAGON = (short) 25; + public static final short ST_TEXTHEXAGON = (short) 26; + public static final short ST_TEXTCURVE = (short) 27; + public static final short ST_TEXTWAVE = (short) 28; + public static final short ST_TEXTRING = (short) 29; + public static final short ST_TEXTONCURVE = (short) 30; + public static final short ST_TEXTONRING = (short) 31; + public static final short ST_STRAIGHTCONNECTOR1 = (short) 32; + public static final short ST_BENTCONNECTOR2 = (short) 33; + public static final short ST_BENTCONNECTOR3 = (short) 34; + public static final short ST_BENTCONNECTOR4 = (short) 35; + public static final short ST_BENTCONNECTOR5 = (short) 36; + public static final short ST_CURVEDCONNECTOR2 = (short) 37; + public static final short ST_CURVEDCONNECTOR3 = (short) 38; + public static final short ST_CURVEDCONNECTOR4 = (short) 39; + public static final short ST_CURVEDCONNECTOR5 = (short) 40; + public static final short ST_CALLOUT1 = (short) 41; + public static final short ST_CALLOUT2 = (short) 42; + public static final short ST_CALLOUT3 = (short) 43; + public static final short ST_ACCENTCALLOUT1 = (short) 44; + public static final short ST_ACCENTCALLOUT2 = (short) 45; + public static final short ST_ACCENTCALLOUT3 = (short) 46; + public static final short ST_BORDERCALLOUT1 = (short) 47; + public static final short ST_BORDERCALLOUT2 = (short) 48; + public static final short ST_BORDERCALLOUT3 = (short) 49; + public static final short ST_ACCENTBORDERCALLOUT1 = (short) 50; + public static final short ST_ACCENTBORDERCALLOUT2 = (short) 51; + public static final short ST_ACCENTBORDERCALLOUT3 = (short) 52; + public static final short ST_RIBBON = (short) 53; + public static final short ST_RIBBON2 = (short) 54; + public static final short ST_CHEVRON = (short) 55; + public static final short ST_PENTAGON = (short) 56; + public static final short ST_NOSMOKING = (short) 57; + public static final short ST_SEAL8 = (short) 58; + public static final short ST_SEAL16 = (short) 59; + public static final short ST_SEAL32 = (short) 60; + public static final short ST_WEDGERECTCALLOUT = (short) 61; + public static final short ST_WEDGERRECTCALLOUT = (short) 62; + public static final short ST_WEDGEELLIPSECALLOUT = (short) 63; + public static final short ST_WAVE = (short) 64; + public static final short ST_FOLDEDCORNER = (short) 65; + public static final short ST_LEFTARROW = (short) 66; + public static final short ST_DOWNARROW = (short) 67; + public static final short ST_UPARROW = (short) 68; + public static final short ST_LEFTRIGHTARROW = (short) 69; + public static final short ST_UPDOWNARROW = (short) 70; + public static final short ST_IRREGULARSEAL1 = (short) 71; + public static final short ST_IRREGULARSEAL2 = (short) 72; + public static final short ST_LIGHTNINGBOLT = (short) 73; + public static final short ST_HEART = (short) 74; + public static final short ST_PICTUREFRAME = (short) 75; + public static final short ST_QUADARROW = (short) 76; + public static final short ST_LEFTARROWCALLOUT = (short) 77; + public static final short ST_RIGHTARROWCALLOUT = (short) 78; + public static final short ST_UPARROWCALLOUT = (short) 79; + public static final short ST_DOWNARROWCALLOUT = (short) 80; + public static final short ST_LEFTRIGHTARROWCALLOUT = (short) 81; + public static final short ST_UPDOWNARROWCALLOUT = (short) 82; + public static final short ST_QUADARROWCALLOUT = (short) 83; + public static final short ST_BEVEL = (short) 84; + public static final short ST_LEFTBRACKET = (short) 85; + public static final short ST_RIGHTBRACKET = (short) 86; + public static final short ST_LEFTBRACE = (short) 87; + public static final short ST_RIGHTBRACE = (short) 88; + public static final short ST_LEFTUPARROW = (short) 89; + public static final short ST_BENTUPARROW = (short) 90; + public static final short ST_BENTARROW = (short) 91; + public static final short ST_SEAL24 = (short) 92; + public static final short ST_STRIPEDRIGHTARROW = (short) 93; + public static final short ST_NOTCHEDRIGHTARROW = (short) 94; + public static final short ST_BLOCKARC = (short) 95; + public static final short ST_SMILEYFACE = (short) 96; + public static final short ST_VERTICALSCROLL = (short) 97; + public static final short ST_HORIZONTALSCROLL = (short) 98; + public static final short ST_CIRCULARARROW = (short) 99; + public static final short ST_NOTCHEDCIRCULARARROW = (short) 100; + public static final short ST_UTURNARROW = (short) 101; + public static final short ST_CURVEDRIGHTARROW = (short) 102; + public static final short ST_CURVEDLEFTARROW = (short) 103; + public static final short ST_CURVEDUPARROW = (short) 104; + public static final short ST_CURVEDDOWNARROW = (short) 105; + public static final short ST_CLOUDCALLOUT = (short) 106; + public static final short ST_ELLIPSERIBBON = (short) 107; + public static final short ST_ELLIPSERIBBON2 = (short) 108; + public static final short ST_FLOWCHARTPROCESS = (short) 109; + public static final short ST_FLOWCHARTDECISION = (short) 110; + public static final short ST_FLOWCHARTINPUTOUTPUT = (short) 111; + public static final short ST_FLOWCHARTPREDEFINEDPROCESS = (short) 112; + public static final short ST_FLOWCHARTINTERNALSTORAGE = (short) 113; + public static final short ST_FLOWCHARTDOCUMENT = (short) 114; + public static final short ST_FLOWCHARTMULTIDOCUMENT = (short) 115; + public static final short ST_FLOWCHARTTERMINATOR = (short) 116; + public static final short ST_FLOWCHARTPREPARATION = (short) 117; + public static final short ST_FLOWCHARTMANUALINPUT = (short) 118; + public static final short ST_FLOWCHARTMANUALOPERATION = (short) 119; + public static final short ST_FLOWCHARTCONNECTOR = (short) 120; + public static final short ST_FLOWCHARTPUNCHEDCARD = (short) 121; + public static final short ST_FLOWCHARTPUNCHEDTAPE = (short) 122; + public static final short ST_FLOWCHARTSUMMINGJUNCTION = (short) 123; + public static final short ST_FLOWCHARTOR = (short) 124; + public static final short ST_FLOWCHARTCOLLATE = (short) 125; + public static final short ST_FLOWCHARTSORT = (short) 126; + public static final short ST_FLOWCHARTEXTRACT = (short) 127; + public static final short ST_FLOWCHARTMERGE = (short) 128; + public static final short ST_FLOWCHARTOFFLINESTORAGE = (short) 129; + public static final short ST_FLOWCHARTONLINESTORAGE = (short) 130; + public static final short ST_FLOWCHARTMAGNETICTAPE = (short) 131; + public static final short ST_FLOWCHARTMAGNETICDISK = (short) 132; + public static final short ST_FLOWCHARTMAGNETICDRUM = (short) 133; + public static final short ST_FLOWCHARTDISPLAY = (short) 134; + public static final short ST_FLOWCHARTDELAY = (short) 135; + public static final short ST_TEXTPLAINTEXT = (short) 136; + public static final short ST_TEXTSTOP = (short) 137; + public static final short ST_TEXTTRIANGLE = (short) 138; + public static final short ST_TEXTTRIANGLEINVERTED = (short) 139; + public static final short ST_TEXTCHEVRON = (short) 140; + public static final short ST_TEXTCHEVRONINVERTED = (short) 141; + public static final short ST_TEXTRINGINSIDE = (short) 142; + public static final short ST_TEXTRINGOUTSIDE = (short) 143; + public static final short ST_TEXTARCHUPCURVE = (short) 144; + public static final short ST_TEXTARCHDOWNCURVE = (short) 145; + public static final short ST_TEXTCIRCLECURVE = (short) 146; + public static final short ST_TEXTBUTTONCURVE = (short) 147; + public static final short ST_TEXTARCHUPPOUR = (short) 148; + public static final short ST_TEXTARCHDOWNPOUR = (short) 149; + public static final short ST_TEXTCIRCLEPOUR = (short) 150; + public static final short ST_TEXTBUTTONPOUR = (short) 151; + public static final short ST_TEXTCURVEUP = (short) 152; + public static final short ST_TEXTCURVEDOWN = (short) 153; + public static final short ST_TEXTCASCADEUP = (short) 154; + public static final short ST_TEXTCASCADEDOWN = (short) 155; + public static final short ST_TEXTWAVE1 = (short) 156; + public static final short ST_TEXTWAVE2 = (short) 157; + public static final short ST_TEXTWAVE3 = (short) 158; + public static final short ST_TEXTWAVE4 = (short) 159; + public static final short ST_TEXTINFLATE = (short) 160; + public static final short ST_TEXTDEFLATE = (short) 161; + public static final short ST_TEXTINFLATEBOTTOM = (short) 162; + public static final short ST_TEXTDEFLATEBOTTOM = (short) 163; + public static final short ST_TEXTINFLATETOP = (short) 164; + public static final short ST_TEXTDEFLATETOP = (short) 165; + public static final short ST_TEXTDEFLATEINFLATE = (short) 166; + public static final short ST_TEXTDEFLATEINFLATEDEFLATE = (short) 167; + public static final short ST_TEXTFADERIGHT = (short) 168; + public static final short ST_TEXTFADELEFT = (short) 169; + public static final short ST_TEXTFADEUP = (short) 170; + public static final short ST_TEXTFADEDOWN = (short) 171; + public static final short ST_TEXTSLANTUP = (short) 172; + public static final short ST_TEXTSLANTDOWN = (short) 173; + public static final short ST_TEXTCANUP = (short) 174; + public static final short ST_TEXTCANDOWN = (short) 175; + public static final short ST_FLOWCHARTALTERNATEPROCESS = (short) 176; + public static final short ST_FLOWCHARTOFFPAGECONNECTOR = (short) 177; + public static final short ST_CALLOUT90 = (short) 178; + public static final short ST_ACCENTCALLOUT90 = (short) 179; + public static final short ST_BORDERCALLOUT90 = (short) 180; + public static final short ST_ACCENTBORDERCALLOUT90 = (short) 181; + public static final short ST_LEFTRIGHTUPARROW = (short) 182; + public static final short ST_SUN = (short) 183; + public static final short ST_MOON = (short) 184; + public static final short ST_BRACKETPAIR = (short) 185; + public static final short ST_BRACEPAIR = (short) 186; + public static final short ST_SEAL4 = (short) 187; + public static final short ST_DOUBLEWAVE = (short) 188; + public static final short ST_ACTIONBUTTONBLANK = (short) 189; + public static final short ST_ACTIONBUTTONHOME = (short) 190; + public static final short ST_ACTIONBUTTONHELP = (short) 191; + public static final short ST_ACTIONBUTTONINFORMATION = (short) 192; + public static final short ST_ACTIONBUTTONFORWARDNEXT = (short) 193; + public static final short ST_ACTIONBUTTONBACKPREVIOUS = (short) 194; + public static final short ST_ACTIONBUTTONEND = (short) 195; + public static final short ST_ACTIONBUTTONBEGINNING = (short) 196; + public static final short ST_ACTIONBUTTONRETURN = (short) 197; + public static final short ST_ACTIONBUTTONDOCUMENT = (short) 198; + public static final short ST_ACTIONBUTTONSOUND = (short) 199; + public static final short ST_ACTIONBUTTONMOVIE = (short) 200; + public static final short ST_HOSTCONTROL = (short) 201; + public static final short ST_TEXTBOX = (short) 202; + public static final short ST_NIL = (short) 0x0FFF; + + protected HSSFPatriarch patriarch; + + /** Maps shape container objects to their OBJ records */ + private Map shapeToObj = new HashMap(); + private DrawingManager drawingManager; + private short drawingGroupId; + + public EscherAggregate( DrawingManager drawingManager ) + { + this.drawingManager = drawingManager; + } + + /** + * @return Returns the current sid. + */ + public short getSid() + { + return sid; + } + + /** + * Unused since this is an aggregate record. Use createAggregate(). + * + * @see #createAggregate + */ + protected void fillFields( byte[] data, short size, int offset ) + { + throw new IllegalStateException( "Should not reach here" ); + } + + /** + * Calculates the string representation of this record. This is + * simply a dump of all the records. + */ + public String toString() + { + String nl = System.getProperty( "line.separtor" ); + + StringBuffer result = new StringBuffer(); + result.append( '[' ).append( getRecordName() ).append( ']' + nl ); + for ( Iterator iterator = getEscherRecords().iterator(); iterator.hasNext(); ) + { + EscherRecord escherRecord = (EscherRecord) iterator.next(); + result.append( escherRecord.toString() ); + } + result.append( "[/" ).append( getRecordName() ).append( ']' + nl ); + + return result.toString(); + } + + /** + * Collapses the drawing records into an aggregate. + */ + public static EscherAggregate createAggregate( List records, int locFirstDrawingRecord, DrawingManager drawingManager ) + { + // Keep track of any shape records created so we can match them back to the object id's. + // Textbox objects are also treated as shape objects. + final List shapeRecords = new ArrayList(); + EscherRecordFactory recordFactory = new DefaultEscherRecordFactory() + { + public EscherRecord createRecord( byte[] data, int offset ) + { + EscherRecord r = super.createRecord( data, offset ); + if ( r.getRecordId() == EscherClientDataRecord.RECORD_ID || r.getRecordId() == EscherTextboxRecord.RECORD_ID ) + { + shapeRecords.add( r ); + } + return r; + } + }; + + // Calculate the size of the buffer + EscherAggregate agg = new EscherAggregate(drawingManager); + int loc = locFirstDrawingRecord; + int dataSize = 0; + while ( loc + 1 < records.size() + && sid( records, loc ) == DrawingRecord.sid + && isObjectRecord( records, loc + 1 ) ) + { + dataSize += ( (DrawingRecord) records.get( loc ) ).getData().length; + loc += 2; + } + + // Create one big buffer + byte buffer[] = new byte[dataSize]; + int offset = 0; + loc = locFirstDrawingRecord; + while ( loc + 1 < records.size() + && sid( records, loc ) == DrawingRecord.sid + && isObjectRecord( records, loc + 1 ) ) + { + DrawingRecord drawingRecord = (DrawingRecord) records.get( loc ); + System.arraycopy( drawingRecord.getData(), 0, buffer, offset, drawingRecord.getData().length ); + offset += drawingRecord.getData().length; + loc += 2; + } + + // Decode the shapes + // agg.escherRecords = new ArrayList(); + int pos = 0; + while ( pos < dataSize ) + { + EscherRecord r = recordFactory.createRecord( buffer, pos ); + int bytesRead = r.fillFields( buffer, pos, recordFactory ); + agg.addEscherRecord( r ); + pos += bytesRead; + } + + // Associate the object records with the shapes + loc = locFirstDrawingRecord; + int shapeIndex = 0; + agg.shapeToObj = new HashMap(); + while ( loc + 1 < records.size() + && sid( records, loc ) == DrawingRecord.sid + && isObjectRecord( records, loc + 1 ) ) + { + Record objRecord = (Record) records.get( loc + 1 ); + agg.shapeToObj.put( shapeRecords.get( shapeIndex++ ), objRecord ); + loc += 2; + } + + return agg; + + } + + /** + * Serializes this aggregate to a byte array. Since this is an aggregate + * record it will effectively serialize the aggregated records. + * + * @param offset The offset into the start of the array. + * @param data The byte array to serialize to. + * @return The number of bytes serialized. + */ + public int serialize( int offset, byte[] data ) + { + convertUserModelToRecords(); + + // Determine buffer size + List records = getEscherRecords(); + int size = getEscherRecordSize( records ); + byte[] buffer = new byte[size]; + + + // Serialize escher records into one big data structure and keep note of ending offsets. + final List spEndingOffsets = new ArrayList(); + final List shapes = new ArrayList(); + int pos = 0; + for ( Iterator iterator = records.iterator(); iterator.hasNext(); ) + { + EscherRecord e = (EscherRecord) iterator.next(); + pos += e.serialize( pos, buffer, new EscherSerializationListener() + { + public void beforeRecordSerialize( int offset, short recordId, EscherRecord record ) + { + } + + public void afterRecordSerialize( int offset, short recordId, int size, EscherRecord record ) + { + if ( recordId == EscherClientDataRecord.RECORD_ID || recordId == EscherTextboxRecord.RECORD_ID ) + { + spEndingOffsets.add( new Integer( offset ) ); + shapes.add( record ); + } + } + } ); + } + // todo: fix this + shapes.add( 0, null ); + spEndingOffsets.add( 0, null ); + + // Split escher records into separate MSODRAWING and OBJ, TXO records. (We don't break on + // the first one because it's the patriach). + pos = offset; + for ( int i = 1; i < shapes.size(); i++ ) + { + int endOffset = ( (Integer) spEndingOffsets.get( i ) ).intValue() - 1; + int startOffset; + if ( i == 1 ) + startOffset = 0; + else + startOffset = ( (Integer) spEndingOffsets.get( i - 1 ) ).intValue(); + + // Create and write a new MSODRAWING record + DrawingRecord drawing = new DrawingRecord(); + byte[] drawingData = new byte[endOffset - startOffset + 1]; + System.arraycopy( buffer, startOffset, drawingData, 0, drawingData.length ); + drawing.setData( drawingData ); + int temp = drawing.serialize( pos, data ); + pos += temp; + + // Write the matching OBJ record + Record obj = (Record) shapeToObj.get( shapes.get( i ) ); + temp = obj.serialize( pos, data ); + pos += temp; + + } + + int bytesWritten = pos - offset; + if ( bytesWritten != getRecordSize() ) + throw new RecordFormatException( bytesWritten + " bytes written but getRecordSize() reports " + getRecordSize() ); + return bytesWritten; + } + + /** + * How many bytes do the raw escher records contain. + * @param records List of escher records + * @return the number of bytes + */ + private int getEscherRecordSize( List records ) + { + int size = 0; + for ( Iterator iterator = records.iterator(); iterator.hasNext(); ) + size += ( (EscherRecord) iterator.next() ).getRecordSize(); + return size; + } + + /** + * The number of bytes required to serialize this record. + */ + public int getRecordSize() + { + convertUserModelToRecords(); + List records = getEscherRecords(); + int rawEscherSize = getEscherRecordSize( records ); + int drawingRecordSize = rawEscherSize + ( shapeToObj.size() ) * 4; + int objRecordSize = 0; + for ( Iterator iterator = shapeToObj.values().iterator(); iterator.hasNext(); ) + { + Record r = (Record) iterator.next(); + objRecordSize += r.getRecordSize(); + } + return drawingRecordSize + objRecordSize; + } + + /** + * Associates an escher record to an OBJ record or a TXO record. + */ + public Object assoicateShapeToObjRecord( EscherRecord r, Record objRecord ) + { + return shapeToObj.put( r, objRecord ); + } + + public HSSFPatriarch getPatriarch() + { + return patriarch; + } + + public void setPatriarch( HSSFPatriarch patriarch ) + { + this.patriarch = patriarch; + } + + public void clear() + { + clearEscherRecords(); + shapeToObj.clear(); +// lastShapeId = 1024; + } + + protected String getRecordName() + { + return "ESCHERAGGREGATE"; + } + + // =============== Private methods ======================== + + private static boolean isObjectRecord( List records, int loc ) + { + return sid( records, loc ) == ObjRecord.sid || sid( records, loc ) == TextObjectRecord.sid; + } + + private void convertUserModelToRecords() + { + if ( patriarch != null ) + { + shapeToObj.clear(); + clearEscherRecords(); + if ( patriarch.getChildren().size() != 0 ) + { + convertPatriarch( patriarch ); + EscherContainerRecord dgContainer = (EscherContainerRecord) getEscherRecord( 0 ); + EscherContainerRecord spgrContainer = null; + for ( int i = 0; i < dgContainer.getChildRecords().size(); i++ ) + if ( dgContainer.getChild( i ).getRecordId() == EscherContainerRecord.SPGR_CONTAINER ) + spgrContainer = (EscherContainerRecord) dgContainer.getChild( i ); + convertShapes( patriarch, spgrContainer, shapeToObj ); + + patriarch = null; + } + } + } + + private void convertShapes( HSSFShapeContainer parent, EscherContainerRecord escherParent, Map shapeToObj ) + { + if ( escherParent == null ) throw new IllegalArgumentException( "Parent record required" ); + + List shapes = parent.getChildren(); + for ( Iterator iterator = shapes.iterator(); iterator.hasNext(); ) + { + HSSFShape shape = (HSSFShape) iterator.next(); + if ( shape instanceof HSSFShapeGroup ) + { + convertGroup( (HSSFShapeGroup) shape, escherParent, shapeToObj ); + } + else + { + AbstractShape shapeModel = AbstractShape.createShape( + shape, + drawingManager.allocateShapeId(drawingGroupId) ); + shapeToObj.put( findClientData( shapeModel.getSpContainer() ), shapeModel.getObjRecord() ); + if ( shapeModel instanceof TextboxShape ) + { + EscherRecord escherTextbox = ( (TextboxShape) shapeModel ).getEscherTextbox(); + shapeToObj.put( escherTextbox, ( (TextboxShape) shapeModel ).getTextObjectRecord() ); + // escherParent.addChildRecord(escherTextbox); + } + escherParent.addChildRecord( shapeModel.getSpContainer() ); + } + } + } + + private void convertGroup( HSSFShapeGroup shape, EscherContainerRecord escherParent, Map shapeToObj ) + { + EscherContainerRecord spgrContainer = new EscherContainerRecord(); + EscherContainerRecord spContainer = new EscherContainerRecord(); + EscherSpgrRecord spgr = new EscherSpgrRecord(); + EscherSpRecord sp = new EscherSpRecord(); + EscherOptRecord opt = new EscherOptRecord(); + EscherRecord anchor; + EscherClientDataRecord clientData = new EscherClientDataRecord(); + + spgrContainer.setRecordId( EscherContainerRecord.SPGR_CONTAINER ); + spgrContainer.setOptions( (short) 0x000F ); + spContainer.setRecordId( EscherContainerRecord.SP_CONTAINER ); + spContainer.setOptions( (short) 0x000F ); + spgr.setRecordId( EscherSpgrRecord.RECORD_ID ); + spgr.setOptions( (short) 0x0001 ); + spgr.setRectX1( shape.getX1() ); + spgr.setRectY1( shape.getY1() ); + spgr.setRectX2( shape.getX2() ); + spgr.setRectY2( shape.getY2() ); + sp.setRecordId( EscherSpRecord.RECORD_ID ); + sp.setOptions( (short) 0x0002 ); + int shapeId = drawingManager.allocateShapeId(drawingGroupId); + sp.setShapeId( shapeId ); + if (shape.getAnchor() instanceof HSSFClientAnchor) + sp.setFlags( EscherSpRecord.FLAG_GROUP | EscherSpRecord.FLAG_HAVEANCHOR ); + else + sp.setFlags( EscherSpRecord.FLAG_GROUP | EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_CHILD ); + opt.setRecordId( EscherOptRecord.RECORD_ID ); + opt.setOptions( (short) 0x0023 ); + opt.addEscherProperty( new EscherBoolProperty( EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x00040004 ) ); + opt.addEscherProperty( new EscherBoolProperty( EscherProperties.GROUPSHAPE__PRINT, 0x00080000 ) ); + + anchor = ConvertAnchor.createAnchor( shape.getAnchor() ); +// clientAnchor.setCol1( ( (HSSFClientAnchor) shape.getAnchor() ).getCol1() ); +// clientAnchor.setRow1( (short) ( (HSSFClientAnchor) shape.getAnchor() ).getRow1() ); +// clientAnchor.setDx1( (short) shape.getAnchor().getDx1() ); +// clientAnchor.setDy1( (short) shape.getAnchor().getDy1() ); +// clientAnchor.setCol2( ( (HSSFClientAnchor) shape.getAnchor() ).getCol2() ); +// clientAnchor.setRow2( (short) ( (HSSFClientAnchor) shape.getAnchor() ).getRow2() ); +// clientAnchor.setDx2( (short) shape.getAnchor().getDx2() ); +// clientAnchor.setDy2( (short) shape.getAnchor().getDy2() ); + clientData.setRecordId( EscherClientDataRecord.RECORD_ID ); + clientData.setOptions( (short) 0x0000 ); + + spgrContainer.addChildRecord( spContainer ); + spContainer.addChildRecord( spgr ); + spContainer.addChildRecord( sp ); + spContainer.addChildRecord( opt ); + spContainer.addChildRecord( anchor ); + spContainer.addChildRecord( clientData ); + + ObjRecord obj = new ObjRecord(); + CommonObjectDataSubRecord cmo = new CommonObjectDataSubRecord(); + cmo.setObjectType( CommonObjectDataSubRecord.OBJECT_TYPE_GROUP ); + cmo.setObjectId( (short) ( shapeId ) ); + cmo.setLocked( true ); + cmo.setPrintable( true ); + cmo.setAutofill( true ); + cmo.setAutoline( true ); + GroupMarkerSubRecord gmo = new GroupMarkerSubRecord(); + EndSubRecord end = new EndSubRecord(); + obj.addSubRecord( cmo ); + obj.addSubRecord( gmo ); + obj.addSubRecord( end ); + shapeToObj.put( clientData, obj ); + + escherParent.addChildRecord( spgrContainer ); + + convertShapes( shape, spgrContainer, shapeToObj ); + + } + + private EscherRecord findClientData( EscherContainerRecord spContainer ) + { + for ( Iterator iterator = spContainer.getChildRecords().iterator(); iterator.hasNext(); ) + { + EscherRecord r = (EscherRecord) iterator.next(); + if ( r.getRecordId() == EscherClientDataRecord.RECORD_ID ) + return r; + } + throw new IllegalArgumentException( "Can not find client data record" ); + } + + private void convertPatriarch( HSSFPatriarch patriarch ) + { + EscherContainerRecord dgContainer = new EscherContainerRecord(); + EscherDgRecord dg; + EscherContainerRecord spgrContainer = new EscherContainerRecord(); + EscherContainerRecord spContainer1 = new EscherContainerRecord(); + EscherSpgrRecord spgr = new EscherSpgrRecord(); + EscherSpRecord sp1 = new EscherSpRecord(); + + dgContainer.setRecordId( EscherContainerRecord.DG_CONTAINER ); + dgContainer.setOptions( (short) 0x000F ); + dg = drawingManager.createDgRecord(); + drawingGroupId = dg.getDrawingGroupId(); +// dg.setOptions( (short) ( drawingId << 4 ) ); +// dg.setNumShapes( getNumberOfShapes( patriarch ) ); +// dg.setLastMSOSPID( 0 ); // populated after all shape id's are assigned. + spgrContainer.setRecordId( EscherContainerRecord.SPGR_CONTAINER ); + spgrContainer.setOptions( (short) 0x000F ); + spContainer1.setRecordId( EscherContainerRecord.SP_CONTAINER ); + spContainer1.setOptions( (short) 0x000F ); + spgr.setRecordId( EscherSpgrRecord.RECORD_ID ); + spgr.setOptions( (short) 0x0001 ); // don't know what the 1 is for. + spgr.setRectX1( patriarch.getX1() ); + spgr.setRectY1( patriarch.getY1() ); + spgr.setRectX2( patriarch.getX2() ); + spgr.setRectY2( patriarch.getY2() ); + sp1.setRecordId( EscherSpRecord.RECORD_ID ); + sp1.setOptions( (short) 0x0002 ); + sp1.setShapeId( drawingManager.allocateShapeId(dg.getDrawingGroupId()) ); + sp1.setFlags( EscherSpRecord.FLAG_GROUP | EscherSpRecord.FLAG_PATRIARCH ); + + dgContainer.addChildRecord( dg ); + dgContainer.addChildRecord( spgrContainer ); + spgrContainer.addChildRecord( spContainer1 ); + spContainer1.addChildRecord( spgr ); + spContainer1.addChildRecord( sp1 ); + + addEscherRecord( dgContainer ); + } + + /** Retrieve the number of shapes (including the patriarch). */ +// private int getNumberOfShapes( HSSFPatriarch patriarch ) +// { +// return patriarch.countOfAllChildren(); +// } + + private static short sid( List records, int loc ) + { + return ( (Record) records.get( loc ) ).getSid(); + } + + +} diff --git a/src/java/org/apache/poi/hssf/record/GroupMarkerSubRecord.java b/src/java/org/apache/poi/hssf/record/GroupMarkerSubRecord.java new file mode 100644 index 000000000..56209aefd --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/GroupMarkerSubRecord.java @@ -0,0 +1,176 @@ + +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" and + * "Apache POI" must not be used to endorse or promote products + * derived from this software without prior written permission. For + * written permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * "Apache POI", nor may "Apache" appear in their name, without + * prior written permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ + + +package org.apache.poi.hssf.record; + + + +import org.apache.poi.util.*; + +/** + * The group marker record is used as a position holder for groups. + + * @author Glen Stampoultzis (glens at apache.org) + */ +public class GroupMarkerSubRecord + extends SubRecord +{ + public final static short sid = 0x06; + + private byte[] reserved = new byte[0]; // would really love to know what goes in here. + + public GroupMarkerSubRecord() + { + + } + + /** + * Constructs a group marker record and sets its fields appropriately. + * + * @param id id must be 0x00 or an exception + * will be throw upon validation + * @param size size the size of the data area of the record + * @param data data of the record (should not contain sid/len) + */ + + public GroupMarkerSubRecord(short id, short size, byte [] data) + { + super(id, size, data); + + } + + /** + * Constructs a group marker record and sets its fields appropriately. + * + * @param id id must be 0x00 or an exception + * will be throw upon validation + * @param size size the size of the data area of the record + * @param data data of the record (should not contain sid/len) + * @param offset of the record's data + */ + + public GroupMarkerSubRecord(short id, short size, byte [] data, int offset) + { + super(id, size, data, offset); + + } + + /** + * Checks the sid matches the expected side for this record + * + * @param id the expected sid. + */ + protected void validateSid(short id) + { + if (id != sid) + { + throw new RecordFormatException("Not a Group Marker record"); + } + } + + protected void fillFields(byte [] data, short size, int offset) + { +// int pos = 0; + reserved = new byte[size]; + System.arraycopy(data, offset, reserved, 0, size); + } + + public String toString() + { + StringBuffer buffer = new StringBuffer(); + + String nl = System.getProperty("line.separator"); + buffer.append("[ftGmo]" + nl); + buffer.append(" reserved = ").append(HexDump.toHex(reserved)).append(nl); + buffer.append("[/ftGmo]" + nl); + return buffer.toString(); + } + + public int serialize(int offset, byte[] data) + { + LittleEndian.putShort(data, 0 + offset, sid); + LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize() - 4)); + System.arraycopy(reserved, 0, data, offset + 4, getRecordSize() - 4); + + return getRecordSize(); + } + + /** + * Size of record (exluding 4 byte header) + */ + public int getRecordSize() + { + return 4 + reserved.length; + } + + public short getSid() + { + return sid; + } + + public Object clone() { + GroupMarkerSubRecord rec = new GroupMarkerSubRecord(); + rec.reserved = new byte[reserved.length]; + for ( int i = 0; i < reserved.length; i++ ) + rec.reserved[i] = reserved[i]; + return rec; + } + + + +} // END OF CLASS + + diff --git a/src/java/org/apache/poi/hssf/record/ObjRecord.java b/src/java/org/apache/poi/hssf/record/ObjRecord.java new file mode 100644 index 000000000..5939b487a --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/ObjRecord.java @@ -0,0 +1,227 @@ +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" and + * "Apache POI" must not be used to endorse or promote products + * derived from this software without prior written permission. For + * written permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * "Apache POI", nor may "Apache" appear in their name, without + * prior written permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ + + +package org.apache.poi.hssf.record; + + + +import org.apache.poi.util.*; + +import java.util.List; +import java.util.Iterator; +import java.util.ArrayList; + +/** + * The obj record is used to hold various graphic objects and controls. + * + * @author Glen Stampoultzis (glens at apache.org) + */ +public class ObjRecord + extends Record +{ + public final static short sid = 0x5D; + private List subrecords; + + //00000000 15 00 12 00 01 00 01 00 11 60 00 00 00 00 00 0D .........`...... + //00000010 26 01 00 00 00 00 00 00 00 00 &......... + + + public ObjRecord() + { + subrecords = new ArrayList(2); + } + + /** + * Constructs a OBJ record and sets its fields appropriately. + * + * @param id id must be 0x5D or an exception + * will be throw upon validation + * @param size size the size of the data area of the record + * @param data data of the record (should not contain sid/len) + */ + + public ObjRecord(short id, short size, byte [] data) + { + super(id, size, data); + } + + /** + * Constructs a obj record and sets its fields appropriately. + * + * @param id id must be 0x5D or an exception + * will be throw upon validation + * @param size size the size of the data area of the record + * @param data data of the record (should not contain sid/len) + * @param offset of the record's data + */ + public ObjRecord(short id, short size, byte[] data, int offset) + { + super(id, size, data, offset); + } + + /** + * Checks the sid matches the expected side for this record + * + * @param id the expected sid. + */ + protected void validateSid(short id) + { + if (id != sid) + { + throw new RecordFormatException("Not an OBJ record"); + } + } + + protected void fillFields(byte [] data, short size, int offset) + { + subrecords = new ArrayList(); + int pos = offset; + while (pos - offset < size) + { + short subRecordSid = LittleEndian.getShort(data, pos); + short subRecordSize = LittleEndian.getShort(data, pos + 2); + Record subRecord = SubRecord.createSubRecord(subRecordSid, subRecordSize, data, pos + 4); + subrecords.add(subRecord); + pos += 4 + subRecordSize; + } + + } + + public String toString() + { + StringBuffer buffer = new StringBuffer(); + + buffer.append("[OBJ]\n"); + for ( Iterator iterator = subrecords.iterator(); iterator.hasNext(); ) + { + Record record = (Record) iterator.next(); + buffer.append("SUBRECORD: " + record.toString()); + } + buffer.append("[/OBJ]\n"); + return buffer.toString(); + } + + public int serialize(int offset, byte[] data) + { + int pos = 0; + + LittleEndian.putShort(data, 0 + offset, sid); + LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize() - 4)); + + pos = offset + 4; + for ( Iterator iterator = subrecords.iterator(); iterator.hasNext(); ) + { + Record record = (Record) iterator.next(); + pos += record.serialize(pos, data); + } + + return getRecordSize(); + } + + /** + * Size of record (excluding 4 byte header) + */ + public int getRecordSize() + { + int size = 0; + for ( Iterator iterator = subrecords.iterator(); iterator.hasNext(); ) + { + Record record = (Record) iterator.next(); + size += record.getRecordSize(); + } + return 4 + size; + } + + public short getSid() + { + return sid; + } + + public List getSubRecords() + { + return subrecords; + } + + public void clearSubRecords() + { + subrecords.clear(); + } + + public void addSubRecord(int index, Object element) + { + subrecords.add( index, element ); + } + + public boolean addSubRecord(Object o) + { + return subrecords.add( o ); + } + + public Object clone() + { + ObjRecord rec = new ObjRecord(); + rec.subrecords = new ArrayList(); + + for ( Iterator iterator = subrecords.iterator(); iterator.hasNext(); ) + subrecords.add(( (Record) iterator.next() ).clone()); + + return rec; + } + +} // END OF CLASS + + + + diff --git a/src/java/org/apache/poi/hssf/record/RecordFactory.java b/src/java/org/apache/poi/hssf/record/RecordFactory.java index 6d6bb4031..ede6b8fbb 100644 --- a/src/java/org/apache/poi/hssf/record/RecordFactory.java +++ b/src/java/org/apache/poi/hssf/record/RecordFactory.java @@ -55,15 +55,13 @@ package org.apache.poi.hssf.record; -import java.io.InputStream; -import java.io.IOException; - -import java.util.*; - -import java.lang.reflect.Constructor; - import org.apache.poi.util.LittleEndian; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Constructor; +import java.util.*; + /** * Title: Record Factory

* Description: Takes a stream and outputs an array of Record objects.

@@ -112,6 +110,8 @@ public class RecordFactory FormulaRecord.class, BoolErrRecord.class, ExternSheetRecord.class, NameRecord.class, LeftMarginRecord.class, RightMarginRecord.class, TopMarginRecord.class, BottomMarginRecord.class, + DrawingRecord.class, DrawingGroupRecord.class, DrawingSelectionRecord.class, + ObjRecord.class, TextObjectRecord.class, PaletteRecord.class, StringRecord.class, RecalcIdRecord.class, SharedFormulaRecord.class, HorizontalPageBreakRecord.class, VerticalPageBreakRecord.class }; @@ -145,6 +145,8 @@ public class RecordFactory LeftMarginRecord.class, RightMarginRecord.class, TopMarginRecord.class, BottomMarginRecord.class, PaletteRecord.class, StringRecord.class, RecalcIdRecord.class, SharedFormulaRecord.class, + DrawingRecord.class, DrawingGroupRecord.class, DrawingSelectionRecord.class, + ObjRecord.class, TextObjectRecord.class, HorizontalPageBreakRecord.class, VerticalPageBreakRecord.class }; @@ -362,6 +364,7 @@ public class RecordFactory } catch (Exception illegalArgumentException) { + illegalArgumentException.printStackTrace(); throw new RecordFormatException( "Unable to determine record types"); } diff --git a/src/java/org/apache/poi/hssf/record/SubRecord.java b/src/java/org/apache/poi/hssf/record/SubRecord.java new file mode 100644 index 000000000..6b27eb3e0 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/SubRecord.java @@ -0,0 +1,98 @@ +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" and + * "Apache POI" must not be used to endorse or promote products + * derived from this software without prior written permission. For + * written permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * "Apache POI", nor may "Apache" appear in their name, without + * prior written permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ + +package org.apache.poi.hssf.record; + +/** + * Subrecords are part of the OBJ class. + */ +abstract public class SubRecord + extends Record +{ + public SubRecord() + { + } + + public SubRecord( short id, short size, byte[] data ) + { + super( id, size, data ); + } + + public SubRecord( short id, short size, byte[] data, int offset ) + { + super( id, size, data, offset ); + } + + public static Record createSubRecord( short subRecordSid, short size, byte[] data, int offset ) + { + Record r = null; + + switch ( subRecordSid ) + { + case CommonObjectDataSubRecord.sid: + r = new CommonObjectDataSubRecord( subRecordSid, size, data, offset ); + break; + case GroupMarkerSubRecord.sid: + r = new GroupMarkerSubRecord( subRecordSid, size, data, offset ); + break; + case EndSubRecord.sid: + r = new EndSubRecord( subRecordSid, size, data, offset ); + break; + default: + r = new UnknownRecord( subRecordSid, size, data, offset ); + } + + return r; + } +} diff --git a/src/java/org/apache/poi/hssf/record/TextObjectBaseRecord.java b/src/java/org/apache/poi/hssf/record/TextObjectBaseRecord.java new file mode 100644 index 000000000..21d83a0c8 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/TextObjectBaseRecord.java @@ -0,0 +1,519 @@ + +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" and + * "Apache POI" must not be used to endorse or promote products + * derived from this software without prior written permission. For + * written permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * "Apache POI", nor may "Apache" appear in their name, without + * prior written permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ + + +package org.apache.poi.hssf.record; + + + +import org.apache.poi.util.*; + +/** + * The TXO record is used to define the properties of a text box. It is followed + by two continue records unless there is no actual text. The first continue record contains + the text data and the next continue record contains the formatting runs. + * NOTE: This source is automatically generated please do not modify this file. Either subclass or + * remove the record in src/records/definitions. + + * @author Glen Stampoultzis (glens at apache.org) + */ +public class TextObjectBaseRecord + extends Record +{ + public final static short sid = 0x1B6; + private short field_1_options; + private BitField reserved1 = new BitField(0x1); + private BitField HorizontalTextAlignment = new BitField(0x000E); + public final static short HORIZONTAL_TEXT_ALIGNMENT_LEFT_ALIGNED = 1; + public final static short HORIZONTAL_TEXT_ALIGNMENT_CENTERED = 2; + public final static short HORIZONTAL_TEXT_ALIGNMENT_RIGHT_ALIGNED = 3; + public final static short HORIZONTAL_TEXT_ALIGNMENT_JUSTIFIED = 4; + private BitField VerticalTextAlignment = new BitField(0x0070); + public final static short VERTICAL_TEXT_ALIGNMENT_TOP = 1; + public final static short VERTICAL_TEXT_ALIGNMENT_CENTER = 2; + public final static short VERTICAL_TEXT_ALIGNMENT_BOTTOM = 3; + public final static short VERTICAL_TEXT_ALIGNMENT_JUSTIFY = 4; + private BitField reserved2 = new BitField(0x0180); + private BitField textLocked = new BitField(0x200); + private BitField reserved3 = new BitField(0xFC00); + private short field_2_textOrientation; + public final static short TEXT_ORIENTATION_NONE = 0; + public final static short TEXT_ORIENTATION_TOP_TO_BOTTOM = 1; + public final static short TEXT_ORIENTATION_ROT_RIGHT = 2; + public final static short TEXT_ORIENTATION_ROT_LEFT = 3; + private short field_3_reserved4; + private short field_4_reserved5; + private short field_5_reserved6; + private short field_6_textLength; + private short field_7_formattingRunLength; + private int field_8_reserved7; + + + public TextObjectBaseRecord() + { + + } + + /** + * Constructs a TextObjectBase record and sets its fields appropriately. + * + * @param id id must be 0x1B6 or an exception + * will be throw upon validation + * @param size size the size of the data area of the record + * @param data data of the record (should not contain sid/len) + */ + + public TextObjectBaseRecord(short id, short size, byte [] data) + { + super(id, size, data); + + } + + /** + * Constructs a TextObjectBase record and sets its fields appropriately. + * + * @param id id must be 0x1B6 or an exception + * will be throw upon validation + * @param size size the size of the data area of the record + * @param data data of the record (should not contain sid/len) + * @param offset of the record's data + */ + + public TextObjectBaseRecord(short id, short size, byte [] data, int offset) + { + super(id, size, data, offset); + + } + + /** + * Checks the sid matches the expected side for this record + * + * @param id the expected sid. + */ + protected void validateSid(short id) + { + if (id != sid) + { + throw new RecordFormatException("Not a TextObjectBase record"); + } + } + + protected void fillFields(byte [] data, short size, int offset) + { + + int pos = 0; + field_1_options = LittleEndian.getShort(data, pos + 0x0 + offset); + field_2_textOrientation = LittleEndian.getShort(data, pos + 0x2 + offset); + field_3_reserved4 = LittleEndian.getShort(data, pos + 0x4 + offset); + field_4_reserved5 = LittleEndian.getShort(data, pos + 0x6 + offset); + field_5_reserved6 = LittleEndian.getShort(data, pos + 0x8 + offset); + field_6_textLength = LittleEndian.getShort(data, pos + 0xa + offset); + field_7_formattingRunLength = LittleEndian.getShort(data, pos + 0xc + offset); + field_8_reserved7 = LittleEndian.getInt(data, pos + 0xe + offset); + + } + + public String toString() + { + StringBuffer buffer = new StringBuffer(); + + buffer.append("[TXO]\n"); + buffer.append(" .options = ") + .append("0x").append(HexDump.toHex( getOptions ())) + .append(" (").append( getOptions() ).append(" )"); + buffer.append(System.getProperty("line.separator")); + buffer.append(" .reserved1 = ").append(isReserved1()).append('\n'); + buffer.append(" .HorizontalTextAlignment = ").append(getHorizontalTextAlignment()).append('\n'); + buffer.append(" .VerticalTextAlignment = ").append(getVerticalTextAlignment()).append('\n'); + buffer.append(" .reserved2 = ").append(getReserved2()).append('\n'); + buffer.append(" .textLocked = ").append(isTextLocked()).append('\n'); + buffer.append(" .reserved3 = ").append(getReserved3()).append('\n'); + buffer.append(" .textOrientation = ") + .append("0x").append(HexDump.toHex( getTextOrientation ())) + .append(" (").append( getTextOrientation() ).append(" )"); + buffer.append(System.getProperty("line.separator")); + buffer.append(" .reserved4 = ") + .append("0x").append(HexDump.toHex( getReserved4 ())) + .append(" (").append( getReserved4() ).append(" )"); + buffer.append(System.getProperty("line.separator")); + buffer.append(" .reserved5 = ") + .append("0x").append(HexDump.toHex( getReserved5 ())) + .append(" (").append( getReserved5() ).append(" )"); + buffer.append(System.getProperty("line.separator")); + buffer.append(" .reserved6 = ") + .append("0x").append(HexDump.toHex( getReserved6 ())) + .append(" (").append( getReserved6() ).append(" )"); + buffer.append(System.getProperty("line.separator")); + buffer.append(" .textLength = ") + .append("0x").append(HexDump.toHex( getTextLength ())) + .append(" (").append( getTextLength() ).append(" )"); + buffer.append(System.getProperty("line.separator")); + buffer.append(" .formattingRunLength = ") + .append("0x").append(HexDump.toHex( getFormattingRunLength ())) + .append(" (").append( getFormattingRunLength() ).append(" )"); + buffer.append(System.getProperty("line.separator")); + buffer.append(" .reserved7 = ") + .append("0x").append(HexDump.toHex( getReserved7 ())) + .append(" (").append( getReserved7() ).append(" )"); + buffer.append(System.getProperty("line.separator")); + + buffer.append("[/TXO]\n"); + return buffer.toString(); + } + + public int serialize(int offset, byte[] data) + { + int pos = 0; + + LittleEndian.putShort(data, 0 + offset, sid); + LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize() - 4)); + + LittleEndian.putShort(data, 4 + offset + pos, field_1_options); + LittleEndian.putShort(data, 6 + offset + pos, field_2_textOrientation); + LittleEndian.putShort(data, 8 + offset + pos, field_3_reserved4); + LittleEndian.putShort(data, 10 + offset + pos, field_4_reserved5); + LittleEndian.putShort(data, 12 + offset + pos, field_5_reserved6); + LittleEndian.putShort(data, 14 + offset + pos, field_6_textLength); + LittleEndian.putShort(data, 16 + offset + pos, field_7_formattingRunLength); + LittleEndian.putInt(data, 18 + offset + pos, field_8_reserved7); + + return getRecordSize(); + } + + /** + * Size of record (exluding 4 byte header) + */ + public int getRecordSize() + { + return 4 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 4; + } + + public short getSid() + { + return this.sid; + } + + public Object clone() { + TextObjectBaseRecord rec = new TextObjectBaseRecord(); + + rec.field_1_options = field_1_options; + rec.field_2_textOrientation = field_2_textOrientation; + rec.field_3_reserved4 = field_3_reserved4; + rec.field_4_reserved5 = field_4_reserved5; + rec.field_5_reserved6 = field_5_reserved6; + rec.field_6_textLength = field_6_textLength; + rec.field_7_formattingRunLength = field_7_formattingRunLength; + rec.field_8_reserved7 = field_8_reserved7; + return rec; + } + + + + + /** + * Get the options field for the TextObjectBase record. + */ + public short getOptions() + { + return field_1_options; + } + + /** + * Set the options field for the TextObjectBase record. + */ + public void setOptions(short field_1_options) + { + this.field_1_options = field_1_options; + } + + /** + * Get the text orientation field for the TextObjectBase record. + * + * @return One of + * TEXT_ORIENTATION_NONE + * TEXT_ORIENTATION_TOP_TO_BOTTOM + * TEXT_ORIENTATION_ROT_RIGHT + * TEXT_ORIENTATION_ROT_LEFT + */ + public short getTextOrientation() + { + return field_2_textOrientation; + } + + /** + * Set the text orientation field for the TextObjectBase record. + * + * @param field_2_textOrientation + * One of + * TEXT_ORIENTATION_NONE + * TEXT_ORIENTATION_TOP_TO_BOTTOM + * TEXT_ORIENTATION_ROT_RIGHT + * TEXT_ORIENTATION_ROT_LEFT + */ + public void setTextOrientation(short field_2_textOrientation) + { + this.field_2_textOrientation = field_2_textOrientation; + } + + /** + * Get the reserved4 field for the TextObjectBase record. + */ + public short getReserved4() + { + return field_3_reserved4; + } + + /** + * Set the reserved4 field for the TextObjectBase record. + */ + public void setReserved4(short field_3_reserved4) + { + this.field_3_reserved4 = field_3_reserved4; + } + + /** + * Get the reserved5 field for the TextObjectBase record. + */ + public short getReserved5() + { + return field_4_reserved5; + } + + /** + * Set the reserved5 field for the TextObjectBase record. + */ + public void setReserved5(short field_4_reserved5) + { + this.field_4_reserved5 = field_4_reserved5; + } + + /** + * Get the reserved6 field for the TextObjectBase record. + */ + public short getReserved6() + { + return field_5_reserved6; + } + + /** + * Set the reserved6 field for the TextObjectBase record. + */ + public void setReserved6(short field_5_reserved6) + { + this.field_5_reserved6 = field_5_reserved6; + } + + /** + * Get the text length field for the TextObjectBase record. + */ + public short getTextLength() + { + return field_6_textLength; + } + + /** + * Set the text length field for the TextObjectBase record. + */ + public void setTextLength(short field_6_textLength) + { + this.field_6_textLength = field_6_textLength; + } + + /** + * Get the formatting run length field for the TextObjectBase record. + */ + public short getFormattingRunLength() + { + return field_7_formattingRunLength; + } + + /** + * Set the formatting run length field for the TextObjectBase record. + */ + public void setFormattingRunLength(short field_7_formattingRunLength) + { + this.field_7_formattingRunLength = field_7_formattingRunLength; + } + + /** + * Get the reserved7 field for the TextObjectBase record. + */ + public int getReserved7() + { + return field_8_reserved7; + } + + /** + * Set the reserved7 field for the TextObjectBase record. + */ + public void setReserved7(int field_8_reserved7) + { + this.field_8_reserved7 = field_8_reserved7; + } + + /** + * Sets the reserved1 field value. + * reserved field + */ + public void setReserved1(boolean value) + { + field_1_options = reserved1.setShortBoolean(field_1_options, value); + } + + /** + * reserved field + * @return the reserved1 field value. + */ + public boolean isReserved1() + { + return reserved1.isSet(field_1_options); + } + + /** + * Sets the Horizontal text alignment field value. + * + */ + public void setHorizontalTextAlignment(short value) + { + field_1_options = HorizontalTextAlignment.setShortValue(field_1_options, value); + } + + /** + * + * @return the Horizontal text alignment field value. + */ + public short getHorizontalTextAlignment() + { + return HorizontalTextAlignment.getShortValue(field_1_options); + } + + /** + * Sets the Vertical text alignment field value. + * + */ + public void setVerticalTextAlignment(short value) + { + field_1_options = VerticalTextAlignment.setShortValue(field_1_options, value); + } + + /** + * + * @return the Vertical text alignment field value. + */ + public short getVerticalTextAlignment() + { + return VerticalTextAlignment.getShortValue(field_1_options); + } + + /** + * Sets the reserved2 field value. + * + */ + public void setReserved2(short value) + { + field_1_options = reserved2.setShortValue(field_1_options, value); + } + + /** + * + * @return the reserved2 field value. + */ + public short getReserved2() + { + return reserved2.getShortValue(field_1_options); + } + + /** + * Sets the text locked field value. + * Text has been locked + */ + public void setTextLocked(boolean value) + { + field_1_options = textLocked.setShortBoolean(field_1_options, value); + } + + /** + * Text has been locked + * @return the text locked field value. + */ + public boolean isTextLocked() + { + return textLocked.isSet(field_1_options); + } + + /** + * Sets the reserved3 field value. + * + */ + public void setReserved3(short value) + { + field_1_options = reserved3.setShortValue(field_1_options, value); + } + + /** + * + * @return the reserved3 field value. + */ + public short getReserved3() + { + return reserved3.getShortValue(field_1_options); + } + + +} // END OF CLASS + + + + diff --git a/src/java/org/apache/poi/hssf/record/TextObjectRecord.java b/src/java/org/apache/poi/hssf/record/TextObjectRecord.java new file mode 100644 index 000000000..e5652e802 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/TextObjectRecord.java @@ -0,0 +1,216 @@ +package org.apache.poi.hssf.record; + +import org.apache.poi.hssf.usermodel.HSSFRichTextString; +import org.apache.poi.util.StringUtil; +import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.HexDump; +import java.io.UnsupportedEncodingException; + +public class TextObjectRecord + extends TextObjectBaseRecord +{ + HSSFRichTextString str = new HSSFRichTextString( "" ); + int continueRecordCount = 0; // how many times has continue record been called? + + public TextObjectRecord() + { + } + + public TextObjectRecord( short id, short size, byte[] data ) + { + super( id, size, data ); + } + + public TextObjectRecord( short id, short size, byte[] data, int offset ) + { + super( id, size, data, offset ); + } + + public int getRecordSize() + { + int continue1Size = 0; + int continue2Size = 0; + if (str.length() != 0) + { + continue1Size = str.length() * 2 + 1 + 4; + continue2Size = (str.numFormattingRuns() + 1) * 8 + 4; + } + return super.getRecordSize() + continue1Size + continue2Size; + } + + public int serialize( int offset, byte[] data ) + { + // Temporarily blank out str so that record size is calculated without the continue records. + HSSFRichTextString temp = str; + str = new HSSFRichTextString(""); + int bytesWritten1 = super.serialize( offset, data ); + str = temp; + + int pos = offset + bytesWritten1; + if ( str.toString().equals( "" ) == false ) + { + ContinueRecord c1 = createContinue1(); + ContinueRecord c2 = createContinue2(); + int bytesWritten2 = c1.serialize( pos, data ); + pos += bytesWritten2; + int bytesWritten3 = c2.serialize( pos, data ); + pos += bytesWritten3; + + int size = bytesWritten1 + bytesWritten2 + bytesWritten3; + if ( size != getRecordSize() ) + throw new RecordFormatException(size + " bytes written but getRecordSize() reports " + getRecordSize()); + return size; + } + if ( bytesWritten1 != getRecordSize() ) + throw new RecordFormatException(bytesWritten1 + " bytes written but getRecordSize() reports " + getRecordSize()); + return bytesWritten1; + } + + private ContinueRecord createContinue1() + { + ContinueRecord c1 = new ContinueRecord(); + byte[] c1Data = new byte[str.length() * 2 + 1]; + try + { + c1Data[0] = 1; + System.arraycopy( str.toString().getBytes( "UTF-16LE" ), 0, c1Data, 1, str.length() * 2 ); + } + catch ( UnsupportedEncodingException e ) + { + throw new RuntimeException( e.getMessage() ); + } + c1.setData( c1Data ); + return c1; + } + + private ContinueRecord createContinue2() + { + ContinueRecord c2 = new ContinueRecord(); + byte[] c2Data = new byte[str.numFormattingRuns() * 8 + 8]; + int pos = 0; + for ( int i = 0; i < str.numFormattingRuns(); i++ ) + { + LittleEndian.putShort( c2Data, pos, (short) str.getIndexOfFormattingRun( i ) ); + pos += 2; + LittleEndian.putShort( c2Data, pos, str.getFontOfFormattingRun( i ) == str.NO_FONT ? 0 : str.getFontOfFormattingRun( i ) ); + pos += 2; + pos += 4; // skip reserved + } + LittleEndian.putShort( c2Data, pos, (short) str.length() ); + pos += 2; + LittleEndian.putShort( c2Data, pos, (short) 0 ); + pos += 2; + pos += 4; // skip reserved + + c2.setData( c2Data ); + + return c2; + } + + public void processContinueRecord( byte[] data ) + { + if ( continueRecordCount == 0 ) + processRawString( data ); + else + processFontRuns( data ); + continueRecordCount++; + } + + private void processFontRuns( byte[] data ) + { + int pos = 0; + do + { + short index = LittleEndian.getShort( data, pos ); + pos += 2; + short iFont = LittleEndian.getShort( data, pos ); + pos += 2; + pos += 4; // skip reserved. + + if ( index >= str.length() ) + break; + str.applyFont( index, str.length(), iFont ); + } + while ( true ); + } + + private void processRawString( byte[] data ) + { + String s; + int pos = 0; + byte compressByte = data[pos++]; + boolean isCompressed = compressByte == 0; + try + { + if ( isCompressed ) + { + s = new String( data, pos, getTextLength(), StringUtil.getPreferredEncoding() ); + } + else + { + s = new String( data, pos, getTextLength() * 2, "UTF-16LE" ); + } + } + catch ( UnsupportedEncodingException e ) + { + throw new RuntimeException( e.getMessage() ); + } + str = new HSSFRichTextString( s ); + } + + public HSSFRichTextString getStr() + { + return str; + } + + public void setStr( HSSFRichTextString str ) + { + this.str = str; + } + + public String toString() + { + StringBuffer buffer = new StringBuffer(); + + buffer.append( "[TXO]\n" ); + buffer.append( " .options = " ) + .append( "0x" ).append( HexDump.toHex( getOptions() ) ) + .append( " (" ).append( getOptions() ).append( " )" ); + buffer.append( System.getProperty( "line.separator" ) ); + buffer.append( " .reserved1 = " ).append( isReserved1() ).append( '\n' ); + buffer.append( " .HorizontalTextAlignment = " ).append( getHorizontalTextAlignment() ).append( '\n' ); + buffer.append( " .VerticalTextAlignment = " ).append( getVerticalTextAlignment() ).append( '\n' ); + buffer.append( " .reserved2 = " ).append( getReserved2() ).append( '\n' ); + buffer.append( " .textLocked = " ).append( isTextLocked() ).append( '\n' ); + buffer.append( " .reserved3 = " ).append( getReserved3() ).append( '\n' ); + buffer.append( " .textOrientation = " ) + .append( "0x" ).append( HexDump.toHex( getTextOrientation() ) ) + .append( " (" ).append( getTextOrientation() ).append( " )" ); + buffer.append( System.getProperty( "line.separator" ) ); + buffer.append( " .reserved4 = " ) + .append( "0x" ).append( HexDump.toHex( getReserved4() ) ) + .append( " (" ).append( getReserved4() ).append( " )" ); + buffer.append( System.getProperty( "line.separator" ) ); + buffer.append( " .reserved5 = " ) + .append( "0x" ).append( HexDump.toHex( getReserved5() ) ) + .append( " (" ).append( getReserved5() ).append( " )" ); + buffer.append( System.getProperty( "line.separator" ) ); + buffer.append( " .reserved6 = " ) + .append( "0x" ).append( HexDump.toHex( getReserved6() ) ) + .append( " (" ).append( getReserved6() ).append( " )" ); + buffer.append( System.getProperty( "line.separator" ) ); + buffer.append( " .textLength = " ) + .append( "0x" ).append( HexDump.toHex( getTextLength() ) ) + .append( " (" ).append( getTextLength() ).append( " )" ); + buffer.append( System.getProperty( "line.separator" ) ); + buffer.append( " .reserved7 = " ) + .append( "0x" ).append( HexDump.toHex( getReserved7() ) ) + .append( " (" ).append( getReserved7() ).append( " )" ); + buffer.append( System.getProperty( "line.separator" ) ); + + buffer.append( " .string = " ).append(str).append('\n'); + + buffer.append( "[/TXO]\n" ); + return buffer.toString(); + } +} diff --git a/src/java/org/apache/poi/hssf/record/UnknownRecord.java b/src/java/org/apache/poi/hssf/record/UnknownRecord.java index b88d22f45..1292f0011 100644 --- a/src/java/org/apache/poi/hssf/record/UnknownRecord.java +++ b/src/java/org/apache/poi/hssf/record/UnknownRecord.java @@ -1,4 +1,3 @@ - /* ==================================================================== * The Apache Software License, Version 1.1 * @@ -92,10 +91,16 @@ public class UnknownRecord thedata = data; } - /** - * spit the record out AS IS. no interperatation or identification - */ + public UnknownRecord( short id, short size, byte[] data, int offset ) + { + sid = id; + thedata = new byte[size]; + System.arraycopy(data, offset, thedata, 0, size); + } + /** + * spit the record out AS IS. no interpretation or identification + */ public int serialize(int offset, byte [] data) { if (thedata == null)