]> source.dussan.org Git - poi.git/commitdiff
add classes that will replace VariantSupport class just a bit later
authorSergey Vladimirov <sergey@apache.org>
Fri, 21 Oct 2011 23:45:01 +0000 (23:45 +0000)
committerSergey Vladimirov <sergey@apache.org>
Fri, 21 Oct 2011 23:45:01 +0000 (23:45 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1187595 13f79535-47bb-0310-9956-ffa450edef68

17 files changed:
src/java/org/apache/poi/hpsf/Array.java [new file with mode: 0644]
src/java/org/apache/poi/hpsf/Blob.java [new file with mode: 0644]
src/java/org/apache/poi/hpsf/ClipboardData.java [new file with mode: 0644]
src/java/org/apache/poi/hpsf/CodePageString.java [new file with mode: 0644]
src/java/org/apache/poi/hpsf/Currency.java [new file with mode: 0644]
src/java/org/apache/poi/hpsf/Date.java [new file with mode: 0644]
src/java/org/apache/poi/hpsf/Decimal.java [new file with mode: 0644]
src/java/org/apache/poi/hpsf/Filetime.java [new file with mode: 0644]
src/java/org/apache/poi/hpsf/GUID.java [new file with mode: 0644]
src/java/org/apache/poi/hpsf/IndirectPropertyName.java [new file with mode: 0644]
src/java/org/apache/poi/hpsf/TypedPropertyValue.java [new file with mode: 0644]
src/java/org/apache/poi/hpsf/UnicodeString.java [new file with mode: 0644]
src/java/org/apache/poi/hpsf/Variant.java
src/java/org/apache/poi/hpsf/VariantBool.java [new file with mode: 0644]
src/java/org/apache/poi/hpsf/VariantVector.java [new file with mode: 0644]
src/java/org/apache/poi/hpsf/Vector.java [new file with mode: 0644]
src/java/org/apache/poi/hpsf/VersionedStream.java [new file with mode: 0644]

diff --git a/src/java/org/apache/poi/hpsf/Array.java b/src/java/org/apache/poi/hpsf/Array.java
new file mode 100644 (file)
index 0000000..cdb78f6
--- /dev/null
@@ -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 (file)
index 0000000..a3421c2
--- /dev/null
@@ -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 (file)
index 0000000..477a40b
--- /dev/null
@@ -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 (file)
index 0000000..c0e9de9
--- /dev/null
@@ -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 (file)
index 0000000..204cb91
--- /dev/null
@@ -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 (file)
index 0000000..ede62ee
--- /dev/null
@@ -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 (file)
index 0000000..7572945
--- /dev/null
@@ -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 (file)
index 0000000..99aa23b
--- /dev/null
@@ -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 (file)
index 0000000..050cb93
--- /dev/null
@@ -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 (file)
index 0000000..826136c
--- /dev/null
@@ -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 (file)
index 0000000..b421fcd
--- /dev/null
@@ -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 (file)
index 0000000..b2595d8
--- /dev/null
@@ -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;
+    }
+}
index a37cbf0479c8e150ec4cf1a8cf913d18bbe775bb..8330a6d5a9b0b5b9de95ef1b8b3cf11727b848f9 100644 (file)
@@ -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>[P] simple counted array. <span style="background-color:
      * #ffff00">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 (file)
index 0000000..4342cdf
--- /dev/null
@@ -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 (file)
index 0000000..7335c97
--- /dev/null
@@ -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<Property> 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<Property>();
+        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 (file)
index 0000000..07c3456
--- /dev/null
@@ -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 (file)
index 0000000..89a269e
--- /dev/null
@@ -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();
+    }
+}