You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@poi.apache.org by kl...@apache.org on 2003/08/30 11:13:53 UTC

cvs commit: jakarta-poi/src/java/org/apache/poi/hpsf/wellknown PropertyIDMap.java

klute       2003/08/30 02:13:53

  Modified:    src/java/org/apache/poi/hpsf ClassID.java
                        DocumentSummaryInformation.java HPSFException.java
                        HPSFRuntimeException.java
                        MarkUnsupportedException.java
                        NoPropertySetStreamException.java
                        NoSingleSectionException.java Property.java
                        PropertySet.java PropertySetFactory.java
                        ReadingNotSupportedException.java Section.java
                        SpecialPropertySet.java SummaryInformation.java
                        TypeWriter.java
                        UnexpectedPropertySetTypeException.java
                        UnsupportedVariantTypeException.java Util.java
                        Variant.java VariantSupport.java
                        WritingNotSupportedException.java
               src/java/org/apache/poi/hpsf/wellknown PropertyIDMap.java
  Added:       src/java/org/apache/poi/hpsf MutableProperty.java
                        MutablePropertySet.java MutableSection.java
  Log:
  HPSF writing capability added.
  
  Revision  Changes    Path
  1.8       +15 -4     jakarta-poi/src/java/org/apache/poi/hpsf/ClassID.java
  
  Index: ClassID.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/ClassID.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- ClassID.java	3 Aug 2003 20:16:46 -0000	1.7
  +++ ClassID.java	30 Aug 2003 09:13:52 -0000	1.8
  @@ -61,7 +61,8 @@
    *  order. Instead, it is a double word (4 bytes) followed by two
    *  words (2 bytes each) followed by 8 bytes.</p>
    *
  - * @author Rainer Klute (klute@rainer-klute.de)
  + * @author Rainer Klute <a
  + * href="mailto:klute@rainer-klute.de">&lt;klute@rainer-klute.de&gt;</a>
    * @version $Id$
    * @since 2002-02-09
    */
  @@ -120,7 +121,7 @@
       /**
        * <p>Gets the bytes making out the class ID. They are returned in
        * correct order, i.e. big-endian.</p>
  -     * 
  +     *
        * @return the bytes making out the class ID.
        */
       public byte[] getBytes()
  @@ -175,7 +176,7 @@
        *
        * @param offset The offset within the <var>dst</var> byte array.
        *
  -     * @exception ArrayStoreException if there is not enough room for the class 
  +     * @exception ArrayStoreException if there is not enough room for the class
        * ID 16 bytes in the byte array after the <var>offset</var> position.
        */
       public void write(final byte[] dst, final int offset)
  @@ -226,6 +227,16 @@
               if (bytes[i] != cid.bytes[i])
                   return false;
           return true;
  +    }
  +
  +
  +
  +    /**
  +     * @see Object#hashCode()
  +     */
  +    public int hashCode()
  +    {
  +        throw new UnsupportedOperationException("FIXME: Not yet implemented.");
       }
   
   }
  
  
  
  1.11      +4 -3      jakarta-poi/src/java/org/apache/poi/hpsf/DocumentSummaryInformation.java
  
  Index: DocumentSummaryInformation.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/DocumentSummaryInformation.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- DocumentSummaryInformation.java	2 Aug 2003 19:02:28 -0000	1.10
  +++ DocumentSummaryInformation.java	30 Aug 2003 09:13:52 -0000	1.11
  @@ -60,7 +60,8 @@
    * <p>Convenience class representing a DocumentSummary Information stream in a
    * Microsoft Office document.</p>
    *
  - * @author Rainer Klute (klute@rainer-klute.de)
  + * @author Rainer Klute <a
  + * href="mailto:klute@rainer-klute.de">&lt;klute@rainer-klute.de&gt;</a>
    * @author Drew Varner (Drew.Varner closeTo sc.edu)
    * @see SummaryInformation
    * @version $Id$
  @@ -289,7 +290,7 @@
        * <p>Returns <code>true</code> if the custom links are hampered
        * by excessive noise, for all applications.</p> <p>
        *
  -     * <strong>FIXME:</strong> Explain this some more! I (Rainer)
  +     * <strong>FIXME (3):</strong> Explain this some more! I (Rainer)
        * don't understand it.</p>
        *
        * @return The linksDirty value
  
  
  
  1.8       +3 -2      jakarta-poi/src/java/org/apache/poi/hpsf/HPSFException.java
  
  Index: HPSFException.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/HPSFException.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- HPSFException.java	2 Aug 2003 19:02:28 -0000	1.7
  +++ HPSFException.java	30 Aug 2003 09:13:52 -0000	1.8
  @@ -59,7 +59,8 @@
    * thrown in this package. It supports a nested "reason" throwable,
    * i.e. an exception that caused this one to be thrown.</p>
    *
  - * @author Rainer Klute (klute@rainer-klute.de)
  + * @author Rainer Klute <a
  + * href="mailto:klute@rainer-klute.de">&lt;klute@rainer-klute.de&gt;</a>
    * @version $Id$
    * @since 2002-02-09
    */
  
  
  
  1.8       +48 -2     jakarta-poi/src/java/org/apache/poi/hpsf/HPSFRuntimeException.java
  
  Index: HPSFRuntimeException.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/HPSFRuntimeException.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- HPSFRuntimeException.java	2 Aug 2003 19:02:28 -0000	1.7
  +++ HPSFRuntimeException.java	30 Aug 2003 09:13:52 -0000	1.8
  @@ -54,12 +54,16 @@
    */
   package org.apache.poi.hpsf;
   
  +import java.io.PrintStream;
  +import java.io.PrintWriter;
  +
   /**
    * <p>This exception is the superclass of all other unchecked
    * exceptions thrown in this package. It supports a nested "reason"
    * throwable, i.e. an exception that caused this one to be thrown.</p>
    *
  - * @author Rainer Klute (klute@rainer-klute.de)
  + * @author Rainer Klute <a
  + * href="mailto:klute@rainer-klute.de">&lt;klute@rainer-klute.de&gt;</a>
    * @version $Id$
    * @since 2002-02-09
    */
  @@ -136,6 +140,48 @@
       public Throwable getReason()
       {
           return reason;
  +    }
  +
  +
  +
  +    /**
  +     * @see Throwable#printStackTrace()
  +     */
  +    public void printStackTrace()
  +    {
  +        printStackTrace(System.err);
  +    }
  +
  +
  +
  +    /**
  +     * @see Throwable#printStackTrace(java.io.PrintStream)
  +     */
  +    public void printStackTrace(final PrintStream p)
  +    {
  +        final Throwable reason = getReason();
  +        super.printStackTrace(p);
  +        if (reason != null)
  +        {
  +            p.println("Caused by:");
  +            reason.printStackTrace(p);
  +        }
  +    }
  +
  +
  +
  +    /**
  +     * @see Throwable#printStackTrace(java.io.PrintWriter)
  +     */
  +    public void printStackTrace(final PrintWriter p)
  +    {
  +        final Throwable reason = getReason();
  +        super.printStackTrace(p);
  +        if (reason != null)
  +        {
  +            p.println("Caused by:");
  +            reason.printStackTrace(p);
  +        }
       }
   
   }
  
  
  
  1.8       +7 -6      jakarta-poi/src/java/org/apache/poi/hpsf/MarkUnsupportedException.java
  
  Index: MarkUnsupportedException.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/MarkUnsupportedException.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- MarkUnsupportedException.java	2 Aug 2003 19:02:28 -0000	1.7
  +++ MarkUnsupportedException.java	30 Aug 2003 09:13:52 -0000	1.8
  @@ -58,7 +58,8 @@
    * <p>This exception is thrown if an {@link java.io.InputStream} does
    * not support the {@link java.io.InputStream#mark} operation.</p>
    *
  - * @author Rainer Klute (klute@rainer-klute.de)
  + * @author Rainer Klute <a
  + * href="mailto:klute@rainer-klute.de">&lt;klute@rainer-klute.de&gt;</a>
    * @version $Id$
    * @since 2002-02-09
    */
  @@ -76,7 +77,7 @@
   
       /**
        * <p>Constructor</p>
  -     * 
  +     *
        * @param msg The exception's message string
        */
       public MarkUnsupportedException(final String msg)
  @@ -87,7 +88,7 @@
   
       /**
        * <p>Constructor</p>
  -     * 
  +     *
        * @param reason This exception's underlying reason
        */
       public MarkUnsupportedException(final Throwable reason)
  @@ -98,7 +99,7 @@
   
      /**
       * <p>Constructor</p>
  -    * 
  +    *
       * @param msg The exception's message string
       * @param reason This exception's underlying reason
       */
  @@ -107,4 +108,4 @@
           super(msg, reason);
       }
   
  -}
  \ No newline at end of file
  +}
  
  
  
  1.8       +12 -11    jakarta-poi/src/java/org/apache/poi/hpsf/NoPropertySetStreamException.java
  
  Index: NoPropertySetStreamException.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/NoPropertySetStreamException.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- NoPropertySetStreamException.java	2 Aug 2003 19:02:28 -0000	1.7
  +++ NoPropertySetStreamException.java	30 Aug 2003 09:13:52 -0000	1.8
  @@ -55,18 +55,16 @@
   package org.apache.poi.hpsf;
   
   /**
  - *  <p>
  + * <p>This exception is thrown if a format error in a property set stream is
  + * detected or when the input data do not constitute a property set stream.</p>
  + * 
  + * <p>The constructors of this class are analogous to those of its superclass
  + * and are documented there.</p>
    *
  - *  This exception is thrown if a format error in a property set stream is
  - *  detected or when the input data do not constitute a property set stream.</p>
  - *  <p>
  - *
  - *  The constructors of this class are analogous to those of its superclass and
  - *  documented there.</p>
  - *
  - *@author     Rainer Klute (klute@rainer-klute.de)
  - *@version    $Id$
  - *@since      2002-02-09
  + * @author Rainer Klute <a
  + * href="mailto:klute@rainer-klute.de">&lt;klute@rainer-klute.de&gt;</a>
  + * @version $Id$
  + * @since 2002-02-09
    */
   public class NoPropertySetStreamException extends HPSFException
   {
  @@ -80,6 +78,7 @@
       }
   
   
  +
       /**
        * <p>Constructor</p>
        * 
  @@ -91,6 +90,7 @@
       }
   
   
  +
       /**
        * <p>Constructor</p>
        * 
  @@ -100,6 +100,7 @@
       {
           super(reason);
       }
  +
   
   
       /**
  
  
  
  1.8       +3 -2      jakarta-poi/src/java/org/apache/poi/hpsf/NoSingleSectionException.java
  
  Index: NoSingleSectionException.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/NoSingleSectionException.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- NoSingleSectionException.java	2 Aug 2003 19:02:28 -0000	1.7
  +++ NoSingleSectionException.java	30 Aug 2003 09:13:52 -0000	1.8
  @@ -63,7 +63,8 @@
    * <p>The constructors of this class are analogous to those of its
    * superclass and documented there.</p>
    *
  - * @author Rainer Klute (klute@rainer-klute.de)
  + * @author Rainer Klute <a
  + * href="mailto:klute@rainer-klute.de">&lt;klute@rainer-klute.de&gt;</a>
    * @version $Id$
    * @since 2002-02-09
    */
  
  
  
  1.14      +75 -33    jakarta-poi/src/java/org/apache/poi/hpsf/Property.java
  
  Index: Property.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/Property.java,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- Property.java	23 Aug 2003 15:12:22 -0000	1.13
  +++ Property.java	30 Aug 2003 09:13:52 -0000	1.14
  @@ -63,8 +63,6 @@
   package org.apache.poi.hpsf;
   
   import java.util.HashMap;
  -import java.util.LinkedList;
  -import java.util.List;
   import java.util.Map;
   
   import org.apache.poi.util.LittleEndian;
  @@ -85,11 +83,13 @@
    * value, {@link Variant#VT_FILETIME} some date and time (of a
    * file).</p>
    *
  - * <p><strong>FIXME:</strong> Reading is not implemented for all
  - * {@link Variant} types yet. Feel free to submit error reports or
  - * patches for the types you need.</p>
  + * <p>Please note that not all {@link Variant} types yet. This might change
  + * over time but largely depends on your feedback so that the POI team knows
  + * which variant types are really needed. So please feel free to submit error
  + * reports or patches for the types you need.</p>
    *
  - * @author Rainer Klute (klute@rainer-klute.de)
  + * @author Rainer Klute <a
  + * href="mailto:klute@rainer-klute.de">&lt;klute@rainer-klute.de&gt;</a>
    * @author Drew Varner (Drew.Varner InAndAround sc.edu)
    * @see Section
    * @see Variant
  @@ -103,7 +103,7 @@
       private static final int CP_UNICODE = 1200;
   
       /** <p>The property's ID.</p> */
  -    protected int id;
  +    protected long id;
   
   
       /**
  @@ -111,7 +111,7 @@
        *
        * @return The ID value
        */
  -    public int getID()
  +    public long getID()
       {
           return id;
       }
  @@ -162,7 +162,7 @@
        * @param codepage The section's and thus the property's
        * codepage. It is needed only when reading string values.
        */
  -    public Property(final int id, final byte[] src, final long offset,
  +    public Property(final long id, final byte[] src, final long offset,
                       final int length, final int codepage)
       {
           this.id = id;
  @@ -187,7 +187,7 @@
           }
           catch (UnsupportedVariantTypeException ex)
           {
  -            logUnsupported(ex);
  +            VariantSupport.writeUnsupportedTypeMessage(ex);
               value = ex.getValue();
           }
       }
  @@ -281,15 +281,21 @@
        * 4.</p>
        *
        * @return the property's size in bytes
  +     * 
  +     * @exception WritingNotSupportedException if HPSF does not yet support the
  +     * property's variant type.
        */
  -    protected int getSize()
  +    protected int getSize() throws WritingNotSupportedException
       {
  -        int length = LittleEndian.INT_SIZE;
  +        int length = VariantSupport.getVariantLength(type);
  +        if (length >= 0)
  +            return length; /* Fixed length */
  +        if (length == -2)
  +            /* Unknown length */
  +            throw new WritingNotSupportedException(type, null);
  +
  +        /* Variable length: */
           final int PADDING = 4; /* Pad to multiples of 4. */
  -        if (type > Integer.MAX_VALUE)
  -            throw new HPSFRuntimeException
  -                ("Variant type " + type + " is greater than " +
  -                Integer.MAX_VALUE + ".");
           switch ((int) type)
           {
               case Variant.VT_LPSTR:
  @@ -304,9 +310,7 @@
               case Variant.VT_EMPTY:
                   break;
               default:
  -                throw new HPSFRuntimeException
  -                    ("Writing is not yet implemented for variant type " +
  -                     type + ". Please report this problem to the POI team!");
  +                throw new WritingNotSupportedException(type, value);
           }
           return length;
       }
  @@ -318,27 +322,65 @@
        */
       public boolean equals(final Object o)
       {
  -        throw new UnsupportedOperationException("FIXME: Not yet implemented.");
  +        if (!(o instanceof Property))
  +            return false;
  +        final Property p = (Property) o;
  +        final Object pValue = p.getValue();
  +        if (id != p.getID() || type != p.getType())
  +            return false;
  +        if (value == null && pValue == null)
  +            return true;
  +        if (value == null || pValue == null)
  +            return false;
  +        
  +        /* It's clear now that both values are non-null. */
  +        final Class valueClass = value.getClass();
  +        final Class pValueClass = pValue.getClass();
  +        if (!(valueClass.isAssignableFrom(pValueClass)) &&
  +            !(pValueClass.isAssignableFrom(valueClass)))
  +            return false;
  +
  +        if (value instanceof byte[])
  +            return Util.equal((byte[]) value, (byte[]) pValue);
  +
  +        return value.equals(pValue);
       }
   
   
   
       /**
  -     * <p>Keeps a list of those variant types for those an "unsupported" message
  -     * has already been issued.</p>
  +     * @see Object#hashCode()
        */
  -    protected static List unsupportedMessage;
  +    public int hashCode()
  +    {
  +        long hashCode = 0;
  +        hashCode += id;
  +        hashCode += type;
  +        if (value != null)
  +            hashCode += value.hashCode();
  +        final int returnHashCode = (int) (hashCode & 0x0ffffffffL );
  +        return returnHashCode;
  +
  +    }
   
  -    private static void logUnsupported(final UnsupportedVariantTypeException ex)
  +
  +
  +    /**
  +     * @see Object#toString()
  +     */
  +    public String toString()
       {
  -        if (unsupportedMessage == null)
  -            unsupportedMessage = new LinkedList();
  -        Long vt = new Long(ex.getVariantType());
  -        if (!unsupportedMessage.contains(vt))
  -        {
  -            System.err.println(ex.getMessage());
  -            unsupportedMessage.add(vt);
  -        }
  +        final StringBuffer b = new StringBuffer();
  +        b.append(getClass().getName());
  +        b.append('[');
  +        b.append("id: ");
  +        b.append(getID());
  +        b.append(", type: ");
  +        b.append(getType());
  +        b.append(", value: ");
  +        b.append(getValue());
  +        b.append(']');
  +        return b.toString();
       }
   
   }
  
  
  
  1.12      +47 -5     jakarta-poi/src/java/org/apache/poi/hpsf/PropertySet.java
  
  Index: PropertySet.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/PropertySet.java,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- PropertySet.java	3 Aug 2003 20:16:46 -0000	1.11
  +++ PropertySet.java	30 Aug 2003 09:13:52 -0000	1.12
  @@ -57,7 +57,6 @@
   import java.io.IOException;
   import java.io.InputStream;
   import java.util.ArrayList;
  -import java.util.LinkedList;
   import java.util.List;
   
   import org.apache.poi.hpsf.wellknown.SectionIDMap;
  @@ -91,7 +90,8 @@
    * NoSingleSectionException} if the {@link PropertySet} contains more
    * (or less) than exactly one {@link Section}).</p>
    *
  - * @author Rainer Klute (klute@rainer-klute.de)
  + * @author Rainer Klute <a
  + * href="mailto:klute@rainer-klute.de">&lt;klute@rainer-klute.de&gt;</a>
    * @author Drew Varner (Drew.Varner hanginIn sc.edu)
    * @version $Id$
    * @since 2002-02-09
  @@ -397,7 +397,7 @@
                                                 final int offset,
                                                 final int length)
       {
  -        /* FIXME: Ensure that at most "length" bytes are read. */
  +        /* FIXME (3): Ensure that at most "length" bytes are read. */
   
           /*
            * Read the header fields of the stream. They must always be
  @@ -442,7 +442,7 @@
        */
       private void init(final byte[] src, final int offset, final int length)
       {
  -        /* FIXME: Ensure that at most "length" bytes are read. */
  +        /* FIXME (3): Ensure that at most "length" bytes are read. */
           
           /*
            * Read the stream's header fields.
  @@ -645,6 +645,9 @@
        * to the specified parameter, else <code>false</code>.</p>
        *
        * @param o the object to compare this <code>PropertySet</code> with
  +     * 
  +     * @return <code>true</code> if the objects are equal, <code>false</code>
  +     * if not
        */
       public boolean equals(final Object o)
       {
  @@ -672,4 +675,43 @@
           return Util.equals(getSections(), ps.getSections());
       }
   
  +
  +
  +    /**
  +     * @see Object#hashCode()
  +     */
  +    public int hashCode()
  +    {
  +        throw new UnsupportedOperationException("FIXME: Not yet implemented.");
  +    }
  +
  +
  +
  +    /**
  +     * @see Object#toString()
  +     */
  +    public String 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: [");
  +        final List sections = getSections();
  +        for (int i = 0; i < sectionCount; i++)
  +            b.append(((Section) sections.get(0)).toString());
  +        b.append(']');
  +        b.append(']');
  +        return b.toString();
  +    }
   }
  
  
  
  1.8       +3 -2      jakarta-poi/src/java/org/apache/poi/hpsf/PropertySetFactory.java
  
  Index: PropertySetFactory.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/PropertySetFactory.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- PropertySetFactory.java	2 Aug 2003 19:02:28 -0000	1.7
  +++ PropertySetFactory.java	30 Aug 2003 09:13:52 -0000	1.8
  @@ -61,7 +61,8 @@
    * <p>Factory class to create instances of {@link SummaryInformation},
    * {@link DocumentSummaryInformation} and {@link PropertySet}.</p>
    *
  - * @author Rainer Klute (klute@rainer-klute.de)
  + * @author Rainer Klute <a
  + * href="mailto:klute@rainer-klute.de">&lt;klute@rainer-klute.de&gt;</a>
    * @version $Id$
    * @since 2002-02-09
    */
  
  
  
  1.3       +10 -6     jakarta-poi/src/java/org/apache/poi/hpsf/ReadingNotSupportedException.java
  
  Index: ReadingNotSupportedException.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/ReadingNotSupportedException.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ReadingNotSupportedException.java	25 Aug 2003 19:46:00 -0000	1.2
  +++ ReadingNotSupportedException.java	30 Aug 2003 09:13:52 -0000	1.3
  @@ -63,8 +63,11 @@
   package org.apache.poi.hpsf;
   
   /**
  - * <p>This exception is thrown when trying to read a (yet) unsupported variant
  - * type.</p>
  + * <p>This exception is thrown when HPSF tries to read a (yet) unsupported
  + * variant type.</p>
  + * 
  + * @see WritingNotSupportedException
  + * @see UnsupportedVariantTypeException
    *
    * @author Rainer Klute <a
    * href="mailto:klute@rainer-klute.de">&lt;klute@rainer-klute.de&gt;</a>
  @@ -78,10 +81,11 @@
       /**
        * <p>Constructor</p>
        * 
  -     * @param variantType
  -     * @param value
  +     * @param variantType The unsupported variant type.
  +     * @param value The value.
        */
  -    public ReadingNotSupportedException(long variantType, Object value)
  +    public ReadingNotSupportedException(final long variantType,
  +                                        final Object value)
       {
           super(variantType, value);
       }
  
  
  
  1.14      +50 -3     jakarta-poi/src/java/org/apache/poi/hpsf/Section.java
  
  Index: Section.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/Section.java,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- Section.java	23 Aug 2003 15:12:22 -0000	1.13
  +++ Section.java	30 Aug 2003 09:13:52 -0000	1.14
  @@ -67,7 +67,8 @@
   /**
    * <p>Represents a section in a {@link PropertySet}.</p>
    *
  - * @author Rainer Klute (klute@rainer-klute.de)
  + * @author Rainer Klute <a
  + * href="mailto:klute@rainer-klute.de">&lt;klute@rainer-klute.de&gt;</a>
    * @author Drew Varner (Drew.Varner allUpIn sc.edu)
    * @version $Id$
    * @since 2002-02-09
  @@ -493,7 +494,7 @@
       /**
        * <p>Checks whether this section is equal to another object.</p>
        * 
  -     * @param o The object to cpmpare this section with
  +     * @param o The object to compare this section with
        * @return <code>true</code> if the objects are equal, <code>false</code> if
        * not
        */
  @@ -507,6 +508,52 @@
           if (s.getPropertyCount() != getPropertyCount())
               return false;
           return Util.equals(s.getProperties(), getProperties());
  +    }
  +
  +
  +
  +    /**
  +     * @see Object#hashCode()
  +     */
  +    public int hashCode()
  +    {
  +        long hashCode = 0;
  +        hashCode += getFormatID().hashCode();
  +        final Property[] pa = getProperties();
  +        for (int i = 0; i < pa.length; i++)
  +            hashCode += pa[i].hashCode();
  +        final int returnHashCode = (int) (hashCode & 0x0ffffffffL);
  +        return returnHashCode;
  +    }
  +
  +
  +
  +    /**
  +     * @see Object#toString()
  +     */
  +    public String toString()
  +    {
  +        final StringBuffer b = new StringBuffer();
  +        final Property[] pa = getProperties();
  +        b.append(getClass().getName());
  +        b.append('[');
  +        b.append("formatID: ");
  +        b.append(getFormatID());
  +        b.append(", offset: ");
  +        b.append(getOffset());
  +        b.append(", propertyCount: ");
  +        b.append(getPropertyCount());
  +        b.append(", size: ");
  +        b.append(getSize());
  +        b.append(", properties: [\n");
  +        for (int i = 0; i < pa.length; i++)
  +        {
  +            b.append(pa[i].toString());
  +            b.append(",\n");
  +        }
  +        b.append(']');
  +        b.append(']');
  +        return b.toString();
       }
   
   }
  
  
  
  1.10      +3 -2      jakarta-poi/src/java/org/apache/poi/hpsf/SpecialPropertySet.java
  
  Index: SpecialPropertySet.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/SpecialPropertySet.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- SpecialPropertySet.java	2 Aug 2003 19:02:28 -0000	1.9
  +++ SpecialPropertySet.java	30 Aug 2003 09:13:52 -0000	1.10
  @@ -82,7 +82,8 @@
    * went the other way round historically: the convenience classes came
    * only late to my mind.</p>
    *
  - * @author Rainer Klute (klute@rainer-klute.de)
  + * @author Rainer Klute <a
  + * href="mailto:klute@rainer-klute.de">&lt;klute@rainer-klute.de&gt;</a>
    * @version $Id$
    * @since 2002-02-09
    */
  
  
  
  1.12      +4 -3      jakarta-poi/src/java/org/apache/poi/hpsf/SummaryInformation.java
  
  Index: SummaryInformation.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/SummaryInformation.java,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- SummaryInformation.java	2 Aug 2003 19:02:28 -0000	1.11
  +++ SummaryInformation.java	30 Aug 2003 09:13:52 -0000	1.12
  @@ -69,7 +69,8 @@
    * href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/stgu_8910.asp">http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/stgu_8910.asp</a>
    * for documentation from That Redmond Company.</p>
    *
  - * @author Rainer Klute (klute@rainer-klute.de)
  + * @author Rainer Klute <a
  + * href="mailto:klute@rainer-klute.de">&lt;klute@rainer-klute.de&gt;</a>
    * @see DocumentSummaryInformation
    * @version $Id$
    * @since 2002-02-09
  @@ -297,7 +298,7 @@
        * <strong>when this method is implemented. Please note that the
        * return type is likely to change!</strong></p>
        *
  -     * <p><strong>FIXME / Hint to developers:</strong> Drew Varner
  +     * <p><strong>FIXME (3) / Hint to developers:</strong> Drew Varner
        * &lt;Drew.Varner -at- sc.edu&gt; said that this is an image in
        * WMF or Clipboard (BMP?) format. He also provided two links that
        * might be helpful: <a
  
  
  
  1.2       +7 -6      jakarta-poi/src/java/org/apache/poi/hpsf/TypeWriter.java
  
  Index: TypeWriter.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/TypeWriter.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- TypeWriter.java	23 Aug 2003 15:12:22 -0000	1.1
  +++ TypeWriter.java	30 Aug 2003 09:13:52 -0000	1.2
  @@ -66,12 +66,12 @@
   import java.io.OutputStream;
   
   import org.apache.poi.util.LittleEndian;
  -import org.apache.poi.util.LittleEndianConsts;
   
   /**
    * <p>Class for writing little-endian data and more.</p>
    *
  - * @author Rainer Klute (klute@rainer-klute.de)
  + * @author Rainer Klute <a
  + * href="mailto:klute@rainer-klute.de">&lt;klute@rainer-klute.de&gt;</a>
    * @version $Id$
    * @since 2003-02-20
    */
  @@ -81,8 +81,9 @@
       /**
        * <p>Writes a two-byte value (short) to an output stream.</p>
        *
  -     * @param out The stream to write to
  -     * @param n The value to write
  +     * @param out The stream to write to.
  +     * @param n The value to write.
  +     * @return The number of bytes that have been written.
        * @exception IOException if an I/O error occurs
        */
       public static int writeToStream(final OutputStream out, final short n)
  @@ -149,7 +150,7 @@
           throws IOException
       {
           long high = n & 0xFFFFFFFF00000000L;
  -        if (high != 0)
  +        if (high != 0 && high != 0xFFFFFFFF00000000L)
               throw new IllegalPropertySetDataException
                   ("Value " + n + " cannot be represented by 4 bytes.");
           return writeToStream(out, (int) n);
  
  
  
  1.8       +3 -2      jakarta-poi/src/java/org/apache/poi/hpsf/UnexpectedPropertySetTypeException.java
  
  Index: UnexpectedPropertySetTypeException.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/UnexpectedPropertySetTypeException.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- UnexpectedPropertySetTypeException.java	2 Aug 2003 19:02:28 -0000	1.7
  +++ UnexpectedPropertySetTypeException.java	30 Aug 2003 09:13:52 -0000	1.8
  @@ -62,7 +62,8 @@
    * <p>The constructors of this class are analogous to those of its
    * superclass and documented there.</p>
    *
  - * @author Rainer Klute (klute@rainer-klute.de)
  + * @author Rainer Klute <a
  + * href="mailto:klute@rainer-klute.de">&lt;klute@rainer-klute.de&gt;</a>
    * @version $Id$
    * @since 2002-02-09
    */
  
  
  
  1.2       +2 -2      jakarta-poi/src/java/org/apache/poi/hpsf/UnsupportedVariantTypeException.java
  
  Index: UnsupportedVariantTypeException.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/UnsupportedVariantTypeException.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- UnsupportedVariantTypeException.java	23 Aug 2003 15:12:22 -0000	1.1
  +++ UnsupportedVariantTypeException.java	30 Aug 2003 09:13:52 -0000	1.2
  @@ -88,7 +88,7 @@
       {
           super("HPSF does not yet support the variant type " + variantType + 
                 " (" + Variant.getVariantName(variantType) + ", " +
  -              HexDump.toHex((int) variantType) + "). If you want support for " +
  +              HexDump.toHex(variantType) + "). If you want support for " +
                 "this variant type in one of the next POI releases please " +
                 "submit a request for enhancement (RFE) to " +
                 "<http://nagoya.apache.org/bugzilla/>! Thank you!");
  
  
  
  1.11      +87 -2     jakarta-poi/src/java/org/apache/poi/hpsf/Util.java
  
  Index: Util.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/Util.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- Util.java	23 Aug 2003 15:12:22 -0000	1.10
  +++ Util.java	30 Aug 2003 09:13:52 -0000	1.11
  @@ -78,7 +78,7 @@
        *  <li><p>if for each <var>i</var> with
        *  <var>i</var>&nbsp;&gt;=&nbsp;0 and
        *  <var>i</var>&nbsp;&lt;&nbsp;<var>a.length</var> holds
  -     *  <var>a</var>[<var>i</var>]&nbsp;==&nbsp;<var>b</var>[<var>i</var>].</p></li>
  +     *  <var>a</var>[<var>i</var>]&nbsp;== <var>b</var>[<var>i</var>].</p></li>
        *
        * </ul>
        *
  @@ -191,6 +191,16 @@
           return new Date(ms_since_19700101);
       }
   
  +
  +
  +    /**
  +     * <p>Converts a {@link Date} into a filetime.</p>
  +     *
  +     * @param date The date to be converted
  +     * @return The filetime
  +     * 
  +     * @see #filetimeToDate
  +     */
       public static long dateToFileTime(final Date date)
       {
           long ms_since_19700101 = date.getTime();
  @@ -228,6 +238,17 @@
           return internalEquals(o1, o2);
       }
   
  +
  +
  +    /**
  +     * <p>Compares to object arrays with regarding the objects' order. For
  +     * example, [1, 2, 3] and [2, 1, 3] are equal.</p>
  +     *
  +     * @param c1 The first object array.
  +     * @param c2 The second object array.
  +     * @return <code>true</code> if the object arrays are equal,
  +     * <code>false</code> if they are not.
  +     */
       public static boolean equals(final Object[] c1, final Object[] c2)
       {
           final Object[] o1 = (Object[]) c1.clone();
  @@ -250,6 +271,70 @@
                   return false;
           }
           return true;
  +    }
  +
  +
  +
  +    /**
  +     * <p>Pads a byte array with 0x00 bytes so that its length is a multiple of
  +     * 4.</p>
  +     *
  +     * @param ba The byte array to pad.
  +     * @return The padded byte array.
  +     */
  +    public static byte[] pad4(final byte[] ba)
  +    {
  +        final int PAD = 4;
  +        final byte[] result;
  +        int l = ba.length % PAD;
  +        if (l == 0)
  +            result = ba;
  +        else
  +        {
  +            l = PAD - l;
  +            result = new byte[ba.length + l];
  +            System.arraycopy(ba, 0, result, 0, ba.length);
  +        }
  +        return result;
  +    }
  +
  +
  +
  +    /**
  +     * <p>Pads a character array with 0x0000 characters so that its length is a
  +     * multiple of 4.</p>
  +     *
  +     * @param ca The character array to pad.
  +     * @return The padded character array.
  +     */
  +    public static char[] pad4(final char[] ca)
  +    {
  +        final int PAD = 4;
  +        final char[] result;
  +        int l = ca.length % PAD;
  +        if (l == 0)
  +            result = ca;
  +        else
  +        {
  +            l = PAD - l;
  +            result = new char[ca.length + l];
  +            System.arraycopy(ca, 0, result, 0, ca.length);
  +        }
  +        return result;
  +    }
  +
  +
  +
  +    /**
  +     * <p>Pads a string with 0x0000 characters so that its length is a
  +     * multiple of 4.</p>
  +     *
  +     * @param s The string to pad.
  +     * @return The padded string as a character array.
  +     */
  +    public static char[] pad4(final String s)
  +    {
  +        return pad4(s.toCharArray());
       }
   
   }
  
  
  
  1.9       +163 -48   jakarta-poi/src/java/org/apache/poi/hpsf/Variant.java
  
  Index: Variant.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/Variant.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- Variant.java	23 Aug 2003 15:12:22 -0000	1.8
  +++ Variant.java	30 Aug 2003 09:13:52 -0000	1.9
  @@ -54,6 +54,7 @@
    */
   package org.apache.poi.hpsf;
   
  +import java.util.Collections;
   import java.util.HashMap;
   import java.util.Map;
   
  @@ -357,79 +358,193 @@
       public static final int VT_BYREF = 0x4000;
   
       /**
  -     * <p>FIXME: Document this!</p>
  +     * <p>FIXME (3): Document this!</p>
        */
       public static final int VT_RESERVED = 0x8000;
   
       /**
  -     * <p>FIXME: Document this!</p>
  +     * <p>FIXME (3): Document this!</p>
        */
       public static final int VT_ILLEGAL = 0xFFFF;
   
       /**
  -     * <p>FIXME: Document this!</p>
  +     * <p>FIXME (3): Document this!</p>
        */
       public static final int VT_ILLEGALMASKED = 0xFFF;
   
       /**
  -     * <p>FIXME: Document this!</p>
  +     * <p>FIXME (3): Document this!</p>
        */
       public static final int VT_TYPEMASK = 0xFFF;
   
   
   
  -    public static final Map m = new HashMap();
  +    /**
  +     * <p>Maps the numbers denoting the variant types to their corresponding
  +     * variant type names.</p>
  +     */
  +    private static Map numberToName;
  +
  +    private static Map numberToLength;
  +
  +    /**
  +     * <p>Denotes a variant type with a length that is unknown to HPSF yet.</p>
  +     */
  +    public static final Integer LENGTH_UNKNOWN = new Integer(-2);
  +
  +    /**
  +     * <p>Denotes a variant type with a variable length.</p>
  +     */
  +    public static final Integer LENGTH_VARIABLE = new Integer(-1);
  +
  +    /**
  +     * <p>Denotes a variant type with a length of 0 bytes.</p>
  +     */
  +    public static final Integer LENGTH_0 = new Integer(0);
  +
  +    /**
  +     * <p>Denotes a variant type with a length of 2 bytes.</p>
  +     */
  +    public static final Integer LENGTH_2 = new Integer(2);
  +
  +    /**
  +     * <p>Denotes a variant type with a length of 4 bytes.</p>
  +     */
  +    public static final Integer LENGTH_4 = new Integer(4);
  +
  +    /**
  +     * <p>Denotes a variant type with a length of 8 bytes.</p>
  +     */
  +    public static final Integer LENGTH_8 = new Integer(8);
  +
  +
   
       static
       {
  -        m.put(new Integer(0), "VT_EMPTY");
  -        m.put(new Integer(1), "VT_NULL");
  -        m.put(new Integer(2), "VT_I2");
  -        m.put(new Integer(3), "VT_I4");
  -        m.put(new Integer(4), "VT_R4");
  -        m.put(new Integer(5), "VT_R8");
  -        m.put(new Integer(6), "VT_CY");
  -        m.put(new Integer(7), "VT_DATE");
  -        m.put(new Integer(8), "VT_BSTR");
  -        m.put(new Integer(9), "VT_DISPATCH");
  -        m.put(new Integer(10), "VT_ERROR");
  -        m.put(new Integer(11), "VT_BOOL");
  -        m.put(new Integer(12), "VT_VARIANT");
  -        m.put(new Integer(13), "VT_UNKNOWN");
  -        m.put(new Integer(14), "VT_DECIMAL");
  -        m.put(new Integer(16), "VT_I1");
  -        m.put(new Integer(17), "VT_UI1");
  -        m.put(new Integer(18), "VT_UI2");
  -        m.put(new Integer(19), "VT_UI4");
  -        m.put(new Integer(20), "VT_I8");
  -        m.put(new Integer(21), "VT_UI8");
  -        m.put(new Integer(22), "VT_INT");
  -        m.put(new Integer(23), "VT_UINT");
  -        m.put(new Integer(24), "VT_VOID");
  -        m.put(new Integer(25), "VT_HRESULT");
  -        m.put(new Integer(26), "VT_PTR");
  -        m.put(new Integer(27), "VT_SAFEARRAY");
  -        m.put(new Integer(28), "VT_CARRAY");
  -        m.put(new Integer(29), "VT_USERDEFINED");
  -        m.put(new Integer(30), "VT_LPSTR");
  -        m.put(new Integer(31), "VT_LPWSTR");
  -        m.put(new Integer(64), "VT_FILETIME");
  -        m.put(new Integer(65), "VT_BLOB");
  -        m.put(new Integer(66), "VT_STREAM");
  -        m.put(new Integer(67), "VT_STORAGE");
  -        m.put(new Integer(68), "VT_STREAMED_OBJECT");
  -        m.put(new Integer(69), "VT_STORED_OBJECT");
  -        m.put(new Integer(70), "VT_BLOB_OBJECT");
  -        m.put(new Integer(71), "VT_CF");
  -        m.put(new Integer(72), "VT_CLSID");
  +        /* Initialize the number-to-name map: */
  +        Map tm1 = new HashMap();
  +        tm1.put(new Long(0), "VT_EMPTY");
  +        tm1.put(new Long(1), "VT_NULL");
  +        tm1.put(new Long(2), "VT_I2");
  +        tm1.put(new Long(3), "VT_I4");
  +        tm1.put(new Long(4), "VT_R4");
  +        tm1.put(new Long(5), "VT_R8");
  +        tm1.put(new Long(6), "VT_CY");
  +        tm1.put(new Long(7), "VT_DATE");
  +        tm1.put(new Long(8), "VT_BSTR");
  +        tm1.put(new Long(9), "VT_DISPATCH");
  +        tm1.put(new Long(10), "VT_ERROR");
  +        tm1.put(new Long(11), "VT_BOOL");
  +        tm1.put(new Long(12), "VT_VARIANT");
  +        tm1.put(new Long(13), "VT_UNKNOWN");
  +        tm1.put(new Long(14), "VT_DECIMAL");
  +        tm1.put(new Long(16), "VT_I1");
  +        tm1.put(new Long(17), "VT_UI1");
  +        tm1.put(new Long(18), "VT_UI2");
  +        tm1.put(new Long(19), "VT_UI4");
  +        tm1.put(new Long(20), "VT_I8");
  +        tm1.put(new Long(21), "VT_UI8");
  +        tm1.put(new Long(22), "VT_INT");
  +        tm1.put(new Long(23), "VT_UINT");
  +        tm1.put(new Long(24), "VT_VOID");
  +        tm1.put(new Long(25), "VT_HRESULT");
  +        tm1.put(new Long(26), "VT_PTR");
  +        tm1.put(new Long(27), "VT_SAFEARRAY");
  +        tm1.put(new Long(28), "VT_CARRAY");
  +        tm1.put(new Long(29), "VT_USERDEFINED");
  +        tm1.put(new Long(30), "VT_LPSTR");
  +        tm1.put(new Long(31), "VT_LPWSTR");
  +        tm1.put(new Long(64), "VT_FILETIME");
  +        tm1.put(new Long(65), "VT_BLOB");
  +        tm1.put(new Long(66), "VT_STREAM");
  +        tm1.put(new Long(67), "VT_STORAGE");
  +        tm1.put(new Long(68), "VT_STREAMED_OBJECT");
  +        tm1.put(new Long(69), "VT_STORED_OBJECT");
  +        tm1.put(new Long(70), "VT_BLOB_OBJECT");
  +        tm1.put(new Long(71), "VT_CF");
  +        tm1.put(new Long(72), "VT_CLSID");
  +        Map tm2 = new HashMap(tm1.size(), 1.0F);
  +        tm2.putAll(tm1);
  +        numberToName = Collections.unmodifiableMap(tm2);
  +
  +        /* Initialize the number-to-length map: */
  +        tm1.clear();
  +        tm1.put(new Long(0), LENGTH_0);
  +        tm1.put(new Long(1), LENGTH_UNKNOWN);
  +        tm1.put(new Long(2), LENGTH_2);
  +        tm1.put(new Long(3), LENGTH_4);
  +        tm1.put(new Long(4), LENGTH_4);
  +        tm1.put(new Long(5), LENGTH_8);
  +        tm1.put(new Long(6), LENGTH_UNKNOWN);
  +        tm1.put(new Long(7), LENGTH_UNKNOWN);
  +        tm1.put(new Long(8), LENGTH_UNKNOWN);
  +        tm1.put(new Long(9), LENGTH_UNKNOWN);
  +        tm1.put(new Long(10), LENGTH_UNKNOWN);
  +        tm1.put(new Long(11), LENGTH_UNKNOWN);
  +        tm1.put(new Long(12), LENGTH_UNKNOWN);
  +        tm1.put(new Long(13), LENGTH_UNKNOWN);
  +        tm1.put(new Long(14), LENGTH_UNKNOWN);
  +        tm1.put(new Long(16), LENGTH_UNKNOWN);
  +        tm1.put(new Long(17), LENGTH_UNKNOWN);
  +        tm1.put(new Long(18), LENGTH_UNKNOWN);
  +        tm1.put(new Long(19), LENGTH_UNKNOWN);
  +        tm1.put(new Long(20), LENGTH_UNKNOWN);
  +        tm1.put(new Long(21), LENGTH_UNKNOWN);
  +        tm1.put(new Long(22), LENGTH_UNKNOWN);
  +        tm1.put(new Long(23), LENGTH_UNKNOWN);
  +        tm1.put(new Long(24), LENGTH_UNKNOWN);
  +        tm1.put(new Long(25), LENGTH_UNKNOWN);
  +        tm1.put(new Long(26), LENGTH_UNKNOWN);
  +        tm1.put(new Long(27), LENGTH_UNKNOWN);
  +        tm1.put(new Long(28), LENGTH_UNKNOWN);
  +        tm1.put(new Long(29), LENGTH_UNKNOWN);
  +        tm1.put(new Long(30), LENGTH_VARIABLE);
  +        tm1.put(new Long(31), LENGTH_UNKNOWN);
  +        tm1.put(new Long(64), LENGTH_8);
  +        tm1.put(new Long(65), LENGTH_UNKNOWN);
  +        tm1.put(new Long(66), LENGTH_UNKNOWN);
  +        tm1.put(new Long(67), LENGTH_UNKNOWN);
  +        tm1.put(new Long(68), LENGTH_UNKNOWN);
  +        tm1.put(new Long(69), LENGTH_UNKNOWN);
  +        tm1.put(new Long(70), LENGTH_UNKNOWN);
  +        tm1.put(new Long(71), LENGTH_UNKNOWN);
  +        tm1.put(new Long(72), LENGTH_UNKNOWN);
  +        tm2 = new HashMap(tm1.size(), 1.0F);
  +        tm2.putAll(tm1);
  +        numberToLength = Collections.unmodifiableMap(tm2);
       }
   
   
   
  +    /**
  +     * <p>Returns the variant type name associated with a variant type
  +     * number.</p>
  +     *
  +     * @param variantType The variant type number
  +     * @return The variant type name or the string "unknown variant type"
  +     */
       public static String getVariantName(final long variantType)
       {
  -        String name = (String) m.get(new Integer((int) variantType));
  +        final String name = (String) numberToName.get(new Long(variantType));
           return name != null ? name : "unknown variant type";
       }
   
  -}
  \ No newline at end of file
  +    /**
  +     * <p>Returns a variant type's length.</p>
  +     *
  +     * @param variantType The variant type number
  +     * @return The length of the variant type's data in bytes. If the length is
  +     * variable, i.e. the length of a string, -1 is returned. If HPSF does not
  +     * know the length, -2 is returned. The latter usually indicates an
  +     * unsupported variant type.
  +     */
  +    public static int getVariantLength(final long variantType)
  +    {
  +        final Long key = new Long((int) variantType);
  +        final Long length = (Long) numberToLength.get(key);
  +        if (length == null)
  +            return -2;
  +        return length.intValue();
  +    }
  +
  +}
  
  
  
  1.2       +126 -65   jakarta-poi/src/java/org/apache/poi/hpsf/VariantSupport.java
  
  Index: VariantSupport.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/VariantSupport.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- VariantSupport.java	23 Aug 2003 15:12:22 -0000	1.1
  +++ VariantSupport.java	30 Aug 2003 09:13:52 -0000	1.2
  @@ -65,6 +65,8 @@
   import java.io.IOException;
   import java.io.OutputStream;
   import java.util.Date;
  +import java.util.LinkedList;
  +import java.util.List;
   
   import org.apache.poi.util.LittleEndian;
   import org.apache.poi.util.LittleEndianConsts;
  @@ -72,8 +74,8 @@
   /**
    * <p>Supports reading and writing of variant data.</p>
    * 
  - * <p><strong>FIXME:</strong> Reading and writing must be made more uniform than
  - * it is now. The following items should be resolved:
  + * <p><strong>FIXME (3):</strong> Reading and writing should be made more
  + * uniform than it is now. The following items should be resolved:
    * 
    * <ul>
    *
  @@ -87,14 +89,73 @@
    *
    * @author Rainer Klute <a
    * href="mailto:klute@rainer-klute.de">&lt;klute@rainer-klute.de&gt;</a>
  - * @since 08.08.2003
  + * @since 2003-08-08
    * @version $Id$
    */
   public class VariantSupport extends Variant
   {
   
  +    private static boolean logUnsupportedTypes = false;
  +
  +    /**
  +     * <p>Specifies whether warnings about unsupported variant types are to be
  +     * written to <code>System.err</code> or not.</p>
  +     *
  +     * @param logUnsupportedTypes If <code>true</code> warnings will be written,
  +     * if <code>false</code> they won't.
  +     */
  +    public static void setLogUnsupportedTypes(final boolean logUnsupportedTypes)
  +    {
  +        VariantSupport.logUnsupportedTypes = logUnsupportedTypes;
  +    }
  +
       /**
  -     * <p>Reads a variant data type from a byte array.</p>
  +     * <p>Checks whether logging of unsupported variant types warning is turned
  +     * on or off.</p>
  +     *
  +     * @return <code>true</code> if logging is turned on, else
  +     * <code>false</code>. 
  +     */
  +    public static boolean isLogUnsupportedTypes()
  +    {
  +        return logUnsupportedTypes;
  +    }
  +
  +
  +
  +    /**
  +     * <p>Keeps a list of the variant types an "unsupported" message has already
  +     * been issued for.</p>
  +     */
  +    protected static List unsupportedMessage;
  +
  +    /**
  +     * <p>Writes a warning to <code>System.err</code> that a variant type is
  +     * unsupported by HPSF. Such a warning is written only once for each variant
  +     * type. Log messages can be turned on or off by </p>
  +     *
  +     * @param ex The exception to log
  +     */
  +    protected static void writeUnsupportedTypeMessage
  +        (final UnsupportedVariantTypeException ex)
  +    {
  +        if (isLogUnsupportedTypes())
  +        {
  +            if (unsupportedMessage == null)
  +                unsupportedMessage = new LinkedList();
  +            Long vt = new Long(ex.getVariantType());
  +            if (!unsupportedMessage.contains(vt))
  +            {
  +                System.err.println(ex.getMessage());
  +                unsupportedMessage.add(vt);
  +            }
  +        }
  +    }
  +
  +
  +
  +    /**
  +     * <p>Reads a variant type from a byte array.</p>
        *
        * @param src The byte array
        * @param offset The offset in the byte array where the variant
  @@ -105,8 +166,8 @@
        * @return A Java object that corresponds best to the variant
        * field. For example, a VT_I4 is returned as a {@link Long}, a
        * VT_LPSTR as a {@link String}.
  -     * @exception UnsupportedVariantTypeException if HPSF does not (yet)
  -     * support the variant type which is to be read 
  +     * @exception ReadingNotSupportedException if a property is to be written
  +     * who's variant type HPSF does not yet support
        *
        * @see Variant
        */
  @@ -161,7 +222,7 @@
                    * String object. The 0x00 bytes at the end must be
                    * stripped.
                    *
  -                 * FIXME: Reading an 8-bit string should pay attention
  +                 * FIXME (2): Reading an 8-bit string should pay attention
                    * to the codepage. Currently the byte making out the
                    * property's value are interpreted according to the
                    * platform's default character set.
  @@ -238,51 +299,57 @@
   
   
       /**
  -     * <p>Writes a variant value to an output stream.</p>
  +     * <p>Writes a variant value to an output stream. This method ensures that
  +     * always a multiple of 4 bytes is written.</p>
        *
        * @param out The stream to write the value to.
        * @param type The variant's type.
        * @param value The variant's value.
        * @return The number of entities that have been written. In many cases an
        * "entity" is a byte but this is not always the case.
  +     * @exception IOException if an I/O exceptions occurs
  +     * @exception WritingNotSupportedException if a property is to be written
  +     * who's variant type HPSF does not yet support
        */
       public static int write(final OutputStream out, final long type,
  -                               final Object value)
  +                            final Object value)
           throws IOException, WritingNotSupportedException
       {
  +        int length = 0;
           switch ((int) type)
           {
               case Variant.VT_BOOL:
               {
                   int trueOrFalse;
  -                int length = 0;
                   if (((Boolean) value).booleanValue())
                       trueOrFalse = 1;
                   else
                       trueOrFalse = 0;
  -                length += TypeWriter.writeUIntToStream(out, trueOrFalse);
  -                return length;
  +                length = TypeWriter.writeUIntToStream(out, trueOrFalse);
  +                break;
               }
               case Variant.VT_LPSTR:
               {
  -                TypeWriter.writeUIntToStream
  +                length = TypeWriter.writeUIntToStream
                       (out, ((String) value).length() + 1);
  -                char[] s = toPaddedCharArray((String) value);
  -                /* FIXME: The following line forces characters to bytes. This
  -                 * is generally wrong and should only be done according to a
  -                 * codepage. Alternatively Unicode could be written (see 
  +                char[] s = Util.pad4((String) value);
  +                /* FIXME (2): The following line forces characters to bytes.
  +                 * This is generally wrong and should only be done according to
  +                 * a codepage. Alternatively Unicode could be written (see 
                    * Variant.VT_LPWSTR). */
  -                byte[] b = new byte[s.length];
  +                byte[] b = new byte[s.length + 1];
                   for (int i = 0; i < s.length; i++)
                       b[i] = (byte) s[i];
  +                b[b.length - 1] = 0x00;
                   out.write(b);
  -                return b.length;
  +                length += b.length;
  +                break;
               }
               case Variant.VT_LPWSTR:
               {
                   final int nrOfChars = ((String) value).length() + 1; 
                   TypeWriter.writeUIntToStream(out, nrOfChars);
  -                char[] s = toPaddedCharArray((String) value);
  +                char[] s = Util.pad4((String) value);
                   for (int i = 0; i < s.length; i++)
                   {
                       final int high = (int) ((s[i] & 0xff00) >> 8);
  @@ -292,79 +359,73 @@
                       out.write(lowb);
                       out.write(highb);
                   }
  -                return nrOfChars * 2;
  +                length = nrOfChars * 2;
  +                out.write(0x00);
  +                out.write(0x00);
  +                length += 2;
  +                break;
               }
               case Variant.VT_CF:
               {
                   final byte[] b = (byte[]) value; 
                   out.write(b);
  -                return b.length;
  +                length = b.length;
  +                break;
               }
               case Variant.VT_EMPTY:
               {
                   TypeWriter.writeUIntToStream(out, Variant.VT_EMPTY);
  -                return LittleEndianConsts.INT_SIZE;
  +                length = LittleEndianConsts.INT_SIZE;
  +                break;
               }
               case Variant.VT_I2:
               {
                   TypeWriter.writeToStream(out, ((Integer) value).shortValue());
  -                return LittleEndianConsts.SHORT_SIZE;
  +                length = LittleEndianConsts.SHORT_SIZE;
  +                break;
               }
               case Variant.VT_I4:
               {
                   TypeWriter.writeToStream(out, ((Long) value).intValue());
  -                return LittleEndianConsts.INT_SIZE;
  +                length = LittleEndianConsts.INT_SIZE;
  +                break;
               }
               case Variant.VT_FILETIME:
               {
  -                int length = 0;
                   long filetime = Util.dateToFileTime((Date) value);
                   int high = (int) ((filetime >> 32) & 0xFFFFFFFFL);
                   int low = (int) (filetime & 0x00000000FFFFFFFFL);
  -                length += TypeWriter.writeUIntToStream(out, 0x0000000FFFFFFFFL & low);
  -                length += TypeWriter.writeUIntToStream(out, 0x0000000FFFFFFFFL & high);
  -                return length;
  +                length += TypeWriter.writeUIntToStream
  +                    (out, 0x0000000FFFFFFFFL & low);
  +                length += TypeWriter.writeUIntToStream
  +                    (out, 0x0000000FFFFFFFFL & high);
  +                break;
               }
               default:
               {
  -                throw new WritingNotSupportedException(type, value);
  -             }
  +                /* The variant type is not supported yet. However, if the value
  +                 * is a byte array we can write it nevertheless. */
  +                if (value instanceof byte[])
  +                {
  +                    final byte[] b = (byte[]) value; 
  +                    out.write(b);
  +                    length = b.length;
  +                    writeUnsupportedTypeMessage
  +                        (new WritingNotSupportedException(type, value));
  +                }
  +                else
  +                    throw new WritingNotSupportedException(type, value);
  +                break;
  +            }
           }
  -    }
  -
  -
  -
  -    /**
  -     * <p>Converts a string into a 0x00-terminated character sequence padded 
  -     * with 0x00 bytes to a multiple of 4.</p>
  -     *
  -     * @param value The string to convert
  -     * @return The padded character array
  -     */
  -    private static char[] toPaddedCharArray(final String s)
  -    {
  -        final int PADDING = 4;
  -        int dl = s.length() + 1;
  -        final int r = dl % 4;
  -        if (r > 0)
  -            dl += PADDING - r;
  -        char[] buffer = new char[dl];
  -        s.getChars(0, s.length(), buffer, 0);
  -        for (int i = s.length(); i < dl; i++)
  -            buffer[i] = (char) 0;
  -        return buffer;
  -    }
  -
  -
   
  -    public static int getLength(final long variantType, final int lengthInBytes)
  -    {
  -        switch ((int) variantType)
  +        /* Add 0x00 character to write a multiple of four bytes: */
  +        while (length % 4 != 0)
           {
  -            case VT_LPWSTR:
  -                return lengthInBytes / 2;
  -            default:
  -                return lengthInBytes;
  +            out.write(0);
  +            length++;
           }
  +        return length;
       }
  +
   }
  
  
  
  1.3       +8 -4      jakarta-poi/src/java/org/apache/poi/hpsf/WritingNotSupportedException.java
  
  Index: WritingNotSupportedException.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/WritingNotSupportedException.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- WritingNotSupportedException.java	25 Aug 2003 19:46:00 -0000	1.2
  +++ WritingNotSupportedException.java	30 Aug 2003 09:13:52 -0000	1.3
  @@ -65,6 +65,9 @@
   /**
    * <p>This exception is thrown when trying to write a (yet) unsupported variant
    * type.</p>
  + * 
  + * @see ReadingNotSupportedException
  + * @see UnsupportedVariantTypeException
    *
    * @author Rainer Klute <a
    * href="mailto:klute@rainer-klute.de">&lt;klute@rainer-klute.de&gt;</a>
  @@ -78,10 +81,11 @@
       /**
        * <p>Constructor</p>
        * 
  -     * @param variantType
  -     * @param value
  +     * @param variantType The unsupported varian type.
  +     * @param value The value.
        */
  -    public WritingNotSupportedException(long variantType, Object value)
  +    public WritingNotSupportedException(final long variantType,
  +                                        final Object value)
       {
           super(variantType, value);
       }
  
  
  
  1.1                  jakarta-poi/src/java/org/apache/poi/hpsf/MutableProperty.java
  
  Index: MutableProperty.java
  ===================================================================
  package org.apache.poi.hpsf;
  
  import java.io.IOException;
  import java.io.OutputStream;
  
  /**
   * <p>Adds writing capability to the {@link Property} class.</p>
   * 
   * <p>Please be aware that this class' functionality will be merged into the
   * {@link Property} class at a later time, so the API will change.</p>
   *
   * @author Rainer Klute <a
   * href="mailto:klute@rainer-klute.de">&lt;klute@rainer-klute.de&gt;</a>
   * @since 2003-08-03
   * @version $Id: MutableProperty.java,v 1.1 2003/08/30 09:13:52 klute Exp $
   */
  public class MutableProperty extends Property
  {
  
      /**
       * <p>Creates an empty property. It must be filled using the set method to
       * be usable.</p>
       */
      public MutableProperty()
      { }
  
  
  
      /**
       * <p>Sets the property's ID.</p>
       *
       * @param id the ID
       */
      public void setID(final long id)
      {
          this.id = id;
      }
  
  
  
      /**
       * <p>Sets the property's type.</p>
       *
       * @param type the property's type
       */
      public void setType(final long type)
      {
          this.type = type;
      }
  
  
  
      /**
       * <p>Sets the property's value.</p>
       *
       * @param value the property's value
       */
      public void setValue(final Object value)
      {
          this.value = value;
      }
  
  
  
      /**
       * <p>Writes the property to an output stream.</p>
       * 
       * @param out The output stream to write to.
       * @return the number of bytes written to the stream
       * 
       * @exception IOException if an I/O error occurs
       * @exception WritingNotSupportedException if a variant type is to be
       * written that is not yet supported
       */
      public int write(final OutputStream out)
          throws IOException, WritingNotSupportedException
      {
          int length = 0;
          long variantType = getType();
          length += TypeWriter.writeUIntToStream(out, variantType);
          length += VariantSupport.write(out, variantType, getValue());
          return length;
      }
  
  }
  
  
  
  1.1                  jakarta-poi/src/java/org/apache/poi/hpsf/MutablePropertySet.java
  
  Index: MutablePropertySet.java
  ===================================================================
  /*
   *  ====================================================================
   *  The Apache Software License, Version 1.1
   *
   *  Copyright (c) 2003 The Apache Software Foundation.  All rights
   *  reserved.
   *
   *  Redistribution and use in source and binary forms, with or without
   *  modification, are permitted provided that the following conditions
   *  are met:
   *
   *  1. Redistributions of source code must retain the above copyright
   *  notice, this list of conditions and the following disclaimer.
   *
   *  2. Redistributions in binary form must reproduce the above copyright
   *  notice, this list of conditions and the following disclaimer in
   *  the documentation and/or other materials provided with the
   *  distribution.
   *
   *  3. The end-user documentation included with the redistribution,
   *  if any, must include the following acknowledgment:
   *  "This product includes software developed by the
   *  Apache Software Foundation (http://www.apache.org/)."
   *  Alternately, this acknowledgment may appear in the software itself,
   *  if and wherever such third-party acknowledgments normally appear.
   *
   *  4. The names "Apache" and "Apache Software Foundation" must
   *  not be used to endorse or promote products derived from this
   *  software without prior written permission. For written
   *  permission, please contact apache@apache.org.
   *
   *  5. Products derived from this software may not be called "Apache",
   *  nor may "Apache" appear in their name, without prior written
   *  permission of the Apache Software Foundation.
   *
   *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   *  DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   *  ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   *  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   *  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   *  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   *  SUCH DAMAGE.
   *  ====================================================================
   *
   *  This software consists of voluntary contributions made by many
   *  individuals on behalf of the Apache Software Foundation.  For more
   *  information on the Apache Software Foundation, please see
   *  <http://www.apache.org/>.
   */
  package org.apache.poi.hpsf;
  
  import java.io.IOException;
  import java.io.OutputStream;
  import java.util.LinkedList;
  import java.util.ListIterator;
  import org.apache.poi.util.LittleEndian;
  import org.apache.poi.util.LittleEndianConsts;
  
  
  
  /**
   * <p>Adds writing support to the {@link PropertySet} class.</p>
   *
   * <p>Please be aware that this class' functionality will be merged into the
   * {@link PropertySet} class at a later time, so the API will change.</p>
   *
   * @author Rainer Klute <a
   * href="mailto:klute@rainer-klute.de">&lt;klute@rainer-klute.de&gt;</a>
   * @version $Id: MutablePropertySet.java,v 1.1 2003/08/30 09:13:52 klute Exp $
   * @since 2003-02-19
   */
  public class MutablePropertySet extends PropertySet
  {
  
      /**
       * <p>Constructs a <code>MutablePropertySet</code> instance. Its
       * primary task is to initialize the immutable field with their proper
       * values. It also sets fields that might change to reasonable defaults.</p>
       */
      public MutablePropertySet()
      {
          /* Initialize the "byteOrder" field. */
          byteOrder = LittleEndian.getUShort(BYTE_ORDER_ASSERTION);
  
          /* Initialize the "format" field. */
          format = LittleEndian.getUShort(FORMAT_ASSERTION);
  
          /* Initialize "osVersion" field as if the property has been created on
           * a Win32 platform, whether this is the case or not. */
          osVersion = (OS_WIN32 << 16) | 0x0A04;
  
          /* Initailize the "classID" field. */
          classID = new ClassID();
  
          /* Initialize the sections. Since property set must have at least
           * one section it is added right here. */
          sections = new LinkedList();
          sections.add(new MutableSection());
      }
  
  
  
      /**
       * <p>The length of the property set stream header.</p>
       */
      private final int OFFSET_HEADER =
          BYTE_ORDER_ASSERTION.length + /* Byte order    */
          FORMAT_ASSERTION.length +     /* Format        */
          LittleEndianConsts.INT_SIZE + /* OS version    */
          ClassID.LENGTH +              /* Class ID      */
          LittleEndianConsts.INT_SIZE;  /* Section count */
  
  
  
      /**
       * <p>Sets the "byteOrder" property.</p>
       *
       * @param byteOrder the byteOrder value to set
       */
      public void setByteOrder(final int byteOrder)
      {
          this.byteOrder = byteOrder;
      }
  
  
  
      /**
       * <p>Sets the "format" property.</p>
       *
       * @param format the format value to set
       */
      public void setFormat(final int format)
      {
          this.format = format;
      }
  
  
  
      /**
       * <p>Sets the "osVersion" property.</p>
       *
       * @param osVersion the osVersion value to set
       */
      public void setOSVersion(final int osVersion)
      {
          this.osVersion = osVersion;
      }
  
  
  
      /**
       * <p>Sets the property set stream's low-level "class ID"
       * field.</p>
       *
       * @param classID The property set stream's low-level "class ID" field.
       *
       * @see #getClassID
       */
      public void setClassID(final ClassID classID)
      {
          this.classID = classID;
      }
  
  
  
      /**
       * <p>Removes all sections from this property set.</p>
       */
      public void clearSections()
      {
          sections = null;
      }
  
  
  
      /**
       * <p>Adds a section to this property set.</p>
       *
       * @param section The {@link Section} to add. It will be appended
       * after any sections that are already present in the property set
       * and thus become the last section.
       */
      public void addSection(final Section section)
      {
          if (sections == null)
              sections = new LinkedList();
          sections.add(section);
      }
  
  
  
      /**
       * <p>Writes the property set to an output stream.</p>
       * 
       * @param out the output stream to write the section to
       * @exception IOException if an error when writing to the output stream
       * occurs
       * @exception WritingNotSupportedException if HPSF does not yet support
       * writing a property's variant type.
       */
      public void write(final OutputStream out)
          throws WritingNotSupportedException, IOException
      {
          /* Write the number of sections in this property set stream. */
          final int nrSections = sections.size();
          int length = 0;
  
          /* Write the property set's header. */
          length += TypeWriter.writeToStream(out, (short) getByteOrder());
          length += TypeWriter.writeToStream(out, (short) getFormat());
          length += TypeWriter.writeToStream(out, (int) getOSVersion());
          length += TypeWriter.writeToStream(out, getClassID());
          length += TypeWriter.writeToStream(out, (int) nrSections);
          int offset = OFFSET_HEADER;
  
          /* Write the section list, i.e. the references to the sections. Each
           * entry in the section list consist of a class ID and the offset to the
           * section's begin. */
          offset += nrSections * (ClassID.LENGTH + LittleEndian.INT_SIZE);
          final int sectionsBegin = offset;
          for (final ListIterator i = sections.listIterator(); i.hasNext();)
          {
              final MutableSection s = (MutableSection) i.next();
              length += TypeWriter.writeToStream(out, s.getFormatID());
              length += TypeWriter.writeUIntToStream(out, offset);
              offset += s.getSize();
          }
  
          /* Write the sections themselves. */
          offset = sectionsBegin;
          for (final ListIterator i = sections.listIterator(); i.hasNext();)
          {
              final MutableSection s = (MutableSection) i.next();
              offset = s.write(out, offset);
          }
      }
  
  }
  
  
  1.1                  jakarta-poi/src/java/org/apache/poi/hpsf/MutableSection.java
  
  Index: MutableSection.java
  ===================================================================
  /*
   *  ====================================================================
   *  The Apache Software License, Version 1.1
   *
   *  Copyright (c) 2000 The Apache Software Foundation.  All rights
   *  reserved.
   *
   *  Redistribution and use in source and binary forms, with or without
   *  modification, are permitted provided that the following conditions
   *  are met:
   *
   *  1. Redistributions of source code must retain the above copyright
   *  notice, this list of conditions and the following disclaimer.
   *
   *  2. Redistributions in binary form must reproduce the above copyright
   *  notice, this list of conditions and the following disclaimer in
   *  the documentation and/or other materials provided with the
   *  distribution.
   *
   *  3. The end-user documentation included with the redistribution,
   *  if any, must include the following acknowledgment:
   *  "This product includes software developed by the
   *  Apache Software Foundation (http://www.apache.org/)."
   *  Alternately, this acknowledgment may appear in the software itself,
   *  if and wherever such third-party acknowledgments normally appear.
   *
   *  4. The names "Apache" and "Apache Software Foundation" must
   *  not be used to endorse or promote products derived from this
   *  software without prior written permission. For written
   *  permission, please contact apache@apache.org.
   *
   *  5. Products derived from this software may not be called "Apache",
   *  nor may "Apache" appear in their name, without prior written
   *  permission of the Apache Software Foundation.
   *
   *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   *  DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   *  ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   *  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   *  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   *  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   *  SUCH DAMAGE.
   *  ====================================================================
   *
   *  This software consists of voluntary contributions made by many
   *  individuals on behalf of the Apache Software Foundation.  For more
   *  information on the Apache Software Foundation, please see
   *  <http://www.apache.org/>.
   */
  package org.apache.poi.hpsf;
  
  import java.io.ByteArrayOutputStream;
  import java.io.IOException;
  import java.io.OutputStream;
  import java.util.Iterator;
  import java.util.LinkedList;
  import java.util.List;
  
  import org.apache.poi.util.LittleEndian;
  import org.apache.poi.util.LittleEndianConsts;
  
  /**
   * <p>Adds writing capability to the {@link Section} class.</p>
   *
   * <p>Please be aware that this class' functionality will be merged into the
   * {@link Section} class at a later time, so the API will change.</p>
   *
   * @author Rainer Klute <a
   * href="mailto:klute@rainer-klute.de">&lt;klute@rainer-klute.de&gt;</a>
   * @version $Id: MutableSection.java,v 1.1 2003/08/30 09:13:52 klute Exp $
   * @since 2002-02-20
   */
  public class MutableSection extends Section
  {
  
      /**
       * <p>If the "dirty" flag is true, the section's size must be
       * (re-)calculated before the section is written.</p>
       */
      private boolean dirty = true;
  
  
  
      /**
       * <p>List to assemble the properties. Unfortunately a wrong
       * decision has been taken when specifying the "properties" field
       * as an Property[]. It should have been a {@link java.util.List}.</p>
       */
      private List preprops;
  
  
  
      /**
       * <p>Creates an empty mutable section.</p>
       */
      public MutableSection()
      {
          dirty = true;
          formatID = null;
          offset = -1;
          preprops = new LinkedList();
      }
  
  
  
      /**
       * <p>Sets the section's format ID.</p>
       *
       * @param formatID The section's format ID
       *
       * @see #setFormatID(byte[])
       * @see #getFormatID
       */
      public void setFormatID(final ClassID formatID)
      {
          this.formatID = formatID;
      }
  
  
  
      /**
       * <p>Sets the section's format ID.</p>
       *
       * @param formatID The section's format ID as a byte array. It components
       * are in big-endian format.
       *
       * @see #setFormatID(ClassID)
       * @see #getFormatID
       */
      public void setFormatID(final byte[] formatID)
      {
          setFormatID(new ClassID(formatID, 0));
      }
  
  
  
      /**
       * <p>Sets this section's properties. Any former values are overwritten.</p>
       *
       * @param properties This section's new properties.
       */
      public void setProperties(final Property[] properties)
      {
          preprops = new LinkedList();
          for (int i = 0; i < properties.length; i++)
              preprops.add(properties[i]);
          dirty = true;
      }
  
  
  
      /**
       * <p>Sets the value of the property with the specified ID. If a
       * property with this ID is not yet present in the section, it
       * will be added. An already present property with the specified
       * ID will be overwritten.</p>
       *
       * @param id The property's ID
       * @param value The property's value. It will be written as a Unicode
       * string.
       *
       * @see #setProperty(int, int, Object)
       * @see #getProperty
       */
      public void setProperty(final int id, final String value)
      {
          setProperty(id, Variant.VT_LPWSTR, value);
          dirty = true;
      }
  
  
  
      /**
       * <p>Sets the value and the variant type of the property with the
       * specified ID. If a property with this ID is not yet present in
       * the section, it will be added. An already present property with
       * the specified ID will be overwritten. A default mapping will be
       * used to choose the property's type.</p>
       *
       * @param id The property's ID.
       * @param variantType The property's variant type.
       * @param value The property's value.
       *
       * @see #setProperty(int, Object)
       * @see #getProperty
       * @see Variant
       */
      public void setProperty(final int id, final long variantType,
                              final Object value)
      {
          final MutableProperty p = new MutableProperty();
          p.setID(id);
          p.setType(variantType);
          p.setValue(value);
          setProperty(p);
          dirty = true;
      }
  
  
  
      /**
       * <p>Sets a property. If a property with the same ID is not yet present in
       * the section, the property will be added to the section. If there is
       * already a property with the same ID present in the section, it will be
       * overwritten.</p>
       *
       * @param p The property to be added to the section
       *
       * @see #setProperty(int, int, Object)
       * @see #setProperty(int, String)
       * @see #getProperty
       * @see Variant
       */
      public void setProperty(final Property p)
      {
          final long id = p.getID();
          for (final Iterator i = preprops.iterator(); i.hasNext();)
              if (((Property) i.next()).getID() == id)
              {
                  i.remove();
                  break;
              }
          preprops.add(p);
          dirty = true;
      }
  
  
  
      /**
       * <p>Sets the value of the boolean property with the specified
       * ID.</p>
       *
       * @param id The property's ID
       * @param value The property's value
       *
       * @see #setProperty(int, int, Object)
       * @see #getProperty
       * @see Variant
       */
      protected void setPropertyBooleanValue(final int id, final boolean value)
      {
          setProperty(id, (long) Variant.VT_BOOL, new Boolean(value));
      }
  
  
  
      /**
       * <p>Returns the section's size.</p>
       *
       * @return the section's size.
       */
      public int getSize()
      {
          if (dirty)
          {
              size = calcSize();
              dirty = false;
          }
          return size;
      }
  
  
  
      /**
       * <p>Calculates the section's size. It is the sum of the lengths of the
       * section's header (8), the properties list (16 times the number of
       * properties) and the properties themselves.</p>
       *
       * @return the section's length in bytes.
       */
      private int calcSize()
      {
          int length = 0;
  
          /* The section header. */
          length += LittleEndianConsts.INT_SIZE * 2;
  
          /* The length of the property list. */
          Property[] psa = getProperties();
          if (psa == null)
              psa = new MutableProperty[0];
          length += psa.length * LittleEndianConsts.INT_SIZE * 3;
  
          /* The sum of the lengths of the properties - it is calculated by simply
           * writing the properties to a temporary byte array output stream: */
          final ByteArrayOutputStream b = new ByteArrayOutputStream();
          for (int i = 0; i < psa.length; i++)
          {
              final MutableProperty mp = new MutableProperty();
              mp.setID(psa[i].getID());
              mp.setType(psa[i].getType());
              mp.setValue(psa[i].getValue());
              try
              {
                  length += mp.write(b);
              }
              catch (WritingNotSupportedException ex)
              {
                  /* It was not possible to write the property, not even as a
                   * byte array. We cannot do anything about that. Instead of the
                   * property we insert an empty one into the stream. */
                  mp.setType(Variant.VT_EMPTY);
                  mp.setValue(null);
                  try
                  {
                      length += mp.write(b);
                  }
                  catch (Exception ex2)
                  {
                      /* Even writing an empty property went awfully wrong.
                       * Let's give up. */
                      throw new HPSFRuntimeException(ex2);
                  }
              }
              catch (IOException ex)
              {
                  /* Should never occur. */
                  throw new HPSFRuntimeException(ex);
              }
          }
  
          return length;
      }
  
  
  
      /**
       * <p>Writes this section into an output stream.</p>
       * 
       * <p>Internally this is done by writing into three byte array output
       * streams: one for the properties, one for the property list and one for
       * the section as such. The two former are appended to the latter when they
       * have received all their data.</p>
       *
       * @param out The stream to write into
       * @param offset The offset from the beginning of the property set
       * stream this section begins at
       *
       * @return The offset of the first byte following this section in
       * the property set stream.
       * @exception IOException if an I/O error occurs
       * @exception WritingNotSupportedException if HPSF does not yet support
       * writing a property's variant type.
       */
      public int write(final OutputStream out, final int offset)
          throws WritingNotSupportedException, IOException
      {
          /* The properties are written to this stream. */
          final ByteArrayOutputStream propertyStream =
              new ByteArrayOutputStream();
  
          /* The property list is established here. After each property that has
           * been written to "propertyStream", a property list entry is written to
           * "propertyListStream". */
          final ByteArrayOutputStream propertyListStream =
              new ByteArrayOutputStream();
   
          /* Maintain the current position in the list. */
          int position = 0;
  
          /* Increase the position variable by the size of the property list so
           * that it points to the beginning of the properties themselves. */
          position += 2 * LittleEndian.INT_SIZE +
                      getPropertyCount() * 2 * LittleEndian.INT_SIZE;
  
          /* Write the properties and the property list into their respective
           * streams: */
          for (final Iterator i = preprops.iterator(); i.hasNext();)
          {
              final MutableProperty p = (MutableProperty) i.next();
              
              /* Write the property list entry. */
              TypeWriter.writeUIntToStream(propertyListStream, p.getID());
              TypeWriter.writeUIntToStream(propertyListStream, position);
              
              /* Write the property and update the position to the next
               * property. */
              position += p.write(propertyStream);
          }
          propertyStream.close();
          propertyListStream.close();
  
          /* Write the section: */
          byte[] pb1 = propertyListStream.toByteArray();
          byte[] pb2 = propertyStream.toByteArray();
          TypeWriter.writeToStream(out, LittleEndian.INT_SIZE * 2 + pb1.length +
                                   pb2.length);
          TypeWriter.writeToStream(out, getPropertyCount());
          out.write(pb1);
          out.write(pb2);
  
          return offset + position;
      }
  
  
  
      /**
       * <p>Overwrites the super class' method to cope with a redundancy:
       * the property count is maintained in a separate member variable, but
       * shouldn't.</p>
       * 
       * @return The number of properties in this section
       */
      public int getPropertyCount()
      {
          return preprops.size();
      }
  
  
  
      /**
       * <p>Returns this section's properties.</p>
       * 
       * @return this section's properties.
       */
      public Property[] getProperties()
      {
          return (Property[]) preprops.toArray(new Property[0]);
      }
  
  }
  
  
  
  1.9       +4 -4      jakarta-poi/src/java/org/apache/poi/hpsf/wellknown/PropertyIDMap.java
  
  Index: PropertyIDMap.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/wellknown/PropertyIDMap.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- PropertyIDMap.java	2 Aug 2003 19:02:28 -0000	1.8
  +++ PropertyIDMap.java	30 Aug 2003 09:13:53 -0000	1.9
  @@ -66,9 +66,9 @@
    * should treat them as unmodifiable, copy them and modifiy the
    * copies.</p>
    *
  - * <p><strong>FIXME:</strong> Make the singletons unmodifiable. However, 
  + * <p><strong>FIXME (3):</strong> Make the singletons unmodifiable. However, 
    * since this requires to use a {@link HashMap} delegate instead of
  - * extending {@link HashMap} and thus requires a lot of stupid typing. I won't
  + * extending {@link HashMap} and thus requires a lot of stupid typing, I won't
    * do that for the time being.</p>
    *
    * @author Rainer Klute (klute@rainer-klute.de)
  @@ -141,7 +141,7 @@
        * document</p> */
       public static final int PID_APPNAME = 18;
   
  -    /** <p>ID of the property that denotes... FIXME</p> */
  +    /** <p>ID of the property that denotes... FIXME (2)</p> */
       public static final int PID_SECURITY = 19;
   
   
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: poi-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: poi-dev-help@jakarta.apache.org