Browse Source

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
tags/REL_3_8_BETA5
Sergey Vladimirov 12 years ago
parent
commit
0df5442322

+ 121
- 0
src/java/org/apache/poi/hpsf/Array.java View File

@@ -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;
}
}

+ 30
- 0
src/java/org/apache/poi/hpsf/Blob.java View File

@@ -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;
}
}

+ 27
- 0
src/java/org/apache/poi/hpsf/ClipboardData.java View File

@@ -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;
}
}

+ 31
- 0
src/java/org/apache/poi/hpsf/CodePageString.java View File

@@ -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;
}
}

+ 18
- 0
src/java/org/apache/poi/hpsf/Currency.java View File

@@ -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 );
}
}

+ 18
- 0
src/java/org/apache/poi/hpsf/Date.java View File

@@ -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 );
}
}

+ 37
- 0
src/java/org/apache/poi/hpsf/Decimal.java View File

@@ -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;
}
}

+ 17
- 0
src/java/org/apache/poi/hpsf/Filetime.java View File

@@ -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 );
}
}

+ 24
- 0
src/java/org/apache/poi/hpsf/GUID.java View File

@@ -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 );
}
}

+ 19
- 0
src/java/org/apache/poi/hpsf/IndirectPropertyName.java View File

@@ -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();
}
}

+ 224
- 0
src/java/org/apache/poi/hpsf/TypedPropertyValue.java View File

@@ -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 ) );
}
}

+ 35
- 0
src/java/org/apache/poi/hpsf/UnicodeString.java View File

@@ -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;
}
}

+ 8
- 0
src/java/org/apache/poi/hpsf/Variant.java View 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

+ 32
- 0
src/java/org/apache/poi/hpsf/VariantBool.java View File

@@ -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" );
}
}

+ 43
- 0
src/java/org/apache/poi/hpsf/VariantVector.java View File

@@ -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 );
}
}
}

+ 64
- 0
src/java/org/apache/poi/hpsf/Vector.java View File

@@ -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;
}

}

+ 21
- 0
src/java/org/apache/poi/hpsf/VersionedStream.java View File

@@ -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();
}
}

Loading…
Cancel
Save