| |
| /* ==================================================================== |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| ==================================================================== */ |
| |
| package org.apache.poi.ddf; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.apache.poi.util.HexDump; |
| import org.apache.poi.util.LittleEndian; |
| |
| /** |
| * The opt record is used to store property values for a shape. It is the key to determining |
| * the attributes of a shape. Properties can be of two types: simple or complex. Simple types |
| * are fixed length. Complex properties are variable length. |
| * |
| * @author Glen Stampoultzis |
| */ |
| public class EscherOptRecord |
| extends EscherRecord |
| { |
| public static final short RECORD_ID = (short) 0xF00B; |
| public static final String RECORD_DESCRIPTION = "msofbtOPT"; |
| |
| private List properties = new ArrayList(); |
| |
| /** |
| * This method deserializes the record from a byte array. |
| * |
| * @param data The byte array containing the escher record information |
| * @param offset The starting offset into <code>data</code>. |
| * @param recordFactory May be null since this is not a container record. |
| * @return The number of bytes read from the byte array. |
| */ |
| public int fillFields( byte[] data, int offset, EscherRecordFactory recordFactory ) |
| { |
| int bytesRemaining = readHeader( data, offset ); |
| int pos = offset + 8; |
| |
| EscherPropertyFactory f = new EscherPropertyFactory(); |
| properties = f.createProperties( data, pos, getInstance() ); |
| return bytesRemaining + 8; |
| } |
| |
| /** |
| * This method serializes this escher record into a byte array. |
| * |
| * @param offset The offset into <code>data</code> to start writing the record data to. |
| * @param data The byte array to serialize to. |
| * @param listener A listener to retrieve start and end callbacks. Use a <code>NullEscherSerailizationListener</code> to ignore these events. |
| * |
| * @return The number of bytes written. |
| * @see NullEscherSerializationListener |
| */ |
| public int serialize( int offset, byte[] data, EscherSerializationListener listener ) |
| { |
| listener.beforeRecordSerialize( offset, getRecordId(), this ); |
| |
| LittleEndian.putShort( data, offset, getOptions() ); |
| LittleEndian.putShort( data, offset + 2, getRecordId() ); |
| LittleEndian.putInt( data, offset + 4, getPropertiesSize() ); |
| int pos = offset + 8; |
| for ( Iterator iterator = properties.iterator(); iterator.hasNext(); ) |
| { |
| EscherProperty escherProperty = (EscherProperty) iterator.next(); |
| pos += escherProperty.serializeSimplePart( data, pos ); |
| } |
| for ( Iterator iterator = properties.iterator(); iterator.hasNext(); ) |
| { |
| EscherProperty escherProperty = (EscherProperty) iterator.next(); |
| pos += escherProperty.serializeComplexPart( data, pos ); |
| } |
| listener.afterRecordSerialize( pos, getRecordId(), pos - offset, this ); |
| return pos - offset; |
| } |
| |
| /** |
| * Returns the number of bytes that are required to serialize this record. |
| * |
| * @return Number of bytes |
| */ |
| public int getRecordSize() |
| { |
| return 8 + getPropertiesSize(); |
| } |
| |
| /** |
| * Automatically recalculate the correct option |
| */ |
| public short getOptions() |
| { |
| setOptions( (short) ( ( properties.size() << 4 ) | 0x3 ) ); |
| return super.getOptions(); |
| } |
| |
| /** |
| * The short name for this record |
| */ |
| public String getRecordName() |
| { |
| return "Opt"; |
| } |
| |
| private int getPropertiesSize() |
| { |
| int totalSize = 0; |
| for ( Iterator iterator = properties.iterator(); iterator.hasNext(); ) |
| { |
| EscherProperty escherProperty = (EscherProperty) iterator.next(); |
| totalSize += escherProperty.getPropertySize(); |
| } |
| return totalSize; |
| } |
| |
| /** |
| * Retrieve the string representation of this record. |
| */ |
| public String toString() |
| { |
| String nl = System.getProperty( "line.separator" ); |
| StringBuffer propertiesBuf = new StringBuffer(); |
| for ( Iterator iterator = properties.iterator(); iterator.hasNext(); ) |
| propertiesBuf.append( " " |
| + iterator.next().toString() |
| + nl ); |
| |
| return "org.apache.poi.ddf.EscherOptRecord:" + nl + |
| " isContainer: " + isContainerRecord() + nl + |
| " options: 0x" + HexDump.toHex( getOptions() ) + nl + |
| " recordId: 0x" + HexDump.toHex( getRecordId() ) + nl + |
| " numchildren: " + getChildRecords().size() + nl + |
| " properties:" + nl + |
| propertiesBuf.toString(); |
| } |
| |
| /** |
| * The list of properties stored by this record. |
| */ |
| public List getEscherProperties() |
| { |
| return properties; |
| } |
| |
| /** |
| * The list of properties stored by this record. |
| */ |
| public EscherProperty getEscherProperty( int index ) |
| { |
| return (EscherProperty) properties.get( index ); |
| } |
| |
| /** |
| * Add a property to this record. |
| */ |
| public void addEscherProperty( EscherProperty prop ) |
| { |
| properties.add( prop ); |
| } |
| |
| /** |
| * Records should be sorted by property number before being stored. |
| */ |
| public void sortProperties() |
| { |
| Collections.sort( properties, new Comparator() |
| { |
| public int compare( Object o1, Object o2 ) |
| { |
| EscherProperty p1 = (EscherProperty) o1; |
| EscherProperty p2 = (EscherProperty) o2; |
| return new Short( p1.getPropertyNumber() ).compareTo( new Short( p2.getPropertyNumber() ) ); |
| } |
| } ); |
| } |
| |
| |
| } |