diff --git a/src/java/org/apache/poi/hpsf/Array.java b/src/java/org/apache/poi/hpsf/Array.java index 8850ab9cd6..f8c70fe127 100644 --- a/src/java/org/apache/poi/hpsf/Array.java +++ b/src/java/org/apache/poi/hpsf/Array.java @@ -17,23 +17,19 @@ package org.apache.poi.hpsf; import org.apache.poi.util.Internal; -import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.LittleEndianByteArrayInputStream; @Internal class Array { - static class ArrayDimension - { - static final int SIZE = 8; - - private int _indexOffset; + static class ArrayDimension { private long _size; + @SuppressWarnings("unused") + private int _indexOffset; - ArrayDimension( byte[] data, int offset ) - { - _size = LittleEndian.getUInt( data, offset ); - _indexOffset = LittleEndian.getInt( data, offset - + LittleEndian.INT_SIZE ); + void read( LittleEndianByteArrayInputStream lei ) { + _size = lei.readUInt(); + _indexOffset = lei.readInt(); } } @@ -42,96 +38,69 @@ class Array private ArrayDimension[] _dimensions; private int _type; - ArrayHeader( byte[] data, int startOffset ) - { - int offset = startOffset; + void read( LittleEndianByteArrayInputStream lei ) { + _type = lei.readInt(); - _type = LittleEndian.getInt( data, offset ); - offset += LittleEndian.INT_SIZE; + long numDimensionsUnsigned = lei.readUInt(); - long numDimensionsUnsigned = LittleEndian.getUInt( data, offset ); - offset += LittleEndian.INT_SIZE; - - if ( !( 1 <= numDimensionsUnsigned && numDimensionsUnsigned <= 31 ) ) - throw new IllegalPropertySetDataException( - "Array dimension number " + numDimensionsUnsigned - + " is not in [1; 31] range" ); + if ( !( 1 <= numDimensionsUnsigned && numDimensionsUnsigned <= 31 ) ) { + String msg = "Array dimension number "+numDimensionsUnsigned+" is not in [1; 31] range"; + throw new IllegalPropertySetDataException(msg); + } + int numDimensions = (int) numDimensionsUnsigned; _dimensions = new ArrayDimension[numDimensions]; - for ( int i = 0; i < numDimensions; i++ ) - { - _dimensions[i] = new ArrayDimension( data, offset ); - offset += ArrayDimension.SIZE; + for ( int i = 0; i < numDimensions; i++ ) { + ArrayDimension ad = new ArrayDimension(); + ad.read(lei); + _dimensions[i] = ad; } } - long getNumberOfScalarValues() - { + long getNumberOfScalarValues() { long result = 1; - for ( ArrayDimension dimension : _dimensions ) + for ( ArrayDimension dimension : _dimensions ) { result *= dimension._size; + } return result; } - int getSize() - { - return LittleEndian.INT_SIZE * 2 + _dimensions.length - * ArrayDimension.SIZE; - } - - int getType() - { + int getType() { return _type; } } - private ArrayHeader _header; + private final ArrayHeader _header = new ArrayHeader(); private TypedPropertyValue[] _values; - Array() - { - } + Array() {} - Array( final byte[] data, final int offset ) - { - read( data, offset ); - } - - int read( final byte[] data, final int startOffset ) - { - int offset = startOffset; - - _header = new ArrayHeader( data, offset ); - offset += _header.getSize(); + void read( LittleEndianByteArrayInputStream lei ) { + _header.read(lei); long numberOfScalarsLong = _header.getNumberOfScalarValues(); - if ( numberOfScalarsLong > Integer.MAX_VALUE ) - throw new UnsupportedOperationException( - "Sorry, but POI can't store array of properties with size of " - + numberOfScalarsLong + " in memory" ); + if ( numberOfScalarsLong > Integer.MAX_VALUE ) { + String msg = + "Sorry, but POI can't store array of properties with size of " + + numberOfScalarsLong + " in memory"; + throw new UnsupportedOperationException(msg); + } int numberOfScalars = (int) numberOfScalarsLong; _values = new TypedPropertyValue[numberOfScalars]; - final int type = _header._type; - if ( type == Variant.VT_VARIANT ) - { - for ( int i = 0; i < numberOfScalars; i++ ) - { - TypedPropertyValue typedPropertyValue = new TypedPropertyValue(); - offset += typedPropertyValue.read( data, offset ); + int paddedType = (_header._type == Variant.VT_VARIANT) ? 0 : _header._type; + for ( int i = 0; i < numberOfScalars; i++ ) { + TypedPropertyValue typedPropertyValue = new TypedPropertyValue(paddedType, null); + typedPropertyValue.read(lei); + _values[i] = typedPropertyValue; + if (paddedType != 0) { + TypedPropertyValue.skipPadding(lei); } } - else - { - for ( int i = 0; i < numberOfScalars; i++ ) - { - TypedPropertyValue typedPropertyValue = new TypedPropertyValue( - type, null ); - offset += typedPropertyValue.readValuePadded( data, offset ); - } - } - - return offset - startOffset; + } + + TypedPropertyValue[] getValues(){ + return _values; } } diff --git a/src/java/org/apache/poi/hpsf/Blob.java b/src/java/org/apache/poi/hpsf/Blob.java index 547e2392ba..af207feabb 100644 --- a/src/java/org/apache/poi/hpsf/Blob.java +++ b/src/java/org/apache/poi/hpsf/Blob.java @@ -17,29 +17,19 @@ package org.apache.poi.hpsf; import org.apache.poi.util.Internal; -import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.LittleEndianInput; @Internal -class Blob -{ +class Blob { private byte[] _value; - Blob( byte[] data, int offset ) - { - int size = LittleEndian.getInt( data, offset ); - - if ( size == 0 ) - { - _value = new byte[0]; - return; + Blob() {} + + void read( LittleEndianInput lei ) { + int size = lei.readInt(); + _value = new byte[size]; + if ( size > 0 ) { + lei.readFully(_value); } - - _value = LittleEndian.getByteArray( data, offset - + LittleEndian.INT_SIZE, size ); - } - - int getSize() - { - return LittleEndian.INT_SIZE + _value.length; } } diff --git a/src/java/org/apache/poi/hpsf/ClassID.java b/src/java/org/apache/poi/hpsf/ClassID.java index 0dacf80139..ec9c35555e 100644 --- a/src/java/org/apache/poi/hpsf/ClassID.java +++ b/src/java/org/apache/poi/hpsf/ClassID.java @@ -20,16 +20,16 @@ package org.apache.poi.hpsf; import java.util.Arrays; import org.apache.poi.util.HexDump; -import org.apache.poi.util.StringUtil; /** - *
Represents a class ID (16 bytes). Unlike other little-endian - * type the {@link ClassID} is not just 16 bytes stored in the wrong - * order. Instead, it is a double word (4 bytes) followed by two - * words (2 bytes each) followed by 8 bytes.
+ * Represents a class ID (16 bytes). Unlike other little-endian + * type the {@link ClassID} is not just 16 bytes stored in the wrong + * order. Instead, it is a double word (4 bytes) followed by two + * words (2 bytes each) followed by 8 bytes.+ * + * The ClassID (or CLSID) is a UUID - see RFC 4122 */ -public class ClassID -{ +public class ClassID { public static final ClassID OLE10_PACKAGE = new ClassID("{0003000C-0000-0000-C000-000000000046}"); public static final ClassID PPT_SHOW = new ClassID("{64818D10-4F9B-11CF-86EA-00AA00B929E8}"); public static final ClassID XLS_WORKBOOK = new ClassID("{00020841-0000-0000-C000-000000000046}"); @@ -68,21 +68,16 @@ public class ClassID public static final ClassID EQUATION30 = new ClassID("{0002CE02-0000-0000-C000-000000000046}"); - /**
The number of bytes occupied by this object in the byte - * stream.
*/ + /** The number of bytes occupied by this object in the byte stream. */ public static final int LENGTH = 16; /** - *The bytes making out the class ID in correct order, - * i.e. big-endian.
+ * The bytes making out the class ID in correct order, i.e. big-endian. */ private final byte[] bytes = new byte[LENGTH]; - - /** - *Creates a {@link ClassID} and reads its value from a byte - * array.
+ * Creates a {@link ClassID} and reads its value from a byte array. * * @param src The byte array to read from. * @param offset The offset of the first byte to read. @@ -93,8 +88,7 @@ public class ClassID /** - *Creates a {@link ClassID} and initializes its value with - * 0x00 bytes.
+ * Creates a {@link ClassID} and initializes its value with 0x00 bytes. */ public ClassID() { Arrays.fill(bytes, (byte)0); @@ -102,8 +96,8 @@ public class ClassID /** - *Creates a {@link ClassID} from a human-readable representation of the Class ID in standard
- * format "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}".
Gets the bytes making out the class ID. They are returned in - * correct order, i.e. big-endian.
+ * Gets the bytes making out the class ID. They are returned in correct order, i.e. big-endian. * * @return the bytes making out the class ID. */ @@ -138,7 +130,7 @@ public class ClassID /** - *Sets the bytes making out the class ID.
+ * Sets the bytes making out the class ID. * * @param bytes The bytes making out the class ID in big-endian format. They * are copied without their order being changed. @@ -150,13 +142,10 @@ public class ClassID /** - *Reads the class ID's value from a byte array by turning - * little-endian into big-endian.
+ * Reads the class ID's value from a byte array by turning little-endian into big-endian. * * @param src The byte array to read from - * - * @param offset The offset within the src byte array - * + * @param offset The offset within the {@code src} byte array * @return A byte array containing the class ID. */ public byte[] read(final byte[] src, final int offset) { @@ -180,18 +169,15 @@ public class ClassID return bytes; } - - /** - *Writes the class ID to a byte array in the - * little-endian format.
+ * Writes the class ID to a byte array in the little-endian format. * * @param dst The byte array to write to. * - * @param offset The offset within the dst byte array. + * @param offset The offset within the {@code dst} byte array. * * @exception ArrayStoreException if there is not enough room for the class - * ID 16 bytes in the byte array after the offset position. + * ID 16 bytes in the byte array after the {@code offset} position. */ public void write(final byte[] dst, final int offset) throws ArrayStoreException { @@ -223,30 +209,44 @@ public class ClassID /** - *Checks whether this ClassID is equal to another
- * object.
PropertySet with
- * @return true if the objects are equal, else
- * false.
+ * @param o the object to compare this {@code ClassID} with
+ * @return {@code true} if the objects are equal, else {@code false}.
*/
@Override
public boolean equals(final Object o) {
- if (o == null || !(o instanceof ClassID)) {
- return false;
- }
- final ClassID cid = (ClassID) o;
- if (bytes.length != cid.bytes.length) {
- return false;
- }
- for (int i = 0; i < bytes.length; i++) {
- if (bytes[i] != cid.bytes[i]) {
- return false;
- }
- }
- return true;
+ return (o instanceof ClassID) && Arrays.equals(bytes, ((ClassID)o).bytes);
}
+ /**
+ * Checks whether this {@code ClassID} is equal to another ClassID with inverted endianess,
+ * because there are apparently not only version 1 GUIDs (aka "network" with big-endian encoding),
+ * but also version 2 GUIDs (aka "native" with little-endian encoding) out there.
+ *
+ * @param o the object to compare this {@code ClassID} with
+ * @return {@code true} if the objects are equal, else {@code false}.
+ */
+ public boolean equalsInverted(ClassID o) {
+ return
+ o.bytes[0] == bytes[3] &&
+ o.bytes[1] == bytes[2] &&
+ o.bytes[2] == bytes[1] &&
+ o.bytes[3] == bytes[0] &&
+ o.bytes[4] == bytes[5] &&
+ o.bytes[5] == bytes[4] &&
+ o.bytes[6] == bytes[7] &&
+ o.bytes[7] == bytes[6] &&
+ o.bytes[8] == bytes[8] &&
+ o.bytes[9] == bytes[9] &&
+ o.bytes[10] == bytes[10] &&
+ o.bytes[11] == bytes[11] &&
+ o.bytes[12] == bytes[12] &&
+ o.bytes[13] == bytes[13] &&
+ o.bytes[14] == bytes[14] &&
+ o.bytes[15] == bytes[15]
+ ;
+ }
/**
@@ -254,12 +254,12 @@ public class ClassID
*/
@Override
public int hashCode() {
- return new String(bytes, StringUtil.UTF8).hashCode();
+ return toString().hashCode();
}
/**
- * Returns a human-readable representation of the Class ID in standard
- * format "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}".
Gets the dictionary which contains IDs and names of the named custom
@@ -317,16 +333,6 @@ public class CustomProperties extends HashMap
+ *
+ * The constructor reads the first few bytes from the stream
+ * and determines whether it is really a property set stream. If
+ * it is, it parses the rest of the stream. If it is not, it
+ * resets the stream to its beginning in order to let other
+ * components mess around with the data and throws an
+ * exception.
+ *
+ * @param stream Holds the data making out the property set
+ * stream.
+ * @throws MarkUnsupportedException
+ * if the stream does not support the {@link InputStream#markSupported} method.
+ * @throws IOException
+ * if the {@link InputStream} cannot be accessed as needed.
+ * @exception NoPropertySetStreamException
+ * if the input stream does not contain a property set.
+ * @exception UnsupportedEncodingException
+ * if a character encoding is not supported.
+ */
+ public DocumentSummaryInformation(final InputStream stream)
+ throws NoPropertySetStreamException, MarkUnsupportedException, IOException, UnsupportedEncodingException {
+ super(stream);
+ }
/**
* Returns the category (or {@code null}).
@@ -732,13 +760,13 @@ public class DocumentSummaryInformation extends SpecialPropertySet {
final Map Class for writing little-endian data and more. Compares to object arrays with regarding the objects' order. For
- * example, [1, 2, 3] and [2, 1, 3] are equal. Pads a byte array with 0x00 bytes so that its length is a multiple of
* 4. The Variant types as defined by Microsoft's COM. I
- * found this information in
- * http://www.marin.clara.net/COM/variant_type_definitions.htm. In the variant types descriptions the following shortcuts are
- * used: [V] - may appear in a VARIANT,
- * [T] - may appear in a TYPEDESC,
- * [P] - may appear in an OLE property set,
- * [S] - may appear in a Safe Array. [V][P] Nothing, i.e. not a single byte of data. [V][P] SQL style Null. [V][T][P][S] 2 byte signed int. [V][T][P][S] 4 byte signed int. [V][T][P][S] 4 byte real. [V][T][P][S] 8 byte real. [V][T][P][S] currency. How long is this? How is it to be
- * interpreted? [V][T][P][S] date. How long is this? How is it to be
- * interpreted? [V][T][P][S] OLE Automation string. How long is this? How is it
- * to be interpreted? [V][T][P][S] IDispatch *. How long is this? How is it to be
- * interpreted? [V][T][S] SCODE. How
- * long is this? How is it to be interpreted? [V][T][P][S] True=-1, False=0. [V][T][P][S] VARIANT *. How long is this? How is it to be
- * interpreted? [V][T][S] IUnknown *. How long is this? How is it to be
- * interpreted? [V][T][S] 16 byte fixed point. [T] signed char. [V][T][P][S] unsigned char. [T][P] unsigned short. [T][P] unsigned int. [T][P] signed 64-bit int. [T][P] unsigned 64-bit int. [T] signed machine int. [T] unsigned machine int. [T] C style void. [T] Standard return type. How long is this? How is it to be
- * interpreted? [T] pointer type. How long is this? How is it to be
- * interpreted? [T] (use VT_ARRAY in VARIANT). [T] C style array. How long is this? How is it to be
- * interpreted? [T] user defined type. How long is this? How is it to be
- * interpreted? [T][P] null terminated string. [T][P] wide (Unicode) null terminated string. [P] FILETIME. The FILETIME structure holds a date and time
+ * [P] FILETIME. The FILETIME structure holds a date and time
* associated with a file. The structure identifies a 64-bit
* integer specifying the number of 100-nanosecond intervals which
* have passed since January 1, 1601. This 64-bit value is split
- * into the two dwords stored in the structure. [P] Length prefixed bytes. [P] Name of the stream follows. [P] Name of the storage follows. [P] Stream contains an object. How long is this? How is it
- * to be interpreted? [P] Storage contains an object. How long is this? How is it
- * to be interpreted? [P] Blob contains an object. How long is this? How is it to be
- * interpreted? [P] Clipboard format. How long is this? How is it to be
- * interpreted? [P] A Class ID.
*
- * It consists of a 32 bit unsigned integer indicating the size
+ * It consists of a 32 bit unsigned integer indicating the size
* of the structure, a 32 bit signed integer indicating (Clipboard
* Format Tag) indicating the type of data that it contains, and
- * then a byte array containing the data.
*
- * The valid Clipboard Format Tags are: See
- * msdn.microsoft.com/library/en-us/com/stgrstrc_0uwk.asp. [P] simple counted array. How long is this? How is it to be
- * interpreted? [V] SAFEARRAY*. How
- * long is this? How is it to be interpreted? [V] void* for local use. How long is this? How is it to be
- * interpreted? FIXME (3): Document this! FIXME (3): Document this! FIXME (3): Document this! FIXME (3): Document this! Maps the numbers denoting the variant types to their corresponding
- * variant type names. Denotes a variant type with a length that is unknown to HPSF yet. Denotes a variant type with a variable length. Denotes a variant type with a length of 0 bytes. Denotes a variant type with a length of 2 bytes. Denotes a variant type with a length of 4 bytes. Denotes a variant type with a length of 8 bytes. Returns the variant type name associated with a variant type
- * number. Returns a variant type's length.true if the object arrays are equal,
- * false if they are not.
- */
- public static boolean equals(Object[] c1, Object[] c2)
- {
- for (int i1 = 0; i1 < c1.length; i1++)
- {
- final Object obj1 = c1[i1];
- boolean matchFound = false;
- for (int i2 = 0; !matchFound && i2 < c1.length; i2++)
- {
- final Object obj2 = c2[i2];
- if (obj1.equals(obj2))
- {
- matchFound = true;
- c2[i2] = null;
- }
- }
- if (!matchFound)
- return false;
- }
- return true;
- }
-
/**
*
+ *
*/
public class Variant
{
/**
- *
- *
*
- * typedef struct tagCLIPDATA {
+ *
*
- * {@code
+ * typedef struct tagCLIPDATA {
* // cbSize is the size of the buffer pointed to
* // by pClipData, plus sizeof(ulClipFmt)
* ULONG cbSize;
* long ulClipFmt;
* BYTE* pClipData;
- * } CLIPDATA;
+ * } CLIPDATA;}