FileDocCategorySizeDatePackage
PropertySet.javaAPI DocApache Poi 3.0.123357Mon Jan 01 12:39:34 GMT 2007org.apache.poi.hpsf

PropertySet

public class PropertySet extends Object

Represents a property set in the Horrible Property Set Format (HPSF). These are usually metadata of a Microsoft Office document.

An application that wants to access these metadata should create an instance of this class or one of its subclasses by calling the factory method {@link PropertySetFactory#create} and then retrieve the information its needs by calling appropriate methods.

{@link PropertySetFactory#create} does its work by calling one of the constructors {@link PropertySet#PropertySet(InputStream)} or {@link PropertySet#PropertySet(byte[])}. If the constructor's argument is not in the Horrible Property Set Format, i.e. not a property set stream, or if any other error occurs, an appropriate exception is thrown.

A {@link PropertySet} has a list of {@link Section}s, and each {@link Section} has a {@link Property} array. Use {@link #getSections} to retrieve the {@link Section}s, then call {@link Section#getProperties} for each {@link Section} to get hold of the {@link Property} arrays.

Since the vast majority of {@link PropertySet}s contains only a single {@link Section}, the convenience method {@link #getProperties} returns the properties of a {@link PropertySet}'s {@link Section} (throwing a {@link NoSingleSectionException} if the {@link PropertySet} contains more (or less) than exactly one {@link Section}).

author
Rainer Klute <klute@rainer-klute.de>
author
Drew Varner (Drew.Varner hanginIn sc.edu)
version
$Id: PropertySet.java 489730 2006-12-22 19:18:16Z bayard $
since
2002-02-09

Fields Summary
static final byte[]
BYTE_ORDER_ASSERTION

The "byteOrder" field must equal this value.

protected int
byteOrder

Specifies this {@link PropertySet}'s byte order. See the HPFS documentation for details!

static final byte[]
FORMAT_ASSERTION

The "format" field must equal this value.

protected int
format

Specifies this {@link PropertySet}'s format. See the HPFS documentation for details!

protected int
osVersion

Specifies the version of the operating system that created this {@link PropertySet}. See the HPFS documentation for details!

public static final int
OS_WIN16

If the OS version field holds this value the property set stream was created on a 16-bit Windows system.

public static final int
OS_MACINTOSH

If the OS version field holds this value the property set stream was created on a Macintosh system.

public static final int
OS_WIN32

If the OS version field holds this value the property set stream was created on a 32-bit Windows system.

protected ClassID
classID

Specifies this {@link PropertySet}'s "classID" field. See the HPFS documentation for details!

protected List
sections

The sections in this {@link PropertySet}.

Constructors Summary
public PropertySet(byte[] stream)

Creates a {@link PropertySet} instance from a byte array that represents a stream in the Horrible Property Set Format.

param
stream The byte array holding the stream data. The complete byte array contents is the stream data.
throws
NoPropertySetStreamException if the byte array is not a property set stream.
exception
UnsupportedEncodingException if the codepage is not supported.

        this(stream, 0, stream.length);
    
protected PropertySet()

Creates an empty (uninitialized) {@link PropertySet}.

Please note: For the time being this constructor is protected since it is used for internal purposes only, but expect it to become public once the property set's writing functionality is implemented.

 
public PropertySet(InputStream stream)

Creates a {@link PropertySet} instance from an {@link InputStream} in the Horrible Property Set Format.

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 not 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.

        if (isPropertySetStream(stream))
        {
            final int avail = stream.available();
            final byte[] buffer = new byte[avail];
            stream.read(buffer, 0, buffer.length);
            init(buffer, 0, buffer.length);
        }
        else
            throw new NoPropertySetStreamException();
    
public PropertySet(byte[] stream, int offset, int length)

Creates a {@link PropertySet} instance from a byte array that represents a stream in the Horrible Property Set Format.

param
stream The byte array holding the stream data.
param
offset The offset in stream where the stream data begin. If the stream data begin with the first byte in the array, the offset is 0.
param
length The length of the stream data.
throws
NoPropertySetStreamException if the byte array is not a property set stream.
exception
UnsupportedEncodingException if the codepage is not supported.

        if (isPropertySetStream(stream, offset, length))
            init(stream, offset, length);
        else
            throw new NoPropertySetStreamException();
    
Methods Summary
public booleanequals(java.lang.Object o)

Returns true if the PropertySet is equal to the specified parameter, else false.

param
o the object to compare this PropertySet with
return
true if the objects are equal, false if not

        if (o == null || !(o instanceof PropertySet))
            return false;
        final PropertySet ps = (PropertySet) o;
        int byteOrder1 = ps.getByteOrder();
        int byteOrder2 = getByteOrder();
        ClassID classID1 = ps.getClassID();
        ClassID classID2 = getClassID();
        int format1 = ps.getFormat();
        int format2 = getFormat();
        int osVersion1 = ps.getOSVersion();
        int osVersion2 = getOSVersion();
        int sectionCount1 = ps.getSectionCount();
        int sectionCount2 = getSectionCount();
        if (byteOrder1 != byteOrder2      ||
            !classID1.equals(classID2)    ||
            format1 != format2            ||
            osVersion1 != osVersion2      ||
            sectionCount1 != sectionCount2)
            return false;

        /* Compare the sections: */
        return Util.equals(getSections(), ps.getSections());
    
public intgetByteOrder()

Returns the property set stream's low-level "byte order" field. It is always 0xFFFE .

return
The property set stream's low-level "byte order" field.


                                
      
    
        return byteOrder;
    
public org.apache.poi.hpsf.ClassIDgetClassID()

Returns the property set stream's low-level "class ID" field.

return
The property set stream's low-level "class ID" field.

        return classID;
    
public org.apache.poi.hpsf.SectiongetFirstSection()

Gets the {@link PropertySet}'s first section.

return
The {@link PropertySet}'s first section.

        if (getSectionCount() < 1)
            throw new MissingSectionException("Property set does not contain any sections.");
        return ((Section) sections.get(0));
    
public intgetFormat()

Returns the property set stream's low-level "format" field. It is always 0x0000 .

return
The property set stream's low-level "format" field.


                              
      
    
        return format;
    
public intgetOSVersion()

Returns the property set stream's low-level "OS version" field.

return
The property set stream's low-level "OS version" field.


                           
      
    
        return osVersion;
    
public org.apache.poi.hpsf.Property[]getProperties()

Convenience method returning the {@link Property} array contained in this property set. It is a shortcut for getting the {@link PropertySet}'s {@link Section}s list and then getting the {@link Property} array from the first {@link Section}.

return
The properties of the only {@link Section} of this {@link PropertySet}.
throws
NoSingleSectionException if the {@link PropertySet} has more or less than one {@link Section}.

        return getFirstSection().getProperties();
    
protected java.lang.ObjectgetProperty(int id)

Convenience method returning the value of the property with the specified ID. If the property is not available, null is returned and a subsequent call to {@link #wasNull} will return true .

param
id The property ID
return
The property value
throws
NoSingleSectionException if the {@link PropertySet} has more or less than one {@link Section}.

        return getFirstSection().getProperty(id);
    
protected booleangetPropertyBooleanValue(int id)

Convenience method returning the value of a boolean property with the specified ID. If the property is not available, false is returned. A subsequent call to {@link #wasNull} will return true to let the caller distinguish that case from a real property value of false.

param
id The property ID
return
The property value
throws
NoSingleSectionException if the {@link PropertySet} has more or less than one {@link Section}.

        return getFirstSection().getPropertyBooleanValue(id);
    
protected intgetPropertyIntValue(int id)

Convenience method returning the value of the numeric property with the specified ID. If the property is not available, 0 is returned. A subsequent call to {@link #wasNull} will return true to let the caller distinguish that case from a real property value of 0.

param
id The property ID
return
The propertyIntValue value
throws
NoSingleSectionException if the {@link PropertySet} has more or less than one {@link Section}.

        return getFirstSection().getPropertyIntValue(id);
    
public intgetSectionCount()

Returns the number of {@link Section}s in the property set.

return
The number of {@link Section}s in the property set.

        return sections.size();
    
public java.util.ListgetSections()

Returns the {@link Section}s in the property set.

return
The {@link Section}s in the property set.

        return sections;
    
public org.apache.poi.hpsf.SectiongetSingleSection()

If the {@link PropertySet} has only a single section this method returns it.

return
The singleSection value

        final int sectionCount = getSectionCount();
        if (sectionCount != 1)
            throw new NoSingleSectionException
                ("Property set contains " + sectionCount + " sections.");
        return ((Section) sections.get(0));
    
public inthashCode()

see
Object#hashCode()

        throw new UnsupportedOperationException("FIXME: Not yet implemented.");
    
private voidinit(byte[] src, int offset, int length)

Initializes this {@link PropertySet} instance from a byte array. The method assumes that it has been checked already that the byte array indeed represents a property set stream. It does no more checks on its own.

param
src Byte array containing the property set stream
param
offset The property set stream starts at this offset from the beginning of src
param
length Length of the property set stream.
throws
UnsupportedEncodingException if HPSF does not (yet) support the property set's character encoding.

        /* FIXME (3): Ensure that at most "length" bytes are read. */
        
        /*
         * Read the stream's header fields.
         */
        int o = offset;
        byteOrder = LittleEndian.getUShort(src, o);
        o += LittleEndian.SHORT_SIZE;
        format = LittleEndian.getUShort(src, o);
        o += LittleEndian.SHORT_SIZE;
        osVersion = (int) LittleEndian.getUInt(src, o);
        o += LittleEndian.INT_SIZE;
        classID = new ClassID(src, o);
        o += ClassID.LENGTH;
        final int sectionCount = LittleEndian.getInt(src, o);
        o += LittleEndian.INT_SIZE;
        if (sectionCount <= 0)
            throw new HPSFRuntimeException("Section count " + sectionCount +
                                           " must be greater than 0.");

        /*
         * Read the sections, which are following the header. They
         * start with an array of section descriptions. Each one
         * consists of a format ID telling what the section contains
         * and an offset telling how many bytes from the start of the
         * stream the section begins.
         */
        /*
         * Most property sets have only one section. The Document
         * Summary Information stream has 2. Everything else is a rare
         * exception and is no longer fostered by Microsoft.
         */
        sections = new ArrayList(sectionCount);

        /*
         * Loop over the section descriptor array. Each descriptor
         * consists of a ClassID and a DWord, and we have to increment
         * "offset" accordingly.
         */
        for (int i = 0; i < sectionCount; i++)
        {
            final Section s = new Section(src, o);
            o += ClassID.LENGTH + LittleEndian.INT_SIZE;
            sections.add(s);
        }
    
public booleanisDocumentSummaryInformation()

Checks whether this {@link PropertySet} is a Document Summary Information.

return
true if this {@link PropertySet} represents a Document Summary Information, else false.

        return Util.equal(((Section) sections.get(0)).getFormatID().getBytes(),
                          SectionIDMap.DOCUMENT_SUMMARY_INFORMATION_ID[0]);
    
public static booleanisPropertySetStream(java.io.InputStream stream)

Checks whether an {@link InputStream} is in the Horrible Property Set Format.

param
stream The {@link InputStream} to check. In order to perform the check, the method reads the first bytes from the stream. After reading, the stream is reset to the position it had before reading. The {@link InputStream} must support the {@link InputStream#mark} method.
return
true if the stream is a property set stream, else false.
throws
MarkUnsupportedException if the {@link InputStream} does not support the {@link InputStream#mark} method.
exception
IOException if an I/O error occurs

        /*
         * Read at most this many bytes.
         */
        final int BUFFER_SIZE = 50;

        /*
         * Mark the current position in the stream so that we can
         * reset to this position if the stream does not contain a
         * property set.
         */
        if (!stream.markSupported())
            throw new MarkUnsupportedException(stream.getClass().getName());
        stream.mark(BUFFER_SIZE);

        /*
         * Read a couple of bytes from the stream.
         */
        final byte[] buffer = new byte[BUFFER_SIZE];
        final int bytes =
            stream.read(buffer, 0,
                        Math.min(buffer.length, stream.available()));
        final boolean isPropertySetStream =
            isPropertySetStream(buffer, 0, bytes);
        stream.reset();
        return isPropertySetStream;
    
public static booleanisPropertySetStream(byte[] src, int offset, int length)

Checks whether a byte array is in the Horrible Property Set Format.

param
src The byte array to check.
param
offset The offset in the byte array.
param
length The significant number of bytes in the byte array. Only this number of bytes will be checked.
return
true if the byte array is a property set stream, false if not.

        /* FIXME (3): Ensure that at most "length" bytes are read. */

        /*
         * Read the header fields of the stream. They must always be
         * there.
         */
        int o = offset;
        final int byteOrder = LittleEndian.getUShort(src, o);
        o += LittleEndian.SHORT_SIZE;
        byte[] temp = new byte[LittleEndian.SHORT_SIZE];
        LittleEndian.putShort(temp, (short) byteOrder);
        if (!Util.equal(temp, BYTE_ORDER_ASSERTION))
            return false;
        final int format = LittleEndian.getUShort(src, o);
        o += LittleEndian.SHORT_SIZE;
        temp = new byte[LittleEndian.SHORT_SIZE];
        LittleEndian.putShort(temp, (short) format);
        if (!Util.equal(temp, FORMAT_ASSERTION))
            return false;
        // final long osVersion = LittleEndian.getUInt(src, offset);
        o += LittleEndian.INT_SIZE;
        // final ClassID classID = new ClassID(src, offset);
        o += ClassID.LENGTH;
        final long sectionCount = LittleEndian.getUInt(src, o);
        o += LittleEndian.INT_SIZE;
        if (sectionCount < 1)
            return false;
        return true;
    
public booleanisSummaryInformation()

Checks whether this {@link PropertySet} represents a Summary Information.

return
true if this {@link PropertySet} represents a Summary Information, else false.

        return Util.equal(((Section) sections.get(0)).getFormatID().getBytes(),
                          SectionIDMap.SUMMARY_INFORMATION_ID);
    
public java.lang.StringtoString()

see
Object#toString()

        final StringBuffer b = new StringBuffer();
        final int sectionCount = getSectionCount();
        b.append(getClass().getName());
        b.append('[");
        b.append("byteOrder: ");
        b.append(getByteOrder());
        b.append(", classID: ");
        b.append(getClassID());
        b.append(", format: ");
        b.append(getFormat());
        b.append(", OSVersion: ");
        b.append(getOSVersion());
        b.append(", sectionCount: ");
        b.append(sectionCount);
        b.append(", sections: [\n");
        final List sections = getSections();
        for (int i = 0; i < sectionCount; i++)
            b.append(((Section) sections.get(i)).toString());
        b.append(']");
        b.append(']");
        return b.toString();
    
public booleanwasNull()

Checks whether the property which the last call to {@link #getPropertyIntValue} or {@link #getProperty} tried to access was available or not. This information might be important for callers of {@link #getPropertyIntValue} since the latter returns 0 if the property does not exist. Using {@link #wasNull}, the caller can distiguish this case from a property's real value of 0.

return
true if the last call to {@link #getPropertyIntValue} or {@link #getProperty} tried to access a property that was not available, else false.
throws
NoSingleSectionException if the {@link PropertySet} has more than one {@link Section}.

        return getFirstSection().wasNull();