97e991ec6e
git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@527816 13f79535-47bb-0310-9956-ffa450edef68
218 lines
7.9 KiB
Java
218 lines
7.9 KiB
Java
|
|
/* ====================================================================
|
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
|
contributor license agreements. See the NOTICE file distributed with
|
|
this work for additional information regarding copyright ownership.
|
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
|
(the "License"); you may not use this file except in compliance with
|
|
the License. You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
==================================================================== */
|
|
|
|
package org.apache.poi.ddf;
|
|
|
|
import org.apache.poi.util.LittleEndian;
|
|
import org.apache.poi.util.HexDump;
|
|
|
|
/**
|
|
* 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
|
|
{
|
|
/**
|
|
* The size of the header that goes at the
|
|
* start of the array, before the data
|
|
*/
|
|
private static final int FIXED_SIZE = 3 * 2;
|
|
/**
|
|
* Normally, the size recorded in the simple data (for the complex
|
|
* data) includes the size of the header.
|
|
* There are a few cases when it doesn't though...
|
|
*/
|
|
private boolean sizeIncludesHeaderSize = true;
|
|
|
|
/**
|
|
* When reading a property from data stream remeber if the complex part is empty and set this flag.
|
|
*/
|
|
private boolean emptyComplexPart = false;
|
|
|
|
public EscherArrayProperty( short id, byte[] complexData )
|
|
{
|
|
super( id, checkComplexData(complexData) );
|
|
emptyComplexPart = complexData.length == 0;
|
|
}
|
|
|
|
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 )
|
|
{
|
|
if (emptyComplexPart){
|
|
complexData = new byte[0];
|
|
} else {
|
|
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) {
|
|
// The stored data size in the simple block excludes the header size
|
|
complexData = new byte[arraySize + 6];
|
|
sizeIncludesHeaderSize = false;
|
|
}
|
|
System.arraycopy(data, offset, complexData, 0, complexData.length );
|
|
}
|
|
return complexData.length;
|
|
}
|
|
|
|
/**
|
|
* Serializes the simple part of this property. ie the first 6 bytes.
|
|
*
|
|
* Needs special code to handle the case when the size doesn't
|
|
* include the size of the header block
|
|
*/
|
|
public int serializeSimplePart( byte[] data, int pos )
|
|
{
|
|
LittleEndian.putShort(data, pos, getId());
|
|
int recordSize = complexData.length;
|
|
if(!sizeIncludesHeaderSize) {
|
|
recordSize -= 6;
|
|
}
|
|
LittleEndian.putInt(data, pos + 2, recordSize);
|
|
return 6;
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
}
|