The escher records themselves
git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/branches/REL_2_BRANCH@353499 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
8e27ed87eb
commit
ed9f2b0bac
114
src/java/org/apache/poi/ddf/DefaultEscherRecordFactory.java
Normal file
114
src/java/org/apache/poi/ddf/DefaultEscherRecordFactory.java
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.record.RecordFormatException;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates escher records when provided the byte array containing those records.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis
|
||||||
|
* @see EscherRecordFactory
|
||||||
|
*/
|
||||||
|
public class DefaultEscherRecordFactory
|
||||||
|
implements EscherRecordFactory
|
||||||
|
{
|
||||||
|
private static Class[] escherRecordClasses = {
|
||||||
|
EscherBSERecord.class, EscherOptRecord.class, EscherClientAnchorRecord.class, EscherDgRecord.class,
|
||||||
|
EscherSpgrRecord.class, EscherSpRecord.class, EscherClientDataRecord.class, EscherDggRecord.class,
|
||||||
|
EscherSplitMenuColorsRecord.class, EscherChildAnchorRecord.class, EscherTextboxRecord.class
|
||||||
|
};
|
||||||
|
private static Map recordsMap = recordsToMap( escherRecordClasses );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of the escher record factory
|
||||||
|
*/
|
||||||
|
public DefaultEscherRecordFactory()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an escher record including the any children contained under that record.
|
||||||
|
* An exception is thrown if the record could not be generated.
|
||||||
|
*
|
||||||
|
* @param data The byte array containing the records
|
||||||
|
* @param offset The starting offset into the byte array
|
||||||
|
* @return The generated escher record
|
||||||
|
*/
|
||||||
|
public EscherRecord createRecord( byte[] data, int offset )
|
||||||
|
{
|
||||||
|
EscherRecord.EscherRecordHeader header = EscherRecord.EscherRecordHeader.readHeader( data, offset );
|
||||||
|
if ( ( header.getOptions() & (short) 0x000F ) == (short) 0x000F )
|
||||||
|
{
|
||||||
|
EscherContainerRecord r = new EscherContainerRecord();
|
||||||
|
r.setRecordId( header.getRecordId() );
|
||||||
|
r.setOptions( header.getOptions() );
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
else if ( header.getRecordId() >= EscherBlipRecord.RECORD_ID_START && header.getRecordId() <= EscherBlipRecord.RECORD_ID_END )
|
||||||
|
{
|
||||||
|
EscherBlipRecord r = new EscherBlipRecord();
|
||||||
|
r.setRecordId( header.getRecordId() );
|
||||||
|
r.setOptions( header.getOptions() );
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Constructor recordConstructor = (Constructor) recordsMap.get( new Short( header.getRecordId() ) );
|
||||||
|
EscherRecord escherRecord = null;
|
||||||
|
if ( recordConstructor != null )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
escherRecord = (EscherRecord) recordConstructor.newInstance( new Object[]{} );
|
||||||
|
escherRecord.setRecordId( header.getRecordId() );
|
||||||
|
escherRecord.setOptions( header.getOptions() );
|
||||||
|
}
|
||||||
|
catch ( Exception e )
|
||||||
|
{
|
||||||
|
escherRecord = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return escherRecord == null ? new UnknownEscherRecord() : escherRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts from a list of classes into a map that contains the record id as the key and
|
||||||
|
* the Constructor in the value part of the map. It does this by using reflection to look up
|
||||||
|
* the RECORD_ID field then using reflection again to find a reference to the constructor.
|
||||||
|
*
|
||||||
|
* @param records The records to convert
|
||||||
|
* @return The map containing the id/constructor pairs.
|
||||||
|
*/
|
||||||
|
private static Map recordsToMap( Class[] records )
|
||||||
|
{
|
||||||
|
Map result = new HashMap();
|
||||||
|
Constructor constructor;
|
||||||
|
|
||||||
|
for ( int i = 0; i < records.length; i++ )
|
||||||
|
{
|
||||||
|
Class record = null;
|
||||||
|
short sid = 0;
|
||||||
|
|
||||||
|
record = records[i];
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sid = record.getField( "RECORD_ID" ).getShort( null );
|
||||||
|
constructor = record.getConstructor( new Class[]
|
||||||
|
{
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
catch ( Exception illegalArgumentException )
|
||||||
|
{
|
||||||
|
throw new RecordFormatException(
|
||||||
|
"Unable to determine record types" );
|
||||||
|
}
|
||||||
|
result.put( new Short( sid ), constructor );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
162
src/java/org/apache/poi/ddf/EscherArrayProperty.java
Normal file
162
src/java/org/apache/poi/ddf/EscherArrayProperty.java
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escher array properties are the most wierd construction ever invented
|
||||||
|
* with all sorts of special cases. I'm hopeful I've got them all.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at superlinksoftware.com)
|
||||||
|
*/
|
||||||
|
public class EscherArrayProperty
|
||||||
|
extends EscherComplexProperty
|
||||||
|
{
|
||||||
|
private static final int FIXED_SIZE = 3 * 2;
|
||||||
|
|
||||||
|
public EscherArrayProperty( short id, byte[] complexData )
|
||||||
|
{
|
||||||
|
super( id, checkComplexData(complexData) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public EscherArrayProperty( short propertyNumber, boolean isBlipId, byte[] complexData )
|
||||||
|
{
|
||||||
|
super( propertyNumber, isBlipId, checkComplexData(complexData) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] checkComplexData( byte[] complexData )
|
||||||
|
{
|
||||||
|
if (complexData == null || complexData.length == 0)
|
||||||
|
complexData = new byte[6];
|
||||||
|
|
||||||
|
return complexData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumberOfElementsInArray()
|
||||||
|
{
|
||||||
|
return LittleEndian.getUShort( complexData, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumberOfElementsInArray( int numberOfElements )
|
||||||
|
{
|
||||||
|
int expectedArraySize = numberOfElements * getActualSizeOfElements(getSizeOfElements()) + FIXED_SIZE;
|
||||||
|
if ( expectedArraySize != complexData.length )
|
||||||
|
{
|
||||||
|
byte[] newArray = new byte[expectedArraySize];
|
||||||
|
System.arraycopy( complexData, 0, newArray, 0, complexData.length );
|
||||||
|
complexData = newArray;
|
||||||
|
}
|
||||||
|
LittleEndian.putShort( complexData, 0, (short) numberOfElements );
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumberOfElementsInMemory()
|
||||||
|
{
|
||||||
|
return LittleEndian.getUShort( complexData, 2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumberOfElementsInMemory( int numberOfElements )
|
||||||
|
{
|
||||||
|
int expectedArraySize = numberOfElements * getActualSizeOfElements(getSizeOfElements()) + FIXED_SIZE;
|
||||||
|
if ( expectedArraySize != complexData.length )
|
||||||
|
{
|
||||||
|
byte[] newArray = new byte[expectedArraySize];
|
||||||
|
System.arraycopy( complexData, 0, newArray, 0, expectedArraySize );
|
||||||
|
complexData = newArray;
|
||||||
|
}
|
||||||
|
LittleEndian.putShort( complexData, 2, (short) numberOfElements );
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getSizeOfElements()
|
||||||
|
{
|
||||||
|
return LittleEndian.getShort( complexData, 4 );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSizeOfElements( int sizeOfElements )
|
||||||
|
{
|
||||||
|
LittleEndian.putShort( complexData, 4, (short) sizeOfElements );
|
||||||
|
|
||||||
|
int expectedArraySize = getNumberOfElementsInArray() * getActualSizeOfElements(getSizeOfElements()) + FIXED_SIZE;
|
||||||
|
if ( expectedArraySize != complexData.length )
|
||||||
|
{
|
||||||
|
// Keep just the first 6 bytes. The rest is no good to us anyway.
|
||||||
|
byte[] newArray = new byte[expectedArraySize];
|
||||||
|
System.arraycopy( complexData, 0, newArray, 0, 6 );
|
||||||
|
complexData = newArray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getElement( int index )
|
||||||
|
{
|
||||||
|
int actualSize = getActualSizeOfElements(getSizeOfElements());
|
||||||
|
byte[] result = new byte[actualSize];
|
||||||
|
System.arraycopy(complexData, FIXED_SIZE + index * actualSize, result, 0, result.length );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setElement( int index, byte[] element )
|
||||||
|
{
|
||||||
|
int actualSize = getActualSizeOfElements(getSizeOfElements());
|
||||||
|
System.arraycopy( element, 0, complexData, FIXED_SIZE + index * actualSize, actualSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
StringBuffer results = new StringBuffer();
|
||||||
|
results.append(" {EscherArrayProperty:" + nl);
|
||||||
|
results.append(" Num Elements: " + getNumberOfElementsInArray() + nl);
|
||||||
|
results.append(" Num Elements In Memory: " + getNumberOfElementsInMemory() + nl);
|
||||||
|
results.append(" Size of elements: " + getSizeOfElements() + nl);
|
||||||
|
for (int i = 0; i < getNumberOfElementsInArray(); i++)
|
||||||
|
{
|
||||||
|
results.append(" Element " + i + ": " + HexDump.toHex(getElement(i)) + nl);
|
||||||
|
}
|
||||||
|
results.append("}" + nl);
|
||||||
|
|
||||||
|
return "propNum: " + getPropertyNumber()
|
||||||
|
+ ", propName: " + EscherProperties.getPropertyName( getPropertyNumber() )
|
||||||
|
+ ", complex: " + isComplex()
|
||||||
|
+ ", blipId: " + isBlipId()
|
||||||
|
+ ", data: " + nl + results.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We have this method because the way in which arrays in escher works
|
||||||
|
* is screwed for seemly arbitary reasons. While most properties are
|
||||||
|
* fairly consistent and have a predictable array size, escher arrays
|
||||||
|
* have special cases.
|
||||||
|
*
|
||||||
|
* @param data The data array containing the escher array information
|
||||||
|
* @param offset The offset into the array to start reading from.
|
||||||
|
* @return the number of bytes used by this complex property.
|
||||||
|
*/
|
||||||
|
public int setArrayData( byte[] data, int offset )
|
||||||
|
{
|
||||||
|
short numElements = LittleEndian.getShort(data, offset);
|
||||||
|
short numReserved = LittleEndian.getShort(data, offset + 2);
|
||||||
|
short sizeOfElements = LittleEndian.getShort(data, offset + 4);
|
||||||
|
|
||||||
|
int arraySize = getActualSizeOfElements(sizeOfElements) * numElements;
|
||||||
|
if (arraySize == complexData.length)
|
||||||
|
complexData = new byte[arraySize + 6]; // Calculation missing the header for some reason
|
||||||
|
System.arraycopy(data, offset, complexData, 0, complexData.length );
|
||||||
|
return complexData.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sometimes the element size is stored as a negative number. We
|
||||||
|
* negate it and shift it to get the real value.
|
||||||
|
*/
|
||||||
|
public static int getActualSizeOfElements(short sizeOfElements)
|
||||||
|
{
|
||||||
|
if (sizeOfElements < 0)
|
||||||
|
return (short) ( ( -sizeOfElements ) >> 2 );
|
||||||
|
else
|
||||||
|
return sizeOfElements;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
383
src/java/org/apache/poi/ddf/EscherBSERecord.java
Normal file
383
src/java/org/apache/poi/ddf/EscherBSERecord.java
Normal file
@ -0,0 +1,383 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The BSE record is related closely to the <code>EscherBlipRecord</code> and stores
|
||||||
|
* extra information about the blip.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis
|
||||||
|
* @see EscherBlipRecord
|
||||||
|
*/
|
||||||
|
public class EscherBSERecord
|
||||||
|
extends EscherRecord
|
||||||
|
{
|
||||||
|
public static final short RECORD_ID = (short) 0xF007;
|
||||||
|
public static final String RECORD_DESCRIPTION = "MsofbtBSE";
|
||||||
|
|
||||||
|
public static final byte BT_ERROR = 0;
|
||||||
|
public static final byte BT_UNKNOWN = 1;
|
||||||
|
public static final byte BT_EMF = 2;
|
||||||
|
public static final byte BT_WMF = 3;
|
||||||
|
public static final byte BT_PICT = 4;
|
||||||
|
public static final byte BT_JPEG = 5;
|
||||||
|
public static final byte BT_PNG = 6;
|
||||||
|
public static final byte BT_DIB = 7;
|
||||||
|
|
||||||
|
private byte field_1_blipTypeWin32;
|
||||||
|
private byte field_2_blipTypeMacOS;
|
||||||
|
private byte[] field_3_uid; // 16 bytes
|
||||||
|
private short field_4_tag;
|
||||||
|
private int field_5_size;
|
||||||
|
private int field_6_ref;
|
||||||
|
private int field_7_offset;
|
||||||
|
private byte field_8_usage;
|
||||||
|
private byte field_9_name;
|
||||||
|
private byte field_10_unused2;
|
||||||
|
private byte field_11_unused3;
|
||||||
|
|
||||||
|
private byte[] remainingData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
field_1_blipTypeWin32 = data[pos];
|
||||||
|
field_2_blipTypeMacOS = data[pos + 1];
|
||||||
|
System.arraycopy( data, pos + 2, field_3_uid = new byte[16], 0, 16 );
|
||||||
|
field_4_tag = LittleEndian.getShort( data, pos + 18 );
|
||||||
|
field_5_size = LittleEndian.getInt( data, pos + 20 );
|
||||||
|
field_6_ref = LittleEndian.getInt( data, pos + 24 );
|
||||||
|
field_7_offset = LittleEndian.getInt( data, pos + 28 );
|
||||||
|
field_8_usage = data[pos + 32];
|
||||||
|
field_9_name = data[pos + 33];
|
||||||
|
field_10_unused2 = data[pos + 34];
|
||||||
|
field_11_unused3 = data[pos + 35];
|
||||||
|
bytesRemaining -= 36;
|
||||||
|
remainingData = new byte[bytesRemaining];
|
||||||
|
System.arraycopy( data, pos + 36, remainingData, 0, bytesRemaining );
|
||||||
|
return bytesRemaining + 8 + 36;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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() );
|
||||||
|
int remainingBytes = remainingData.length + 36;
|
||||||
|
LittleEndian.putInt( data, offset + 4, remainingBytes );
|
||||||
|
|
||||||
|
data[offset + 8] = field_1_blipTypeWin32;
|
||||||
|
data[offset + 9] = field_2_blipTypeMacOS;
|
||||||
|
for ( int i = 0; i < 16; i++ )
|
||||||
|
data[offset + 10 + i] = field_3_uid[i];
|
||||||
|
LittleEndian.putShort( data, offset + 26, field_4_tag );
|
||||||
|
LittleEndian.putInt( data, offset + 28, field_5_size );
|
||||||
|
LittleEndian.putInt( data, offset + 32, field_6_ref );
|
||||||
|
LittleEndian.putInt( data, offset + 36, field_7_offset );
|
||||||
|
data[offset + 40] = field_8_usage;
|
||||||
|
data[offset + 41] = field_9_name;
|
||||||
|
data[offset + 42] = field_10_unused2;
|
||||||
|
data[offset + 43] = field_11_unused3;
|
||||||
|
System.arraycopy( remainingData, 0, data, offset + 44, remainingData.length );
|
||||||
|
int pos = offset + 8 + 36 + remainingData.length;
|
||||||
|
|
||||||
|
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 + 1 + 1 + 16 + 2 + 4 + 4 + 4 + 1 + 1 + 1 + 1 + remainingData.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The short name for this record
|
||||||
|
*/
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
return "BSE";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The expected blip type under windows (failure to match this blip type will result in
|
||||||
|
* Excel converting to this format).
|
||||||
|
*/
|
||||||
|
public byte getBlipTypeWin32()
|
||||||
|
{
|
||||||
|
return field_1_blipTypeWin32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected win32 blip type
|
||||||
|
*/
|
||||||
|
public void setBlipTypeWin32( byte blipTypeWin32 )
|
||||||
|
{
|
||||||
|
this.field_1_blipTypeWin32 = blipTypeWin32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The expected blip type under MacOS (failure to match this blip type will result in
|
||||||
|
* Excel converting to this format).
|
||||||
|
*/
|
||||||
|
public byte getBlipTypeMacOS()
|
||||||
|
{
|
||||||
|
return field_2_blipTypeMacOS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected MacOS blip type
|
||||||
|
*/
|
||||||
|
public void setBlipTypeMacOS( byte blipTypeMacOS )
|
||||||
|
{
|
||||||
|
this.field_2_blipTypeMacOS = blipTypeMacOS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 16 byte MD4 checksum.
|
||||||
|
*/
|
||||||
|
public byte[] getUid()
|
||||||
|
{
|
||||||
|
return field_3_uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 16 byte MD4 checksum.
|
||||||
|
*/
|
||||||
|
public void setUid( byte[] uid )
|
||||||
|
{
|
||||||
|
this.field_3_uid = uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* unused
|
||||||
|
*/
|
||||||
|
public short getTag()
|
||||||
|
{
|
||||||
|
return field_4_tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* unused
|
||||||
|
*/
|
||||||
|
public void setTag( short tag )
|
||||||
|
{
|
||||||
|
this.field_4_tag = tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blip size in stream.
|
||||||
|
*/
|
||||||
|
public int getSize()
|
||||||
|
{
|
||||||
|
return field_5_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blip size in stream.
|
||||||
|
*/
|
||||||
|
public void setSize( int size )
|
||||||
|
{
|
||||||
|
this.field_5_size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The reference count of this blip.
|
||||||
|
*/
|
||||||
|
public int getRef()
|
||||||
|
{
|
||||||
|
return field_6_ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The reference count of this blip.
|
||||||
|
*/
|
||||||
|
public void setRef( int ref )
|
||||||
|
{
|
||||||
|
this.field_6_ref = ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File offset in the delay stream.
|
||||||
|
*/
|
||||||
|
public int getOffset()
|
||||||
|
{
|
||||||
|
return field_7_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File offset in the delay stream.
|
||||||
|
*/
|
||||||
|
public void setOffset( int offset )
|
||||||
|
{
|
||||||
|
this.field_7_offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the way this blip is used.
|
||||||
|
*/
|
||||||
|
public byte getUsage()
|
||||||
|
{
|
||||||
|
return field_8_usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the way this blip is used.
|
||||||
|
*/
|
||||||
|
public void setUsage( byte usage )
|
||||||
|
{
|
||||||
|
this.field_8_usage = usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The length in characters of the blip name.
|
||||||
|
*/
|
||||||
|
public byte getName()
|
||||||
|
{
|
||||||
|
return field_9_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The length in characters of the blip name.
|
||||||
|
*/
|
||||||
|
public void setName( byte name )
|
||||||
|
{
|
||||||
|
this.field_9_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getUnused2()
|
||||||
|
{
|
||||||
|
return field_10_unused2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUnused2( byte unused2 )
|
||||||
|
{
|
||||||
|
this.field_10_unused2 = unused2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getUnused3()
|
||||||
|
{
|
||||||
|
return field_11_unused3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUnused3( byte unused3 )
|
||||||
|
{
|
||||||
|
this.field_11_unused3 = unused3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any remaining data in this record.
|
||||||
|
*/
|
||||||
|
public byte[] getRemainingData()
|
||||||
|
{
|
||||||
|
return remainingData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any remaining data in this record.
|
||||||
|
*/
|
||||||
|
public void setRemainingData( byte[] remainingData )
|
||||||
|
{
|
||||||
|
this.remainingData = remainingData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the string representation of this object
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty( "line.separator" );
|
||||||
|
|
||||||
|
String extraData;
|
||||||
|
ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HexDump.dump( this.remainingData, 0, b, 0 );
|
||||||
|
extraData = b.toString();
|
||||||
|
}
|
||||||
|
catch ( Exception e )
|
||||||
|
{
|
||||||
|
extraData = e.toString();
|
||||||
|
}
|
||||||
|
return getClass().getName() + ":" + nl +
|
||||||
|
" RecordId: 0x" + HexDump.toHex( RECORD_ID ) + nl +
|
||||||
|
" Options: 0x" + HexDump.toHex( getOptions() ) + nl +
|
||||||
|
" BlipTypeWin32: " + field_1_blipTypeWin32 + nl +
|
||||||
|
" BlipTypeMacOS: " + field_2_blipTypeMacOS + nl +
|
||||||
|
" SUID: " + HexDump.toHex(field_3_uid) + nl +
|
||||||
|
" Tag: " + field_4_tag + nl +
|
||||||
|
" Size: " + field_5_size + nl +
|
||||||
|
" Ref: " + field_6_ref + nl +
|
||||||
|
" Offset: " + field_7_offset + nl +
|
||||||
|
" Usage: " + field_8_usage + nl +
|
||||||
|
" Name: " + field_9_name + nl +
|
||||||
|
" Unused2: " + field_10_unused2 + nl +
|
||||||
|
" Unused3: " + field_11_unused3 + nl +
|
||||||
|
" Extra Data:" + nl + extraData;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the string representation given a blip id.
|
||||||
|
*/
|
||||||
|
public String getBlipType( byte b )
|
||||||
|
{
|
||||||
|
switch ( b )
|
||||||
|
{
|
||||||
|
case BT_ERROR:
|
||||||
|
return " ERROR";
|
||||||
|
case BT_UNKNOWN:
|
||||||
|
return " UNKNOWN";
|
||||||
|
case BT_EMF:
|
||||||
|
return " EMF";
|
||||||
|
case BT_WMF:
|
||||||
|
return " WMF";
|
||||||
|
case BT_PICT:
|
||||||
|
return " PICT";
|
||||||
|
case BT_JPEG:
|
||||||
|
return " JPEG";
|
||||||
|
case BT_PNG:
|
||||||
|
return " PNG";
|
||||||
|
case BT_DIB:
|
||||||
|
return " DIB";
|
||||||
|
default:
|
||||||
|
if ( b < 32 )
|
||||||
|
return " NotKnown";
|
||||||
|
else
|
||||||
|
return " Client";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
417
src/java/org/apache/poi/ddf/EscherBlipRecord.java
Normal file
417
src/java/org/apache/poi/ddf/EscherBlipRecord.java
Normal file
@ -0,0 +1,417 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.record.RecordFormatException;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.zip.InflaterInputStream;
|
||||||
|
import java.util.zip.DeflaterOutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The blip record is used to hold details about large binary objects that occur in escher such
|
||||||
|
* as JPEG, GIF, PICT and WMF files. The contents of the stream is usually compressed. Inflate
|
||||||
|
* can be used to decompress the data.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis
|
||||||
|
* @see java.util.zip.Inflater
|
||||||
|
*/
|
||||||
|
public class EscherBlipRecord
|
||||||
|
extends EscherRecord
|
||||||
|
{
|
||||||
|
public static final short RECORD_ID_START = (short) 0xF018;
|
||||||
|
public static final short RECORD_ID_END = (short) 0xF117;
|
||||||
|
public static final String RECORD_DESCRIPTION = "msofbtBlip";
|
||||||
|
private static final int HEADER_SIZE = 8;
|
||||||
|
|
||||||
|
private byte[] field_1_secondaryUID;
|
||||||
|
private int field_2_cacheOfSize;
|
||||||
|
private int field_3_boundaryTop;
|
||||||
|
private int field_4_boundaryLeft;
|
||||||
|
private int field_5_boundaryWidth;
|
||||||
|
private int field_6_boundaryHeight;
|
||||||
|
private int field_7_width;
|
||||||
|
private int field_8_height;
|
||||||
|
private int field_9_cacheOfSavedSize;
|
||||||
|
private byte field_10_compressionFlag;
|
||||||
|
private byte field_11_filter;
|
||||||
|
private byte[] field_12_data;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 bytesAfterHeader = readHeader( data, offset );
|
||||||
|
int pos = offset + HEADER_SIZE;
|
||||||
|
|
||||||
|
int size = 0;
|
||||||
|
field_1_secondaryUID = new byte[16];
|
||||||
|
System.arraycopy( data, pos + size, field_1_secondaryUID, 0, 16 ); size += 16;
|
||||||
|
field_2_cacheOfSize = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_3_boundaryTop = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_4_boundaryLeft = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_5_boundaryWidth = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_6_boundaryHeight = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_7_width = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_8_height = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_9_cacheOfSavedSize = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_10_compressionFlag = data[pos + size]; size++;
|
||||||
|
field_11_filter = data[pos + size]; size++;
|
||||||
|
|
||||||
|
int bytesRemaining = bytesAfterHeader - size;
|
||||||
|
field_12_data = new byte[bytesRemaining];
|
||||||
|
System.arraycopy(data, pos + size, field_12_data, 0, bytesRemaining);
|
||||||
|
|
||||||
|
return bytesRemaining + HEADER_SIZE + bytesAfterHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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() );
|
||||||
|
int remainingBytes = field_12_data.length + 36;
|
||||||
|
LittleEndian.putInt( data, offset + 4, remainingBytes );
|
||||||
|
|
||||||
|
int pos = offset + HEADER_SIZE;
|
||||||
|
System.arraycopy(field_1_secondaryUID, 0, data, pos, 16 ); pos += 16;
|
||||||
|
LittleEndian.putInt( data, pos, field_2_cacheOfSize); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_3_boundaryTop); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_4_boundaryLeft); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_5_boundaryWidth); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_6_boundaryHeight); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_7_width); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_8_height); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_9_cacheOfSavedSize); pos += 4;
|
||||||
|
data[pos++] = field_10_compressionFlag;
|
||||||
|
data[pos++] = field_11_filter;
|
||||||
|
System.arraycopy(field_12_data, 0, data, pos, field_12_data.length); pos += field_12_data.length;
|
||||||
|
|
||||||
|
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 58 + field_12_data.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The short name for this record
|
||||||
|
*/
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
return "Blip";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the secondary UID
|
||||||
|
*/
|
||||||
|
public byte[] getSecondaryUID()
|
||||||
|
{
|
||||||
|
return field_1_secondaryUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the secondary UID
|
||||||
|
*/
|
||||||
|
public void setSecondaryUID( byte[] field_1_secondaryUID )
|
||||||
|
{
|
||||||
|
this.field_1_secondaryUID = field_1_secondaryUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the cache of the metafile size
|
||||||
|
*/
|
||||||
|
public int getCacheOfSize()
|
||||||
|
{
|
||||||
|
return field_2_cacheOfSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the cache of the metafile size
|
||||||
|
*/
|
||||||
|
public void setCacheOfSize( int field_2_cacheOfSize )
|
||||||
|
{
|
||||||
|
this.field_2_cacheOfSize = field_2_cacheOfSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the top boundary of the metafile drawing commands
|
||||||
|
*/
|
||||||
|
public int getBoundaryTop()
|
||||||
|
{
|
||||||
|
return field_3_boundaryTop;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the top boundary of the metafile drawing commands
|
||||||
|
*/
|
||||||
|
public void setBoundaryTop( int field_3_boundaryTop )
|
||||||
|
{
|
||||||
|
this.field_3_boundaryTop = field_3_boundaryTop;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the left boundary of the metafile drawing commands
|
||||||
|
*/
|
||||||
|
public int getBoundaryLeft()
|
||||||
|
{
|
||||||
|
return field_4_boundaryLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the left boundary of the metafile drawing commands
|
||||||
|
*/
|
||||||
|
public void setBoundaryLeft( int field_4_boundaryLeft )
|
||||||
|
{
|
||||||
|
this.field_4_boundaryLeft = field_4_boundaryLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the boundary width of the metafile drawing commands
|
||||||
|
*/
|
||||||
|
public int getBoundaryWidth()
|
||||||
|
{
|
||||||
|
return field_5_boundaryWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the boundary width of the metafile drawing commands
|
||||||
|
*/
|
||||||
|
public void setBoundaryWidth( int field_5_boundaryWidth )
|
||||||
|
{
|
||||||
|
this.field_5_boundaryWidth = field_5_boundaryWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the boundary height of the metafile drawing commands
|
||||||
|
*/
|
||||||
|
public int getBoundaryHeight()
|
||||||
|
{
|
||||||
|
return field_6_boundaryHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the boundary height of the metafile drawing commands
|
||||||
|
*/
|
||||||
|
public void setBoundaryHeight( int field_6_boundaryHeight )
|
||||||
|
{
|
||||||
|
this.field_6_boundaryHeight = field_6_boundaryHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the width of the metafile in EMU's (English Metric Units).
|
||||||
|
*/
|
||||||
|
public int getWidth()
|
||||||
|
{
|
||||||
|
return field_7_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the width of the metafile in EMU's (English Metric Units).
|
||||||
|
*/
|
||||||
|
public void setWidth( int width )
|
||||||
|
{
|
||||||
|
this.field_7_width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the height of the metafile in EMU's (English Metric Units).
|
||||||
|
*/
|
||||||
|
public int getHeight()
|
||||||
|
{
|
||||||
|
return field_8_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the height of the metafile in EMU's (English Metric Units).
|
||||||
|
*/
|
||||||
|
public void setHeight( int height )
|
||||||
|
{
|
||||||
|
this.field_8_height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the cache of the saved size
|
||||||
|
*/
|
||||||
|
public int getCacheOfSavedSize()
|
||||||
|
{
|
||||||
|
return field_9_cacheOfSavedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the cache of the saved size
|
||||||
|
*/
|
||||||
|
public void setCacheOfSavedSize( int field_9_cacheOfSavedSize )
|
||||||
|
{
|
||||||
|
this.field_9_cacheOfSavedSize = field_9_cacheOfSavedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the contents of the blip compressed?
|
||||||
|
*/
|
||||||
|
public byte getCompressionFlag()
|
||||||
|
{
|
||||||
|
return field_10_compressionFlag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether the contents of the blip is compressed
|
||||||
|
*/
|
||||||
|
public void setCompressionFlag( byte field_10_compressionFlag )
|
||||||
|
{
|
||||||
|
this.field_10_compressionFlag = field_10_compressionFlag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter should always be 0
|
||||||
|
*/
|
||||||
|
public byte getFilter()
|
||||||
|
{
|
||||||
|
return field_11_filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter should always be 0
|
||||||
|
*/
|
||||||
|
public void setFilter( byte field_11_filter )
|
||||||
|
{
|
||||||
|
this.field_11_filter = field_11_filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The BLIP data
|
||||||
|
*/
|
||||||
|
public byte[] getData()
|
||||||
|
{
|
||||||
|
return field_12_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The BLIP data
|
||||||
|
*/
|
||||||
|
public void setData( byte[] field_12_data )
|
||||||
|
{
|
||||||
|
this.field_12_data = field_12_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The string representation of this record.
|
||||||
|
*
|
||||||
|
* @return A string
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty( "line.separator" );
|
||||||
|
|
||||||
|
String extraData;
|
||||||
|
ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HexDump.dump( this.field_12_data, 0, b, 0 );
|
||||||
|
extraData = b.toString();
|
||||||
|
}
|
||||||
|
catch ( Exception e )
|
||||||
|
{
|
||||||
|
extraData = e.toString();
|
||||||
|
}
|
||||||
|
return getClass().getName() + ":" + nl +
|
||||||
|
" RecordId: 0x" + HexDump.toHex( getRecordId() ) + nl +
|
||||||
|
" Options: 0x" + HexDump.toHex( getOptions() ) + nl +
|
||||||
|
" Secondary UID: " + HexDump.toHex( field_1_secondaryUID ) + nl +
|
||||||
|
" CacheOfSize: " + field_2_cacheOfSize + nl +
|
||||||
|
" BoundaryTop: " + field_3_boundaryTop + nl +
|
||||||
|
" BoundaryLeft: " + field_4_boundaryLeft + nl +
|
||||||
|
" BoundaryWidth: " + field_5_boundaryWidth + nl +
|
||||||
|
" BoundaryHeight: " + field_6_boundaryHeight + nl +
|
||||||
|
" X: " + field_7_width + nl +
|
||||||
|
" Y: " + field_8_height + nl +
|
||||||
|
" CacheOfSavedSize: " + field_9_cacheOfSavedSize + nl +
|
||||||
|
" CompressionFlag: " + field_10_compressionFlag + nl +
|
||||||
|
" Filter: " + field_11_filter + nl +
|
||||||
|
" Data:" + nl + extraData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compress the contents of the provided array
|
||||||
|
*
|
||||||
|
* @param data An uncompressed byte array
|
||||||
|
* @see DeflaterOutputStream#write(int b)
|
||||||
|
*/
|
||||||
|
public static byte[] compress( byte[] data )
|
||||||
|
{
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
DeflaterOutputStream deflaterOutputStream = new DeflaterOutputStream( out );
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < data.length; i++ )
|
||||||
|
deflaterOutputStream.write( data[i] );
|
||||||
|
}
|
||||||
|
catch ( IOException e )
|
||||||
|
{
|
||||||
|
throw new RecordFormatException( e.toString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
return out.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decompresses a byte array.
|
||||||
|
*
|
||||||
|
* @param data The compressed byte array
|
||||||
|
* @param pos The starting position into the byte array
|
||||||
|
* @param length The number of compressed bytes to decompress
|
||||||
|
* @return An uncompressed byte array
|
||||||
|
* @see InflaterInputStream#read
|
||||||
|
*/
|
||||||
|
public static byte[] decompress( byte[] data, int pos, int length )
|
||||||
|
{
|
||||||
|
byte[] compressedData = new byte[length];
|
||||||
|
System.arraycopy( data, pos + 50, compressedData, 0, length );
|
||||||
|
InputStream compressedInputStream = new ByteArrayInputStream( compressedData );
|
||||||
|
InflaterInputStream inflaterInputStream = new InflaterInputStream( compressedInputStream );
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
int c;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while ( ( c = inflaterInputStream.read() ) != -1 )
|
||||||
|
out.write( c );
|
||||||
|
}
|
||||||
|
catch ( IOException e )
|
||||||
|
{
|
||||||
|
throw new RecordFormatException( e.toString() );
|
||||||
|
}
|
||||||
|
return out.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
50
src/java/org/apache/poi/ddf/EscherBoolProperty.java
Normal file
50
src/java/org/apache/poi/ddf/EscherBoolProperty.java
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a boolean property. The actual utility of this property is in doubt because many
|
||||||
|
* of the properties marked as boolean seem to actually contain special values. In other words
|
||||||
|
* they're not true booleans.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis
|
||||||
|
* @see EscherSimpleProperty
|
||||||
|
* @see EscherProperty
|
||||||
|
*/
|
||||||
|
public class EscherBoolProperty
|
||||||
|
extends EscherSimpleProperty
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create an instance of an escher boolean property.
|
||||||
|
*
|
||||||
|
* @param propertyNumber The property number
|
||||||
|
* @param value The 32 bit value of this bool property
|
||||||
|
*/
|
||||||
|
public EscherBoolProperty( short propertyNumber, int value )
|
||||||
|
{
|
||||||
|
super( propertyNumber, false, false, value );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this boolean property is true
|
||||||
|
*/
|
||||||
|
public boolean isTrue()
|
||||||
|
{
|
||||||
|
return propertyValue != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this boolean property is false
|
||||||
|
*/
|
||||||
|
public boolean isFalse()
|
||||||
|
{
|
||||||
|
return propertyValue == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public String toString()
|
||||||
|
// {
|
||||||
|
// return "propNum: " + getPropertyNumber()
|
||||||
|
// + ", complex: " + isComplex()
|
||||||
|
// + ", blipId: " + isBlipId()
|
||||||
|
// + ", value: " + (getValue() != 0);
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
176
src/java/org/apache/poi/ddf/EscherChildAnchorRecord.java
Normal file
176
src/java/org/apache/poi/ddf/EscherChildAnchorRecord.java
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The escher child achor record is used to specify the position of a shape under an
|
||||||
|
* existing group. The first level of shape records use a EscherClientAnchor record instead.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis
|
||||||
|
* @see EscherChildAnchorRecord
|
||||||
|
*/
|
||||||
|
public class EscherChildAnchorRecord
|
||||||
|
extends EscherRecord
|
||||||
|
{
|
||||||
|
public static final short RECORD_ID = (short) 0xF00F;
|
||||||
|
public static final String RECORD_DESCRIPTION = "MsofbtChildAnchor";
|
||||||
|
|
||||||
|
private int field_1_dx1;
|
||||||
|
private int field_2_dy1;
|
||||||
|
private int field_3_dx2;
|
||||||
|
private int field_4_dy2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
int size = 0;
|
||||||
|
field_1_dx1 = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_2_dy1 = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_3_dx2 = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_4_dy2 = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
return 8 + size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 );
|
||||||
|
int pos = offset;
|
||||||
|
LittleEndian.putShort( data, pos, getOptions() ); pos += 2;
|
||||||
|
LittleEndian.putShort( data, pos, getRecordId() ); pos += 2;
|
||||||
|
LittleEndian.putInt( data, pos, getRecordSize()-8 ); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_1_dx1 ); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_2_dy1 ); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_3_dx2 ); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_4_dy2 ); pos += 4;
|
||||||
|
|
||||||
|
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 + 4 * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The record id for the EscherChildAnchorRecord.
|
||||||
|
*/
|
||||||
|
public short getRecordId()
|
||||||
|
{
|
||||||
|
return RECORD_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The short name for this record
|
||||||
|
*/
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
return "ChildAnchor";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The string representation of this record
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
return getClass().getName() + ":" + nl +
|
||||||
|
" RecordId: 0x" + HexDump.toHex(RECORD_ID) + nl +
|
||||||
|
" Options: 0x" + HexDump.toHex(getOptions()) + nl +
|
||||||
|
" X1: " + field_1_dx1 + nl +
|
||||||
|
" Y1: " + field_2_dy1 + nl +
|
||||||
|
" X2: " + field_3_dx2 + nl +
|
||||||
|
" Y2: " + field_4_dy2 + nl ;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves offset within the parent coordinate space for the top left point.
|
||||||
|
*/
|
||||||
|
public int getDx1()
|
||||||
|
{
|
||||||
|
return field_1_dx1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets offset within the parent coordinate space for the top left point.
|
||||||
|
*/
|
||||||
|
public void setDx1( int field_1_dx1 )
|
||||||
|
{
|
||||||
|
this.field_1_dx1 = field_1_dx1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets offset within the parent coordinate space for the top left point.
|
||||||
|
*/
|
||||||
|
public int getDy1()
|
||||||
|
{
|
||||||
|
return field_2_dy1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets offset within the parent coordinate space for the top left point.
|
||||||
|
*/
|
||||||
|
public void setDy1( int field_2_dy1 )
|
||||||
|
{
|
||||||
|
this.field_2_dy1 = field_2_dy1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves offset within the parent coordinate space for the bottom right point.
|
||||||
|
*/
|
||||||
|
public int getDx2()
|
||||||
|
{
|
||||||
|
return field_3_dx2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets offset within the parent coordinate space for the bottom right point.
|
||||||
|
*/
|
||||||
|
public void setDx2( int field_3_dx2 )
|
||||||
|
{
|
||||||
|
this.field_3_dx2 = field_3_dx2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the offset within the parent coordinate space for the bottom right point.
|
||||||
|
*/
|
||||||
|
public int getDy2()
|
||||||
|
{
|
||||||
|
return field_4_dy2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the offset within the parent coordinate space for the bottom right point.
|
||||||
|
*/
|
||||||
|
public void setDy2( int field_4_dy2 )
|
||||||
|
{
|
||||||
|
this.field_4_dy2 = field_4_dy2;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
317
src/java/org/apache/poi/ddf/EscherClientAnchorRecord.java
Normal file
317
src/java/org/apache/poi/ddf/EscherClientAnchorRecord.java
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The escher client anchor specifies which rows and cells the shape is bound to as well as
|
||||||
|
* the offsets within those cells. Each cell is 1024 units wide by 256 units long regardless
|
||||||
|
* of the actual size of the cell. The EscherClientAnchorRecord only applies to the top-most
|
||||||
|
* shapes. Shapes contained in groups are bound using the EscherChildAnchorRecords.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis
|
||||||
|
* @see EscherChildAnchorRecord
|
||||||
|
*/
|
||||||
|
public class EscherClientAnchorRecord
|
||||||
|
extends EscherRecord
|
||||||
|
{
|
||||||
|
public static final short RECORD_ID = (short) 0xF010;
|
||||||
|
public static final String RECORD_DESCRIPTION = "MsofbtClientAnchor";
|
||||||
|
|
||||||
|
private short field_1_flag;
|
||||||
|
private short field_2_col1;
|
||||||
|
private short field_3_dx1;
|
||||||
|
private short field_4_row1;
|
||||||
|
private short field_5_dy1;
|
||||||
|
private short field_6_col2;
|
||||||
|
private short field_7_dx2;
|
||||||
|
private short field_8_row2;
|
||||||
|
private short field_9_dy2;
|
||||||
|
private byte[] remainingData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
int size = 0;
|
||||||
|
field_1_flag = LittleEndian.getShort( data, pos + size ); size += 2;
|
||||||
|
field_2_col1 = LittleEndian.getShort( data, pos + size ); size += 2;
|
||||||
|
field_3_dx1 = LittleEndian.getShort( data, pos + size ); size += 2;
|
||||||
|
field_4_row1 = LittleEndian.getShort( data, pos + size ); size += 2;
|
||||||
|
field_5_dy1 = LittleEndian.getShort( data, pos + size ); size += 2;
|
||||||
|
field_6_col2 = LittleEndian.getShort( data, pos + size ); size += 2;
|
||||||
|
field_7_dx2 = LittleEndian.getShort( data, pos + size ); size += 2;
|
||||||
|
field_8_row2 = LittleEndian.getShort( data, pos + size ); size += 2;
|
||||||
|
field_9_dy2 = LittleEndian.getShort( data, pos + size ); size += 2;
|
||||||
|
bytesRemaining -= size;
|
||||||
|
remainingData = new byte[bytesRemaining];
|
||||||
|
System.arraycopy( data, pos + size, remainingData, 0, bytesRemaining );
|
||||||
|
return 8 + size + bytesRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 );
|
||||||
|
|
||||||
|
if (remainingData == null) remainingData = new byte[0];
|
||||||
|
LittleEndian.putShort( data, offset, getOptions() );
|
||||||
|
LittleEndian.putShort( data, offset + 2, getRecordId() );
|
||||||
|
int remainingBytes = remainingData.length + 18;
|
||||||
|
LittleEndian.putInt( data, offset + 4, remainingBytes );
|
||||||
|
LittleEndian.putShort( data, offset + 8, field_1_flag );
|
||||||
|
LittleEndian.putShort( data, offset + 10, field_2_col1 );
|
||||||
|
LittleEndian.putShort( data, offset + 12, field_3_dx1 );
|
||||||
|
LittleEndian.putShort( data, offset + 14, field_4_row1 );
|
||||||
|
LittleEndian.putShort( data, offset + 16, field_5_dy1 );
|
||||||
|
LittleEndian.putShort( data, offset + 18, field_6_col2 );
|
||||||
|
LittleEndian.putShort( data, offset + 20, field_7_dx2 );
|
||||||
|
LittleEndian.putShort( data, offset + 22, field_8_row2 );
|
||||||
|
LittleEndian.putShort( data, offset + 24, field_9_dy2 );
|
||||||
|
System.arraycopy( remainingData, 0, data, offset + 26, remainingData.length );
|
||||||
|
int pos = offset + 8 + 18 + remainingData.length;
|
||||||
|
|
||||||
|
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 + 18 + (remainingData == null ? 0 : remainingData.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The record id for this record.
|
||||||
|
*/
|
||||||
|
public short getRecordId()
|
||||||
|
{
|
||||||
|
return RECORD_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The short name for this record
|
||||||
|
*/
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
return "ClientAnchor";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the string representation for this record.
|
||||||
|
*
|
||||||
|
* @return A string
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
String extraData;
|
||||||
|
ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HexDump.dump(this.remainingData, 0, b, 0);
|
||||||
|
extraData = b.toString();
|
||||||
|
}
|
||||||
|
catch ( Exception e )
|
||||||
|
{
|
||||||
|
extraData = "error";
|
||||||
|
}
|
||||||
|
return getClass().getName() + ":" + nl +
|
||||||
|
" RecordId: 0x" + HexDump.toHex(RECORD_ID) + nl +
|
||||||
|
" Options: 0x" + HexDump.toHex(getOptions()) + nl +
|
||||||
|
" Flag: " + field_1_flag + nl +
|
||||||
|
" Col1: " + field_2_col1 + nl +
|
||||||
|
" DX1: " + field_3_dx1 + nl +
|
||||||
|
" Row1: " + field_4_row1 + nl +
|
||||||
|
" DY1: " + field_5_dy1 + nl +
|
||||||
|
" Col2: " + field_6_col2 + nl +
|
||||||
|
" DX2: " + field_7_dx2 + nl +
|
||||||
|
" Row2: " + field_8_row2 + nl +
|
||||||
|
" DY2: " + field_9_dy2 + nl +
|
||||||
|
" Extra Data:" + nl + extraData;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 0 = Move and size with Cells, 2 = Move but don't size with cells, 3 = Don't move or size with cells.
|
||||||
|
*/
|
||||||
|
public short getFlag()
|
||||||
|
{
|
||||||
|
return field_1_flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 0 = Move and size with Cells, 2 = Move but don't size with cells, 3 = Don't move or size with cells.
|
||||||
|
*/
|
||||||
|
public void setFlag( short field_1_flag )
|
||||||
|
{
|
||||||
|
this.field_1_flag = field_1_flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The column number for the top-left position. 0 based.
|
||||||
|
*/
|
||||||
|
public short getCol1()
|
||||||
|
{
|
||||||
|
return field_2_col1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The column number for the top-left position. 0 based.
|
||||||
|
*/
|
||||||
|
public void setCol1( short field_2_col1 )
|
||||||
|
{
|
||||||
|
this.field_2_col1 = field_2_col1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The x offset within the top-left cell. Range is from 0 to 1023.
|
||||||
|
*/
|
||||||
|
public short getDx1()
|
||||||
|
{
|
||||||
|
return field_3_dx1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The x offset within the top-left cell. Range is from 0 to 1023.
|
||||||
|
*/
|
||||||
|
public void setDx1( short field_3_dx1 )
|
||||||
|
{
|
||||||
|
this.field_3_dx1 = field_3_dx1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The row number for the top-left corner of the shape.
|
||||||
|
*/
|
||||||
|
public short getRow1()
|
||||||
|
{
|
||||||
|
return field_4_row1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The row number for the top-left corner of the shape.
|
||||||
|
*/
|
||||||
|
public void setRow1( short field_4_row1 )
|
||||||
|
{
|
||||||
|
this.field_4_row1 = field_4_row1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The y offset within the top-left corner of the current shape.
|
||||||
|
*/
|
||||||
|
public short getDy1()
|
||||||
|
{
|
||||||
|
return field_5_dy1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The y offset within the top-left corner of the current shape.
|
||||||
|
*/
|
||||||
|
public void setDy1( short field_5_dy1 )
|
||||||
|
{
|
||||||
|
this.field_5_dy1 = field_5_dy1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The column of the bottom right corner of this shape.
|
||||||
|
*/
|
||||||
|
public short getCol2()
|
||||||
|
{
|
||||||
|
return field_6_col2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The column of the bottom right corner of this shape.
|
||||||
|
*/
|
||||||
|
public void setCol2( short field_6_col2 )
|
||||||
|
{
|
||||||
|
this.field_6_col2 = field_6_col2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The x offset withing the cell for the bottom-right corner of this shape.
|
||||||
|
*/
|
||||||
|
public short getDx2()
|
||||||
|
{
|
||||||
|
return field_7_dx2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The x offset withing the cell for the bottom-right corner of this shape.
|
||||||
|
*/
|
||||||
|
public void setDx2( short field_7_dx2 )
|
||||||
|
{
|
||||||
|
this.field_7_dx2 = field_7_dx2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The row number for the bottom-right corner of the current shape.
|
||||||
|
*/
|
||||||
|
public short getRow2()
|
||||||
|
{
|
||||||
|
return field_8_row2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The row number for the bottom-right corner of the current shape.
|
||||||
|
*/
|
||||||
|
public void setRow2( short field_8_row2 )
|
||||||
|
{
|
||||||
|
this.field_8_row2 = field_8_row2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The y offset withing the cell for the bottom-right corner of this shape.
|
||||||
|
*/
|
||||||
|
public short getDy2()
|
||||||
|
{
|
||||||
|
return field_9_dy2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The y offset withing the cell for the bottom-right corner of this shape.
|
||||||
|
*/
|
||||||
|
public void setDy2( short field_9_dy2 )
|
||||||
|
{
|
||||||
|
this.field_9_dy2 = field_9_dy2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any remaining data in the record
|
||||||
|
*/
|
||||||
|
public byte[] getRemainingData()
|
||||||
|
{
|
||||||
|
return remainingData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any remaining data in the record
|
||||||
|
*/
|
||||||
|
public void setRemainingData( byte[] remainingData )
|
||||||
|
{
|
||||||
|
this.remainingData = remainingData;
|
||||||
|
}
|
||||||
|
}
|
130
src/java/org/apache/poi/ddf/EscherClientDataRecord.java
Normal file
130
src/java/org/apache/poi/ddf/EscherClientDataRecord.java
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The EscherClientDataRecord is used to store client specific data about the position of a
|
||||||
|
* shape within a container.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis
|
||||||
|
*/
|
||||||
|
public class EscherClientDataRecord
|
||||||
|
extends EscherRecord
|
||||||
|
{
|
||||||
|
public static final short RECORD_ID = (short) 0xF011;
|
||||||
|
public static final String RECORD_DESCRIPTION = "MsofbtClientData";
|
||||||
|
|
||||||
|
private byte[] remainingData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
remainingData = new byte[bytesRemaining];
|
||||||
|
System.arraycopy( data, pos, remainingData, 0, bytesRemaining );
|
||||||
|
return 8 + bytesRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 );
|
||||||
|
|
||||||
|
if (remainingData == null) remainingData = new byte[0];
|
||||||
|
LittleEndian.putShort( data, offset, getOptions() );
|
||||||
|
LittleEndian.putShort( data, offset + 2, getRecordId() );
|
||||||
|
LittleEndian.putInt( data, offset + 4, remainingData.length );
|
||||||
|
System.arraycopy( remainingData, 0, data, offset + 8, remainingData.length );
|
||||||
|
int pos = offset + 8 + remainingData.length;
|
||||||
|
|
||||||
|
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 + (remainingData == null ? 0 : remainingData.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the identifier of this record.
|
||||||
|
*/
|
||||||
|
public short getRecordId()
|
||||||
|
{
|
||||||
|
return RECORD_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The short name for this record
|
||||||
|
*/
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
return "ClientData";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the string representation of this record.
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
String extraData;
|
||||||
|
ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HexDump.dump(this.remainingData, 0, b, 0);
|
||||||
|
extraData = b.toString();
|
||||||
|
}
|
||||||
|
catch ( Exception e )
|
||||||
|
{
|
||||||
|
extraData = "error";
|
||||||
|
}
|
||||||
|
return getClass().getName() + ":" + nl +
|
||||||
|
" RecordId: 0x" + HexDump.toHex(RECORD_ID) + nl +
|
||||||
|
" Options: 0x" + HexDump.toHex(getOptions()) + nl +
|
||||||
|
" Extra Data:" + nl +
|
||||||
|
extraData;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any data recording this record.
|
||||||
|
*/
|
||||||
|
public byte[] getRemainingData()
|
||||||
|
{
|
||||||
|
return remainingData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any data recording this record.
|
||||||
|
*/
|
||||||
|
public void setRemainingData( byte[] remainingData )
|
||||||
|
{
|
||||||
|
this.remainingData = remainingData;
|
||||||
|
}
|
||||||
|
}
|
152
src/java/org/apache/poi/ddf/EscherComplexProperty.java
Normal file
152
src/java/org/apache/poi/ddf/EscherComplexProperty.java
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A complex property differs from a simple property in that the data can not fit inside a 32 bit
|
||||||
|
* integer. See the specification for more detailed information regarding exactly what is
|
||||||
|
* stored here.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis
|
||||||
|
*/
|
||||||
|
public class EscherComplexProperty
|
||||||
|
extends EscherProperty
|
||||||
|
{
|
||||||
|
byte[] complexData = new byte[0];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a complex property using the property id and a byte array containing the complex
|
||||||
|
* data value.
|
||||||
|
*
|
||||||
|
* @param id The id consists of the property number, a flag indicating whether this is a blip id and a flag
|
||||||
|
* indicating that this is a complex property.
|
||||||
|
* @param complexData The value of this property.
|
||||||
|
*/
|
||||||
|
public EscherComplexProperty( short id, byte[] complexData )
|
||||||
|
{
|
||||||
|
super( id );
|
||||||
|
this.complexData = complexData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a complex property using the property number, a flag to indicate whether this is a
|
||||||
|
* blip reference and the complex property data.
|
||||||
|
*
|
||||||
|
* @param propertyNumber The property number
|
||||||
|
* @param isBlipId Whether this is a blip id. Should be false.
|
||||||
|
* @param complexData The value of this complex property.
|
||||||
|
*/
|
||||||
|
public EscherComplexProperty( short propertyNumber, boolean isBlipId, byte[] complexData )
|
||||||
|
{
|
||||||
|
super( propertyNumber, true, isBlipId );
|
||||||
|
this.complexData = complexData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes the simple part of this property. ie the first 6 bytes.
|
||||||
|
*/
|
||||||
|
public int serializeSimplePart( byte[] data, int pos )
|
||||||
|
{
|
||||||
|
LittleEndian.putShort(data, pos, getId());
|
||||||
|
LittleEndian.putInt(data, pos + 2, complexData.length);
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes the complex part of this property
|
||||||
|
*
|
||||||
|
* @param data The data array to serialize to
|
||||||
|
* @param pos The offset within data to start serializing to.
|
||||||
|
* @return The number of bytes serialized.
|
||||||
|
*/
|
||||||
|
public int serializeComplexPart( byte[] data, int pos )
|
||||||
|
{
|
||||||
|
System.arraycopy(complexData, 0, data, pos, complexData.length);
|
||||||
|
return complexData.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the complex data value.
|
||||||
|
*/
|
||||||
|
public byte[] getComplexData()
|
||||||
|
{
|
||||||
|
return complexData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether this property is equal to another property.
|
||||||
|
*
|
||||||
|
* @param o The object to compare to.
|
||||||
|
* @return True if the objects are equal.
|
||||||
|
*/
|
||||||
|
public boolean equals( Object o )
|
||||||
|
{
|
||||||
|
if ( this == o ) return true;
|
||||||
|
if ( !( o instanceof EscherComplexProperty ) ) return false;
|
||||||
|
|
||||||
|
final EscherComplexProperty escherComplexProperty = (EscherComplexProperty) o;
|
||||||
|
|
||||||
|
if ( !Arrays.equals( complexData, escherComplexProperty.complexData ) ) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Caclulates the number of bytes required to serialize this property.
|
||||||
|
*
|
||||||
|
* @return Number of bytes
|
||||||
|
*/
|
||||||
|
public int getPropertySize()
|
||||||
|
{
|
||||||
|
return 6 + complexData.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates a hashcode for this property.
|
||||||
|
*/
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return getId() * 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the string representation for this property.
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String dataStr;
|
||||||
|
ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HexDump.dump( this.complexData, 0, b, 0 );
|
||||||
|
dataStr = b.toString();
|
||||||
|
}
|
||||||
|
catch ( Exception e )
|
||||||
|
{
|
||||||
|
dataStr = e.toString();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
b.close();
|
||||||
|
}
|
||||||
|
catch ( IOException e )
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "propNum: " + getPropertyNumber()
|
||||||
|
+ ", propName: " + EscherProperties.getPropertyName( getPropertyNumber() )
|
||||||
|
+ ", complex: " + isComplex()
|
||||||
|
+ ", blipId: " + isBlipId()
|
||||||
|
+ ", data: " + System.getProperty("line.separator") + dataStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
168
src/java/org/apache/poi/ddf/EscherContainerRecord.java
Normal file
168
src/java/org/apache/poi/ddf/EscherContainerRecord.java
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escher container records store other escher records as children.
|
||||||
|
* The container records themselves never store any information beyond
|
||||||
|
* the standard header used by all escher records. This one record is
|
||||||
|
* used to represent many different types of records.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis
|
||||||
|
*/
|
||||||
|
public class EscherContainerRecord extends EscherRecord
|
||||||
|
{
|
||||||
|
public static final short DGG_CONTAINER = (short)0xF000;
|
||||||
|
public static final short BSTORE_CONTAINER = (short)0xF001;
|
||||||
|
public static final short DG_CONTAINER = (short)0xF002;
|
||||||
|
public static final short SPGR_CONTAINER = (short)0xF003;
|
||||||
|
public static final short SP_CONTAINER = (short)0xF004;
|
||||||
|
public static final short SOLVER_CONTAINER = (short)0xF005;
|
||||||
|
|
||||||
|
private List childRecords = new ArrayList();
|
||||||
|
|
||||||
|
public int fillFields( byte[] data, int offset, EscherRecordFactory recordFactory )
|
||||||
|
{
|
||||||
|
int bytesRemaining = readHeader( data, offset );
|
||||||
|
int bytesWritten = 8;
|
||||||
|
offset += 8;
|
||||||
|
while ( bytesRemaining > 0 && offset < data.length )
|
||||||
|
{
|
||||||
|
EscherRecord child = recordFactory.createRecord(data, offset);
|
||||||
|
int childBytesWritten = child.fillFields( data, offset, recordFactory );
|
||||||
|
bytesWritten += childBytesWritten;
|
||||||
|
offset += childBytesWritten;
|
||||||
|
bytesRemaining -= childBytesWritten;
|
||||||
|
getChildRecords().add( child );
|
||||||
|
if (offset >= data.length && bytesRemaining > 0)
|
||||||
|
{
|
||||||
|
System.out.println("WARNING: " + bytesRemaining + " bytes remaining but no space left");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bytesWritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
int remainingBytes = 0;
|
||||||
|
for ( Iterator iterator = getChildRecords().iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord r = (EscherRecord) iterator.next();
|
||||||
|
remainingBytes += r.getRecordSize();
|
||||||
|
}
|
||||||
|
LittleEndian.putInt(data, offset+4, remainingBytes);
|
||||||
|
int pos = offset+8;
|
||||||
|
for ( Iterator iterator = getChildRecords().iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord r = (EscherRecord) iterator.next();
|
||||||
|
pos += r.serialize(pos, data, listener );
|
||||||
|
}
|
||||||
|
|
||||||
|
listener.afterRecordSerialize( pos, getRecordId(), pos - offset, this );
|
||||||
|
return pos - offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
int childRecordsSize = 0;
|
||||||
|
for ( Iterator iterator = getChildRecords().iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord r = (EscherRecord) iterator.next();
|
||||||
|
childRecordsSize += r.getRecordSize();
|
||||||
|
}
|
||||||
|
return 8 + childRecordsSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List getChildRecords()
|
||||||
|
{
|
||||||
|
return childRecords;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChildRecords( List childRecords )
|
||||||
|
{
|
||||||
|
this.childRecords = childRecords;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
switch ((short)getRecordId())
|
||||||
|
{
|
||||||
|
case DGG_CONTAINER:
|
||||||
|
return "DggContainer";
|
||||||
|
case BSTORE_CONTAINER:
|
||||||
|
return "BStoreContainer";
|
||||||
|
case DG_CONTAINER:
|
||||||
|
return "DgContainer";
|
||||||
|
case SPGR_CONTAINER:
|
||||||
|
return "SpgrContainer";
|
||||||
|
case SP_CONTAINER:
|
||||||
|
return "SpContainer";
|
||||||
|
case SOLVER_CONTAINER:
|
||||||
|
return "SolverContainer";
|
||||||
|
default:
|
||||||
|
return "Container 0x" + HexDump.toHex(getRecordId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display( PrintWriter w, int indent )
|
||||||
|
{
|
||||||
|
super.display( w, indent );
|
||||||
|
for ( Iterator iterator = childRecords.iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord escherRecord = (EscherRecord) iterator.next();
|
||||||
|
escherRecord.display( w, indent + 1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addChildRecord( EscherRecord record )
|
||||||
|
{
|
||||||
|
this.childRecords.add( record );
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty( "line.separator" );
|
||||||
|
|
||||||
|
StringBuffer children = new StringBuffer();
|
||||||
|
if ( getChildRecords().size() > 0 )
|
||||||
|
{
|
||||||
|
children.append( " children: " + nl );
|
||||||
|
for ( Iterator iterator = getChildRecords().iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord record = (EscherRecord) iterator.next();
|
||||||
|
children.append( record.toString() );
|
||||||
|
// children.append( nl );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return getClass().getName() + " (" + getRecordName() + "):" + nl +
|
||||||
|
" isContainer: " + isContainerRecord() + nl +
|
||||||
|
" options: 0x" + HexDump.toHex( getOptions() ) + nl +
|
||||||
|
" recordId: 0x" + HexDump.toHex( getRecordId() ) + nl +
|
||||||
|
" numchildren: " + getChildRecords().size() + nl +
|
||||||
|
children.toString();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public EscherSpRecord getChildById( short recordId )
|
||||||
|
{
|
||||||
|
for ( Iterator iterator = childRecords.iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord escherRecord = (EscherRecord) iterator.next();
|
||||||
|
if (escherRecord.getRecordId() == recordId)
|
||||||
|
return (EscherSpRecord) escherRecord;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
163
src/java/org/apache/poi/ddf/EscherDgRecord.java
Normal file
163
src/java/org/apache/poi/ddf/EscherDgRecord.java
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This record simply holds the number of shapes in the drawing group and the
|
||||||
|
* last shape id used for this drawing group.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis
|
||||||
|
*/
|
||||||
|
public class EscherDgRecord
|
||||||
|
extends EscherRecord
|
||||||
|
{
|
||||||
|
public static final short RECORD_ID = (short) 0xF008;
|
||||||
|
public static final String RECORD_DESCRIPTION = "MsofbtDg";
|
||||||
|
|
||||||
|
private int field_1_numShapes;
|
||||||
|
private int field_2_lastMSOSPID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
int size = 0;
|
||||||
|
field_1_numShapes = LittleEndian.getInt( data, pos + size ); size += 4;
|
||||||
|
field_2_lastMSOSPID = LittleEndian.getInt( data, pos + size ); size += 4;
|
||||||
|
// bytesRemaining -= size;
|
||||||
|
// remainingData = new byte[bytesRemaining];
|
||||||
|
// System.arraycopy( data, pos + size, remainingData, 0, bytesRemaining );
|
||||||
|
return getRecordSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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, 8 );
|
||||||
|
LittleEndian.putInt( data, offset + 8, field_1_numShapes );
|
||||||
|
LittleEndian.putInt( data, offset + 12, field_2_lastMSOSPID );
|
||||||
|
// System.arraycopy( remainingData, 0, data, offset + 26, remainingData.length );
|
||||||
|
// int pos = offset + 8 + 18 + remainingData.length;
|
||||||
|
|
||||||
|
listener.afterRecordSerialize( offset + 16, getRecordId(), getRecordSize(), this );
|
||||||
|
return getRecordSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes that are required to serialize this record.
|
||||||
|
*
|
||||||
|
* @return Number of bytes
|
||||||
|
*/
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
return 8 + 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getRecordId()
|
||||||
|
{
|
||||||
|
return RECORD_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The short name for this record
|
||||||
|
*/
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
return "Dg";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the string representation of this record.
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
// String extraData;
|
||||||
|
// ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// HexDump.dump(this.remainingData, 0, b, 0);
|
||||||
|
// extraData = b.toString();
|
||||||
|
// }
|
||||||
|
// catch ( Exception e )
|
||||||
|
// {
|
||||||
|
// extraData = "error";
|
||||||
|
// }
|
||||||
|
return getClass().getName() + ":" + nl +
|
||||||
|
" RecordId: 0x" + HexDump.toHex(RECORD_ID) + nl +
|
||||||
|
" Options: 0x" + HexDump.toHex(getOptions()) + nl +
|
||||||
|
" NumShapes: " + field_1_numShapes + nl +
|
||||||
|
" LastMSOSPID: " + field_2_lastMSOSPID + nl;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of shapes in this drawing group.
|
||||||
|
*/
|
||||||
|
public int getNumShapes()
|
||||||
|
{
|
||||||
|
return field_1_numShapes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of shapes in this drawing group.
|
||||||
|
*/
|
||||||
|
public void setNumShapes( int field_1_numShapes )
|
||||||
|
{
|
||||||
|
this.field_1_numShapes = field_1_numShapes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The last shape id used in this drawing group.
|
||||||
|
*/
|
||||||
|
public int getLastMSOSPID()
|
||||||
|
{
|
||||||
|
return field_2_lastMSOSPID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The last shape id used in this drawing group.
|
||||||
|
*/
|
||||||
|
public void setLastMSOSPID( int field_2_lastMSOSPID )
|
||||||
|
{
|
||||||
|
this.field_2_lastMSOSPID = field_2_lastMSOSPID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the drawing group id for this record. This is encoded in the
|
||||||
|
* instance part of the option record.
|
||||||
|
*
|
||||||
|
* @return a drawing group id.
|
||||||
|
*/
|
||||||
|
public short getDrawingGroupId()
|
||||||
|
{
|
||||||
|
return (short) ( getOptions() >> 4 );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void incrementShapeCount()
|
||||||
|
{
|
||||||
|
this.field_1_numShapes++;
|
||||||
|
}
|
||||||
|
}
|
241
src/java/org/apache/poi/ddf/EscherDggRecord.java
Normal file
241
src/java/org/apache/poi/ddf/EscherDggRecord.java
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.hssf.record.RecordFormatException;
|
||||||
|
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This record defines the drawing groups used for a particular sheet.
|
||||||
|
*/
|
||||||
|
public class EscherDggRecord
|
||||||
|
extends EscherRecord
|
||||||
|
{
|
||||||
|
public static final short RECORD_ID = (short) 0xF006;
|
||||||
|
public static final String RECORD_DESCRIPTION = "MsofbtDgg";
|
||||||
|
|
||||||
|
private int field_1_shapeIdMax;
|
||||||
|
// private int field_2_numIdClusters; // for some reason the number of clusters is actually the real number + 1
|
||||||
|
private int field_3_numShapesSaved;
|
||||||
|
private int field_4_drawingsSaved;
|
||||||
|
private FileIdCluster[] field_5_fileIdClusters;
|
||||||
|
|
||||||
|
public static class FileIdCluster
|
||||||
|
{
|
||||||
|
public FileIdCluster( int drawingGroupId, int numShapeIdsUsed )
|
||||||
|
{
|
||||||
|
this.field_1_drawingGroupId = drawingGroupId;
|
||||||
|
this.field_2_numShapeIdsUsed = numShapeIdsUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int field_1_drawingGroupId;
|
||||||
|
private int field_2_numShapeIdsUsed;
|
||||||
|
|
||||||
|
public int getDrawingGroupId()
|
||||||
|
{
|
||||||
|
return field_1_drawingGroupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumShapeIdsUsed()
|
||||||
|
{
|
||||||
|
return field_2_numShapeIdsUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void incrementShapeId( )
|
||||||
|
{
|
||||||
|
this.field_2_numShapeIdsUsed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
int size = 0;
|
||||||
|
field_1_shapeIdMax = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
int field_2_numIdClusters = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_3_numShapesSaved = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_4_drawingsSaved = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_5_fileIdClusters = new FileIdCluster[field_2_numIdClusters-1];
|
||||||
|
for (int i = 0; i < field_2_numIdClusters-1; i++)
|
||||||
|
{
|
||||||
|
field_5_fileIdClusters[i] = new FileIdCluster(LittleEndian.getInt( data, pos + size ), LittleEndian.getInt( data, pos + size + 4 ));
|
||||||
|
size += 8;
|
||||||
|
}
|
||||||
|
bytesRemaining -= size;
|
||||||
|
if (bytesRemaining != 0)
|
||||||
|
throw new RecordFormatException("Expecting no remaining data but got " + bytesRemaining + " byte(s).");
|
||||||
|
return 8 + size + bytesRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 );
|
||||||
|
|
||||||
|
int pos = offset;
|
||||||
|
LittleEndian.putShort( data, pos, getOptions() ); pos += 2;
|
||||||
|
LittleEndian.putShort( data, pos, getRecordId() ); pos += 2;
|
||||||
|
int remainingBytes = getRecordSize() - 8;
|
||||||
|
LittleEndian.putInt( data, pos, remainingBytes ); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_1_shapeIdMax ); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, getNumIdClusters() ); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_3_numShapesSaved ); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_4_drawingsSaved ); pos += 4;
|
||||||
|
for ( int i = 0; i < field_5_fileIdClusters.length; i++ )
|
||||||
|
{
|
||||||
|
LittleEndian.putInt( data, pos, field_5_fileIdClusters[i].field_1_drawingGroupId ); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_5_fileIdClusters[i].field_2_numShapeIdsUsed ); pos += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
listener.afterRecordSerialize( pos, getRecordId(), getRecordSize(), this );
|
||||||
|
return getRecordSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes that are required to serialize this record.
|
||||||
|
*
|
||||||
|
* @return Number of bytes
|
||||||
|
*/
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
return 8 + 16 + (8 * field_5_fileIdClusters.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getRecordId()
|
||||||
|
{
|
||||||
|
return RECORD_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The short name for this record
|
||||||
|
*/
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
return "Dgg";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
// String extraData;
|
||||||
|
// ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// HexDump.dump(this.remainingData, 0, b, 0);
|
||||||
|
// extraData = b.toString();
|
||||||
|
// }
|
||||||
|
// catch ( Exception e )
|
||||||
|
// {
|
||||||
|
// extraData = "error";
|
||||||
|
// }
|
||||||
|
StringBuffer field_5_string = new StringBuffer();
|
||||||
|
for ( int i = 0; i < field_5_fileIdClusters.length; i++ )
|
||||||
|
{
|
||||||
|
field_5_string.append(" DrawingGroupId").append(i+1).append(": ");
|
||||||
|
field_5_string.append(field_5_fileIdClusters[i].field_1_drawingGroupId);
|
||||||
|
field_5_string.append(nl);
|
||||||
|
field_5_string.append(" NumShapeIdsUsed").append(i+1).append(": ");
|
||||||
|
field_5_string.append(field_5_fileIdClusters[i].field_2_numShapeIdsUsed);
|
||||||
|
field_5_string.append(nl);
|
||||||
|
}
|
||||||
|
return getClass().getName() + ":" + nl +
|
||||||
|
" RecordId: 0x" + HexDump.toHex(RECORD_ID) + nl +
|
||||||
|
" Options: 0x" + HexDump.toHex(getOptions()) + nl +
|
||||||
|
" ShapeIdMax: " + field_1_shapeIdMax + nl +
|
||||||
|
" NumIdClusters: " + getNumIdClusters() + nl +
|
||||||
|
" NumShapesSaved: " + field_3_numShapesSaved + nl +
|
||||||
|
" DrawingsSaved: " + field_4_drawingsSaved + nl +
|
||||||
|
"" + field_5_string.toString();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getShapeIdMax()
|
||||||
|
{
|
||||||
|
return field_1_shapeIdMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum is actually the next available. shape id.
|
||||||
|
*/
|
||||||
|
public void setShapeIdMax( int field_1_shapeIdMax )
|
||||||
|
{
|
||||||
|
this.field_1_shapeIdMax = field_1_shapeIdMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumIdClusters()
|
||||||
|
{
|
||||||
|
return field_5_fileIdClusters.length + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumShapesSaved()
|
||||||
|
{
|
||||||
|
return field_3_numShapesSaved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumShapesSaved( int field_3_numShapesSaved )
|
||||||
|
{
|
||||||
|
this.field_3_numShapesSaved = field_3_numShapesSaved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDrawingsSaved()
|
||||||
|
{
|
||||||
|
return field_4_drawingsSaved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDrawingsSaved( int field_4_drawingsSaved )
|
||||||
|
{
|
||||||
|
this.field_4_drawingsSaved = field_4_drawingsSaved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileIdCluster[] getFileIdClusters()
|
||||||
|
{
|
||||||
|
return field_5_fileIdClusters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileIdClusters( FileIdCluster[] field_5_fileIdClusters )
|
||||||
|
{
|
||||||
|
this.field_5_fileIdClusters = field_5_fileIdClusters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addCluster( int dgId, int numShapedUsed )
|
||||||
|
{
|
||||||
|
List clusters = new ArrayList(Arrays.asList(field_5_fileIdClusters));
|
||||||
|
clusters.add(new FileIdCluster(dgId, numShapedUsed));
|
||||||
|
Collections.sort(clusters, new Comparator()
|
||||||
|
{
|
||||||
|
public int compare( Object o1, Object o2 )
|
||||||
|
{
|
||||||
|
FileIdCluster f1 = (FileIdCluster) o1;
|
||||||
|
FileIdCluster f2 = (FileIdCluster) o2;
|
||||||
|
if (f1.getDrawingGroupId() == f2.getDrawingGroupId())
|
||||||
|
return 0;
|
||||||
|
if (f1.getDrawingGroupId() < f2.getDrawingGroupId())
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return +1;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
field_5_fileIdClusters = (FileIdCluster[]) clusters.toArray( new FileIdCluster[clusters.size()] );
|
||||||
|
}
|
||||||
|
}
|
990
src/java/org/apache/poi/ddf/EscherDump.java
Normal file
990
src/java/org/apache/poi/ddf/EscherDump.java
Normal file
@ -0,0 +1,990 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
* 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
|
||||||
|
* <http://www.apache.org/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.HexRead;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.util.zip.InflaterInputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to dump the contents of escher records to a PrintStream.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class EscherDump
|
||||||
|
{
|
||||||
|
|
||||||
|
public EscherDump()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes the escher stream from a byte array and dumps the results to
|
||||||
|
* a print stream.
|
||||||
|
*
|
||||||
|
* @param data The data array containing the escher records.
|
||||||
|
* @param offset The starting offset within the data array.
|
||||||
|
* @param size The number of bytes to read.
|
||||||
|
* @param out The output stream to write the results to.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void dump( byte[] data, int offset, int size, PrintStream out ) throws IOException, LittleEndian.BufferUnderrunException
|
||||||
|
{
|
||||||
|
EscherRecordFactory recordFactory = new DefaultEscherRecordFactory();
|
||||||
|
int pos = offset;
|
||||||
|
while ( pos < offset + size )
|
||||||
|
{
|
||||||
|
EscherRecord r = recordFactory.createRecord(data, pos);
|
||||||
|
int bytesRead = r.fillFields(data, pos, recordFactory );
|
||||||
|
System.out.println( r.toString() );
|
||||||
|
pos += bytesRead;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This version of dump is a translation from the open office escher dump routine.
|
||||||
|
*
|
||||||
|
* @param maxLength The number of bytes to read
|
||||||
|
* @param in An input stream to read from.
|
||||||
|
* @param out An output stream to write to.
|
||||||
|
*/
|
||||||
|
public void dumpOld( long maxLength, InputStream in, PrintStream out ) throws IOException, LittleEndian.BufferUnderrunException
|
||||||
|
{
|
||||||
|
long remainingBytes = maxLength;
|
||||||
|
short options; // 4 bits for the version and 12 bits for the instance
|
||||||
|
short recordId;
|
||||||
|
int recordBytesRemaining; // including enclosing records
|
||||||
|
StringBuffer stringBuf = new StringBuffer();
|
||||||
|
short nDumpSize;
|
||||||
|
String recordName;
|
||||||
|
|
||||||
|
boolean atEOF = false;
|
||||||
|
|
||||||
|
while ( !atEOF && ( remainingBytes > 0 ) )
|
||||||
|
{
|
||||||
|
stringBuf = new StringBuffer();
|
||||||
|
options = LittleEndian.readShort( in );
|
||||||
|
recordId = LittleEndian.readShort( in );
|
||||||
|
recordBytesRemaining = LittleEndian.readInt( in );
|
||||||
|
|
||||||
|
remainingBytes -= 2 + 2 + 4;
|
||||||
|
|
||||||
|
switch ( recordId )
|
||||||
|
{
|
||||||
|
case (short) 0xF000:
|
||||||
|
recordName = "MsofbtDggContainer";
|
||||||
|
break;
|
||||||
|
case (short) 0xF006:
|
||||||
|
recordName = "MsofbtDgg";
|
||||||
|
break;
|
||||||
|
case (short) 0xF016:
|
||||||
|
recordName = "MsofbtCLSID";
|
||||||
|
break;
|
||||||
|
case (short) 0xF00B:
|
||||||
|
recordName = "MsofbtOPT";
|
||||||
|
break;
|
||||||
|
case (short) 0xF11A:
|
||||||
|
recordName = "MsofbtColorMRU";
|
||||||
|
break;
|
||||||
|
case (short) 0xF11E:
|
||||||
|
recordName = "MsofbtSplitMenuColors";
|
||||||
|
break;
|
||||||
|
case (short) 0xF001:
|
||||||
|
recordName = "MsofbtBstoreContainer";
|
||||||
|
break;
|
||||||
|
case (short) 0xF007:
|
||||||
|
recordName = "MsofbtBSE";
|
||||||
|
break;
|
||||||
|
case (short) 0xF002:
|
||||||
|
recordName = "MsofbtDgContainer";
|
||||||
|
break;
|
||||||
|
case (short) 0xF008:
|
||||||
|
recordName = "MsofbtDg";
|
||||||
|
break;
|
||||||
|
case (short) 0xF118:
|
||||||
|
recordName = "MsofbtRegroupItem";
|
||||||
|
break;
|
||||||
|
case (short) 0xF120:
|
||||||
|
recordName = "MsofbtColorScheme";
|
||||||
|
break;
|
||||||
|
case (short) 0xF003:
|
||||||
|
recordName = "MsofbtSpgrContainer";
|
||||||
|
break;
|
||||||
|
case (short) 0xF004:
|
||||||
|
recordName = "MsofbtSpContainer";
|
||||||
|
break;
|
||||||
|
case (short) 0xF009:
|
||||||
|
recordName = "MsofbtSpgr";
|
||||||
|
break;
|
||||||
|
case (short) 0xF00A:
|
||||||
|
recordName = "MsofbtSp";
|
||||||
|
break;
|
||||||
|
case (short) 0xF00C:
|
||||||
|
recordName = "MsofbtTextbox";
|
||||||
|
break;
|
||||||
|
case (short) 0xF00D:
|
||||||
|
recordName = "MsofbtClientTextbox";
|
||||||
|
break;
|
||||||
|
case (short) 0xF00E:
|
||||||
|
recordName = "MsofbtAnchor";
|
||||||
|
break;
|
||||||
|
case (short) 0xF00F:
|
||||||
|
recordName = "MsofbtChildAnchor";
|
||||||
|
break;
|
||||||
|
case (short) 0xF010:
|
||||||
|
recordName = "MsofbtClientAnchor";
|
||||||
|
break;
|
||||||
|
case (short) 0xF011:
|
||||||
|
recordName = "MsofbtClientData";
|
||||||
|
break;
|
||||||
|
case (short) 0xF11F:
|
||||||
|
recordName = "MsofbtOleObject";
|
||||||
|
break;
|
||||||
|
case (short) 0xF11D:
|
||||||
|
recordName = "MsofbtDeletedPspl";
|
||||||
|
break;
|
||||||
|
case (short) 0xF005:
|
||||||
|
recordName = "MsofbtSolverContainer";
|
||||||
|
break;
|
||||||
|
case (short) 0xF012:
|
||||||
|
recordName = "MsofbtConnectorRule";
|
||||||
|
break;
|
||||||
|
case (short) 0xF013:
|
||||||
|
recordName = "MsofbtAlignRule";
|
||||||
|
break;
|
||||||
|
case (short) 0xF014:
|
||||||
|
recordName = "MsofbtArcRule";
|
||||||
|
break;
|
||||||
|
case (short) 0xF015:
|
||||||
|
recordName = "MsofbtClientRule";
|
||||||
|
break;
|
||||||
|
case (short) 0xF017:
|
||||||
|
recordName = "MsofbtCalloutRule";
|
||||||
|
break;
|
||||||
|
case (short) 0xF119:
|
||||||
|
recordName = "MsofbtSelection";
|
||||||
|
break;
|
||||||
|
case (short) 0xF122:
|
||||||
|
recordName = "MsofbtUDefProp";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if ( recordId >= (short) 0xF018 && recordId <= (short) 0xF117 )
|
||||||
|
recordName = "MsofbtBLIP";
|
||||||
|
else if ( ( options & (short) 0x000F ) == (short) 0x000F )
|
||||||
|
recordName = "UNKNOWN container";
|
||||||
|
else
|
||||||
|
recordName = "UNKNOWN ID";
|
||||||
|
}
|
||||||
|
|
||||||
|
stringBuf.append( " " );
|
||||||
|
stringBuf.append( HexDump.toHex( recordId ) );
|
||||||
|
stringBuf.append( " " ).append( recordName ).append( " [" );
|
||||||
|
stringBuf.append( HexDump.toHex( options ) );
|
||||||
|
stringBuf.append( ',' );
|
||||||
|
stringBuf.append( HexDump.toHex( recordBytesRemaining ) );
|
||||||
|
stringBuf.append( "] instance: " );
|
||||||
|
stringBuf.append( HexDump.toHex( ( (short) ( options >> 4 ) ) ) );
|
||||||
|
out.println( stringBuf.toString() );
|
||||||
|
|
||||||
|
|
||||||
|
if ( recordId == (short) 0xF007 && 36 <= remainingBytes && 36 <= recordBytesRemaining )
|
||||||
|
{ // BSE, FBSE
|
||||||
|
// ULONG nP = pIn->GetRecPos();
|
||||||
|
|
||||||
|
byte n8;
|
||||||
|
// short n16;
|
||||||
|
// int n32;
|
||||||
|
|
||||||
|
stringBuf = new StringBuffer( " btWin32: " );
|
||||||
|
n8 = (byte) in.read();
|
||||||
|
stringBuf.append( HexDump.toHex( n8 ) );
|
||||||
|
stringBuf.append( getBlipType( n8 ) );
|
||||||
|
stringBuf.append( " btMacOS: " );
|
||||||
|
n8 = (byte) in.read();
|
||||||
|
stringBuf.append( HexDump.toHex( n8 ) );
|
||||||
|
stringBuf.append( getBlipType( n8 ) );
|
||||||
|
out.println( stringBuf.toString() );
|
||||||
|
|
||||||
|
out.println( " rgbUid:" );
|
||||||
|
HexDump.dump( in, out, 0, 16 );
|
||||||
|
|
||||||
|
out.print( " tag: " );
|
||||||
|
outHex( 2, in, out );
|
||||||
|
out.println();
|
||||||
|
out.print( " size: " );
|
||||||
|
outHex( 4, in, out );
|
||||||
|
out.println();
|
||||||
|
out.print( " cRef: " );
|
||||||
|
outHex( 4, in, out );
|
||||||
|
out.println();
|
||||||
|
out.print( " offs: " );
|
||||||
|
outHex( 4, in, out );
|
||||||
|
out.println();
|
||||||
|
out.print( " usage: " );
|
||||||
|
outHex( 1, in, out );
|
||||||
|
out.println();
|
||||||
|
out.print( " cbName: " );
|
||||||
|
outHex( 1, in, out );
|
||||||
|
out.println();
|
||||||
|
out.print( " unused2: " );
|
||||||
|
outHex( 1, in, out );
|
||||||
|
out.println();
|
||||||
|
out.print( " unused3: " );
|
||||||
|
outHex( 1, in, out );
|
||||||
|
out.println();
|
||||||
|
|
||||||
|
// subtract the number of bytes we've read
|
||||||
|
remainingBytes -= 36;
|
||||||
|
//n -= pIn->GetRecPos() - nP;
|
||||||
|
recordBytesRemaining = 0; // loop to MsofbtBLIP
|
||||||
|
}
|
||||||
|
else if ( recordId == (short) 0xF010 && 0x12 <= remainingBytes && 0x12 <= recordBytesRemaining )
|
||||||
|
{ // ClientAnchor
|
||||||
|
//ULONG nP = pIn->GetRecPos();
|
||||||
|
// short n16;
|
||||||
|
|
||||||
|
out.print( " Flag: " );
|
||||||
|
outHex( 2, in, out );
|
||||||
|
out.println();
|
||||||
|
out.print( " Col1: " );
|
||||||
|
outHex( 2, in, out );
|
||||||
|
out.print( " dX1: " );
|
||||||
|
outHex( 2, in, out );
|
||||||
|
out.print( " Row1: " );
|
||||||
|
outHex( 2, in, out );
|
||||||
|
out.print( " dY1: " );
|
||||||
|
outHex( 2, in, out );
|
||||||
|
out.println();
|
||||||
|
out.print( " Col2: " );
|
||||||
|
outHex( 2, in, out );
|
||||||
|
out.print( " dX2: " );
|
||||||
|
outHex( 2, in, out );
|
||||||
|
out.print( " Row2: " );
|
||||||
|
outHex( 2, in, out );
|
||||||
|
out.print( " dY2: " );
|
||||||
|
outHex( 2, in, out );
|
||||||
|
out.println();
|
||||||
|
|
||||||
|
remainingBytes -= 18;
|
||||||
|
recordBytesRemaining -= 18;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if ( recordId == (short) 0xF00B || recordId == (short) 0xF122 )
|
||||||
|
{ // OPT
|
||||||
|
int nComplex = 0;
|
||||||
|
out.println( " PROPID VALUE" );
|
||||||
|
while ( recordBytesRemaining >= 6 + nComplex && remainingBytes >= 6 + nComplex )
|
||||||
|
{
|
||||||
|
short n16;
|
||||||
|
int n32;
|
||||||
|
n16 = LittleEndian.readShort( in );
|
||||||
|
n32 = LittleEndian.readInt( in );
|
||||||
|
|
||||||
|
recordBytesRemaining -= 6;
|
||||||
|
remainingBytes -= 6;
|
||||||
|
out.print( " " );
|
||||||
|
out.print( HexDump.toHex( n16 ) );
|
||||||
|
out.print( " (" );
|
||||||
|
int propertyId = n16 & (short) 0x3FFF;
|
||||||
|
out.print( " " + propertyId );
|
||||||
|
if ( ( n16 & (short) 0x8000 ) == 0 )
|
||||||
|
{
|
||||||
|
if ( ( n16 & (short) 0x4000 ) != 0 )
|
||||||
|
out.print( ", fBlipID" );
|
||||||
|
out.print( ") " );
|
||||||
|
|
||||||
|
out.print( HexDump.toHex( n32 ) );
|
||||||
|
|
||||||
|
if ( ( n16 & (short) 0x4000 ) == 0 )
|
||||||
|
{
|
||||||
|
out.print( " (" );
|
||||||
|
out.print( dec1616( n32 ) );
|
||||||
|
out.print( ')' );
|
||||||
|
out.print( " {" + propName( (short)propertyId ) + "}" );
|
||||||
|
}
|
||||||
|
out.println();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out.print( ", fComplex) " );
|
||||||
|
out.print( HexDump.toHex( n32 ) );
|
||||||
|
out.print( " - Complex prop len" );
|
||||||
|
out.println( " {" + propName( (short)propertyId ) + "}" );
|
||||||
|
|
||||||
|
nComplex += n32;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// complex property data
|
||||||
|
while ( ( nComplex & remainingBytes ) > 0 )
|
||||||
|
{
|
||||||
|
nDumpSize = ( nComplex > (int) remainingBytes ) ? (short) remainingBytes : (short) nComplex;
|
||||||
|
HexDump.dump( in, out, 0, nDumpSize );
|
||||||
|
nComplex -= nDumpSize;
|
||||||
|
recordBytesRemaining -= nDumpSize;
|
||||||
|
remainingBytes -= nDumpSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( recordId == (short) 0xF012 )
|
||||||
|
{
|
||||||
|
out.print( " Connector rule: " );
|
||||||
|
out.print( LittleEndian.readInt( in ) );
|
||||||
|
out.print( " ShapeID A: " );
|
||||||
|
out.print( LittleEndian.readInt( in ) );
|
||||||
|
out.print( " ShapeID B: " );
|
||||||
|
out.print( LittleEndian.readInt( in ) );
|
||||||
|
out.print( " ShapeID connector: " );
|
||||||
|
out.print( LittleEndian.readInt( in ) );
|
||||||
|
out.print( " Connect pt A: " );
|
||||||
|
out.print( LittleEndian.readInt( in ) );
|
||||||
|
out.print( " Connect pt B: " );
|
||||||
|
out.println( LittleEndian.readInt( in ) );
|
||||||
|
|
||||||
|
recordBytesRemaining -= 24;
|
||||||
|
remainingBytes -= 24;
|
||||||
|
}
|
||||||
|
else if ( recordId >= (short) 0xF018 && recordId < (short) 0xF117 )
|
||||||
|
{
|
||||||
|
out.println( " Secondary UID: " );
|
||||||
|
HexDump.dump( in, out, 0, 16 );
|
||||||
|
out.println( " Cache of size: " + HexDump.toHex( LittleEndian.readInt( in ) ) );
|
||||||
|
out.println( " Boundary top: " + HexDump.toHex( LittleEndian.readInt( in ) ) );
|
||||||
|
out.println( " Boundary left: " + HexDump.toHex( LittleEndian.readInt( in ) ) );
|
||||||
|
out.println( " Boundary width: " + HexDump.toHex( LittleEndian.readInt( in ) ) );
|
||||||
|
out.println( " Boundary height: " + HexDump.toHex( LittleEndian.readInt( in ) ) );
|
||||||
|
out.println( " X: " + HexDump.toHex( LittleEndian.readInt( in ) ) );
|
||||||
|
out.println( " Y: " + HexDump.toHex( LittleEndian.readInt( in ) ) );
|
||||||
|
out.println( " Cache of saved size: " + HexDump.toHex( LittleEndian.readInt( in ) ) );
|
||||||
|
out.println( " Compression Flag: " + HexDump.toHex( (byte) in.read() ) );
|
||||||
|
out.println( " Filter: " + HexDump.toHex( (byte) in.read() ) );
|
||||||
|
out.println( " Data (after decompression): " );
|
||||||
|
|
||||||
|
recordBytesRemaining -= 34 + 16;
|
||||||
|
remainingBytes -= 34 + 16;
|
||||||
|
|
||||||
|
nDumpSize = ( recordBytesRemaining > (int) remainingBytes ) ? (short) remainingBytes : (short) recordBytesRemaining;
|
||||||
|
|
||||||
|
|
||||||
|
byte[] buf = new byte[nDumpSize];
|
||||||
|
int read = in.read( buf );
|
||||||
|
while ( read != -1 && read < nDumpSize )
|
||||||
|
read += in.read( buf, read, buf.length );
|
||||||
|
ByteArrayInputStream bin = new ByteArrayInputStream( buf );
|
||||||
|
|
||||||
|
InputStream in1 = new InflaterInputStream( bin );
|
||||||
|
int bytesToDump = -1;
|
||||||
|
HexDump.dump( in1, out, 0, bytesToDump );
|
||||||
|
|
||||||
|
recordBytesRemaining -= nDumpSize;
|
||||||
|
remainingBytes -= nDumpSize;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isContainer = ( options & (short) 0x000F ) == (short) 0x000F;
|
||||||
|
if ( isContainer && remainingBytes >= 0 )
|
||||||
|
{ // Container
|
||||||
|
if ( recordBytesRemaining <= (int) remainingBytes )
|
||||||
|
out.println( " completed within" );
|
||||||
|
else
|
||||||
|
out.println( " continued elsewhere" );
|
||||||
|
}
|
||||||
|
else if ( remainingBytes >= 0 )
|
||||||
|
// -> 0x0000 ... 0x0FFF
|
||||||
|
{
|
||||||
|
nDumpSize = ( recordBytesRemaining > (int) remainingBytes ) ? (short) remainingBytes : (short) recordBytesRemaining;
|
||||||
|
|
||||||
|
if ( nDumpSize != 0 )
|
||||||
|
{
|
||||||
|
HexDump.dump( in, out, 0, nDumpSize );
|
||||||
|
remainingBytes -= nDumpSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
out.println( " >> OVERRUN <<" );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a property name given a property id. This is used only by the
|
||||||
|
* old escher dump routine.
|
||||||
|
*
|
||||||
|
* @param propertyId The property number for the name
|
||||||
|
* @return A descriptive name.
|
||||||
|
*/
|
||||||
|
private String propName( short propertyId )
|
||||||
|
{
|
||||||
|
class PropName {
|
||||||
|
public PropName( int id, String name )
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
int id;
|
||||||
|
String name;
|
||||||
|
}
|
||||||
|
|
||||||
|
final PropName[] props = new PropName[] {
|
||||||
|
new PropName(4, "transform.rotation"),
|
||||||
|
new PropName(119, "protection.lockrotation"),
|
||||||
|
new PropName(120, "protection.lockaspectratio"),
|
||||||
|
new PropName(121, "protection.lockposition"),
|
||||||
|
new PropName(122, "protection.lockagainstselect"),
|
||||||
|
new PropName(123, "protection.lockcropping"),
|
||||||
|
new PropName(124, "protection.lockvertices"),
|
||||||
|
new PropName(125, "protection.locktext"),
|
||||||
|
new PropName(126, "protection.lockadjusthandles"),
|
||||||
|
new PropName(127, "protection.lockagainstgrouping"),
|
||||||
|
new PropName(128, "text.textid"),
|
||||||
|
new PropName(129, "text.textleft"),
|
||||||
|
new PropName(130, "text.texttop"),
|
||||||
|
new PropName(131, "text.textright"),
|
||||||
|
new PropName(132, "text.textbottom"),
|
||||||
|
new PropName(133, "text.wraptext"),
|
||||||
|
new PropName(134, "text.scaletext"),
|
||||||
|
new PropName(135, "text.anchortext"),
|
||||||
|
new PropName(136, "text.textflow"),
|
||||||
|
new PropName(137, "text.fontrotation"),
|
||||||
|
new PropName(138, "text.idofnextshape"),
|
||||||
|
new PropName(139, "text.bidir"),
|
||||||
|
new PropName(187, "text.singleclickselects"),
|
||||||
|
new PropName(188, "text.usehostmargins"),
|
||||||
|
new PropName(189, "text.rotatetextwithshape"),
|
||||||
|
new PropName(190, "text.sizeshapetofittext"),
|
||||||
|
new PropName(191, "text.sizetexttofitshape"),
|
||||||
|
new PropName(192, "geotext.unicode"),
|
||||||
|
new PropName(193, "geotext.rtftext"),
|
||||||
|
new PropName(194, "geotext.alignmentoncurve"),
|
||||||
|
new PropName(195, "geotext.defaultpointsize"),
|
||||||
|
new PropName(196, "geotext.textspacing"),
|
||||||
|
new PropName(197, "geotext.fontfamilyname"),
|
||||||
|
new PropName(240, "geotext.reverseroworder"),
|
||||||
|
new PropName(241, "geotext.hastexteffect"),
|
||||||
|
new PropName(242, "geotext.rotatecharacters"),
|
||||||
|
new PropName(243, "geotext.kerncharacters"),
|
||||||
|
new PropName(244, "geotext.tightortrack"),
|
||||||
|
new PropName(245, "geotext.stretchtofitshape"),
|
||||||
|
new PropName(246, "geotext.charboundingbox"),
|
||||||
|
new PropName(247, "geotext.scaletextonpath"),
|
||||||
|
new PropName(248, "geotext.stretchcharheight"),
|
||||||
|
new PropName(249, "geotext.nomeasurealongpath"),
|
||||||
|
new PropName(250, "geotext.boldfont"),
|
||||||
|
new PropName(251, "geotext.italicfont"),
|
||||||
|
new PropName(252, "geotext.underlinefont"),
|
||||||
|
new PropName(253, "geotext.shadowfont"),
|
||||||
|
new PropName(254, "geotext.smallcapsfont"),
|
||||||
|
new PropName(255, "geotext.strikethroughfont"),
|
||||||
|
new PropName(256, "blip.cropfromtop"),
|
||||||
|
new PropName(257, "blip.cropfrombottom"),
|
||||||
|
new PropName(258, "blip.cropfromleft"),
|
||||||
|
new PropName(259, "blip.cropfromright"),
|
||||||
|
new PropName(260, "blip.bliptodisplay"),
|
||||||
|
new PropName(261, "blip.blipfilename"),
|
||||||
|
new PropName(262, "blip.blipflags"),
|
||||||
|
new PropName(263, "blip.transparentcolor"),
|
||||||
|
new PropName(264, "blip.contrastsetting"),
|
||||||
|
new PropName(265, "blip.brightnesssetting"),
|
||||||
|
new PropName(266, "blip.gamma"),
|
||||||
|
new PropName(267, "blip.pictureid"),
|
||||||
|
new PropName(268, "blip.doublemod"),
|
||||||
|
new PropName(269, "blip.picturefillmod"),
|
||||||
|
new PropName(270, "blip.pictureline"),
|
||||||
|
new PropName(271, "blip.printblip"),
|
||||||
|
new PropName(272, "blip.printblipfilename"),
|
||||||
|
new PropName(273, "blip.printflags"),
|
||||||
|
new PropName(316, "blip.nohittestpicture"),
|
||||||
|
new PropName(317, "blip.picturegray"),
|
||||||
|
new PropName(318, "blip.picturebilevel"),
|
||||||
|
new PropName(319, "blip.pictureactive"),
|
||||||
|
new PropName(320, "geometry.left"),
|
||||||
|
new PropName(321, "geometry.top"),
|
||||||
|
new PropName(322, "geometry.right"),
|
||||||
|
new PropName(323, "geometry.bottom"),
|
||||||
|
new PropName(324, "geometry.shapepath"),
|
||||||
|
new PropName(325, "geometry.vertices"),
|
||||||
|
new PropName(326, "geometry.segmentinfo"),
|
||||||
|
new PropName(327, "geometry.adjustvalue"),
|
||||||
|
new PropName(328, "geometry.adjust2value"),
|
||||||
|
new PropName(329, "geometry.adjust3value"),
|
||||||
|
new PropName(330, "geometry.adjust4value"),
|
||||||
|
new PropName(331, "geometry.adjust5value"),
|
||||||
|
new PropName(332, "geometry.adjust6value"),
|
||||||
|
new PropName(333, "geometry.adjust7value"),
|
||||||
|
new PropName(334, "geometry.adjust8value"),
|
||||||
|
new PropName(335, "geometry.adjust9value"),
|
||||||
|
new PropName(336, "geometry.adjust10value"),
|
||||||
|
new PropName(378, "geometry.shadowOK"),
|
||||||
|
new PropName(379, "geometry.3dok"),
|
||||||
|
new PropName(380, "geometry.lineok"),
|
||||||
|
new PropName(381, "geometry.geotextok"),
|
||||||
|
new PropName(382, "geometry.fillshadeshapeok"),
|
||||||
|
new PropName(383, "geometry.fillok"),
|
||||||
|
new PropName(384, "fill.filltype"),
|
||||||
|
new PropName(385, "fill.fillcolor"),
|
||||||
|
new PropName(386, "fill.fillopacity"),
|
||||||
|
new PropName(387, "fill.fillbackcolor"),
|
||||||
|
new PropName(388, "fill.backopacity"),
|
||||||
|
new PropName(389, "fill.crmod"),
|
||||||
|
new PropName(390, "fill.patterntexture"),
|
||||||
|
new PropName(391, "fill.blipfilename"),
|
||||||
|
new PropName(392, "fill.blipflags"),
|
||||||
|
new PropName(393, "fill.width"),
|
||||||
|
new PropName(394, "fill.height"),
|
||||||
|
new PropName(395, "fill.angle"),
|
||||||
|
new PropName(396, "fill.focus"),
|
||||||
|
new PropName(397, "fill.toleft"),
|
||||||
|
new PropName(398, "fill.totop"),
|
||||||
|
new PropName(399, "fill.toright"),
|
||||||
|
new PropName(400, "fill.tobottom"),
|
||||||
|
new PropName(401, "fill.rectleft"),
|
||||||
|
new PropName(402, "fill.recttop"),
|
||||||
|
new PropName(403, "fill.rectright"),
|
||||||
|
new PropName(404, "fill.rectbottom"),
|
||||||
|
new PropName(405, "fill.dztype"),
|
||||||
|
new PropName(406, "fill.shadepreset"),
|
||||||
|
new PropName(407, "fill.shadecolors"),
|
||||||
|
new PropName(408, "fill.originx"),
|
||||||
|
new PropName(409, "fill.originy"),
|
||||||
|
new PropName(410, "fill.shapeoriginx"),
|
||||||
|
new PropName(411, "fill.shapeoriginy"),
|
||||||
|
new PropName(412, "fill.shadetype"),
|
||||||
|
new PropName(443, "fill.filled"),
|
||||||
|
new PropName(444, "fill.hittestfill"),
|
||||||
|
new PropName(445, "fill.shape"),
|
||||||
|
new PropName(446, "fill.userect"),
|
||||||
|
new PropName(447, "fill.nofillhittest"),
|
||||||
|
new PropName(448, "linestyle.color"),
|
||||||
|
new PropName(449, "linestyle.opacity"),
|
||||||
|
new PropName(450, "linestyle.backcolor"),
|
||||||
|
new PropName(451, "linestyle.crmod"),
|
||||||
|
new PropName(452, "linestyle.linetype"),
|
||||||
|
new PropName(453, "linestyle.fillblip"),
|
||||||
|
new PropName(454, "linestyle.fillblipname"),
|
||||||
|
new PropName(455, "linestyle.fillblipflags"),
|
||||||
|
new PropName(456, "linestyle.fillwidth"),
|
||||||
|
new PropName(457, "linestyle.fillheight"),
|
||||||
|
new PropName(458, "linestyle.filldztype"),
|
||||||
|
new PropName(459, "linestyle.linewidth"),
|
||||||
|
new PropName(460, "linestyle.linemiterlimit"),
|
||||||
|
new PropName(461, "linestyle.linestyle"),
|
||||||
|
new PropName(462, "linestyle.linedashing"),
|
||||||
|
new PropName(463, "linestyle.linedashstyle"),
|
||||||
|
new PropName(464, "linestyle.linestartarrowhead"),
|
||||||
|
new PropName(465, "linestyle.lineendarrowhead"),
|
||||||
|
new PropName(466, "linestyle.linestartarrowwidth"),
|
||||||
|
new PropName(467, "linestyle.lineestartarrowlength"),
|
||||||
|
new PropName(468, "linestyle.lineendarrowwidth"),
|
||||||
|
new PropName(469, "linestyle.lineendarrowlength"),
|
||||||
|
new PropName(470, "linestyle.linejoinstyle"),
|
||||||
|
new PropName(471, "linestyle.lineendcapstyle"),
|
||||||
|
new PropName(507, "linestyle.arrowheadsok"),
|
||||||
|
new PropName(508, "linestyle.anyline"),
|
||||||
|
new PropName(509, "linestyle.hitlinetest"),
|
||||||
|
new PropName(510, "linestyle.linefillshape"),
|
||||||
|
new PropName(511, "linestyle.nolinedrawdash"),
|
||||||
|
new PropName(512, "shadowstyle.type"),
|
||||||
|
new PropName(513, "shadowstyle.color"),
|
||||||
|
new PropName(514, "shadowstyle.highlight"),
|
||||||
|
new PropName(515, "shadowstyle.crmod"),
|
||||||
|
new PropName(516, "shadowstyle.opacity"),
|
||||||
|
new PropName(517, "shadowstyle.offsetx"),
|
||||||
|
new PropName(518, "shadowstyle.offsety"),
|
||||||
|
new PropName(519, "shadowstyle.secondoffsetx"),
|
||||||
|
new PropName(520, "shadowstyle.secondoffsety"),
|
||||||
|
new PropName(521, "shadowstyle.scalextox"),
|
||||||
|
new PropName(522, "shadowstyle.scaleytox"),
|
||||||
|
new PropName(523, "shadowstyle.scalextoy"),
|
||||||
|
new PropName(524, "shadowstyle.scaleytoy"),
|
||||||
|
new PropName(525, "shadowstyle.perspectivex"),
|
||||||
|
new PropName(526, "shadowstyle.perspectivey"),
|
||||||
|
new PropName(527, "shadowstyle.weight"),
|
||||||
|
new PropName(528, "shadowstyle.originx"),
|
||||||
|
new PropName(529, "shadowstyle.originy"),
|
||||||
|
new PropName(574, "shadowstyle.shadow"),
|
||||||
|
new PropName(575, "shadowstyle.shadowobsured"),
|
||||||
|
new PropName(576, "perspective.type"),
|
||||||
|
new PropName(577, "perspective.offsetx"),
|
||||||
|
new PropName(578, "perspective.offsety"),
|
||||||
|
new PropName(579, "perspective.scalextox"),
|
||||||
|
new PropName(580, "perspective.scaleytox"),
|
||||||
|
new PropName(581, "perspective.scalextoy"),
|
||||||
|
new PropName(582, "perspective.scaleytox"),
|
||||||
|
new PropName(583, "perspective.perspectivex"),
|
||||||
|
new PropName(584, "perspective.perspectivey"),
|
||||||
|
new PropName(585, "perspective.weight"),
|
||||||
|
new PropName(586, "perspective.originx"),
|
||||||
|
new PropName(587, "perspective.originy"),
|
||||||
|
new PropName(639, "perspective.perspectiveon"),
|
||||||
|
new PropName(640, "3d.specularamount"),
|
||||||
|
new PropName(661, "3d.diffuseamount"),
|
||||||
|
new PropName(662, "3d.shininess"),
|
||||||
|
new PropName(663, "3d.edgethickness"),
|
||||||
|
new PropName(664, "3d.extrudeforward"),
|
||||||
|
new PropName(665, "3d.extrudebackward"),
|
||||||
|
new PropName(666, "3d.extrudeplane"),
|
||||||
|
new PropName(667, "3d.extrusioncolor"),
|
||||||
|
new PropName(648, "3d.crmod"),
|
||||||
|
new PropName(700, "3d.3deffect"),
|
||||||
|
new PropName(701, "3d.metallic"),
|
||||||
|
new PropName(702, "3d.useextrusioncolor"),
|
||||||
|
new PropName(703, "3d.lightface"),
|
||||||
|
new PropName(704, "3dstyle.yrotationangle"),
|
||||||
|
new PropName(705, "3dstyle.xrotationangle"),
|
||||||
|
new PropName(706, "3dstyle.rotationaxisx"),
|
||||||
|
new PropName(707, "3dstyle.rotationaxisy"),
|
||||||
|
new PropName(708, "3dstyle.rotationaxisz"),
|
||||||
|
new PropName(709, "3dstyle.rotationangle"),
|
||||||
|
new PropName(710, "3dstyle.rotationcenterx"),
|
||||||
|
new PropName(711, "3dstyle.rotationcentery"),
|
||||||
|
new PropName(712, "3dstyle.rotationcenterz"),
|
||||||
|
new PropName(713, "3dstyle.rendermode"),
|
||||||
|
new PropName(714, "3dstyle.tolerance"),
|
||||||
|
new PropName(715, "3dstyle.xviewpoint"),
|
||||||
|
new PropName(716, "3dstyle.yviewpoint"),
|
||||||
|
new PropName(717, "3dstyle.zviewpoint"),
|
||||||
|
new PropName(718, "3dstyle.originx"),
|
||||||
|
new PropName(719, "3dstyle.originy"),
|
||||||
|
new PropName(720, "3dstyle.skewangle"),
|
||||||
|
new PropName(721, "3dstyle.skewamount"),
|
||||||
|
new PropName(722, "3dstyle.ambientintensity"),
|
||||||
|
new PropName(723, "3dstyle.keyx"),
|
||||||
|
new PropName(724, "3dstyle.keyy"),
|
||||||
|
new PropName(725, "3dstyle.keyz"),
|
||||||
|
new PropName(726, "3dstyle.keyintensity"),
|
||||||
|
new PropName(727, "3dstyle.fillx"),
|
||||||
|
new PropName(728, "3dstyle.filly"),
|
||||||
|
new PropName(729, "3dstyle.fillz"),
|
||||||
|
new PropName(730, "3dstyle.fillintensity"),
|
||||||
|
new PropName(763, "3dstyle.constrainrotation"),
|
||||||
|
new PropName(764, "3dstyle.rotationcenterauto"),
|
||||||
|
new PropName(765, "3dstyle.parallel"),
|
||||||
|
new PropName(766, "3dstyle.keyharsh"),
|
||||||
|
new PropName(767, "3dstyle.fillharsh"),
|
||||||
|
new PropName(769, "shape.master"),
|
||||||
|
new PropName(771, "shape.connectorstyle"),
|
||||||
|
new PropName(772, "shape.blackandwhitesettings"),
|
||||||
|
new PropName(773, "shape.wmodepurebw"),
|
||||||
|
new PropName(774, "shape.wmodebw"),
|
||||||
|
new PropName(826, "shape.oleicon"),
|
||||||
|
new PropName(827, "shape.preferrelativeresize"),
|
||||||
|
new PropName(828, "shape.lockshapetype"),
|
||||||
|
new PropName(830, "shape.deleteattachedobject"),
|
||||||
|
new PropName(831, "shape.backgroundshape"),
|
||||||
|
new PropName(832, "callout.callouttype"),
|
||||||
|
new PropName(833, "callout.xycalloutgap"),
|
||||||
|
new PropName(834, "callout.calloutangle"),
|
||||||
|
new PropName(835, "callout.calloutdroptype"),
|
||||||
|
new PropName(836, "callout.calloutdropspecified"),
|
||||||
|
new PropName(837, "callout.calloutlengthspecified"),
|
||||||
|
new PropName(889, "callout.iscallout"),
|
||||||
|
new PropName(890, "callout.calloutaccentbar"),
|
||||||
|
new PropName(891, "callout.callouttextborder"),
|
||||||
|
new PropName(892, "callout.calloutminusx"),
|
||||||
|
new PropName(893, "callout.calloutminusy"),
|
||||||
|
new PropName(894, "callout.dropauto"),
|
||||||
|
new PropName(895, "callout.lengthspecified"),
|
||||||
|
new PropName(896, "groupshape.shapename"),
|
||||||
|
new PropName(897, "groupshape.description"),
|
||||||
|
new PropName(898, "groupshape.hyperlink"),
|
||||||
|
new PropName(899, "groupshape.wrappolygonvertices"),
|
||||||
|
new PropName(900, "groupshape.wrapdistleft"),
|
||||||
|
new PropName(901, "groupshape.wrapdisttop"),
|
||||||
|
new PropName(902, "groupshape.wrapdistright"),
|
||||||
|
new PropName(903, "groupshape.wrapdistbottom"),
|
||||||
|
new PropName(904, "groupshape.regroupid"),
|
||||||
|
new PropName(953, "groupshape.editedwrap"),
|
||||||
|
new PropName(954, "groupshape.behinddocument"),
|
||||||
|
new PropName(955, "groupshape.ondblclicknotify"),
|
||||||
|
new PropName(956, "groupshape.isbutton"),
|
||||||
|
new PropName(957, "groupshape.1dadjustment"),
|
||||||
|
new PropName(958, "groupshape.hidden"),
|
||||||
|
new PropName(959, "groupshape.print"),
|
||||||
|
};
|
||||||
|
|
||||||
|
for ( int i = 0; i < props.length; i++ )
|
||||||
|
{
|
||||||
|
if (props[i].id == propertyId)
|
||||||
|
{
|
||||||
|
return props[i].name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "unknown property";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the blip description given a blip id.
|
||||||
|
*
|
||||||
|
* @param b blip id
|
||||||
|
* @return A description.
|
||||||
|
*/
|
||||||
|
private String getBlipType( byte b )
|
||||||
|
{
|
||||||
|
switch ( b )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return " ERROR";
|
||||||
|
case 1:
|
||||||
|
return " UNKNOWN";
|
||||||
|
case 2:
|
||||||
|
return " EMF";
|
||||||
|
case 3:
|
||||||
|
return " WMF";
|
||||||
|
case 4:
|
||||||
|
return " PICT";
|
||||||
|
case 5:
|
||||||
|
return " JPEG";
|
||||||
|
case 6:
|
||||||
|
return " PNG";
|
||||||
|
case 7:
|
||||||
|
return " DIB";
|
||||||
|
default:
|
||||||
|
if ( b < 32 )
|
||||||
|
return " NotKnown";
|
||||||
|
else
|
||||||
|
return " Client";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Straight conversion from OO. Converts a type of float.
|
||||||
|
*/
|
||||||
|
private String dec1616( int n32 )
|
||||||
|
{
|
||||||
|
String result = "";
|
||||||
|
result += (short) ( n32 >> 16 );
|
||||||
|
result += '.';
|
||||||
|
result += (short) ( n32 & (short) 0xFFFF );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dumps out a hex value by reading from a input stream.
|
||||||
|
*
|
||||||
|
* @param bytes How many bytes this hex value consists of.
|
||||||
|
* @param in The stream to read the hex value from.
|
||||||
|
* @param out The stream to write the nicely formatted hex value to.
|
||||||
|
*/
|
||||||
|
private void outHex( int bytes, InputStream in, PrintStream out ) throws IOException, LittleEndian.BufferUnderrunException
|
||||||
|
{
|
||||||
|
switch ( bytes )
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
out.print( HexDump.toHex( (byte) in.read() ) );
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
out.print( HexDump.toHex( LittleEndian.readShort( in ) ) );
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
out.print( HexDump.toHex( LittleEndian.readInt( in ) ) );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IOException( "Unable to output variable of that width" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple test stub.
|
||||||
|
*/
|
||||||
|
public static void main( String[] args ) throws IOException
|
||||||
|
{
|
||||||
|
String dump =
|
||||||
|
"0F 00 00 F0 89 07 00 00 00 00 06 F0 18 00 00 00 " +
|
||||||
|
"05 04 00 00 02 00 00 00 05 00 00 00 01 00 00 00 " +
|
||||||
|
"01 00 00 00 05 00 00 00 4F 00 01 F0 2F 07 00 00 " +
|
||||||
|
"42 00 07 F0 B7 01 00 00 03 04 3F 14 AE 6B 0F 65 " +
|
||||||
|
"B0 48 BF 5E 94 63 80 E8 91 73 FF 00 93 01 00 00 " +
|
||||||
|
"01 00 00 00 00 00 00 00 00 00 FF FF 20 54 1C F0 " +
|
||||||
|
"8B 01 00 00 3F 14 AE 6B 0F 65 B0 48 BF 5E 94 63 " +
|
||||||
|
"80 E8 91 73 92 0E 00 00 00 00 00 00 00 00 00 00 " +
|
||||||
|
"D1 07 00 00 DD 05 00 00 4A AD 6F 00 8A C5 53 00 " +
|
||||||
|
"59 01 00 00 00 FE 78 9C E3 9B C4 00 04 AC 77 D9 " +
|
||||||
|
"2F 32 08 32 FD E7 61 F8 FF 0F C8 FD 05 C5 30 19 " +
|
||||||
|
"10 90 63 90 FA 0F 06 0C 8C 0C 5C 70 19 43 30 EB " +
|
||||||
|
"0E FB 05 86 85 0C DB 18 58 80 72 8C 70 16 0B 83 " +
|
||||||
|
"05 56 51 29 88 C9 60 D9 69 0C 6C 20 26 23 03 C8 " +
|
||||||
|
"74 B0 A8 0E 03 07 FB 45 56 C7 A2 CC C4 1C 06 66 " +
|
||||||
|
"A0 0D 2C 40 39 5E 86 4C 06 3D A0 4E 10 D0 60 D9 " +
|
||||||
|
"C8 58 CC E8 CF B0 80 61 3A 8A 7E 0D C6 23 AC 4F " +
|
||||||
|
"E0 E2 98 B6 12 2B 06 73 9D 12 E3 52 56 59 F6 08 " +
|
||||||
|
"8A CC 52 66 A3 50 FF 96 2B 94 E9 DF 4C A1 FE 2D " +
|
||||||
|
"3A 03 AB 9F 81 C2 F0 A3 54 BF 0F 85 EE A7 54 FF " +
|
||||||
|
"40 FB 7F A0 E3 9F D2 F4 4F 71 FE 19 58 FF 2B 31 " +
|
||||||
|
"7F 67 36 3B 25 4F 99 1B 4E 53 A6 5F 89 25 95 E9 " +
|
||||||
|
"C4 00 C7 83 12 F3 1F 26 35 4A D3 D2 47 0E 0A C3 " +
|
||||||
|
"41 8E C9 8A 52 37 DC 15 A1 D0 0D BC 4C 06 0C 2B " +
|
||||||
|
"28 2C 13 28 D4 EF 43 61 5A A0 58 3F 85 71 E0 4B " +
|
||||||
|
"69 9E 64 65 FE 39 C0 E5 22 30 1D 30 27 0E 74 3A " +
|
||||||
|
"18 60 FD 4A CC B1 2C 13 7D 07 36 2D 2A 31 85 B2 " +
|
||||||
|
"6A 0D 74 1D 1D 22 4D 99 FE 60 0A F5 9B EC 1C 58 " +
|
||||||
|
"FD 67 06 56 3F 38 0D 84 3C A5 30 0E 28 D3 AF C4 " +
|
||||||
|
"A4 CA FA 44 7A 0D 65 6E 60 7F 4D A1 1B 24 58 F7 " +
|
||||||
|
"49 AF A5 CC 0D CC DF 19 FE 03 00 F0 B1 25 4D 42 " +
|
||||||
|
"00 07 F0 E1 01 00 00 03 04 39 50 BE 98 B0 6F 57 " +
|
||||||
|
"24 31 70 5D 23 2F 9F 10 66 FF 00 BD 01 00 00 01 " +
|
||||||
|
"00 00 00 00 00 00 00 00 00 FF FF 20 54 1C F0 B5 " +
|
||||||
|
"01 00 00 39 50 BE 98 B0 6F 57 24 31 70 5D 23 2F " +
|
||||||
|
"9F 10 66 DA 03 00 00 00 00 00 00 00 00 00 00 D1 " +
|
||||||
|
"07 00 00 DD 05 00 00 4A AD 6F 00 8A C5 53 00 83 " +
|
||||||
|
"01 00 00 00 FE 78 9C A5 52 BF 4B 42 51 14 3E F7 " +
|
||||||
|
"DC 77 7A 16 45 48 8B 3C 48 A8 16 15 0D 6C 88 D0 " +
|
||||||
|
"04 C3 40 A3 32 1C 84 96 08 21 04 A1 C5 5C A2 35 " +
|
||||||
|
"82 C0 35 6A AB 1C 6A 6B A8 24 5A 83 68 08 84 84 " +
|
||||||
|
"96 A2 86 A0 7F C2 86 5E E7 5E F5 41 E4 10 BC 03 " +
|
||||||
|
"1F E7 FB F1 CE B9 F7 F1 9E 7C 05 2E 7A 37 9B E0 " +
|
||||||
|
"45 7B 10 EC 6F 96 5F 1D 74 13 55 7E B0 6C 5D 20 " +
|
||||||
|
"60 C0 49 A2 9A BD 99 4F 50 83 1B 30 38 13 0E 33 " +
|
||||||
|
"60 A6 A7 6B B5 37 EB F4 10 FA 14 15 A0 B6 6B 37 " +
|
||||||
|
"0C 1E B3 49 73 5B A5 C2 26 48 3E C1 E0 6C 08 4A " +
|
||||||
|
"30 C9 93 AA 02 B8 20 13 62 05 4E E1 E8 D7 7C C0 " +
|
||||||
|
"B8 14 95 5E BE B8 A7 CF 1E BE 55 2C 56 B9 78 DF " +
|
||||||
|
"08 7E 88 4C 27 FF 7B DB FF 7A DD B7 1A 17 67 34 " +
|
||||||
|
"6A AE BA DA 35 D1 E7 72 BE FE EC 6E FE DA E5 7C " +
|
||||||
|
"3D EC 7A DE 03 FD 50 06 0B 23 F2 0E F3 B2 A5 11 " +
|
||||||
|
"91 0D 4C B5 B5 F3 BF 94 C1 8F 24 F7 D9 6F 60 94 " +
|
||||||
|
"3B C9 9A F3 1C 6B E7 BB F0 2E 49 B2 25 2B C6 B1 " +
|
||||||
|
"EE 69 EE 15 63 4F 71 7D CE 85 CC C8 35 B9 C3 28 " +
|
||||||
|
"28 CE D0 5C 67 79 F2 4A A2 14 23 A4 38 43 73 9D " +
|
||||||
|
"2D 69 2F C1 08 31 9F C5 5C 9B EB 7B C5 69 19 B3 " +
|
||||||
|
"B4 81 F3 DC E3 B4 8E 8B CC B3 94 53 5A E7 41 2A " +
|
||||||
|
"63 9A AA 38 C5 3D 48 BB EC 57 59 6F 2B AD 73 1F " +
|
||||||
|
"1D 60 92 AE 70 8C BB 8F CE 31 C1 3C 49 27 4A EB " +
|
||||||
|
"DC A4 5B 8C D1 0B 0E 73 37 E9 11 A7 99 C7 E8 41 " +
|
||||||
|
"69 B0 7F 00 96 F2 A7 E8 42 00 07 F0 B4 01 00 00 " +
|
||||||
|
"03 04 1A BA F9 D6 A9 B9 3A 03 08 61 E9 90 FF 7B " +
|
||||||
|
"9E E6 FF 00 90 01 00 00 01 00 00 00 00 00 00 00 " +
|
||||||
|
"00 00 FF FF 20 54 1C F0 88 01 00 00 1A BA F9 D6 " +
|
||||||
|
"A9 B9 3A 03 08 61 E9 90 FF 7B 9E E6 12 0E 00 00 " +
|
||||||
|
"00 00 00 00 00 00 00 00 D1 07 00 00 DD 05 00 00 " +
|
||||||
|
"4A AD 6F 00 8A C5 53 00 56 01 00 00 00 FE 78 9C " +
|
||||||
|
"E3 13 62 00 02 D6 BB EC 17 19 04 99 FE F3 30 FC " +
|
||||||
|
"FF 07 E4 FE 82 62 98 0C 08 C8 31 48 FD 07 03 06 " +
|
||||||
|
"46 06 2E B8 8C 21 98 75 87 FD 02 C3 42 86 6D 0C " +
|
||||||
|
"2C 40 39 46 38 8B 85 C1 02 AB A8 14 C4 64 B0 EC " +
|
||||||
|
"34 06 36 10 93 91 01 64 3A 58 54 87 81 83 FD 22 " +
|
||||||
|
"AB 63 51 66 62 0E 03 33 D0 06 16 A0 1C 2F 43 26 " +
|
||||||
|
"83 1E 50 27 08 68 B0 6C 64 2C 66 F4 67 58 C0 30 " +
|
||||||
|
"1D 45 BF 06 E3 11 D6 27 70 71 4C 5B 89 15 83 B9 " +
|
||||||
|
"4E 89 71 29 AB 2C 7B 04 45 66 29 B3 51 A8 7F CB " +
|
||||||
|
"15 CA F4 6F A6 50 FF 16 9D 81 D5 CF 40 61 F8 51 " +
|
||||||
|
"AA DF 87 42 F7 53 AA 7F A0 FD 3F D0 F1 4F 69 FA " +
|
||||||
|
"A7 38 FF 0C AC FF 95 98 BF 33 9B 9D 92 A7 CC 0D " +
|
||||||
|
"A7 29 D3 AF C4 92 CA 74 62 80 E3 41 89 F9 0F 93 " +
|
||||||
|
"1A A5 69 E9 23 07 85 E1 20 C7 64 45 A9 1B EE 8A " +
|
||||||
|
"50 E8 06 5E 26 03 86 15 14 96 09 14 EA F7 A1 30 " +
|
||||||
|
"2D 50 AC 9F C2 38 F0 A5 34 4F B2 32 FF 1C E0 72 " +
|
||||||
|
"11 98 0E 98 13 07 38 1D 28 31 C7 B2 4C F4 1D D8 " +
|
||||||
|
"B4 A0 C4 14 CA AA 35 D0 75 64 88 34 65 FA 83 29 " +
|
||||||
|
"D4 6F B2 73 60 F5 9F A1 54 FF 0E CA D3 40 C8 53 " +
|
||||||
|
"0A E3 E0 09 85 6E 50 65 7D 22 BD 86 32 37 B0 BF " +
|
||||||
|
"A6 D0 0D 12 AC FB A4 D7 52 E6 06 E6 EF 0C FF 01 " +
|
||||||
|
"97 1D 12 C7 42 00 07 F0 C3 01 00 00 03 04 BA 4C " +
|
||||||
|
"B6 23 BA 8B 27 BE C8 55 59 86 24 9F 89 D4 FF 00 " +
|
||||||
|
"9F 01 00 00 01 00 00 00 00 00 00 00 00 00 FF FF " +
|
||||||
|
"20 54 1C F0 97 01 00 00 BA 4C B6 23 BA 8B 27 BE " +
|
||||||
|
"C8 55 59 86 24 9F 89 D4 AE 0E 00 00 00 00 00 00 " +
|
||||||
|
"00 00 00 00 D1 07 00 00 DD 05 00 00 4A AD 6F 00 " +
|
||||||
|
"8A C5 53 00 65 01 00 00 00 FE 78 9C E3 5B C7 00 " +
|
||||||
|
"04 AC 77 D9 2F 32 08 32 FD E7 61 F8 FF 0F C8 FD " +
|
||||||
|
"05 C5 30 19 10 90 63 90 FA 0F 06 0C 8C 0C 5C 70 " +
|
||||||
|
"19 43 30 EB 0E FB 05 86 85 0C DB 18 58 80 72 8C " +
|
||||||
|
"70 16 0B 83 05 56 51 29 88 C9 60 D9 69 0C 6C 20 " +
|
||||||
|
"26 23 03 C8 74 B0 A8 0E 03 07 FB 45 56 C7 A2 CC " +
|
||||||
|
"C4 1C 06 66 A0 0D 2C 40 39 5E 86 4C 06 3D A0 4E " +
|
||||||
|
"10 D0 60 99 C6 B8 98 D1 9F 61 01 C3 74 14 FD 1A " +
|
||||||
|
"8C 2B D8 84 B1 88 4B A5 A5 75 03 01 50 DF 59 46 " +
|
||||||
|
"77 46 0F A8 3C A6 AB 88 15 83 B9 5E 89 B1 8B D5 " +
|
||||||
|
"97 2D 82 22 B3 94 29 D5 BF E5 CA C0 EA DF AC 43 " +
|
||||||
|
"A1 FD 14 EA 67 A0 30 FC 28 D5 EF 43 A1 FB 7D 87 " +
|
||||||
|
"B8 FF 07 3A FE 07 3A FD 53 EA 7E 0A C3 4F 89 F9 " +
|
||||||
|
"0E 73 EA 69 79 CA DC 70 8A 32 FD 4A 2C 5E 4C DF " +
|
||||||
|
"87 7A 3C BC E0 A5 30 1E 3E 31 C5 33 AC A0 30 2F " +
|
||||||
|
"52 A8 DF 87 C2 30 A4 54 3F A5 65 19 85 65 A9 12 " +
|
||||||
|
"D3 2B 16 0D 8A CB 13 4A F3 E3 27 E6 09 03 9D 0E " +
|
||||||
|
"06 58 BF 12 B3 13 CB C1 01 4E 8B 4A 4C 56 AC 91 " +
|
||||||
|
"03 5D 37 86 48 53 A6 3F 98 42 FD 26 3B 07 56 FF " +
|
||||||
|
"99 1D 14 EA A7 CC 7E 70 1A 08 79 42 61 1C 3C A5 " +
|
||||||
|
"D0 0D 9C 6C C2 32 6B 29 73 03 DB 6B CA DC C0 F8 " +
|
||||||
|
"97 F5 AD CC 1A CA DC C0 F4 83 32 37 B0 A4 30 CE " +
|
||||||
|
"FC C7 48 99 1B FE 33 32 FC 07 00 6C CC 2E 23 33 " +
|
||||||
|
"00 0B F0 12 00 00 00 BF 00 08 00 08 00 81 01 09 " +
|
||||||
|
"00 00 08 C0 01 40 00 00 08 40 00 1E F1 10 00 00 " +
|
||||||
|
"00 0D 00 00 08 0C 00 00 08 17 00 00 08 F7 00 00 " +
|
||||||
|
"10 ";
|
||||||
|
|
||||||
|
// Decode the stream to bytes
|
||||||
|
byte[] bytes = HexRead.readData( new ByteArrayInputStream( dump.getBytes() ), -1 );
|
||||||
|
// Create a new instance of the escher dumper
|
||||||
|
EscherDump dumper = new EscherDump();
|
||||||
|
// Dump the contents of scher to screen.
|
||||||
|
// dumper.dumpOld( bytes.length, new ByteArrayInputStream( bytes ), System.out );
|
||||||
|
dumper.dump(bytes, 0, bytes.length, System.out);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dump( int recordSize, byte[] data, PrintStream out ) throws IOException, LittleEndian.BufferUnderrunException
|
||||||
|
{
|
||||||
|
// ByteArrayInputStream is = new ByteArrayInputStream( data );
|
||||||
|
// dump( recordSize, is, out );
|
||||||
|
dump( data, 0, recordSize, System.out );
|
||||||
|
}
|
||||||
|
}
|
174
src/java/org/apache/poi/ddf/EscherOptRecord.java
Normal file
174
src/java/org/apache/poi/ddf/EscherOptRecord.java
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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() ) );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
607
src/java/org/apache/poi/ddf/EscherProperties.java
Normal file
607
src/java/org/apache/poi/ddf/EscherProperties.java
Normal file
@ -0,0 +1,607 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a list of all known escher properties including the description and
|
||||||
|
* type.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class EscherProperties
|
||||||
|
{
|
||||||
|
|
||||||
|
// Property constants
|
||||||
|
public static final short TRANSFORM__ROTATION = 4;
|
||||||
|
public static final short PROTECTION__LOCKROTATION = 119;
|
||||||
|
public static final short PROTECTION__LOCKASPECTRATIO = 120;
|
||||||
|
public static final short PROTECTION__LOCKPOSITION = 121;
|
||||||
|
public static final short PROTECTION__LOCKAGAINSTSELECT = 122;
|
||||||
|
public static final short PROTECTION__LOCKCROPPING = 123;
|
||||||
|
public static final short PROTECTION__LOCKVERTICES = 124;
|
||||||
|
public static final short PROTECTION__LOCKTEXT = 125;
|
||||||
|
public static final short PROTECTION__LOCKADJUSTHANDLES = 126;
|
||||||
|
public static final short PROTECTION__LOCKAGAINSTGROUPING = 127;
|
||||||
|
public static final short TEXT__TEXTID = 128;
|
||||||
|
public static final short TEXT__TEXTLEFT = 129;
|
||||||
|
public static final short TEXT__TEXTTOP = 130;
|
||||||
|
public static final short TEXT__TEXTRIGHT = 131;
|
||||||
|
public static final short TEXT__TEXTBOTTOM = 132;
|
||||||
|
public static final short TEXT__WRAPTEXT = 133;
|
||||||
|
public static final short TEXT__SCALETEXT = 134;
|
||||||
|
public static final short TEXT__ANCHORTEXT = 135;
|
||||||
|
public static final short TEXT__TEXTFLOW = 136;
|
||||||
|
public static final short TEXT__FONTROTATION = 137;
|
||||||
|
public static final short TEXT__IDOFNEXTSHAPE = 138;
|
||||||
|
public static final short TEXT__BIDIR = 139;
|
||||||
|
public static final short TEXT__SINGLECLICKSELECTS = 187;
|
||||||
|
public static final short TEXT__USEHOSTMARGINS = 188;
|
||||||
|
public static final short TEXT__ROTATETEXTWITHSHAPE = 189;
|
||||||
|
public static final short TEXT__SIZESHAPETOFITTEXT = 190;
|
||||||
|
public static final short TEXT__SIZE_TEXT_TO_FIT_SHAPE = 191 ;
|
||||||
|
public static final short GEOTEXT__UNICODE = 192;
|
||||||
|
public static final short GEOTEXT__RTFTEXT = 193;
|
||||||
|
public static final short GEOTEXT__ALIGNMENTONCURVE = 194;
|
||||||
|
public static final short GEOTEXT__DEFAULTPOINTSIZE = 195;
|
||||||
|
public static final short GEOTEXT__TEXTSPACING = 196;
|
||||||
|
public static final short GEOTEXT__FONTFAMILYNAME = 197;
|
||||||
|
public static final short GEOTEXT__REVERSEROWORDER = 240;
|
||||||
|
public static final short GEOTEXT__HASTEXTEFFECT = 241;
|
||||||
|
public static final short GEOTEXT__ROTATECHARACTERS = 242;
|
||||||
|
public static final short GEOTEXT__KERNCHARACTERS = 243;
|
||||||
|
public static final short GEOTEXT__TIGHTORTRACK = 244;
|
||||||
|
public static final short GEOTEXT__STRETCHTOFITSHAPE = 245;
|
||||||
|
public static final short GEOTEXT__CHARBOUNDINGBOX = 246;
|
||||||
|
public static final short GEOTEXT__SCALETEXTONPATH = 247;
|
||||||
|
public static final short GEOTEXT__STRETCHCHARHEIGHT = 248;
|
||||||
|
public static final short GEOTEXT__NOMEASUREALONGPATH = 249;
|
||||||
|
public static final short GEOTEXT__BOLDFONT = 250;
|
||||||
|
public static final short GEOTEXT__ITALICFONT = 251;
|
||||||
|
public static final short GEOTEXT__UNDERLINEFONT = 252;
|
||||||
|
public static final short GEOTEXT__SHADOWFONT = 253;
|
||||||
|
public static final short GEOTEXT__SMALLCAPSFONT = 254;
|
||||||
|
public static final short GEOTEXT__STRIKETHROUGHFONT = 255;
|
||||||
|
public static final short BLIP__CROPFROMTOP = 256;
|
||||||
|
public static final short BLIP__CROPFROMBOTTOM = 257;
|
||||||
|
public static final short BLIP__CROPFROMLEFT = 258;
|
||||||
|
public static final short BLIP__CROPFROMRIGHT = 259;
|
||||||
|
public static final short BLIP__BLIPTODISPLAY = 260;
|
||||||
|
public static final short BLIP__BLIPFILENAME = 261;
|
||||||
|
public static final short BLIP__BLIPFLAGS = 262;
|
||||||
|
public static final short BLIP__TRANSPARENTCOLOR = 263;
|
||||||
|
public static final short BLIP__CONTRASTSETTING = 264;
|
||||||
|
public static final short BLIP__BRIGHTNESSSETTING = 265;
|
||||||
|
public static final short BLIP__GAMMA = 266;
|
||||||
|
public static final short BLIP__PICTUREID = 267;
|
||||||
|
public static final short BLIP__DOUBLEMOD = 268;
|
||||||
|
public static final short BLIP__PICTUREFILLMOD = 269;
|
||||||
|
public static final short BLIP__PICTURELINE = 270;
|
||||||
|
public static final short BLIP__PRINTBLIP = 271;
|
||||||
|
public static final short BLIP__PRINTBLIPFILENAME = 272;
|
||||||
|
public static final short BLIP__PRINTFLAGS = 273;
|
||||||
|
public static final short BLIP__NOHITTESTPICTURE = 316;
|
||||||
|
public static final short BLIP__PICTUREGRAY = 317;
|
||||||
|
public static final short BLIP__PICTUREBILEVEL = 318;
|
||||||
|
public static final short BLIP__PICTUREACTIVE = 319;
|
||||||
|
public static final short GEOMETRY__LEFT = 320;
|
||||||
|
public static final short GEOMETRY__TOP = 321;
|
||||||
|
public static final short GEOMETRY__RIGHT = 322;
|
||||||
|
public static final short GEOMETRY__BOTTOM = 323;
|
||||||
|
public static final short GEOMETRY__SHAPEPATH = 324;
|
||||||
|
public static final short GEOMETRY__VERTICES = 325;
|
||||||
|
public static final short GEOMETRY__SEGMENTINFO = 326;
|
||||||
|
public static final short GEOMETRY__ADJUSTVALUE = 327;
|
||||||
|
public static final short GEOMETRY__ADJUST2VALUE = 328;
|
||||||
|
public static final short GEOMETRY__ADJUST3VALUE = 329;
|
||||||
|
public static final short GEOMETRY__ADJUST4VALUE = 330;
|
||||||
|
public static final short GEOMETRY__ADJUST5VALUE = 331;
|
||||||
|
public static final short GEOMETRY__ADJUST6VALUE = 332;
|
||||||
|
public static final short GEOMETRY__ADJUST7VALUE = 333;
|
||||||
|
public static final short GEOMETRY__ADJUST8VALUE = 334;
|
||||||
|
public static final short GEOMETRY__ADJUST9VALUE = 335;
|
||||||
|
public static final short GEOMETRY__ADJUST10VALUE = 336;
|
||||||
|
public static final short GEOMETRY__SHADOWok = 378;
|
||||||
|
public static final short GEOMETRY__3DOK = 379;
|
||||||
|
public static final short GEOMETRY__LINEOK = 380;
|
||||||
|
public static final short GEOMETRY__GEOTEXTOK = 381;
|
||||||
|
public static final short GEOMETRY__FILLSHADESHAPEOK = 382;
|
||||||
|
public static final short GEOMETRY__FILLOK = 383;
|
||||||
|
public static final short FILL__FILLTYPE = 384;
|
||||||
|
public static final short FILL__FILLCOLOR = 385 ;
|
||||||
|
public static final short FILL__FILLOPACITY = 386;
|
||||||
|
public static final short FILL__FILLBACKCOLOR = 387;
|
||||||
|
public static final short FILL__BACKOPACITY = 388;
|
||||||
|
public static final short FILL__CRMOD = 389;
|
||||||
|
public static final short FILL__PATTERNTEXTURE = 390;
|
||||||
|
public static final short FILL__BLIPFILENAME = 391;
|
||||||
|
public static final short FILL__BLIPFLAGS = 392;
|
||||||
|
public static final short FILL__WIDTH = 393;
|
||||||
|
public static final short FILL__HEIGHT = 394;
|
||||||
|
public static final short FILL__ANGLE = 395;
|
||||||
|
public static final short FILL__FOCUS = 396;
|
||||||
|
public static final short FILL__TOLEFT = 397;
|
||||||
|
public static final short FILL__TOTOP = 398;
|
||||||
|
public static final short FILL__TORIGHT = 399;
|
||||||
|
public static final short FILL__TOBOTTOM = 400;
|
||||||
|
public static final short FILL__RECTLEFT = 401;
|
||||||
|
public static final short FILL__RECTTOP = 402;
|
||||||
|
public static final short FILL__RECTRIGHT = 403;
|
||||||
|
public static final short FILL__RECTBOTTOM = 404;
|
||||||
|
public static final short FILL__DZTYPE = 405;
|
||||||
|
public static final short FILL__SHADEPRESET = 406;
|
||||||
|
public static final short FILL__SHADECOLORS = 407;
|
||||||
|
public static final short FILL__ORIGINX = 408;
|
||||||
|
public static final short FILL__ORIGINY = 409;
|
||||||
|
public static final short FILL__SHAPEORIGINX = 410;
|
||||||
|
public static final short FILL__SHAPEORIGINY = 411;
|
||||||
|
public static final short FILL__SHADETYPE = 412;
|
||||||
|
public static final short FILL__FILLED = 443;
|
||||||
|
public static final short FILL__HITTESTFILL = 444;
|
||||||
|
public static final short FILL__SHAPE = 445;
|
||||||
|
public static final short FILL__USERECT = 446;
|
||||||
|
public static final short FILL__NOFILLHITTEST = 447;
|
||||||
|
public static final short LINESTYLE__COLOR = 448 ;
|
||||||
|
public static final short LINESTYLE__OPACITY = 449;
|
||||||
|
public static final short LINESTYLE__BACKCOLOR = 450;
|
||||||
|
public static final short LINESTYLE__CRMOD = 451;
|
||||||
|
public static final short LINESTYLE__LINETYPE = 452;
|
||||||
|
public static final short LINESTYLE__FILLBLIP = 453;
|
||||||
|
public static final short LINESTYLE__FILLBLIPNAME = 454;
|
||||||
|
public static final short LINESTYLE__FILLBLIPFLAGS = 455;
|
||||||
|
public static final short LINESTYLE__FILLWIDTH = 456;
|
||||||
|
public static final short LINESTYLE__FILLHEIGHT = 457;
|
||||||
|
public static final short LINESTYLE__FILLDZTYPE = 458;
|
||||||
|
public static final short LINESTYLE__LINEWIDTH = 459;
|
||||||
|
public static final short LINESTYLE__LINEMITERLIMIT = 460;
|
||||||
|
public static final short LINESTYLE__LINESTYLE = 461;
|
||||||
|
public static final short LINESTYLE__LINEDASHING = 462;
|
||||||
|
public static final short LINESTYLE__LINEDASHSTYLE = 463;
|
||||||
|
public static final short LINESTYLE__LINESTARTARROWHEAD = 464;
|
||||||
|
public static final short LINESTYLE__LINEENDARROWHEAD = 465;
|
||||||
|
public static final short LINESTYLE__LINESTARTARROWWIDTH = 466;
|
||||||
|
public static final short LINESTYLE__LINEESTARTARROWLENGTH = 467;
|
||||||
|
public static final short LINESTYLE__LINEENDARROWWIDTH = 468;
|
||||||
|
public static final short LINESTYLE__LINEENDARROWLENGTH = 469;
|
||||||
|
public static final short LINESTYLE__LINEJOINSTYLE = 470;
|
||||||
|
public static final short LINESTYLE__LINEENDCAPSTYLE = 471;
|
||||||
|
public static final short LINESTYLE__ARROWHEADSOK = 507;
|
||||||
|
public static final short LINESTYLE__ANYLINE = 508;
|
||||||
|
public static final short LINESTYLE__HITLINETEST = 509;
|
||||||
|
public static final short LINESTYLE__LINEFILLSHAPE = 510;
|
||||||
|
public static final short LINESTYLE__NOLINEDRAWDASH = 511;
|
||||||
|
public static final short SHADOWSTYLE__TYPE = 512;
|
||||||
|
public static final short SHADOWSTYLE__COLOR = 513;
|
||||||
|
public static final short SHADOWSTYLE__HIGHLIGHT = 514;
|
||||||
|
public static final short SHADOWSTYLE__CRMOD = 515;
|
||||||
|
public static final short SHADOWSTYLE__OPACITY = 516;
|
||||||
|
public static final short SHADOWSTYLE__OFFSETX = 517;
|
||||||
|
public static final short SHADOWSTYLE__OFFSETY = 518;
|
||||||
|
public static final short SHADOWSTYLE__SECONDOFFSETX = 519;
|
||||||
|
public static final short SHADOWSTYLE__SECONDOFFSETY = 520;
|
||||||
|
public static final short SHADOWSTYLE__SCALEXTOX = 521;
|
||||||
|
public static final short SHADOWSTYLE__SCALEYTOX = 522;
|
||||||
|
public static final short SHADOWSTYLE__SCALEXTOY = 523;
|
||||||
|
public static final short SHADOWSTYLE__SCALEYTOY = 524;
|
||||||
|
public static final short SHADOWSTYLE__PERSPECTIVEX = 525;
|
||||||
|
public static final short SHADOWSTYLE__PERSPECTIVEY = 526;
|
||||||
|
public static final short SHADOWSTYLE__WEIGHT = 527;
|
||||||
|
public static final short SHADOWSTYLE__ORIGINX = 528;
|
||||||
|
public static final short SHADOWSTYLE__ORIGINY = 529;
|
||||||
|
public static final short SHADOWSTYLE__SHADOW = 574;
|
||||||
|
public static final short SHADOWSTYLE__SHADOWOBSURED = 575;
|
||||||
|
public static final short PERSPECTIVE__TYPE = 576;
|
||||||
|
public static final short PERSPECTIVE__OFFSETX = 577;
|
||||||
|
public static final short PERSPECTIVE__OFFSETY = 578;
|
||||||
|
public static final short PERSPECTIVE__SCALEXTOX = 579;
|
||||||
|
public static final short PERSPECTIVE__SCALEYTOX = 580;
|
||||||
|
public static final short PERSPECTIVE__SCALEXTOY = 581;
|
||||||
|
public static final short PERSPECTIVE__SCALEYTOY = 582;
|
||||||
|
public static final short PERSPECTIVE__PERSPECTIVEX = 583;
|
||||||
|
public static final short PERSPECTIVE__PERSPECTIVEY = 584;
|
||||||
|
public static final short PERSPECTIVE__WEIGHT = 585;
|
||||||
|
public static final short PERSPECTIVE__ORIGINX = 586;
|
||||||
|
public static final short PERSPECTIVE__ORIGINY = 587;
|
||||||
|
public static final short PERSPECTIVE__PERSPECTIVEON = 639;
|
||||||
|
public static final short THREED__SPECULARAMOUNT = 640;
|
||||||
|
public static final short THREED__DIFFUSEAMOUNT = 661;
|
||||||
|
public static final short THREED__SHININESS = 662;
|
||||||
|
public static final short THREED__EDGETHICKNESS = 663;
|
||||||
|
public static final short THREED__EXTRUDEFORWARD = 664;
|
||||||
|
public static final short THREED__EXTRUDEBACKWARD = 665;
|
||||||
|
public static final short THREED__EXTRUDEPLANE = 666;
|
||||||
|
public static final short THREED__EXTRUSIONCOLOR = 667;
|
||||||
|
public static final short THREED__CRMOD = 648;
|
||||||
|
public static final short THREED__3DEFFECT = 700;
|
||||||
|
public static final short THREED__METALLIC = 701;
|
||||||
|
public static final short THREED__USEEXTRUSIONCOLOR = 702;
|
||||||
|
public static final short THREED__LIGHTFACE = 703;
|
||||||
|
public static final short THREEDSTYLE__YROTATIONANGLE = 704;
|
||||||
|
public static final short THREEDSTYLE__XROTATIONANGLE = 705;
|
||||||
|
public static final short THREEDSTYLE__ROTATIONAXISX = 706;
|
||||||
|
public static final short THREEDSTYLE__ROTATIONAXISY = 707;
|
||||||
|
public static final short THREEDSTYLE__ROTATIONAXISZ = 708;
|
||||||
|
public static final short THREEDSTYLE__ROTATIONANGLE = 709;
|
||||||
|
public static final short THREEDSTYLE__ROTATIONCENTERX = 710;
|
||||||
|
public static final short THREEDSTYLE__ROTATIONCENTERY = 711;
|
||||||
|
public static final short THREEDSTYLE__ROTATIONCENTERZ = 712;
|
||||||
|
public static final short THREEDSTYLE__RENDERMODE = 713;
|
||||||
|
public static final short THREEDSTYLE__TOLERANCE = 714;
|
||||||
|
public static final short THREEDSTYLE__XVIEWPOINT = 715;
|
||||||
|
public static final short THREEDSTYLE__YVIEWPOINT = 716;
|
||||||
|
public static final short THREEDSTYLE__ZVIEWPOINT = 717;
|
||||||
|
public static final short THREEDSTYLE__ORIGINX = 718;
|
||||||
|
public static final short THREEDSTYLE__ORIGINY = 719;
|
||||||
|
public static final short THREEDSTYLE__SKEWANGLE = 720;
|
||||||
|
public static final short THREEDSTYLE__SKEWAMOUNT = 721;
|
||||||
|
public static final short THREEDSTYLE__AMBIENTINTENSITY = 722;
|
||||||
|
public static final short THREEDSTYLE__KEYX = 723;
|
||||||
|
public static final short THREEDSTYLE__KEYY = 724;
|
||||||
|
public static final short THREEDSTYLE__KEYZ = 725;
|
||||||
|
public static final short THREEDSTYLE__KEYINTENSITY = 726;
|
||||||
|
public static final short THREEDSTYLE__FILLX = 727;
|
||||||
|
public static final short THREEDSTYLE__FILLY = 728;
|
||||||
|
public static final short THREEDSTYLE__FILLZ = 729;
|
||||||
|
public static final short THREEDSTYLE__FILLINTENSITY = 730;
|
||||||
|
public static final short THREEDSTYLE__CONSTRAINROTATION = 763;
|
||||||
|
public static final short THREEDSTYLE__ROTATIONCENTERAUTO = 764;
|
||||||
|
public static final short THREEDSTYLE__PARALLEL = 765;
|
||||||
|
public static final short THREEDSTYLE__KEYHARSH = 766;
|
||||||
|
public static final short THREEDSTYLE__FILLHARSH = 767;
|
||||||
|
public static final short SHAPE__MASTER = 769;
|
||||||
|
public static final short SHAPE__CONNECTORSTYLE = 771;
|
||||||
|
public static final short SHAPE__BLACKANDWHITESETTINGS = 772;
|
||||||
|
public static final short SHAPE__WMODEPUREBW = 773;
|
||||||
|
public static final short SHAPE__WMODEBW = 774;
|
||||||
|
public static final short SHAPE__OLEICON = 826;
|
||||||
|
public static final short SHAPE__PREFERRELATIVERESIZE = 827;
|
||||||
|
public static final short SHAPE__LOCKSHAPETYPE = 828;
|
||||||
|
public static final short SHAPE__DELETEATTACHEDOBJECT = 830;
|
||||||
|
public static final short SHAPE__BACKGROUNDSHAPE = 831;
|
||||||
|
public static final short CALLOUT__CALLOUTTYPE = 832;
|
||||||
|
public static final short CALLOUT__XYCALLOUTGAP = 833;
|
||||||
|
public static final short CALLOUT__CALLOUTANGLE = 834;
|
||||||
|
public static final short CALLOUT__CALLOUTDROPTYPE = 835;
|
||||||
|
public static final short CALLOUT__CALLOUTDROPSPECIFIED = 836;
|
||||||
|
public static final short CALLOUT__CALLOUTLENGTHSPECIFIED = 837;
|
||||||
|
public static final short CALLOUT__ISCALLOUT = 889;
|
||||||
|
public static final short CALLOUT__CALLOUTACCENTBAR = 890;
|
||||||
|
public static final short CALLOUT__CALLOUTTEXTBORDER = 891;
|
||||||
|
public static final short CALLOUT__CALLOUTMINUSX = 892;
|
||||||
|
public static final short CALLOUT__CALLOUTMINUSY = 893;
|
||||||
|
public static final short CALLOUT__DROPAUTO = 894;
|
||||||
|
public static final short CALLOUT__LENGTHSPECIFIED = 895;
|
||||||
|
public static final short GROUPSHAPE__SHAPENAME = 896;
|
||||||
|
public static final short GROUPSHAPE__DESCRIPTION = 897;
|
||||||
|
public static final short GROUPSHAPE__HYPERLINK = 898;
|
||||||
|
public static final short GROUPSHAPE__WRAPPOLYGONVERTICES = 899;
|
||||||
|
public static final short GROUPSHAPE__WRAPDISTLEFT = 900;
|
||||||
|
public static final short GROUPSHAPE__WRAPDISTTOP = 901;
|
||||||
|
public static final short GROUPSHAPE__WRAPDISTRIGHT = 902;
|
||||||
|
public static final short GROUPSHAPE__WRAPDISTBOTTOM = 903;
|
||||||
|
public static final short GROUPSHAPE__REGROUPID = 904;
|
||||||
|
public static final short GROUPSHAPE__EDITEDWRAP = 953;
|
||||||
|
public static final short GROUPSHAPE__BEHINDDOCUMENT = 954;
|
||||||
|
public static final short GROUPSHAPE__ONDBLCLICKNOTIFY = 955;
|
||||||
|
public static final short GROUPSHAPE__ISBUTTON = 956;
|
||||||
|
public static final short GROUPSHAPE__1DADJUSTMENT = 957;
|
||||||
|
public static final short GROUPSHAPE__HIDDEN = 958;
|
||||||
|
public static final short GROUPSHAPE__PRINT = 959;
|
||||||
|
|
||||||
|
|
||||||
|
private static Map properties;
|
||||||
|
|
||||||
|
private static void initProps()
|
||||||
|
{
|
||||||
|
if ( properties == null )
|
||||||
|
{
|
||||||
|
properties = new HashMap();
|
||||||
|
addProp( TRANSFORM__ROTATION, data( "transform.rotation" ) );
|
||||||
|
addProp( PROTECTION__LOCKROTATION , data( "protection.lockrotation" ) );
|
||||||
|
addProp( PROTECTION__LOCKASPECTRATIO , data( "protection.lockaspectratio" ) );
|
||||||
|
addProp( PROTECTION__LOCKPOSITION , data( "protection.lockposition" ) );
|
||||||
|
addProp( PROTECTION__LOCKAGAINSTSELECT , data( "protection.lockagainstselect" ) );
|
||||||
|
addProp( PROTECTION__LOCKCROPPING , data( "protection.lockcropping" ) );
|
||||||
|
addProp( PROTECTION__LOCKVERTICES , data( "protection.lockvertices" ) );
|
||||||
|
addProp( PROTECTION__LOCKTEXT , data( "protection.locktext" ) );
|
||||||
|
addProp( PROTECTION__LOCKADJUSTHANDLES , data( "protection.lockadjusthandles" ) );
|
||||||
|
addProp( PROTECTION__LOCKAGAINSTGROUPING , data( "protection.lockagainstgrouping", EscherPropertyMetaData.TYPE_BOOLEAN ) );
|
||||||
|
addProp( TEXT__TEXTID , data( "text.textid" ) );
|
||||||
|
addProp( TEXT__TEXTLEFT , data( "text.textleft" ) );
|
||||||
|
addProp( TEXT__TEXTTOP , data( "text.texttop" ) );
|
||||||
|
addProp( TEXT__TEXTRIGHT , data( "text.textright" ) );
|
||||||
|
addProp( TEXT__TEXTBOTTOM , data( "text.textbottom" ) );
|
||||||
|
addProp( TEXT__WRAPTEXT , data( "text.wraptext" ) );
|
||||||
|
addProp( TEXT__SCALETEXT , data( "text.scaletext" ) );
|
||||||
|
addProp( TEXT__ANCHORTEXT , data( "text.anchortext" ) );
|
||||||
|
addProp( TEXT__TEXTFLOW , data( "text.textflow" ) );
|
||||||
|
addProp( TEXT__FONTROTATION , data( "text.fontrotation" ) );
|
||||||
|
addProp( TEXT__IDOFNEXTSHAPE , data( "text.idofnextshape" ) );
|
||||||
|
addProp( TEXT__BIDIR , data( "text.bidir" ) );
|
||||||
|
addProp( TEXT__SINGLECLICKSELECTS , data( "text.singleclickselects" ) );
|
||||||
|
addProp( TEXT__USEHOSTMARGINS , data( "text.usehostmargins" ) );
|
||||||
|
addProp( TEXT__ROTATETEXTWITHSHAPE , data( "text.rotatetextwithshape" ) );
|
||||||
|
addProp( TEXT__SIZESHAPETOFITTEXT , data( "text.sizeshapetofittext" ) );
|
||||||
|
addProp( TEXT__SIZE_TEXT_TO_FIT_SHAPE, data( "text.sizetexttofitshape", EscherPropertyMetaData.TYPE_BOOLEAN ) );
|
||||||
|
addProp( GEOTEXT__UNICODE , data( "geotext.unicode" ) );
|
||||||
|
addProp( GEOTEXT__RTFTEXT , data( "geotext.rtftext" ) );
|
||||||
|
addProp( GEOTEXT__ALIGNMENTONCURVE , data( "geotext.alignmentoncurve" ) );
|
||||||
|
addProp( GEOTEXT__DEFAULTPOINTSIZE , data( "geotext.defaultpointsize" ) );
|
||||||
|
addProp( GEOTEXT__TEXTSPACING , data( "geotext.textspacing" ) );
|
||||||
|
addProp( GEOTEXT__FONTFAMILYNAME , data( "geotext.fontfamilyname" ) );
|
||||||
|
addProp( GEOTEXT__REVERSEROWORDER , data( "geotext.reverseroworder" ) );
|
||||||
|
addProp( GEOTEXT__HASTEXTEFFECT , data( "geotext.hastexteffect" ) );
|
||||||
|
addProp( GEOTEXT__ROTATECHARACTERS , data( "geotext.rotatecharacters" ) );
|
||||||
|
addProp( GEOTEXT__KERNCHARACTERS , data( "geotext.kerncharacters" ) );
|
||||||
|
addProp( GEOTEXT__TIGHTORTRACK , data( "geotext.tightortrack" ) );
|
||||||
|
addProp( GEOTEXT__STRETCHTOFITSHAPE , data( "geotext.stretchtofitshape" ) );
|
||||||
|
addProp( GEOTEXT__CHARBOUNDINGBOX , data( "geotext.charboundingbox" ) );
|
||||||
|
addProp( GEOTEXT__SCALETEXTONPATH , data( "geotext.scaletextonpath" ) );
|
||||||
|
addProp( GEOTEXT__STRETCHCHARHEIGHT , data( "geotext.stretchcharheight" ) );
|
||||||
|
addProp( GEOTEXT__NOMEASUREALONGPATH , data( "geotext.nomeasurealongpath" ) );
|
||||||
|
addProp( GEOTEXT__BOLDFONT , data( "geotext.boldfont" ) );
|
||||||
|
addProp( GEOTEXT__ITALICFONT , data( "geotext.italicfont" ) );
|
||||||
|
addProp( GEOTEXT__UNDERLINEFONT , data( "geotext.underlinefont" ) );
|
||||||
|
addProp( GEOTEXT__SHADOWFONT , data( "geotext.shadowfont" ) );
|
||||||
|
addProp( GEOTEXT__SMALLCAPSFONT , data( "geotext.smallcapsfont" ) );
|
||||||
|
addProp( GEOTEXT__STRIKETHROUGHFONT , data( "geotext.strikethroughfont" ) );
|
||||||
|
addProp( BLIP__CROPFROMTOP , data( "blip.cropfromtop" ) );
|
||||||
|
addProp( BLIP__CROPFROMBOTTOM , data( "blip.cropfrombottom" ) );
|
||||||
|
addProp( BLIP__CROPFROMLEFT , data( "blip.cropfromleft" ) );
|
||||||
|
addProp( BLIP__CROPFROMRIGHT , data( "blip.cropfromright" ) );
|
||||||
|
addProp( BLIP__BLIPTODISPLAY , data( "blip.bliptodisplay" ) );
|
||||||
|
addProp( BLIP__BLIPFILENAME , data( "blip.blipfilename" ) );
|
||||||
|
addProp( BLIP__BLIPFLAGS , data( "blip.blipflags" ) );
|
||||||
|
addProp( BLIP__TRANSPARENTCOLOR , data( "blip.transparentcolor" ) );
|
||||||
|
addProp( BLIP__CONTRASTSETTING , data( "blip.contrastsetting" ) );
|
||||||
|
addProp( BLIP__BRIGHTNESSSETTING , data( "blip.brightnesssetting" ) );
|
||||||
|
addProp( BLIP__GAMMA , data( "blip.gamma" ) );
|
||||||
|
addProp( BLIP__PICTUREID , data( "blip.pictureid" ) );
|
||||||
|
addProp( BLIP__DOUBLEMOD , data( "blip.doublemod" ) );
|
||||||
|
addProp( BLIP__PICTUREFILLMOD , data( "blip.picturefillmod" ) );
|
||||||
|
addProp( BLIP__PICTURELINE , data( "blip.pictureline" ) );
|
||||||
|
addProp( BLIP__PRINTBLIP , data( "blip.printblip" ) );
|
||||||
|
addProp( BLIP__PRINTBLIPFILENAME , data( "blip.printblipfilename" ) );
|
||||||
|
addProp( BLIP__PRINTFLAGS , data( "blip.printflags" ) );
|
||||||
|
addProp( BLIP__NOHITTESTPICTURE , data( "blip.nohittestpicture" ) );
|
||||||
|
addProp( BLIP__PICTUREGRAY , data( "blip.picturegray" ) );
|
||||||
|
addProp( BLIP__PICTUREBILEVEL , data( "blip.picturebilevel" ) );
|
||||||
|
addProp( BLIP__PICTUREACTIVE , data( "blip.pictureactive" ) );
|
||||||
|
addProp( GEOMETRY__LEFT , data( "geometry.left" ) );
|
||||||
|
addProp( GEOMETRY__TOP , data( "geometry.top" ) );
|
||||||
|
addProp( GEOMETRY__RIGHT , data( "geometry.right" ) );
|
||||||
|
addProp( GEOMETRY__BOTTOM , data( "geometry.bottom" ) );
|
||||||
|
addProp( GEOMETRY__SHAPEPATH , data( "geometry.shapepath", EscherPropertyMetaData.TYPE_SHAPEPATH ) );
|
||||||
|
addProp( GEOMETRY__VERTICES , data( "geometry.vertices" , EscherPropertyMetaData.TYPE_ARRAY ) );
|
||||||
|
addProp( GEOMETRY__SEGMENTINFO , data( "geometry.segmentinfo", EscherPropertyMetaData.TYPE_ARRAY ) );
|
||||||
|
addProp( GEOMETRY__ADJUSTVALUE , data( "geometry.adjustvalue" ) );
|
||||||
|
addProp( GEOMETRY__ADJUST2VALUE , data( "geometry.adjust2value" ) );
|
||||||
|
addProp( GEOMETRY__ADJUST3VALUE , data( "geometry.adjust3value" ) );
|
||||||
|
addProp( GEOMETRY__ADJUST4VALUE , data( "geometry.adjust4value" ) );
|
||||||
|
addProp( GEOMETRY__ADJUST5VALUE , data( "geometry.adjust5value" ) );
|
||||||
|
addProp( GEOMETRY__ADJUST6VALUE , data( "geometry.adjust6value" ) );
|
||||||
|
addProp( GEOMETRY__ADJUST7VALUE , data( "geometry.adjust7value" ) );
|
||||||
|
addProp( GEOMETRY__ADJUST8VALUE , data( "geometry.adjust8value" ) );
|
||||||
|
addProp( GEOMETRY__ADJUST9VALUE , data( "geometry.adjust9value" ) );
|
||||||
|
addProp( GEOMETRY__ADJUST10VALUE , data( "geometry.adjust10value" ) );
|
||||||
|
addProp( GEOMETRY__SHADOWok , data( "geometry.shadowOK" ) );
|
||||||
|
addProp( GEOMETRY__3DOK , data( "geometry.3dok" ) );
|
||||||
|
addProp( GEOMETRY__LINEOK , data( "geometry.lineok" ) );
|
||||||
|
addProp( GEOMETRY__GEOTEXTOK , data( "geometry.geotextok" ) );
|
||||||
|
addProp( GEOMETRY__FILLSHADESHAPEOK , data( "geometry.fillshadeshapeok" ) );
|
||||||
|
addProp( GEOMETRY__FILLOK , data( "geometry.fillok", EscherPropertyMetaData.TYPE_BOOLEAN ) );
|
||||||
|
addProp( FILL__FILLTYPE , data( "fill.filltype" ) );
|
||||||
|
addProp( FILL__FILLCOLOR, data( "fill.fillcolor", EscherPropertyMetaData.TYPE_RGB ) );
|
||||||
|
addProp( FILL__FILLOPACITY , data( "fill.fillopacity" ) );
|
||||||
|
addProp( FILL__FILLBACKCOLOR , data( "fill.fillbackcolor", EscherPropertyMetaData.TYPE_RGB ) );
|
||||||
|
addProp( FILL__BACKOPACITY , data( "fill.backopacity" ) );
|
||||||
|
addProp( FILL__CRMOD , data( "fill.crmod" ) );
|
||||||
|
addProp( FILL__PATTERNTEXTURE , data( "fill.patterntexture" ) );
|
||||||
|
addProp( FILL__BLIPFILENAME , data( "fill.blipfilename" ) );
|
||||||
|
addProp( FILL__BLIPFLAGS, data( "fill.blipflags" ) );
|
||||||
|
addProp( FILL__WIDTH , data( "fill.width" ) );
|
||||||
|
addProp( FILL__HEIGHT , data( "fill.height" ) );
|
||||||
|
addProp( FILL__ANGLE , data( "fill.angle" ) );
|
||||||
|
addProp( FILL__FOCUS , data( "fill.focus" ) );
|
||||||
|
addProp( FILL__TOLEFT , data( "fill.toleft" ) );
|
||||||
|
addProp( FILL__TOTOP , data( "fill.totop" ) );
|
||||||
|
addProp( FILL__TORIGHT , data( "fill.toright" ) );
|
||||||
|
addProp( FILL__TOBOTTOM , data( "fill.tobottom" ) );
|
||||||
|
addProp( FILL__RECTLEFT , data( "fill.rectleft" ) );
|
||||||
|
addProp( FILL__RECTTOP , data( "fill.recttop" ) );
|
||||||
|
addProp( FILL__RECTRIGHT , data( "fill.rectright" ) );
|
||||||
|
addProp( FILL__RECTBOTTOM , data( "fill.rectbottom" ) );
|
||||||
|
addProp( FILL__DZTYPE , data( "fill.dztype" ) );
|
||||||
|
addProp( FILL__SHADEPRESET , data( "fill.shadepreset" ) );
|
||||||
|
addProp( FILL__SHADECOLORS , data( "fill.shadecolors", EscherPropertyMetaData.TYPE_ARRAY ) );
|
||||||
|
addProp( FILL__ORIGINX , data( "fill.originx" ) );
|
||||||
|
addProp( FILL__ORIGINY , data( "fill.originy" ) );
|
||||||
|
addProp( FILL__SHAPEORIGINX , data( "fill.shapeoriginx" ) );
|
||||||
|
addProp( FILL__SHAPEORIGINY , data( "fill.shapeoriginy" ) );
|
||||||
|
addProp( FILL__SHADETYPE , data( "fill.shadetype" ) );
|
||||||
|
addProp( FILL__FILLED , data( "fill.filled" ) );
|
||||||
|
addProp( FILL__HITTESTFILL , data( "fill.hittestfill" ) );
|
||||||
|
addProp( FILL__SHAPE , data( "fill.shape" ) );
|
||||||
|
addProp( FILL__USERECT , data( "fill.userect" ) );
|
||||||
|
addProp( FILL__NOFILLHITTEST , data( "fill.nofillhittest", EscherPropertyMetaData.TYPE_BOOLEAN ) );
|
||||||
|
addProp( LINESTYLE__COLOR, data( "linestyle.color", EscherPropertyMetaData.TYPE_RGB ) );
|
||||||
|
addProp( LINESTYLE__OPACITY , data( "linestyle.opacity" ) );
|
||||||
|
addProp( LINESTYLE__BACKCOLOR , data( "linestyle.backcolor", EscherPropertyMetaData.TYPE_RGB ) );
|
||||||
|
addProp( LINESTYLE__CRMOD , data( "linestyle.crmod" ) );
|
||||||
|
addProp( LINESTYLE__LINETYPE , data( "linestyle.linetype" ) );
|
||||||
|
addProp( LINESTYLE__FILLBLIP , data( "linestyle.fillblip" ) );
|
||||||
|
addProp( LINESTYLE__FILLBLIPNAME , data( "linestyle.fillblipname" ) );
|
||||||
|
addProp( LINESTYLE__FILLBLIPFLAGS , data( "linestyle.fillblipflags" ) );
|
||||||
|
addProp( LINESTYLE__FILLWIDTH , data( "linestyle.fillwidth" ) );
|
||||||
|
addProp( LINESTYLE__FILLHEIGHT , data( "linestyle.fillheight" ) );
|
||||||
|
addProp( LINESTYLE__FILLDZTYPE , data( "linestyle.filldztype" ) );
|
||||||
|
addProp( LINESTYLE__LINEWIDTH , data( "linestyle.linewidth" ) );
|
||||||
|
addProp( LINESTYLE__LINEMITERLIMIT , data( "linestyle.linemiterlimit" ) );
|
||||||
|
addProp( LINESTYLE__LINESTYLE , data( "linestyle.linestyle" ) );
|
||||||
|
addProp( LINESTYLE__LINEDASHING , data( "linestyle.linedashing" ) );
|
||||||
|
addProp( LINESTYLE__LINEDASHSTYLE , data( "linestyle.linedashstyle", EscherPropertyMetaData.TYPE_ARRAY ) );
|
||||||
|
addProp( LINESTYLE__LINESTARTARROWHEAD , data( "linestyle.linestartarrowhead" ) );
|
||||||
|
addProp( LINESTYLE__LINEENDARROWHEAD , data( "linestyle.lineendarrowhead" ) );
|
||||||
|
addProp( LINESTYLE__LINESTARTARROWWIDTH , data( "linestyle.linestartarrowwidth" ) );
|
||||||
|
addProp( LINESTYLE__LINEESTARTARROWLENGTH , data( "linestyle.lineestartarrowlength" ) );
|
||||||
|
addProp( LINESTYLE__LINEENDARROWWIDTH , data( "linestyle.lineendarrowwidth" ) );
|
||||||
|
addProp( LINESTYLE__LINEENDARROWLENGTH , data( "linestyle.lineendarrowlength" ) );
|
||||||
|
addProp( LINESTYLE__LINEJOINSTYLE , data( "linestyle.linejoinstyle" ) );
|
||||||
|
addProp( LINESTYLE__LINEENDCAPSTYLE , data( "linestyle.lineendcapstyle" ) );
|
||||||
|
addProp( LINESTYLE__ARROWHEADSOK , data( "linestyle.arrowheadsok" ) );
|
||||||
|
addProp( LINESTYLE__ANYLINE , data( "linestyle.anyline" ) );
|
||||||
|
addProp( LINESTYLE__HITLINETEST , data( "linestyle.hitlinetest" ) );
|
||||||
|
addProp( LINESTYLE__LINEFILLSHAPE , data( "linestyle.linefillshape" ) );
|
||||||
|
addProp( LINESTYLE__NOLINEDRAWDASH , data( "linestyle.nolinedrawdash", EscherPropertyMetaData.TYPE_BOOLEAN ) );
|
||||||
|
addProp( SHADOWSTYLE__TYPE , data( "shadowstyle.type" ) );
|
||||||
|
addProp( SHADOWSTYLE__COLOR , data( "shadowstyle.color", EscherPropertyMetaData.TYPE_RGB ) );
|
||||||
|
addProp( SHADOWSTYLE__HIGHLIGHT , data( "shadowstyle.highlight" ) );
|
||||||
|
addProp( SHADOWSTYLE__CRMOD , data( "shadowstyle.crmod" ) );
|
||||||
|
addProp( SHADOWSTYLE__OPACITY , data( "shadowstyle.opacity" ) );
|
||||||
|
addProp( SHADOWSTYLE__OFFSETX , data( "shadowstyle.offsetx" ) );
|
||||||
|
addProp( SHADOWSTYLE__OFFSETY , data( "shadowstyle.offsety" ) );
|
||||||
|
addProp( SHADOWSTYLE__SECONDOFFSETX , data( "shadowstyle.secondoffsetx" ) );
|
||||||
|
addProp( SHADOWSTYLE__SECONDOFFSETY , data( "shadowstyle.secondoffsety" ) );
|
||||||
|
addProp( SHADOWSTYLE__SCALEXTOX , data( "shadowstyle.scalextox" ) );
|
||||||
|
addProp( SHADOWSTYLE__SCALEYTOX , data( "shadowstyle.scaleytox" ) );
|
||||||
|
addProp( SHADOWSTYLE__SCALEXTOY , data( "shadowstyle.scalextoy" ) );
|
||||||
|
addProp( SHADOWSTYLE__SCALEYTOY , data( "shadowstyle.scaleytoy" ) );
|
||||||
|
addProp( SHADOWSTYLE__PERSPECTIVEX , data( "shadowstyle.perspectivex" ) );
|
||||||
|
addProp( SHADOWSTYLE__PERSPECTIVEY , data( "shadowstyle.perspectivey" ) );
|
||||||
|
addProp( SHADOWSTYLE__WEIGHT , data( "shadowstyle.weight" ) );
|
||||||
|
addProp( SHADOWSTYLE__ORIGINX , data( "shadowstyle.originx" ) );
|
||||||
|
addProp( SHADOWSTYLE__ORIGINY , data( "shadowstyle.originy" ) );
|
||||||
|
addProp( SHADOWSTYLE__SHADOW , data( "shadowstyle.shadow" ) );
|
||||||
|
addProp( SHADOWSTYLE__SHADOWOBSURED , data( "shadowstyle.shadowobsured" ) );
|
||||||
|
addProp( PERSPECTIVE__TYPE , data( "perspective.type" ) );
|
||||||
|
addProp( PERSPECTIVE__OFFSETX , data( "perspective.offsetx" ) );
|
||||||
|
addProp( PERSPECTIVE__OFFSETY , data( "perspective.offsety" ) );
|
||||||
|
addProp( PERSPECTIVE__SCALEXTOX , data( "perspective.scalextox" ) );
|
||||||
|
addProp( PERSPECTIVE__SCALEYTOX , data( "perspective.scaleytox" ) );
|
||||||
|
addProp( PERSPECTIVE__SCALEXTOY , data( "perspective.scalextoy" ) );
|
||||||
|
addProp( PERSPECTIVE__SCALEYTOY , data( "perspective.scaleytoy" ) );
|
||||||
|
addProp( PERSPECTIVE__PERSPECTIVEX , data( "perspective.perspectivex" ) );
|
||||||
|
addProp( PERSPECTIVE__PERSPECTIVEY , data( "perspective.perspectivey" ) );
|
||||||
|
addProp( PERSPECTIVE__WEIGHT , data( "perspective.weight" ) );
|
||||||
|
addProp( PERSPECTIVE__ORIGINX , data( "perspective.originx" ) );
|
||||||
|
addProp( PERSPECTIVE__ORIGINY , data( "perspective.originy" ) );
|
||||||
|
addProp( PERSPECTIVE__PERSPECTIVEON , data( "perspective.perspectiveon" ) );
|
||||||
|
addProp( THREED__SPECULARAMOUNT , data( "3d.specularamount" ) );
|
||||||
|
addProp( THREED__DIFFUSEAMOUNT , data( "3d.diffuseamount" ) );
|
||||||
|
addProp( THREED__SHININESS , data( "3d.shininess" ) );
|
||||||
|
addProp( THREED__EDGETHICKNESS , data( "3d.edgethickness" ) );
|
||||||
|
addProp( THREED__EXTRUDEFORWARD , data( "3d.extrudeforward" ) );
|
||||||
|
addProp( THREED__EXTRUDEBACKWARD , data( "3d.extrudebackward" ) );
|
||||||
|
addProp( THREED__EXTRUDEPLANE , data( "3d.extrudeplane" ) );
|
||||||
|
addProp( THREED__EXTRUSIONCOLOR , data( "3d.extrusioncolor", EscherPropertyMetaData.TYPE_RGB ) );
|
||||||
|
addProp( THREED__CRMOD , data( "3d.crmod" ) );
|
||||||
|
addProp( THREED__3DEFFECT , data( "3d.3deffect" ) );
|
||||||
|
addProp( THREED__METALLIC , data( "3d.metallic" ) );
|
||||||
|
addProp( THREED__USEEXTRUSIONCOLOR , data( "3d.useextrusioncolor", EscherPropertyMetaData.TYPE_RGB ) );
|
||||||
|
addProp( THREED__LIGHTFACE , data( "3d.lightface" ) );
|
||||||
|
addProp( THREEDSTYLE__YROTATIONANGLE , data( "3dstyle.yrotationangle" ) );
|
||||||
|
addProp( THREEDSTYLE__XROTATIONANGLE , data( "3dstyle.xrotationangle" ) );
|
||||||
|
addProp( THREEDSTYLE__ROTATIONAXISX , data( "3dstyle.rotationaxisx" ) );
|
||||||
|
addProp( THREEDSTYLE__ROTATIONAXISY , data( "3dstyle.rotationaxisy" ) );
|
||||||
|
addProp( THREEDSTYLE__ROTATIONAXISZ , data( "3dstyle.rotationaxisz" ) );
|
||||||
|
addProp( THREEDSTYLE__ROTATIONANGLE , data( "3dstyle.rotationangle" ) );
|
||||||
|
addProp( THREEDSTYLE__ROTATIONCENTERX , data( "3dstyle.rotationcenterx" ) );
|
||||||
|
addProp( THREEDSTYLE__ROTATIONCENTERY , data( "3dstyle.rotationcentery" ) );
|
||||||
|
addProp( THREEDSTYLE__ROTATIONCENTERZ , data( "3dstyle.rotationcenterz" ) );
|
||||||
|
addProp( THREEDSTYLE__RENDERMODE , data( "3dstyle.rendermode" ) );
|
||||||
|
addProp( THREEDSTYLE__TOLERANCE , data( "3dstyle.tolerance" ) );
|
||||||
|
addProp( THREEDSTYLE__XVIEWPOINT , data( "3dstyle.xviewpoint" ) );
|
||||||
|
addProp( THREEDSTYLE__YVIEWPOINT , data( "3dstyle.yviewpoint" ) );
|
||||||
|
addProp( THREEDSTYLE__ZVIEWPOINT , data( "3dstyle.zviewpoint" ) );
|
||||||
|
addProp( THREEDSTYLE__ORIGINX , data( "3dstyle.originx" ) );
|
||||||
|
addProp( THREEDSTYLE__ORIGINY , data( "3dstyle.originy" ) );
|
||||||
|
addProp( THREEDSTYLE__SKEWANGLE , data( "3dstyle.skewangle" ) );
|
||||||
|
addProp( THREEDSTYLE__SKEWAMOUNT , data( "3dstyle.skewamount" ) );
|
||||||
|
addProp( THREEDSTYLE__AMBIENTINTENSITY , data( "3dstyle.ambientintensity" ) );
|
||||||
|
addProp( THREEDSTYLE__KEYX , data( "3dstyle.keyx" ) );
|
||||||
|
addProp( THREEDSTYLE__KEYY , data( "3dstyle.keyy" ) );
|
||||||
|
addProp( THREEDSTYLE__KEYZ , data( "3dstyle.keyz" ) );
|
||||||
|
addProp( THREEDSTYLE__KEYINTENSITY , data( "3dstyle.keyintensity" ) );
|
||||||
|
addProp( THREEDSTYLE__FILLX , data( "3dstyle.fillx" ) );
|
||||||
|
addProp( THREEDSTYLE__FILLY , data( "3dstyle.filly" ) );
|
||||||
|
addProp( THREEDSTYLE__FILLZ , data( "3dstyle.fillz" ) );
|
||||||
|
addProp( THREEDSTYLE__FILLINTENSITY , data( "3dstyle.fillintensity" ) );
|
||||||
|
addProp( THREEDSTYLE__CONSTRAINROTATION , data( "3dstyle.constrainrotation" ) );
|
||||||
|
addProp( THREEDSTYLE__ROTATIONCENTERAUTO , data( "3dstyle.rotationcenterauto" ) );
|
||||||
|
addProp( THREEDSTYLE__PARALLEL , data( "3dstyle.parallel" ) );
|
||||||
|
addProp( THREEDSTYLE__KEYHARSH , data( "3dstyle.keyharsh" ) );
|
||||||
|
addProp( THREEDSTYLE__FILLHARSH , data( "3dstyle.fillharsh" ) );
|
||||||
|
addProp( SHAPE__MASTER , data( "shape.master" ) );
|
||||||
|
addProp( SHAPE__CONNECTORSTYLE , data( "shape.connectorstyle" ) );
|
||||||
|
addProp( SHAPE__BLACKANDWHITESETTINGS , data( "shape.blackandwhitesettings" ) );
|
||||||
|
addProp( SHAPE__WMODEPUREBW , data( "shape.wmodepurebw" ) );
|
||||||
|
addProp( SHAPE__WMODEBW , data( "shape.wmodebw" ) );
|
||||||
|
addProp( SHAPE__OLEICON , data( "shape.oleicon" ) );
|
||||||
|
addProp( SHAPE__PREFERRELATIVERESIZE , data( "shape.preferrelativeresize" ) );
|
||||||
|
addProp( SHAPE__LOCKSHAPETYPE , data( "shape.lockshapetype" ) );
|
||||||
|
addProp( SHAPE__DELETEATTACHEDOBJECT , data( "shape.deleteattachedobject" ) );
|
||||||
|
addProp( SHAPE__BACKGROUNDSHAPE , data( "shape.backgroundshape" ) );
|
||||||
|
addProp( CALLOUT__CALLOUTTYPE , data( "callout.callouttype" ) );
|
||||||
|
addProp( CALLOUT__XYCALLOUTGAP , data( "callout.xycalloutgap" ) );
|
||||||
|
addProp( CALLOUT__CALLOUTANGLE , data( "callout.calloutangle" ) );
|
||||||
|
addProp( CALLOUT__CALLOUTDROPTYPE , data( "callout.calloutdroptype" ) );
|
||||||
|
addProp( CALLOUT__CALLOUTDROPSPECIFIED , data( "callout.calloutdropspecified" ) );
|
||||||
|
addProp( CALLOUT__CALLOUTLENGTHSPECIFIED , data( "callout.calloutlengthspecified" ) );
|
||||||
|
addProp( CALLOUT__ISCALLOUT , data( "callout.iscallout" ) );
|
||||||
|
addProp( CALLOUT__CALLOUTACCENTBAR , data( "callout.calloutaccentbar" ) );
|
||||||
|
addProp( CALLOUT__CALLOUTTEXTBORDER , data( "callout.callouttextborder" ) );
|
||||||
|
addProp( CALLOUT__CALLOUTMINUSX , data( "callout.calloutminusx" ) );
|
||||||
|
addProp( CALLOUT__CALLOUTMINUSY , data( "callout.calloutminusy" ) );
|
||||||
|
addProp( CALLOUT__DROPAUTO , data( "callout.dropauto" ) );
|
||||||
|
addProp( CALLOUT__LENGTHSPECIFIED , data( "callout.lengthspecified" ) );
|
||||||
|
addProp( GROUPSHAPE__SHAPENAME , data( "groupshape.shapename" ) );
|
||||||
|
addProp( GROUPSHAPE__DESCRIPTION , data( "groupshape.description" ) );
|
||||||
|
addProp( GROUPSHAPE__HYPERLINK , data( "groupshape.hyperlink" ) );
|
||||||
|
addProp( GROUPSHAPE__WRAPPOLYGONVERTICES , data( "groupshape.wrappolygonvertices", EscherPropertyMetaData.TYPE_ARRAY ) );
|
||||||
|
addProp( GROUPSHAPE__WRAPDISTLEFT , data( "groupshape.wrapdistleft" ) );
|
||||||
|
addProp( GROUPSHAPE__WRAPDISTTOP , data( "groupshape.wrapdisttop" ) );
|
||||||
|
addProp( GROUPSHAPE__WRAPDISTRIGHT , data( "groupshape.wrapdistright" ) );
|
||||||
|
addProp( GROUPSHAPE__WRAPDISTBOTTOM , data( "groupshape.wrapdistbottom" ) );
|
||||||
|
addProp( GROUPSHAPE__REGROUPID , data( "groupshape.regroupid" ) );
|
||||||
|
addProp( GROUPSHAPE__EDITEDWRAP , data( "groupshape.editedwrap" ) );
|
||||||
|
addProp( GROUPSHAPE__BEHINDDOCUMENT , data( "groupshape.behinddocument" ) );
|
||||||
|
addProp( GROUPSHAPE__ONDBLCLICKNOTIFY , data( "groupshape.ondblclicknotify" ) );
|
||||||
|
addProp( GROUPSHAPE__ISBUTTON , data( "groupshape.isbutton" ) );
|
||||||
|
addProp( GROUPSHAPE__1DADJUSTMENT , data( "groupshape.1dadjustment" ) );
|
||||||
|
addProp( GROUPSHAPE__HIDDEN , data( "groupshape.hidden" ) );
|
||||||
|
addProp( GROUPSHAPE__PRINT , data( "groupshape.print", EscherPropertyMetaData.TYPE_BOOLEAN ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addProp( int s, EscherPropertyMetaData data )
|
||||||
|
{
|
||||||
|
properties.put( new Short( (short) s ), data );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static EscherPropertyMetaData data( String propName, byte type )
|
||||||
|
{
|
||||||
|
return new EscherPropertyMetaData( propName, type );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static EscherPropertyMetaData data( String propName )
|
||||||
|
{
|
||||||
|
return new EscherPropertyMetaData( propName );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getPropertyName( short propertyId )
|
||||||
|
{
|
||||||
|
initProps();
|
||||||
|
EscherPropertyMetaData o = (EscherPropertyMetaData) properties.get( new Short( propertyId ) );
|
||||||
|
return o == null ? "unknown" : o.getDescription();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte getPropertyType( short propertyId )
|
||||||
|
{
|
||||||
|
initProps();
|
||||||
|
EscherPropertyMetaData escherPropertyMetaData = (EscherPropertyMetaData) properties.get( new Short( propertyId ) );
|
||||||
|
return escherPropertyMetaData == null ? 0 : escherPropertyMetaData.getType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
78
src/java/org/apache/poi/ddf/EscherProperty.java
Normal file
78
src/java/org/apache/poi/ddf/EscherProperty.java
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the abstract base class for all escher properties.
|
||||||
|
*
|
||||||
|
* @see EscherOptRecord
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
abstract public class EscherProperty
|
||||||
|
{
|
||||||
|
private short id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The id is distinct from the actual property number. The id includes the property number the blip id
|
||||||
|
* flag and an indicator whether the property is complex or not.
|
||||||
|
*/
|
||||||
|
public EscherProperty( short id )
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new escher property. The three parameters are combined to form a property
|
||||||
|
* id.
|
||||||
|
*/
|
||||||
|
public EscherProperty( short propertyNumber, boolean isComplex, boolean isBlipId )
|
||||||
|
{
|
||||||
|
this.id = (short)(propertyNumber +
|
||||||
|
(isComplex ? 0x8000 : 0x0) +
|
||||||
|
(isBlipId ? 0x4000 : 0x0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getPropertyNumber()
|
||||||
|
{
|
||||||
|
return (short) ( id & (short) 0x3FFF );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isComplex()
|
||||||
|
{
|
||||||
|
return ( id & (short) 0x8000 ) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBlipId()
|
||||||
|
{
|
||||||
|
return ( id & (short) 0x4000 ) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return EscherProperties.getPropertyName(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Most properties are just 6 bytes in length. Override this if we're
|
||||||
|
* dealing with complex properties.
|
||||||
|
*/
|
||||||
|
public int getPropertySize()
|
||||||
|
{
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escher properties consist of a simple fixed length part and a complex variable length part.
|
||||||
|
* The fixed length part is serialized first.
|
||||||
|
*/
|
||||||
|
abstract public int serializeSimplePart( byte[] data, int pos );
|
||||||
|
/**
|
||||||
|
* Escher properties consist of a simple fixed length part and a complex variable length part.
|
||||||
|
* The fixed length part is serialized first.
|
||||||
|
*/
|
||||||
|
abstract public int serializeComplexPart( byte[] data, int pos );
|
||||||
|
}
|
91
src/java/org/apache/poi/ddf/EscherPropertyFactory.java
Normal file
91
src/java/org/apache/poi/ddf/EscherPropertyFactory.java
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.hssf.record.RecordFormatException;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a property given a reference into the byte array storing that property.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis
|
||||||
|
*/
|
||||||
|
public class EscherPropertyFactory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create new properties from a byte array.
|
||||||
|
*
|
||||||
|
* @param data The byte array containing the property
|
||||||
|
* @param offset The starting offset into the byte array
|
||||||
|
* @return The new properties
|
||||||
|
*/
|
||||||
|
public List createProperties( byte[] data, int offset, short numProperties )
|
||||||
|
{
|
||||||
|
List results = new ArrayList();
|
||||||
|
|
||||||
|
int pos = offset;
|
||||||
|
int complexBytes = 0;
|
||||||
|
// while ( bytesRemaining >= 6 )
|
||||||
|
for (int i = 0; i < numProperties; i++)
|
||||||
|
{
|
||||||
|
short propId;
|
||||||
|
int propData;
|
||||||
|
propId = LittleEndian.getShort( data, pos );
|
||||||
|
propData = LittleEndian.getInt( data, pos + 2 );
|
||||||
|
short propNumber = (short) ( propId & (short) 0x3FFF );
|
||||||
|
boolean isComplex = ( propId & (short) 0x8000 ) != 0;
|
||||||
|
boolean isBlipId = ( propId & (short) 0x4000 ) != 0;
|
||||||
|
if ( isComplex )
|
||||||
|
complexBytes = propData;
|
||||||
|
else
|
||||||
|
complexBytes = 0;
|
||||||
|
byte propertyType = EscherProperties.getPropertyType( (short) propNumber );
|
||||||
|
if ( propertyType == EscherPropertyMetaData.TYPE_BOOLEAN )
|
||||||
|
results.add( new EscherBoolProperty( propNumber, propData ) );
|
||||||
|
else if ( propertyType == EscherPropertyMetaData.TYPE_RGB )
|
||||||
|
results.add( new EscherRGBProperty( propNumber, propData ) );
|
||||||
|
else if ( propertyType == EscherPropertyMetaData.TYPE_SHAPEPATH )
|
||||||
|
results.add( new EscherShapePathProperty( propNumber, propData ) );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( !isComplex )
|
||||||
|
results.add( new EscherSimpleProperty( propNumber, propData ) );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( propertyType == EscherPropertyMetaData.TYPE_ARRAY)
|
||||||
|
results.add( new EscherArrayProperty( propId, new byte[propData]) );
|
||||||
|
else
|
||||||
|
results.add( new EscherComplexProperty( propId, new byte[propData]) );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos += 6;
|
||||||
|
// bytesRemaining -= 6 + complexBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get complex data
|
||||||
|
for ( Iterator iterator = results.iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherProperty p = (EscherProperty) iterator.next();
|
||||||
|
if (p instanceof EscherComplexProperty)
|
||||||
|
{
|
||||||
|
if (p instanceof EscherArrayProperty)
|
||||||
|
{
|
||||||
|
pos += ((EscherArrayProperty)p).setArrayData(data, pos);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
byte[] complexData = ((EscherComplexProperty)p).getComplexData();
|
||||||
|
System.arraycopy(data, pos, complexData, 0, complexData.length);
|
||||||
|
pos += complexData.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
51
src/java/org/apache/poi/ddf/EscherPropertyMetaData.java
Normal file
51
src/java/org/apache/poi/ddf/EscherPropertyMetaData.java
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class stores the type and description of an escher property.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class EscherPropertyMetaData
|
||||||
|
{
|
||||||
|
// Escher property types.
|
||||||
|
public final static byte TYPE_UNKNOWN = (byte) 0;
|
||||||
|
public final static byte TYPE_BOOLEAN = (byte) 1;
|
||||||
|
public final static byte TYPE_RGB = (byte) 2;
|
||||||
|
public final static byte TYPE_SHAPEPATH = (byte) 3;
|
||||||
|
public final static byte TYPE_SIMPLE = (byte)4;
|
||||||
|
public final static byte TYPE_ARRAY = (byte)5;;
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
private byte type;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param description The description of the escher property.
|
||||||
|
*/
|
||||||
|
public EscherPropertyMetaData( String description )
|
||||||
|
{
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param description The description of the escher property.
|
||||||
|
* @param type The type of the property.
|
||||||
|
*/
|
||||||
|
public EscherPropertyMetaData( String description, byte type )
|
||||||
|
{
|
||||||
|
this.description = description;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription()
|
||||||
|
{
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getType()
|
||||||
|
{
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
37
src/java/org/apache/poi/ddf/EscherRGBProperty.java
Normal file
37
src/java/org/apache/poi/ddf/EscherRGBProperty.java
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A color property.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class EscherRGBProperty
|
||||||
|
extends EscherSimpleProperty
|
||||||
|
{
|
||||||
|
|
||||||
|
public EscherRGBProperty( short propertyNumber, int rgbColor )
|
||||||
|
{
|
||||||
|
super( propertyNumber, false, false, rgbColor );
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRgbColor()
|
||||||
|
{
|
||||||
|
return propertyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getRed()
|
||||||
|
{
|
||||||
|
return (byte) ( propertyValue & 0xFF );
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getGreen()
|
||||||
|
{
|
||||||
|
return (byte) ( (propertyValue >> 8) & 0xFF );
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getBlue()
|
||||||
|
{
|
||||||
|
return (byte) ( (propertyValue >> 16) & 0xFF );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
273
src/java/org/apache/poi/ddf/EscherRecord.java
Normal file
273
src/java/org/apache/poi/ddf/EscherRecord.java
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base abstract record from which all escher records are defined. Subclasses will need
|
||||||
|
* to define methods for serialization/deserialization and for determining the record size.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis
|
||||||
|
*/
|
||||||
|
abstract public class EscherRecord
|
||||||
|
{
|
||||||
|
private short options;
|
||||||
|
private short recordId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance
|
||||||
|
*/
|
||||||
|
public EscherRecord()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delegates to fillFields(byte[], int, EscherRecordFactory)
|
||||||
|
*
|
||||||
|
* @see #fillFields(byte[], int, org.apache.poi.ddf.EscherRecordFactory)
|
||||||
|
*/
|
||||||
|
protected int fillFields( byte[] data, EscherRecordFactory f )
|
||||||
|
{
|
||||||
|
return fillFields( data, 0, f );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The contract of this method is to deserialize an escher record including
|
||||||
|
* it's children.
|
||||||
|
*
|
||||||
|
* @param data The byte array containing the serialized escher
|
||||||
|
* records.
|
||||||
|
* @param offset The offset into the byte array.
|
||||||
|
* @param recordFactory A factory for creating new escher records.
|
||||||
|
* @return The number of bytes written.
|
||||||
|
*/
|
||||||
|
public abstract int fillFields( byte[] data, int offset, EscherRecordFactory recordFactory );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the 8 byte header information and populates the <code>options</code>
|
||||||
|
* and <code>recordId</code> records.
|
||||||
|
*
|
||||||
|
* @param data the byte array to read from
|
||||||
|
* @param offset the offset to start reading from
|
||||||
|
* @return the number of bytes remaining in this record. This
|
||||||
|
* may include the children if this is a container.
|
||||||
|
*/
|
||||||
|
protected int readHeader( byte[] data, int offset )
|
||||||
|
{
|
||||||
|
EscherRecordHeader header = EscherRecordHeader.readHeader(data, offset);
|
||||||
|
options = header.getOptions();
|
||||||
|
recordId = header.getRecordId();
|
||||||
|
return header.getRemainingBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether this is a container record by inspecting the option
|
||||||
|
* field.
|
||||||
|
* @return true is this is a container field.
|
||||||
|
*/
|
||||||
|
public boolean isContainerRecord()
|
||||||
|
{
|
||||||
|
return (options & (short)0x000f) == (short)0x000f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The options field for this record. All records have one.
|
||||||
|
*/
|
||||||
|
public short getOptions()
|
||||||
|
{
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the options this this record. Container records should have the
|
||||||
|
* last nibble set to 0xF.
|
||||||
|
*/
|
||||||
|
public void setOptions( short options )
|
||||||
|
{
|
||||||
|
this.options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes to a new byte array. This is done by delegating to
|
||||||
|
* serialize(int, byte[]);
|
||||||
|
*
|
||||||
|
* @return the serialized record.
|
||||||
|
* @see #serialize(int, byte[])
|
||||||
|
*/
|
||||||
|
public byte[] serialize()
|
||||||
|
{
|
||||||
|
byte[] retval = new byte[getRecordSize()];
|
||||||
|
|
||||||
|
serialize( 0, retval );
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes to an existing byte array without serialization listener.
|
||||||
|
* This is done by delegating to serialize(int, byte[], EscherSerializationListener).
|
||||||
|
*
|
||||||
|
* @param offset the offset within the data byte array.
|
||||||
|
* @param data the data array to serialize to.
|
||||||
|
* @return The number of bytes written.
|
||||||
|
*
|
||||||
|
* @see #serialize(int, byte[], org.apache.poi.ddf.EscherSerializationListener)
|
||||||
|
*/
|
||||||
|
public int serialize( int offset, byte[] data)
|
||||||
|
{
|
||||||
|
return serialize( offset, data, new NullEscherSerializationListener() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes the record to an existing byte array.
|
||||||
|
*
|
||||||
|
* @param offset the offset within the byte array
|
||||||
|
* @param data the data array to serialize to
|
||||||
|
* @param listener a listener for begin and end serialization events. This
|
||||||
|
* is useful because the serialization is
|
||||||
|
* hierarchical/recursive and sometimes you need to be able
|
||||||
|
* break into that.
|
||||||
|
* @return the number of bytes written.
|
||||||
|
*/
|
||||||
|
public abstract int serialize( int offset, byte[] data, EscherSerializationListener listener );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclasses should effeciently return the number of bytes required to
|
||||||
|
* serialize the record.
|
||||||
|
*
|
||||||
|
* @return number of bytes
|
||||||
|
*/
|
||||||
|
abstract public int getRecordSize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the current record id.
|
||||||
|
*
|
||||||
|
* @return The 16 bit record id.
|
||||||
|
*/
|
||||||
|
public short getRecordId()
|
||||||
|
{
|
||||||
|
return recordId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the record id for this record.
|
||||||
|
*/
|
||||||
|
public void setRecordId( short recordId )
|
||||||
|
{
|
||||||
|
this.recordId = recordId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns the children of this record. By default this will
|
||||||
|
* be an empty list. EscherCotainerRecord is the only record
|
||||||
|
* that may contain children.
|
||||||
|
*
|
||||||
|
* @see EscherContainerRecord
|
||||||
|
*/
|
||||||
|
public List getChildRecords() { return Collections.EMPTY_LIST; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the child records for this record. By default this will throw
|
||||||
|
* an exception as only EscherContainerRecords may have children.
|
||||||
|
*
|
||||||
|
* @param childRecords Not used in base implementation.
|
||||||
|
*/
|
||||||
|
public void setChildRecords( List childRecords ) { throw new IllegalArgumentException("This record does not support child records."); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escher records may need to be clonable in the future.
|
||||||
|
*/
|
||||||
|
public Object clone()
|
||||||
|
{
|
||||||
|
throw new RuntimeException( "The class " + getClass().getName() + " needs to define a clone method" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the indexed child record.
|
||||||
|
*/
|
||||||
|
public EscherRecord getChild( int index )
|
||||||
|
{
|
||||||
|
return (EscherRecord) getChildRecords().get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The display methods allows escher variables to print the record names
|
||||||
|
* according to their hierarchy.
|
||||||
|
*
|
||||||
|
* @param w The print writer to output to.
|
||||||
|
* @param indent The current indent level.
|
||||||
|
*/
|
||||||
|
public void display(PrintWriter w, int indent)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < indent * 4; i++) w.print(' ');
|
||||||
|
w.println(getRecordName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclasses should return the short name for this escher record.
|
||||||
|
*/
|
||||||
|
public abstract String getRecordName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the instance part of the option record.
|
||||||
|
*
|
||||||
|
* @return The instance part of the record
|
||||||
|
*/
|
||||||
|
public short getInstance()
|
||||||
|
{
|
||||||
|
return (short) ( options >> 4 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class reads the standard escher header.
|
||||||
|
*/
|
||||||
|
static class EscherRecordHeader
|
||||||
|
{
|
||||||
|
private short options;
|
||||||
|
private short recordId;
|
||||||
|
private int remainingBytes;
|
||||||
|
|
||||||
|
private EscherRecordHeader()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EscherRecordHeader readHeader( byte[] data, int offset )
|
||||||
|
{
|
||||||
|
EscherRecordHeader header = new EscherRecordHeader();
|
||||||
|
header.options = LittleEndian.getShort(data, offset);
|
||||||
|
header.recordId = LittleEndian.getShort(data, offset + 2);
|
||||||
|
header.remainingBytes = LittleEndian.getInt( data, offset + 4 );
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public short getOptions()
|
||||||
|
{
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getRecordId()
|
||||||
|
{
|
||||||
|
return recordId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRemainingBytes()
|
||||||
|
{
|
||||||
|
return remainingBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return "EscherRecordHeader{" +
|
||||||
|
"options=" + options +
|
||||||
|
", recordId=" + recordId +
|
||||||
|
", remainingBytes=" + remainingBytes +
|
||||||
|
"}";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
16
src/java/org/apache/poi/ddf/EscherRecordFactory.java
Normal file
16
src/java/org/apache/poi/ddf/EscherRecordFactory.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The escher record factory interface allows for the creation of escher
|
||||||
|
* records from a pointer into a data array.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public interface EscherRecordFactory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create a new escher record from the data provided. Does not attempt
|
||||||
|
* to fill the contents of the record however.
|
||||||
|
*/
|
||||||
|
EscherRecord createRecord( byte[] data, int offset );
|
||||||
|
}
|
27
src/java/org/apache/poi/ddf/EscherSerializationListener.java
Normal file
27
src/java/org/apache/poi/ddf/EscherSerializationListener.java
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for listening to escher serialization events.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public interface EscherSerializationListener
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Fired before a given escher record is serialized.
|
||||||
|
*
|
||||||
|
* @param offset The position in the data array at which the record will be serialized.
|
||||||
|
* @param recordId The id of the record about to be serialized.
|
||||||
|
*/
|
||||||
|
void beforeRecordSerialize(int offset, short recordId, EscherRecord record);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fired after a record has been serialized.
|
||||||
|
*
|
||||||
|
* @param offset The position of the end of the serialized record + 1
|
||||||
|
* @param recordId The id of the record about to be serialized
|
||||||
|
* @param size The number of bytes written for this record. If it is a container
|
||||||
|
* record then this will include the size of any included records.
|
||||||
|
*/
|
||||||
|
void afterRecordSerialize(int offset, short recordId, int size, EscherRecord record);
|
||||||
|
}
|
25
src/java/org/apache/poi/ddf/EscherShapePathProperty.java
Normal file
25
src/java/org/apache/poi/ddf/EscherShapePathProperty.java
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the constants for the various possible shape paths.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class EscherShapePathProperty
|
||||||
|
extends EscherSimpleProperty
|
||||||
|
{
|
||||||
|
|
||||||
|
public static final int LINE_OF_STRAIGHT_SEGMENTS = 0;
|
||||||
|
public static final int CLOSED_POLYGON = 1;
|
||||||
|
public static final int CURVES = 2;
|
||||||
|
public static final int CLOSED_CURVES = 3;
|
||||||
|
public static final int COMPLEX = 4;
|
||||||
|
|
||||||
|
public EscherShapePathProperty( short propertyNumber, int shapePath )
|
||||||
|
{
|
||||||
|
super( propertyNumber, false, false, shapePath );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
103
src/java/org/apache/poi/ddf/EscherSimpleProperty.java
Normal file
103
src/java/org/apache/poi/ddf/EscherSimpleProperty.java
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple property is of fixed length and as a property number in addition
|
||||||
|
* to a 32-bit value. Properties that can't be stored in only 32-bits are
|
||||||
|
* stored as EscherComplexProperty objects.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class EscherSimpleProperty extends EscherProperty
|
||||||
|
{
|
||||||
|
protected int propertyValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The id is distinct from the actual property number. The id includes the property number the blip id
|
||||||
|
* flag and an indicator whether the property is complex or not.
|
||||||
|
*/
|
||||||
|
public EscherSimpleProperty( short id, int propertyValue )
|
||||||
|
{
|
||||||
|
super( id );
|
||||||
|
this.propertyValue = propertyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new escher property. The three parameters are combined to form a property
|
||||||
|
* id.
|
||||||
|
*/
|
||||||
|
public EscherSimpleProperty( short propertyNumber, boolean isComplex, boolean isBlipId, int propertyValue )
|
||||||
|
{
|
||||||
|
super( propertyNumber, isComplex, isBlipId );
|
||||||
|
this.propertyValue = propertyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize the simple part of the escher record.
|
||||||
|
*
|
||||||
|
* @return the number of bytes serialized.
|
||||||
|
*/
|
||||||
|
public int serializeSimplePart( byte[] data, int offset )
|
||||||
|
{
|
||||||
|
LittleEndian.putShort(data, offset, getId());
|
||||||
|
LittleEndian.putInt(data, offset + 2, propertyValue);
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escher properties consist of a simple fixed length part and a complex variable length part.
|
||||||
|
* The fixed length part is serialized first.
|
||||||
|
*/
|
||||||
|
public int serializeComplexPart( byte[] data, int pos )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Return the 32 bit value of this property.
|
||||||
|
*/
|
||||||
|
public int getPropertyValue()
|
||||||
|
{
|
||||||
|
return propertyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if one escher property is equal to another.
|
||||||
|
*/
|
||||||
|
public boolean equals( Object o )
|
||||||
|
{
|
||||||
|
if ( this == o ) return true;
|
||||||
|
if ( !( o instanceof EscherSimpleProperty ) ) return false;
|
||||||
|
|
||||||
|
final EscherSimpleProperty escherSimpleProperty = (EscherSimpleProperty) o;
|
||||||
|
|
||||||
|
if ( propertyValue != escherSimpleProperty.propertyValue ) return false;
|
||||||
|
if ( getId() != escherSimpleProperty.getId() ) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a hashcode so that this object can be stored in collections that
|
||||||
|
* require the use of such things.
|
||||||
|
*/
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return propertyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the string representation of this property.
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return "propNum: " + getPropertyNumber()
|
||||||
|
+ ", propName: " + EscherProperties.getPropertyName( getPropertyNumber() )
|
||||||
|
+ ", complex: " + isComplex()
|
||||||
|
+ ", blipId: " + isBlipId()
|
||||||
|
+ ", value: " + propertyValue + " (0x" + HexDump.toHex(propertyValue) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
201
src/java/org/apache/poi/ddf/EscherSpRecord.java
Normal file
201
src/java/org/apache/poi/ddf/EscherSpRecord.java
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Together the the EscherOptRecord this record defines some of the basic
|
||||||
|
* properties of a shape.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class EscherSpRecord
|
||||||
|
extends EscherRecord
|
||||||
|
{
|
||||||
|
public static final short RECORD_ID = (short) 0xF00A;
|
||||||
|
public static final String RECORD_DESCRIPTION = "MsofbtSp";
|
||||||
|
|
||||||
|
public static final int FLAG_GROUP = 0x0001;
|
||||||
|
public static final int FLAG_CHILD = 0x0002;
|
||||||
|
public static final int FLAG_PATRIARCH = 0x0004;
|
||||||
|
public static final int FLAG_DELETED = 0x0008;
|
||||||
|
public static final int FLAG_OLESHAPE = 0x0010;
|
||||||
|
public static final int FLAG_HAVEMASTER = 0x0020;
|
||||||
|
public static final int FLAG_FLIPHORIZ = 0x0040;
|
||||||
|
public static final int FLAG_FLIPVERT = 0x0080;
|
||||||
|
public static final int FLAG_CONNECTOR = 0x0100;
|
||||||
|
public static final int FLAG_HAVEANCHOR = 0x0200;
|
||||||
|
public static final int FLAG_BACKGROUND = 0x0400;
|
||||||
|
public static final int FLAG_HASSHAPETYPE = 0x0800;
|
||||||
|
|
||||||
|
private int field_1_shapeId;
|
||||||
|
private int field_2_flags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
int size = 0;
|
||||||
|
field_1_shapeId = LittleEndian.getInt( data, pos + size ); size += 4;
|
||||||
|
field_2_flags = LittleEndian.getInt( data, pos + size ); size += 4;
|
||||||
|
// bytesRemaining -= size;
|
||||||
|
// remainingData = new byte[bytesRemaining];
|
||||||
|
// System.arraycopy( data, pos + size, remainingData, 0, bytesRemaining );
|
||||||
|
return getRecordSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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() );
|
||||||
|
int remainingBytes = 8;
|
||||||
|
LittleEndian.putInt( data, offset + 4, remainingBytes );
|
||||||
|
LittleEndian.putInt( data, offset + 8, field_1_shapeId );
|
||||||
|
LittleEndian.putInt( data, offset + 12, field_2_flags );
|
||||||
|
// System.arraycopy( remainingData, 0, data, offset + 26, remainingData.length );
|
||||||
|
// int pos = offset + 8 + 18 + remainingData.length;
|
||||||
|
listener.afterRecordSerialize( offset + getRecordSize(), getRecordId(), getRecordSize(), this );
|
||||||
|
return 8 + 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes that are required to serialize this record.
|
||||||
|
*
|
||||||
|
* @return Number of bytes
|
||||||
|
*/
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
return 8 + 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the 16 bit identifier for this record.
|
||||||
|
*/
|
||||||
|
public short getRecordId()
|
||||||
|
{
|
||||||
|
return RECORD_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The short name for this record
|
||||||
|
*/
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
return "Sp";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the string representing this shape.
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
return getClass().getName() + ":" + nl +
|
||||||
|
" RecordId: 0x" + HexDump.toHex(RECORD_ID) + nl +
|
||||||
|
" Options: 0x" + HexDump.toHex(getOptions()) + nl +
|
||||||
|
" ShapeId: " + field_1_shapeId + nl +
|
||||||
|
" Flags: " + decodeFlags(field_2_flags) + " (0x" + HexDump.toHex(field_2_flags) + ")" + nl;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the shape flags into a more descriptive name.
|
||||||
|
*/
|
||||||
|
private String decodeFlags( int flags )
|
||||||
|
{
|
||||||
|
StringBuffer result = new StringBuffer();
|
||||||
|
result.append( ( flags & FLAG_GROUP ) != 0 ? "|GROUP" : "" );
|
||||||
|
result.append( ( flags & FLAG_CHILD ) != 0 ? "|CHILD" : "" );
|
||||||
|
result.append( ( flags & FLAG_PATRIARCH ) != 0 ? "|PATRIARCH" : "" );
|
||||||
|
result.append( ( flags & FLAG_DELETED ) != 0 ? "|DELETED" : "" );
|
||||||
|
result.append( ( flags & FLAG_OLESHAPE ) != 0 ? "|OLESHAPE" : "" );
|
||||||
|
result.append( ( flags & FLAG_HAVEMASTER ) != 0 ? "|HAVEMASTER" : "" );
|
||||||
|
result.append( ( flags & FLAG_FLIPHORIZ ) != 0 ? "|FLIPHORIZ" : "" );
|
||||||
|
result.append( ( flags & FLAG_FLIPVERT ) != 0 ? "|FLIPVERT" : "" );
|
||||||
|
result.append( ( flags & FLAG_CONNECTOR ) != 0 ? "|CONNECTOR" : "" );
|
||||||
|
result.append( ( flags & FLAG_HAVEANCHOR ) != 0 ? "|HAVEANCHOR" : "" );
|
||||||
|
result.append( ( flags & FLAG_BACKGROUND ) != 0 ? "|BACKGROUND" : "" );
|
||||||
|
result.append( ( flags & FLAG_HASSHAPETYPE ) != 0 ? "|HASSHAPETYPE" : "" );
|
||||||
|
|
||||||
|
result.deleteCharAt(0);
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A number that identifies this shape
|
||||||
|
*/
|
||||||
|
public int getShapeId()
|
||||||
|
{
|
||||||
|
return field_1_shapeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a number that identifies this shape.
|
||||||
|
*/
|
||||||
|
public void setShapeId( int field_1_shapeId )
|
||||||
|
{
|
||||||
|
this.field_1_shapeId = field_1_shapeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The flags that apply to this shape.
|
||||||
|
*
|
||||||
|
* @see #FLAG_GROUP
|
||||||
|
* @see #FLAG_CHILD
|
||||||
|
* @see #FLAG_PATRIARCH
|
||||||
|
* @see #FLAG_DELETED
|
||||||
|
* @see #FLAG_OLESHAPE
|
||||||
|
* @see #FLAG_HAVEMASTER
|
||||||
|
* @see #FLAG_FLIPHORIZ
|
||||||
|
* @see #FLAG_FLIPVERT
|
||||||
|
* @see #FLAG_CONNECTOR
|
||||||
|
* @see #FLAG_HAVEANCHOR
|
||||||
|
* @see #FLAG_BACKGROUND
|
||||||
|
* @see #FLAG_HASSHAPETYPE
|
||||||
|
*/
|
||||||
|
public int getFlags()
|
||||||
|
{
|
||||||
|
return field_2_flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The flags that apply to this shape.
|
||||||
|
*
|
||||||
|
* @see #FLAG_GROUP
|
||||||
|
* @see #FLAG_CHILD
|
||||||
|
* @see #FLAG_PATRIARCH
|
||||||
|
* @see #FLAG_DELETED
|
||||||
|
* @see #FLAG_OLESHAPE
|
||||||
|
* @see #FLAG_HAVEMASTER
|
||||||
|
* @see #FLAG_FLIPHORIZ
|
||||||
|
* @see #FLAG_FLIPVERT
|
||||||
|
* @see #FLAG_CONNECTOR
|
||||||
|
* @see #FLAG_HAVEANCHOR
|
||||||
|
* @see #FLAG_BACKGROUND
|
||||||
|
* @see #FLAG_HASSHAPETYPE
|
||||||
|
*/
|
||||||
|
public void setFlags( int field_2_flags )
|
||||||
|
{
|
||||||
|
this.field_2_flags = field_2_flags;
|
||||||
|
}
|
||||||
|
}
|
192
src/java/org/apache/poi/ddf/EscherSpgrRecord.java
Normal file
192
src/java/org/apache/poi/ddf/EscherSpgrRecord.java
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.hssf.record.RecordFormatException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The spgr record defines information about a shape group. Groups in escher
|
||||||
|
* are simply another form of shape that you can't physically see.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class EscherSpgrRecord
|
||||||
|
extends EscherRecord
|
||||||
|
{
|
||||||
|
public static final short RECORD_ID = (short) 0xF009;
|
||||||
|
public static final String RECORD_DESCRIPTION = "MsofbtSpgr";
|
||||||
|
|
||||||
|
private int field_1_rectX1;
|
||||||
|
private int field_2_rectY1;
|
||||||
|
private int field_3_rectX2;
|
||||||
|
private int field_4_rectY2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
int size = 0;
|
||||||
|
field_1_rectX1 = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_2_rectY1 = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_3_rectX2 = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_4_rectY2 = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
bytesRemaining -= size;
|
||||||
|
if (bytesRemaining != 0) throw new RecordFormatException("Expected no remaining bytes but got " + bytesRemaining);
|
||||||
|
// remainingData = new byte[bytesRemaining];
|
||||||
|
// System.arraycopy( data, pos + size, remainingData, 0, bytesRemaining );
|
||||||
|
return 8 + size + bytesRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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() );
|
||||||
|
int remainingBytes = 16;
|
||||||
|
LittleEndian.putInt( data, offset + 4, remainingBytes );
|
||||||
|
LittleEndian.putInt( data, offset + 8, field_1_rectX1 );
|
||||||
|
LittleEndian.putInt( data, offset + 12, field_2_rectY1 );
|
||||||
|
LittleEndian.putInt( data, offset + 16, field_3_rectX2 );
|
||||||
|
LittleEndian.putInt( data, offset + 20, field_4_rectY2 );
|
||||||
|
// System.arraycopy( remainingData, 0, data, offset + 26, remainingData.length );
|
||||||
|
// int pos = offset + 8 + 18 + remainingData.length;
|
||||||
|
listener.afterRecordSerialize( offset + getRecordSize(), getRecordId(), offset + getRecordSize(), this );
|
||||||
|
return 8 + 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes that are required to serialize this record.
|
||||||
|
*
|
||||||
|
* @return Number of bytes
|
||||||
|
*/
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
return 8 + 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The 16 bit identifier of this shape group record.
|
||||||
|
*/
|
||||||
|
public short getRecordId()
|
||||||
|
{
|
||||||
|
return RECORD_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The short name for this record
|
||||||
|
*/
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
return "Spgr";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the string representation of this record.
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
// String extraData;
|
||||||
|
// ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// HexDump.dump(this.remainingData, 0, b, 0);
|
||||||
|
// extraData = b.toString();
|
||||||
|
// }
|
||||||
|
// catch ( Exception e )
|
||||||
|
// {
|
||||||
|
// extraData = "error";
|
||||||
|
// }
|
||||||
|
return getClass().getName() + ":" + nl +
|
||||||
|
" RecordId: 0x" + HexDump.toHex(RECORD_ID) + nl +
|
||||||
|
" Options: 0x" + HexDump.toHex(getOptions()) + nl +
|
||||||
|
" RectX: " + field_1_rectX1 + nl +
|
||||||
|
" RectY: " + field_2_rectY1 + nl +
|
||||||
|
" RectWidth: " + field_3_rectX2 + nl +
|
||||||
|
" RectHeight: " + field_4_rectY2 + nl;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The starting top-left coordinate of child records.
|
||||||
|
*/
|
||||||
|
public int getRectX1()
|
||||||
|
{
|
||||||
|
return field_1_rectX1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The starting top-left coordinate of child records.
|
||||||
|
*/
|
||||||
|
public void setRectX1( int x1 )
|
||||||
|
{
|
||||||
|
this.field_1_rectX1 = x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The starting top-left coordinate of child records.
|
||||||
|
*/
|
||||||
|
public int getRectY1()
|
||||||
|
{
|
||||||
|
return field_2_rectY1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The starting top-left coordinate of child records.
|
||||||
|
*/
|
||||||
|
public void setRectY1( int y1 )
|
||||||
|
{
|
||||||
|
this.field_2_rectY1 = y1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The starting bottom-right coordinate of child records.
|
||||||
|
*/
|
||||||
|
public int getRectX2()
|
||||||
|
{
|
||||||
|
return field_3_rectX2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The starting bottom-right coordinate of child records.
|
||||||
|
*/
|
||||||
|
public void setRectX2( int x2 )
|
||||||
|
{
|
||||||
|
this.field_3_rectX2 = x2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The starting bottom-right coordinate of child records.
|
||||||
|
*/
|
||||||
|
public int getRectY2()
|
||||||
|
{
|
||||||
|
return field_4_rectY2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The starting bottom-right coordinate of child records.
|
||||||
|
*/
|
||||||
|
public void setRectY2( int field_4_rectY2 )
|
||||||
|
{
|
||||||
|
this.field_4_rectY2 = field_4_rectY2;
|
||||||
|
}
|
||||||
|
}
|
171
src/java/org/apache/poi/ddf/EscherSplitMenuColorsRecord.java
Normal file
171
src/java/org/apache/poi/ddf/EscherSplitMenuColorsRecord.java
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.hssf.record.RecordFormatException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of the most recently used colours for the drawings contained in
|
||||||
|
* this document.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class EscherSplitMenuColorsRecord
|
||||||
|
extends EscherRecord
|
||||||
|
{
|
||||||
|
public static final short RECORD_ID = (short) 0xF11E;
|
||||||
|
public static final String RECORD_DESCRIPTION = "MsofbtSplitMenuColors";
|
||||||
|
|
||||||
|
private int field_1_color1;
|
||||||
|
private int field_2_color2;
|
||||||
|
private int field_3_color3;
|
||||||
|
private int field_4_color4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
int size = 0;
|
||||||
|
field_1_color1 = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_2_color2 = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_3_color3 = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_4_color4 = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
bytesRemaining -= size;
|
||||||
|
if (bytesRemaining != 0)
|
||||||
|
throw new RecordFormatException("Expecting no remaining data but got " + bytesRemaining + " byte(s).");
|
||||||
|
return 8 + size + bytesRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 )
|
||||||
|
{
|
||||||
|
// int field_2_numIdClusters = field_5_fileIdClusters.length + 1;
|
||||||
|
listener.beforeRecordSerialize( offset, getRecordId(), this );
|
||||||
|
|
||||||
|
int pos = offset;
|
||||||
|
LittleEndian.putShort( data, pos, getOptions() ); pos += 2;
|
||||||
|
LittleEndian.putShort( data, pos, getRecordId() ); pos += 2;
|
||||||
|
int remainingBytes = getRecordSize() - 8;
|
||||||
|
|
||||||
|
LittleEndian.putInt( data, pos, remainingBytes ); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_1_color1 ); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_2_color2 ); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_3_color3 ); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_4_color4 ); pos += 4;
|
||||||
|
listener.afterRecordSerialize( pos, getRecordId(), pos - offset, this );
|
||||||
|
return getRecordSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes that are required to serialize this record.
|
||||||
|
*
|
||||||
|
* @return Number of bytes
|
||||||
|
*/
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
return 8 + 4 * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the 16 bit identifer for this record.
|
||||||
|
*/
|
||||||
|
public short getRecordId()
|
||||||
|
{
|
||||||
|
return RECORD_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The short name for this record
|
||||||
|
*/
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
return "SplitMenuColors";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a string representation of this record.
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
// String extraData;
|
||||||
|
// ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// HexDump.dump(this.remainingData, 0, b, 0);
|
||||||
|
// extraData = b.toString();
|
||||||
|
// }
|
||||||
|
// catch ( Exception e )
|
||||||
|
// {
|
||||||
|
// extraData = "error";
|
||||||
|
// }
|
||||||
|
return getClass().getName() + ":" + nl +
|
||||||
|
" RecordId: 0x" + HexDump.toHex(RECORD_ID) + nl +
|
||||||
|
" Options: 0x" + HexDump.toHex(getOptions()) + nl +
|
||||||
|
" Color1: 0x" + HexDump.toHex(field_1_color1) + nl +
|
||||||
|
" Color2: 0x" + HexDump.toHex(field_2_color2) + nl +
|
||||||
|
" Color3: 0x" + HexDump.toHex(field_3_color3) + nl +
|
||||||
|
" Color4: 0x" + HexDump.toHex(field_4_color4) + nl +
|
||||||
|
"";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColor1()
|
||||||
|
{
|
||||||
|
return field_1_color1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor1( int field_1_color1 )
|
||||||
|
{
|
||||||
|
this.field_1_color1 = field_1_color1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColor2()
|
||||||
|
{
|
||||||
|
return field_2_color2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor2( int field_2_color2 )
|
||||||
|
{
|
||||||
|
this.field_2_color2 = field_2_color2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColor3()
|
||||||
|
{
|
||||||
|
return field_3_color3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor3( int field_3_color3 )
|
||||||
|
{
|
||||||
|
this.field_3_color3 = field_3_color3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColor4()
|
||||||
|
{
|
||||||
|
return field_4_color4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor4( int field_4_color4 )
|
||||||
|
{
|
||||||
|
this.field_4_color4 = field_4_color4;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
215
src/java/org/apache/poi/ddf/EscherTextboxRecord.java
Normal file
215
src/java/org/apache/poi/ddf/EscherTextboxRecord.java
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
* The Apache Software License, Version 1.1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002 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
|
||||||
|
* <http://www.apache.org/>.
|
||||||
|
*/
|
||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.hssf.record.RecordFormatException;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supports text boxes
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class EscherTextboxRecord extends EscherRecord
|
||||||
|
{
|
||||||
|
public static final short RECORD_ID = (short)0xF00D;
|
||||||
|
public static final String RECORD_DESCRIPTION = "msofbtClientTextbox";
|
||||||
|
|
||||||
|
private static final byte[] NO_BYTES = new byte[0];
|
||||||
|
|
||||||
|
/** The data for this record not including the the 8 byte header */
|
||||||
|
private byte[] thedata = NO_BYTES;
|
||||||
|
|
||||||
|
public EscherTextboxRecord()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 );
|
||||||
|
if ( isContainerRecord() )
|
||||||
|
{
|
||||||
|
int bytesWritten = 0;
|
||||||
|
thedata = new byte[0];
|
||||||
|
offset += 8;
|
||||||
|
bytesWritten += 8;
|
||||||
|
while ( bytesRemaining > 0 )
|
||||||
|
{
|
||||||
|
EscherRecord child = recordFactory.createRecord( data, offset );
|
||||||
|
int childBytesWritten = child.fillFields( data, offset, recordFactory );
|
||||||
|
bytesWritten += childBytesWritten;
|
||||||
|
offset += childBytesWritten;
|
||||||
|
bytesRemaining -= childBytesWritten;
|
||||||
|
getChildRecords().add( child );
|
||||||
|
}
|
||||||
|
return bytesWritten;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
thedata = new byte[bytesRemaining];
|
||||||
|
System.arraycopy( data, offset + 8, thedata, 0, bytesRemaining );
|
||||||
|
return bytesRemaining + 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes this record and any contained records to the supplied byte
|
||||||
|
* array.
|
||||||
|
*
|
||||||
|
* @return the number of bytes written.
|
||||||
|
*/
|
||||||
|
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());
|
||||||
|
int remainingBytes = thedata.length;
|
||||||
|
for ( Iterator iterator = getChildRecords().iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord r = (EscherRecord) iterator.next();
|
||||||
|
remainingBytes += r.getRecordSize();
|
||||||
|
}
|
||||||
|
LittleEndian.putInt(data, offset+4, remainingBytes);
|
||||||
|
System.arraycopy(thedata, 0, data, offset+8, thedata.length);
|
||||||
|
int pos = offset+8+thedata.length;
|
||||||
|
for ( Iterator iterator = getChildRecords().iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord r = (EscherRecord) iterator.next();
|
||||||
|
pos += r.serialize(pos, data, listener );
|
||||||
|
}
|
||||||
|
|
||||||
|
listener.afterRecordSerialize( pos, getRecordId(), pos - offset, this );
|
||||||
|
int size = pos - offset;
|
||||||
|
if (size != getRecordSize())
|
||||||
|
throw new RecordFormatException(size + " bytes written but getRecordSize() reports " + getRecordSize());
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns any extra data associated with this record. In practice excel
|
||||||
|
* does not seem to put anything here.
|
||||||
|
*/
|
||||||
|
public byte[] getData()
|
||||||
|
{
|
||||||
|
return thedata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes that are required to serialize this record.
|
||||||
|
*
|
||||||
|
* @return Number of bytes
|
||||||
|
*/
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
return 8 + thedata.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object clone()
|
||||||
|
{
|
||||||
|
// shallow clone
|
||||||
|
return super.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The short name for this record
|
||||||
|
*/
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
return "ClientTextbox";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty( "line.separator" );
|
||||||
|
|
||||||
|
String theDumpHex = "";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (thedata.length != 0)
|
||||||
|
{
|
||||||
|
theDumpHex = " Extra Data:" + nl;
|
||||||
|
theDumpHex += HexDump.dump(thedata, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch ( Exception e )
|
||||||
|
{
|
||||||
|
theDumpHex = "Error!!";
|
||||||
|
}
|
||||||
|
|
||||||
|
return getClass().getName() + ":" + nl +
|
||||||
|
" isContainer: " + isContainerRecord() + nl +
|
||||||
|
" options: 0x" + HexDump.toHex( getOptions() ) + nl +
|
||||||
|
" recordId: 0x" + HexDump.toHex( getRecordId() ) + nl +
|
||||||
|
" numchildren: " + getChildRecords().size() + nl +
|
||||||
|
theDumpHex;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ignores all serialization events.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class NullEscherSerializationListener implements EscherSerializationListener
|
||||||
|
{
|
||||||
|
public void beforeRecordSerialize( int offset, short recordId, EscherRecord record )
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
public void afterRecordSerialize( int offset, short recordId, int size, EscherRecord record )
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
234
src/java/org/apache/poi/ddf/UnknownEscherRecord.java
Normal file
234
src/java/org/apache/poi/ddf/UnknownEscherRecord.java
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
* The Apache Software License, Version 1.1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002 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
|
||||||
|
* <http://www.apache.org/>.
|
||||||
|
*/
|
||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This record is used whenever a escher record is encountered that
|
||||||
|
* we do not explicitly support.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class UnknownEscherRecord extends EscherRecord
|
||||||
|
{
|
||||||
|
private static final byte[] NO_BYTES = new byte[0];
|
||||||
|
|
||||||
|
/** The data for this record not including the the 8 byte header */
|
||||||
|
private byte[] thedata = NO_BYTES;
|
||||||
|
private List childRecords = new ArrayList();
|
||||||
|
|
||||||
|
public UnknownEscherRecord()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 );
|
||||||
|
if ( isContainerRecord() )
|
||||||
|
{
|
||||||
|
int bytesWritten = 0;
|
||||||
|
thedata = new byte[0];
|
||||||
|
offset += 8;
|
||||||
|
bytesWritten += 8;
|
||||||
|
while ( bytesRemaining > 0 )
|
||||||
|
{
|
||||||
|
EscherRecord child = recordFactory.createRecord( data, offset );
|
||||||
|
int childBytesWritten = child.fillFields( data, offset, recordFactory );
|
||||||
|
bytesWritten += childBytesWritten;
|
||||||
|
offset += childBytesWritten;
|
||||||
|
bytesRemaining -= childBytesWritten;
|
||||||
|
getChildRecords().add( child );
|
||||||
|
}
|
||||||
|
return bytesWritten;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
thedata = new byte[bytesRemaining];
|
||||||
|
System.arraycopy( data, offset + 8, thedata, 0, bytesRemaining );
|
||||||
|
return bytesRemaining + 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes this record and any contained records to the supplied byte
|
||||||
|
* array.
|
||||||
|
*
|
||||||
|
* @return the number of bytes written.
|
||||||
|
*/
|
||||||
|
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());
|
||||||
|
int remainingBytes = thedata.length;
|
||||||
|
for ( Iterator iterator = getChildRecords().iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord r = (EscherRecord) iterator.next();
|
||||||
|
remainingBytes += r.getRecordSize();
|
||||||
|
}
|
||||||
|
LittleEndian.putInt(data, offset+4, remainingBytes);
|
||||||
|
System.arraycopy(thedata, 0, data, offset+8, thedata.length);
|
||||||
|
int pos = offset+8+thedata.length;
|
||||||
|
for ( Iterator iterator = getChildRecords().iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord r = (EscherRecord) iterator.next();
|
||||||
|
pos += r.serialize(pos, data, listener );
|
||||||
|
}
|
||||||
|
|
||||||
|
listener.afterRecordSerialize( pos, getRecordId(), pos - offset, this );
|
||||||
|
return pos - offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getData()
|
||||||
|
{
|
||||||
|
return thedata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes that are required to serialize this record.
|
||||||
|
*
|
||||||
|
* @return Number of bytes
|
||||||
|
*/
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
return 8 + thedata.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List getChildRecords()
|
||||||
|
{
|
||||||
|
return childRecords;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChildRecords( List childRecords )
|
||||||
|
{
|
||||||
|
this.childRecords = childRecords;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object clone()
|
||||||
|
{
|
||||||
|
// shallow clone
|
||||||
|
return super.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The short name for this record
|
||||||
|
*/
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
return "Unknown 0x" + HexDump.toHex(getRecordId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty( "line.separator" );
|
||||||
|
|
||||||
|
StringBuffer children = new StringBuffer();
|
||||||
|
if ( getChildRecords().size() > 0 )
|
||||||
|
{
|
||||||
|
children.append( " children: " + nl );
|
||||||
|
for ( Iterator iterator = getChildRecords().iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord record = (EscherRecord) iterator.next();
|
||||||
|
children.append( record.toString() );
|
||||||
|
children.append( nl );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String theDumpHex = "";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (thedata.length != 0)
|
||||||
|
{
|
||||||
|
theDumpHex = " Extra Data:" + nl;
|
||||||
|
theDumpHex += HexDump.dump(thedata, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch ( Exception e )
|
||||||
|
{
|
||||||
|
theDumpHex = "Error!!";
|
||||||
|
}
|
||||||
|
|
||||||
|
return getClass().getName() + ":" + nl +
|
||||||
|
" isContainer: " + isContainerRecord() + nl +
|
||||||
|
" options: 0x" + HexDump.toHex( getOptions() ) + nl +
|
||||||
|
" recordId: 0x" + HexDump.toHex( getRecordId() ) + nl +
|
||||||
|
" numchildren: " + getChildRecords().size() + nl +
|
||||||
|
theDumpHex +
|
||||||
|
children.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addChildRecord( EscherRecord childRecord )
|
||||||
|
{
|
||||||
|
getChildRecords().add( childRecord );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
11
src/java/org/apache/poi/ddf/package.html
Normal file
11
src/java/org/apache/poi/ddf/package.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<html>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<p>This package contains classes for decoding the Microsoft Office
|
||||||
|
Drawing format otherwise known as escher henceforth known in POI
|
||||||
|
as the Dreadful Drawing Format.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user