From 0df5442322d2e095f77a7ec5bf07c762667cb438 Mon Sep 17 00:00:00 2001 From: Sergey Vladimirov Date: Fri, 21 Oct 2011 23:45:01 +0000 Subject: [PATCH] add classes that will replace VariantSupport class just a bit later git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1187595 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/poi/hpsf/Array.java | 121 ++++++++++ src/java/org/apache/poi/hpsf/Blob.java | 30 +++ .../org/apache/poi/hpsf/ClipboardData.java | 27 +++ .../org/apache/poi/hpsf/CodePageString.java | 31 +++ src/java/org/apache/poi/hpsf/Currency.java | 18 ++ src/java/org/apache/poi/hpsf/Date.java | 18 ++ src/java/org/apache/poi/hpsf/Decimal.java | 37 +++ src/java/org/apache/poi/hpsf/Filetime.java | 17 ++ src/java/org/apache/poi/hpsf/GUID.java | 24 ++ .../apache/poi/hpsf/IndirectPropertyName.java | 19 ++ .../apache/poi/hpsf/TypedPropertyValue.java | 224 ++++++++++++++++++ .../org/apache/poi/hpsf/UnicodeString.java | 35 +++ src/java/org/apache/poi/hpsf/Variant.java | 8 + src/java/org/apache/poi/hpsf/VariantBool.java | 32 +++ .../org/apache/poi/hpsf/VariantVector.java | 43 ++++ src/java/org/apache/poi/hpsf/Vector.java | 64 +++++ .../org/apache/poi/hpsf/VersionedStream.java | 21 ++ 17 files changed, 769 insertions(+) create mode 100644 src/java/org/apache/poi/hpsf/Array.java create mode 100644 src/java/org/apache/poi/hpsf/Blob.java create mode 100644 src/java/org/apache/poi/hpsf/ClipboardData.java create mode 100644 src/java/org/apache/poi/hpsf/CodePageString.java create mode 100644 src/java/org/apache/poi/hpsf/Currency.java create mode 100644 src/java/org/apache/poi/hpsf/Date.java create mode 100644 src/java/org/apache/poi/hpsf/Decimal.java create mode 100644 src/java/org/apache/poi/hpsf/Filetime.java create mode 100644 src/java/org/apache/poi/hpsf/GUID.java create mode 100644 src/java/org/apache/poi/hpsf/IndirectPropertyName.java create mode 100644 src/java/org/apache/poi/hpsf/TypedPropertyValue.java create mode 100644 src/java/org/apache/poi/hpsf/UnicodeString.java create mode 100644 src/java/org/apache/poi/hpsf/VariantBool.java create mode 100644 src/java/org/apache/poi/hpsf/VariantVector.java create mode 100644 src/java/org/apache/poi/hpsf/Vector.java create mode 100644 src/java/org/apache/poi/hpsf/VersionedStream.java diff --git a/src/java/org/apache/poi/hpsf/Array.java b/src/java/org/apache/poi/hpsf/Array.java new file mode 100644 index 0000000000..cdb78f6f92 --- /dev/null +++ b/src/java/org/apache/poi/hpsf/Array.java @@ -0,0 +1,121 @@ +package org.apache.poi.hpsf; + +import org.apache.poi.util.Internal; +import org.apache.poi.util.LittleEndian; + +@Internal +class Array +{ + static class ArrayDimension + { + static final int SIZE = 8; + + private int _indexOffset; + private long _size; + + ArrayDimension( byte[] data, int offset ) + { + _size = LittleEndian.getUInt( data, offset ); + _indexOffset = LittleEndian.getInt( data, offset + + LittleEndian.INT_SIZE ); + } + } + + static class ArrayHeader + { + private ArrayDimension[] _dimensions; + private int _type; + + ArrayHeader( byte[] data, int startOffset ) + { + int offset = startOffset; + + _type = LittleEndian.getInt( data, offset ); + offset += LittleEndian.INT_SIZE; + + 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" ); + int numDimensions = (int) numDimensionsUnsigned; + + _dimensions = new ArrayDimension[numDimensions]; + for ( int i = 0; i < numDimensions; i++ ) + { + _dimensions[i] = new ArrayDimension( data, offset ); + offset += ArrayDimension.SIZE; + } + } + + long getNumberOfScalarValues() + { + long result = 1; + for ( ArrayDimension dimension : _dimensions ) + result *= dimension._size; + return result; + } + + int getSize() + { + return LittleEndian.INT_SIZE * 2 + _dimensions.length + * ArrayDimension.SIZE; + } + + int getType() + { + return _type; + } + } + + private ArrayHeader _header; + private TypedPropertyValue[] _values; + + 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(); + + 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" ); + 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 ); + } + } + else + { + for ( int i = 0; i < numberOfScalars; i++ ) + { + TypedPropertyValue typedPropertyValue = new TypedPropertyValue( + type, null ); + offset += typedPropertyValue.readValuePadded( data, offset ); + } + } + + return offset - startOffset; + } +} diff --git a/src/java/org/apache/poi/hpsf/Blob.java b/src/java/org/apache/poi/hpsf/Blob.java new file mode 100644 index 0000000000..a3421c2e0d --- /dev/null +++ b/src/java/org/apache/poi/hpsf/Blob.java @@ -0,0 +1,30 @@ +package org.apache.poi.hpsf; + +import org.apache.poi.util.LittleEndian; + +import org.apache.poi.util.Internal; + +@Internal +class Blob +{ + private byte[] _value; + + Blob( byte[] data, int offset ) + { + int size = LittleEndian.getInt( data, offset ); + + if ( size == 0 ) + { + _value = new byte[0]; + return; + } + + _value = LittleEndian.getByteArray( _value, offset + + LittleEndian.INT_SIZE, size ); + } + + int getSize() + { + return LittleEndian.INT_SIZE + _value.length; + } +} diff --git a/src/java/org/apache/poi/hpsf/ClipboardData.java b/src/java/org/apache/poi/hpsf/ClipboardData.java new file mode 100644 index 0000000000..477a40b95f --- /dev/null +++ b/src/java/org/apache/poi/hpsf/ClipboardData.java @@ -0,0 +1,27 @@ +package org.apache.poi.hpsf; + +import org.apache.poi.util.LittleEndian; + +class ClipboardData +{ + private int _format; + private byte[] _value; + + ClipboardData( byte[] data, int offset ) + { + int size = LittleEndian.getInt( data, offset ); + + if ( size < 4 ) + throw new IllegalPropertySetDataException( + "ClipboardData size less than 4 bytes " + + "(doesn't even have format field!)" ); + _format = LittleEndian.getInt( data, offset + LittleEndian.INT_SIZE ); + _value = LittleEndian.getByteArray( data, offset + + LittleEndian.INT_SIZE * 2, size - LittleEndian.INT_SIZE ); + } + + int getSize() + { + return LittleEndian.INT_SIZE * 2 + _value.length; + } +} diff --git a/src/java/org/apache/poi/hpsf/CodePageString.java b/src/java/org/apache/poi/hpsf/CodePageString.java new file mode 100644 index 0000000000..c0e9de92e7 --- /dev/null +++ b/src/java/org/apache/poi/hpsf/CodePageString.java @@ -0,0 +1,31 @@ +package org.apache.poi.hpsf; + +import org.apache.poi.util.LittleEndian; + +import org.apache.poi.util.Internal; + +@Internal +class CodePageString +{ + + byte[] _value; + + CodePageString( final byte[] data, final int startOffset ) + { + int offset = startOffset; + + int size = LittleEndian.getInt( data, offset ); + offset += LittleEndian.INT_SIZE; + + _value = LittleEndian.getByteArray( data, offset, size ); + if ( _value[size - 1] != 0 ) + throw new IllegalPropertySetDataException( + "CodePageString started at offset #" + offset + + " is not NULL-terminated" ); + } + + int getSize() + { + return LittleEndian.INT_SIZE + _value.length; + } +} diff --git a/src/java/org/apache/poi/hpsf/Currency.java b/src/java/org/apache/poi/hpsf/Currency.java new file mode 100644 index 0000000000..204cb91db8 --- /dev/null +++ b/src/java/org/apache/poi/hpsf/Currency.java @@ -0,0 +1,18 @@ +package org.apache.poi.hpsf; + +import org.apache.poi.util.LittleEndian; + +import org.apache.poi.util.Internal; + +@Internal +class Currency +{ + static final int SIZE = 8; + + private byte[] _value; + + Currency( byte[] data, int offset ) + { + _value = LittleEndian.getByteArray( data, offset, SIZE ); + } +} diff --git a/src/java/org/apache/poi/hpsf/Date.java b/src/java/org/apache/poi/hpsf/Date.java new file mode 100644 index 0000000000..ede62ee575 --- /dev/null +++ b/src/java/org/apache/poi/hpsf/Date.java @@ -0,0 +1,18 @@ +package org.apache.poi.hpsf; + +import org.apache.poi.util.LittleEndian; + +import org.apache.poi.util.Internal; + +@Internal +class Date +{ + static final int SIZE = 8; + + private byte[] _value; + + Date( byte[] data, int offset ) + { + _value = LittleEndian.getByteArray( data, offset, SIZE ); + } +} diff --git a/src/java/org/apache/poi/hpsf/Decimal.java b/src/java/org/apache/poi/hpsf/Decimal.java new file mode 100644 index 0000000000..7572945f80 --- /dev/null +++ b/src/java/org/apache/poi/hpsf/Decimal.java @@ -0,0 +1,37 @@ +package org.apache.poi.hpsf; + +import org.apache.poi.util.Internal; + +import org.apache.poi.util.LittleEndian; + +@Internal +class Decimal +{ + static final int SIZE = 16; + + private short field_1_wReserved; + private byte field_2_scale; + private byte field_3_sign; + private int field_4_hi32; + private long field_5_lo64; + + Decimal( final byte[] data, final int startOffset ) + { + int offset = startOffset; + + field_1_wReserved = LittleEndian.getShort( data, offset ); + offset += LittleEndian.SHORT_SIZE; + + field_2_scale = data[offset]; + offset += LittleEndian.BYTE_SIZE; + + field_3_sign = data[offset]; + offset += LittleEndian.BYTE_SIZE; + + field_4_hi32 = LittleEndian.getInt( data, offset ); + offset += LittleEndian.INT_SIZE; + + field_5_lo64 = LittleEndian.getLong( data, offset ); + offset += LittleEndian.LONG_SIZE; + } +} diff --git a/src/java/org/apache/poi/hpsf/Filetime.java b/src/java/org/apache/poi/hpsf/Filetime.java new file mode 100644 index 0000000000..99aa23bae2 --- /dev/null +++ b/src/java/org/apache/poi/hpsf/Filetime.java @@ -0,0 +1,17 @@ +package org.apache.poi.hpsf; + +import org.apache.poi.util.LittleEndian; + +class Filetime +{ + static final int SIZE = LittleEndian.LONG_SIZE * 2; + + private long _dwLowDateTime; + private long _dwHighDateTime; + + Filetime( byte[] data, int offset ) + { + _dwLowDateTime = LittleEndian.getLong( data, offset + 0 ); + _dwHighDateTime = LittleEndian.getLong( data, offset + 4 ); + } +} diff --git a/src/java/org/apache/poi/hpsf/GUID.java b/src/java/org/apache/poi/hpsf/GUID.java new file mode 100644 index 0000000000..050cb9327d --- /dev/null +++ b/src/java/org/apache/poi/hpsf/GUID.java @@ -0,0 +1,24 @@ +package org.apache.poi.hpsf; + +import org.apache.poi.util.Internal; + +import org.apache.poi.util.LittleEndian; + +@Internal +class GUID +{ + static final int SIZE = 16; + + private int _data1; + private short _data2; + private short _data3; + private long _data4; + + GUID( byte[] data, int offset ) + { + _data1 = LittleEndian.getInt( data, offset + 0 ); + _data2 = LittleEndian.getShort( data, offset + 4 ); + _data3 = LittleEndian.getShort( data, offset + 6 ); + _data4 = LittleEndian.getLong( data, offset + 8 ); + } +} diff --git a/src/java/org/apache/poi/hpsf/IndirectPropertyName.java b/src/java/org/apache/poi/hpsf/IndirectPropertyName.java new file mode 100644 index 0000000000..826136ccdd --- /dev/null +++ b/src/java/org/apache/poi/hpsf/IndirectPropertyName.java @@ -0,0 +1,19 @@ +package org.apache.poi.hpsf; + +import org.apache.poi.util.Internal; + +@Internal +class IndirectPropertyName +{ + private CodePageString _value; + + IndirectPropertyName( byte[] data, int offset ) + { + _value = new CodePageString( data, offset ); + } + + int getSize() + { + return _value.getSize(); + } +} diff --git a/src/java/org/apache/poi/hpsf/TypedPropertyValue.java b/src/java/org/apache/poi/hpsf/TypedPropertyValue.java new file mode 100644 index 0000000000..b421fcd484 --- /dev/null +++ b/src/java/org/apache/poi/hpsf/TypedPropertyValue.java @@ -0,0 +1,224 @@ +package org.apache.poi.hpsf; + +import org.apache.poi.util.LittleEndian; + +import org.apache.poi.util.Internal; + +@Internal +class TypedPropertyValue +{ + private int _type; + + private Object _value; + + TypedPropertyValue() + { + } + + TypedPropertyValue( byte[] data, int startOffset ) + { + read( data, startOffset ); + } + + TypedPropertyValue( int type, Object value ) + { + _type = type; + _value = value; + } + + int read( byte[] data, int startOffset ) + { + int offset = startOffset; + + _type = LittleEndian.getShort( data, offset ); + offset += LittleEndian.SHORT_SIZE; + + short padding = LittleEndian.getShort( data, offset ); + if ( padding != 0 ) + throw new IllegalPropertySetDataException( + "Property padding at offset " + offset + + " MUST be 0, but it's value is " + padding ); + offset += LittleEndian.SHORT_SIZE; + offset += readValuePadded( data, offset ); + + return offset - startOffset; + } + + int readValue( byte[] data, int offset ) + { + switch ( _type ) + { + case Variant.VT_EMPTY: + case Variant.VT_NULL: + _value = null; + return 0; + + case Variant.VT_I2: + _value = Short.valueOf( LittleEndian.getShort( data, offset ) ); + return 4; + + case Variant.VT_I4: + _value = Integer.valueOf( LittleEndian.getInt( data, offset ) ); + return 4; + + case Variant.VT_R4: + _value = Short.valueOf( LittleEndian.getShort( data, offset ) ); + return 4; + + case Variant.VT_R8: + _value = Double.valueOf( LittleEndian.getDouble( data, offset ) ); + return 8; + + case Variant.VT_CY: + _value = new Currency( data, offset ); + return Currency.SIZE; + + case Variant.VT_DATE: + _value = new Date( data, offset ); + return Date.SIZE; + + case Variant.VT_BSTR: + _value = new CodePageString( data, offset ); + return ( (CodePageString) _value ).getSize(); + + case Variant.VT_ERROR: + _value = Long.valueOf( LittleEndian.getUInt( data, offset ) ); + return 4; + + case Variant.VT_BOOL: + _value = new VariantBool( data, offset ); + return VariantBool.SIZE; + + case Variant.VT_DECIMAL: + _value = new Decimal( data, offset ); + return Decimal.SIZE; + + case Variant.VT_I1: + _value = Byte.valueOf( data[offset] ); + return 1; + + case Variant.VT_UI1: + _value = Short.valueOf( LittleEndian.getUByte( data, offset ) ); + return 2; + + case Variant.VT_UI2: + _value = Integer.valueOf( LittleEndian.getUShort( data, offset ) ); + return 4; + + case Variant.VT_UI4: + _value = Long.valueOf( LittleEndian.getUInt( data, offset ) ); + return 4; + + case Variant.VT_I8: + _value = Long.valueOf( LittleEndian.getLong( data, offset ) ); + return 8; + + case Variant.VT_UI8: + _value = LittleEndian.getByteArray( data, offset, 8 ); + return 8; + + case Variant.VT_INT: + _value = Integer.valueOf( LittleEndian.getInt( data, offset ) ); + return 4; + + case Variant.VT_UINT: + _value = Long.valueOf( LittleEndian.getUInt( data, offset ) ); + return 4; + + case Variant.VT_LPSTR: + _value = new CodePageString( data, offset ); + return ( (CodePageString) _value ).getSize(); + + case Variant.VT_LPWSTR: + _value = new UnicodeString( data, offset ); + return ( (UnicodeString) _value ).getSize(); + + case Variant.VT_FILETIME: + _value = new Filetime( data, offset ); + return Filetime.SIZE; + + case Variant.VT_BLOB: + _value = new Blob( data, offset ); + return ( (Blob) _value ).getSize(); + + case Variant.VT_STREAM: + case Variant.VT_STORAGE: + case Variant.VT_STREAMED_OBJECT: + case Variant.VT_STORED_OBJECT: + _value = new IndirectPropertyName( data, offset ); + return ( (IndirectPropertyName) _value ).getSize(); + + case Variant.VT_BLOB_OBJECT: + _value = new Blob( data, offset ); + return ( (Blob) _value ).getSize(); + + case Variant.VT_CF: + _value = new ClipboardData( data, offset ); + return ( (ClipboardData) _value ).getSize(); + + case Variant.VT_CLSID: + _value = new GUID( data, offset ); + return GUID.SIZE; + + case Variant.VT_VERSIONED_STREAM: + _value = new VersionedStream( data, offset ); + return ( (VersionedStream) _value ).getSize(); + + case Variant.VT_VECTOR | Variant.VT_I2: + case Variant.VT_VECTOR | Variant.VT_I4: + case Variant.VT_VECTOR | Variant.VT_R4: + case Variant.VT_VECTOR | Variant.VT_R8: + case Variant.VT_VECTOR | Variant.VT_CY: + case Variant.VT_VECTOR | Variant.VT_DATE: + case Variant.VT_VECTOR | Variant.VT_BSTR: + case Variant.VT_VECTOR | Variant.VT_ERROR: + case Variant.VT_VECTOR | Variant.VT_BOOL: + case Variant.VT_VECTOR | Variant.VT_VARIANT: + case Variant.VT_VECTOR | Variant.VT_I1: + case Variant.VT_VECTOR | Variant.VT_UI1: + case Variant.VT_VECTOR | Variant.VT_UI2: + case Variant.VT_VECTOR | Variant.VT_UI4: + case Variant.VT_VECTOR | Variant.VT_I8: + case Variant.VT_VECTOR | Variant.VT_UI8: + case Variant.VT_VECTOR | Variant.VT_LPSTR: + case Variant.VT_VECTOR | Variant.VT_LPWSTR: + case Variant.VT_VECTOR | Variant.VT_FILETIME: + case Variant.VT_VECTOR | Variant.VT_CF: + case Variant.VT_VECTOR | Variant.VT_CLSID: + _value = new Vector( (short) ( _type & 0x0FFF ) ); + return ( (Vector) _value ).read( data, offset ); + + case Variant.VT_ARRAY | Variant.VT_I2: + case Variant.VT_ARRAY | Variant.VT_I4: + case Variant.VT_ARRAY | Variant.VT_R4: + case Variant.VT_ARRAY | Variant.VT_R8: + case Variant.VT_ARRAY | Variant.VT_CY: + case Variant.VT_ARRAY | Variant.VT_DATE: + case Variant.VT_ARRAY | Variant.VT_BSTR: + case Variant.VT_ARRAY | Variant.VT_ERROR: + case Variant.VT_ARRAY | Variant.VT_BOOL: + case Variant.VT_ARRAY | Variant.VT_VARIANT: + case Variant.VT_ARRAY | Variant.VT_DECIMAL: + case Variant.VT_ARRAY | Variant.VT_I1: + case Variant.VT_ARRAY | Variant.VT_UI1: + case Variant.VT_ARRAY | Variant.VT_UI2: + case Variant.VT_ARRAY | Variant.VT_UI4: + case Variant.VT_ARRAY | Variant.VT_INT: + case Variant.VT_ARRAY | Variant.VT_UINT: + _value = new Array(); + return ( (Array) _value ).read( data, offset ); + + default: + throw new UnsupportedOperationException( + "Unknown (possibly, incorrect) TypedPropertyValue type: " + + _type ); + } + } + + int readValuePadded( byte[] data, int offset ) + { + int nonPadded = readValue( data, offset ); + return ( nonPadded & 0x03 ) == 0 ? nonPadded : nonPadded + + ( 4 - ( nonPadded & 0x03 ) ); + } +} diff --git a/src/java/org/apache/poi/hpsf/UnicodeString.java b/src/java/org/apache/poi/hpsf/UnicodeString.java new file mode 100644 index 0000000000..b2595d87d5 --- /dev/null +++ b/src/java/org/apache/poi/hpsf/UnicodeString.java @@ -0,0 +1,35 @@ +package org.apache.poi.hpsf; + +import org.apache.poi.util.Internal; +import org.apache.poi.util.LittleEndian; + +@Internal +class UnicodeString +{ + private byte[] _value; + + UnicodeString( byte[] data, int offset ) + { + int length = LittleEndian.getInt( data, offset ); + + if ( length == 0 ) + { + _value = new byte[0]; + return; + } + + _value = new byte[length * 2]; + LittleEndian.getByteArray( data, offset + LittleEndian.INT_SIZE, + length * 2 ); + + if ( _value[length * 2 - 1] != 0 || _value[length * 2 - 2] != 0 ) + throw new IllegalPropertySetDataException( + "UnicodeString started at offset #" + offset + + " is not NULL-terminated" ); + } + + int getSize() + { + return LittleEndian.INT_SIZE + _value.length; + } +} diff --git a/src/java/org/apache/poi/hpsf/Variant.java b/src/java/org/apache/poi/hpsf/Variant.java index a37cbf0479..8330a6d5a9 100644 --- a/src/java/org/apache/poi/hpsf/Variant.java +++ b/src/java/org/apache/poi/hpsf/Variant.java @@ -298,6 +298,14 @@ public class Variant */ public static final int VT_CLSID = 72; + /** + * "MUST be a VersionedStream. The storage representing the (non-simple) + * property set MUST have a stream element with the name in the StreamName + * field." -- [MS-OLEPS] -- v20110920; Object Linking and Embedding (OLE) + * Property Set Data Structures; page 24 / 63 + */ + public static final int VT_VERSIONED_STREAM = 0x0049; + /** *

[P] simple counted array. How long is this? How is it to be diff --git a/src/java/org/apache/poi/hpsf/VariantBool.java b/src/java/org/apache/poi/hpsf/VariantBool.java new file mode 100644 index 0000000000..4342cdfddd --- /dev/null +++ b/src/java/org/apache/poi/hpsf/VariantBool.java @@ -0,0 +1,32 @@ +package org.apache.poi.hpsf; + +import org.apache.poi.util.LittleEndian; + +import org.apache.poi.util.Internal; + +@Internal +class VariantBool +{ + static final int SIZE = 2; + + private boolean _value; + + VariantBool( byte[] data, int offset ) + { + short value = LittleEndian.getShort( data, offset ); + if ( value == 0x0000 ) + { + _value = false; + return; + } + + if ( value == 0xffff ) + { + _value = true; + return; + } + + throw new IllegalPropertySetDataException( "VARIANT_BOOL value '" + + value + "' is incorrect" ); + } +} diff --git a/src/java/org/apache/poi/hpsf/VariantVector.java b/src/java/org/apache/poi/hpsf/VariantVector.java new file mode 100644 index 0000000000..7335c9712a --- /dev/null +++ b/src/java/org/apache/poi/hpsf/VariantVector.java @@ -0,0 +1,43 @@ +package org.apache.poi.hpsf; + +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.poi.util.LittleEndian; + +/** + * Holder for vector-type properties + * + * @author Sergey Vladimirov (vlsergey {at} gmail {dot} com) + */ +public class VariantVector +{ + + private final List values; + + public VariantVector( int codepage, long id, long type, byte[] data, int startOffset ) + throws UnsupportedEncodingException, ReadingNotSupportedException + { + if ( ( type & 0x1000 ) != 0x1000 ) + throw new IllegalArgumentException( "Specified type is not vector" ); + final long elementType = type ^ 0x1000; + + int offset = startOffset; + + final long longLength = LittleEndian.getUInt( data, offset ); + offset += LittleEndian.INT_SIZE; + + if ( longLength > Integer.MAX_VALUE ) + throw new UnsupportedOperationException( "Vector is too long -- " + + longLength ); + final int length = (int) longLength; + + this.values = new ArrayList(); + for ( int i = 0; i < length; i++ ) + { + Property property = new Property( id, elementType, null ); + VariantSupport.read( data, offset, length, elementType, codepage ); + } + } +} diff --git a/src/java/org/apache/poi/hpsf/Vector.java b/src/java/org/apache/poi/hpsf/Vector.java new file mode 100644 index 0000000000..07c3456873 --- /dev/null +++ b/src/java/org/apache/poi/hpsf/Vector.java @@ -0,0 +1,64 @@ +package org.apache.poi.hpsf; + +import org.apache.poi.util.Internal; +import org.apache.poi.util.LittleEndian; + +/** + * Holder for vector-type properties + * + * @author Sergey Vladimirov (vlsergey {at} gmail {dot} com) + */ +@Internal +class Vector +{ + private final short _type; + + private TypedPropertyValue[] _values; + + Vector( short type ) + { + this._type = type; + } + + Vector( byte[] data, int startOffset, short type ) + { + this._type = type; + read( data, startOffset ); + } + + int read( byte[] data, int startOffset ) + { + int offset = startOffset; + + final long longLength = LittleEndian.getUInt( data, offset ); + offset += LittleEndian.INT_SIZE; + + if ( longLength > Integer.MAX_VALUE ) + throw new UnsupportedOperationException( "Vector is too long -- " + + longLength ); + final int length = (int) longLength; + + _values = new TypedPropertyValue[length]; + + if ( _type == Variant.VT_VARIANT ) + { + for ( int i = 0; i < length; i++ ) + { + TypedPropertyValue value = new TypedPropertyValue(); + offset += value.read( data, offset ); + _values[i] = value; + } + } + else + { + for ( int i = 0; i < length; i++ ) + { + TypedPropertyValue value = new TypedPropertyValue( _type, null ); + offset += value.readValuePadded( data, offset ); + _values[i] = value; + } + } + return offset - startOffset; + } + +} diff --git a/src/java/org/apache/poi/hpsf/VersionedStream.java b/src/java/org/apache/poi/hpsf/VersionedStream.java new file mode 100644 index 0000000000..89a269ea7a --- /dev/null +++ b/src/java/org/apache/poi/hpsf/VersionedStream.java @@ -0,0 +1,21 @@ +package org.apache.poi.hpsf; + +import org.apache.poi.util.Internal; + +@Internal +class VersionedStream +{ + private GUID _versionGuid; + private IndirectPropertyName _streamName; + + VersionedStream( byte[] data, int offset ) + { + _versionGuid = new GUID( data, offset ); + _streamName = new IndirectPropertyName( data, offset + GUID.SIZE ); + } + + int getSize() + { + return GUID.SIZE + _streamName.getSize(); + } +} -- 2.39.5