]> source.dussan.org Git - poi.git/commitdiff
These changes introduce the following HPSF enhancements and fixes:
authorRainer Klute <klute@apache.org>
Thu, 18 Sep 2003 18:56:35 +0000 (18:56 +0000)
committerRainer Klute <klute@apache.org>
Thu, 18 Sep 2003 18:56:35 +0000 (18:56 +0000)
- Section dictionaries (aka custom properties) can be written now.
- Constructor MutableProperty(PropertySet) sets the class ID correctly now.
- Possible invalid section count fixed
- More testcases
- Cosmetics

git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@353360 13f79535-47bb-0310-9956-ffa450edef68

14 files changed:
src/examples/src/org/apache/poi/hpsf/examples/WriteAuthorAndTitle.java
src/examples/src/org/apache/poi/hpsf/examples/WriteTitle.java
src/java/org/apache/poi/hpsf/IllegalPropertySetDataException.java
src/java/org/apache/poi/hpsf/MutablePropertySet.java
src/java/org/apache/poi/hpsf/MutableSection.java
src/java/org/apache/poi/hpsf/Property.java
src/java/org/apache/poi/hpsf/PropertySetFactory.java
src/java/org/apache/poi/hpsf/Section.java
src/java/org/apache/poi/hpsf/VariantSupport.java
src/java/org/apache/poi/hpsf/wellknown/PropertyIDMap.java
src/testcases/org/apache/poi/hpsf/basic/TestBasic.java
src/testcases/org/apache/poi/hpsf/basic/TestEmptyProperties.java
src/testcases/org/apache/poi/hpsf/basic/TestWrite.java
src/testcases/org/apache/poi/hpsf/data/TestSectionDictionary.doc [new file with mode: 0644]

index 64ea6c54272843cf6db746ae78cf1bf1895569db..d0b203dfddb726dae2c8c944aaac345e2862b700 100644 (file)
@@ -72,7 +72,6 @@ import org.apache.poi.hpsf.MutableSection;
 import org.apache.poi.hpsf.NoPropertySetStreamException;
 import org.apache.poi.hpsf.PropertySet;
 import org.apache.poi.hpsf.PropertySetFactory;
-import org.apache.poi.hpsf.UnexpectedPropertySetTypeException;
 import org.apache.poi.hpsf.Util;
 import org.apache.poi.hpsf.Variant;
 import org.apache.poi.hpsf.WritingNotSupportedException;
index c98274829b65d5e0dcd6198b897296d8f3b01576..df85917e68b77eeef40485005ea0364f36c6af56 100644 (file)
  */
 package org.apache.poi.hpsf.examples;
 
-import java.io.*;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
 
-import org.apache.poi.hpsf.*;
-import org.apache.poi.hpsf.wellknown.*;
-import org.apache.poi.poifs.filesystem.*;
+import org.apache.poi.hpsf.MutableProperty;
+import org.apache.poi.hpsf.MutablePropertySet;
+import org.apache.poi.hpsf.MutableSection;
+import org.apache.poi.hpsf.SummaryInformation;
+import org.apache.poi.hpsf.Variant;
+import org.apache.poi.hpsf.WritingNotSupportedException;
+import org.apache.poi.hpsf.wellknown.PropertyIDMap;
+import org.apache.poi.hpsf.wellknown.SectionIDMap;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 
 /**
  * <p>This class is a simple sample application showing how to create a property
index 378b1874d10d3ceace011e992a1e1b2899ea36c2..3ad7de6e0b05ba830210a549bdf1c11a84a68bd6 100644 (file)
@@ -66,7 +66,7 @@ package org.apache.poi.hpsf;
  * @version $Id$
  * @since 2002-05-26
  */
-public class  IllegalPropertySetDataException extends HPSFRuntimeException
+public class IllegalPropertySetDataException extends HPSFRuntimeException
 {
 
     /**
index 8a236643d7c0a3c02988705c9772ffea0761f0c6..f9f1333eec97068135cf783f686f26c1baa5fa7f 100644 (file)
@@ -106,6 +106,7 @@ public class MutablePropertySet extends PropertySet
          * one section it is added right here. */
         sections = new LinkedList();
         sections.add(new MutableSection());
+        sectionCount = 1;
     }
 
 
@@ -123,7 +124,7 @@ public class MutablePropertySet extends PropertySet
         byteOrder = ps.getByteOrder();
         format = ps.getFormat();
         osVersion = ps.getOSVersion();
-        classID = new ClassID(ps.getClassID().getBytes(), 0);
+        setClassID(ps.getClassID());
         clearSections();
         for (final Iterator i = ps.getSections().iterator(); i.hasNext();)
         {
index fce86980e4f4e9e453c97355bdeec6db02f5bfc2..e60edf5bd443db93ac887fa6dbc301e4dbdc3470 100644 (file)
@@ -60,7 +60,9 @@ import java.io.OutputStream;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 
+import org.apache.poi.hpsf.wellknown.PropertyIDMap;
 import org.apache.poi.util.LittleEndian;
 
 /**
@@ -129,7 +131,7 @@ public class MutableSection extends Section
         for (int i = 0; i < pa.length; i++)
             mpa[i] = new MutableProperty(pa[i]);
         setProperties(mpa);
-        dictionary = s.dictionary;
+        setDictionary(s.getDictionary());
     }
 
 
@@ -247,13 +249,27 @@ public class MutableSection extends Section
     public void setProperty(final Property p)
     {
         final long id = p.getID();
+        removeProperty(id);
+        preprops.add(p);
+        dirty = true;
+        propertyCount = preprops.size();
+    }
+
+
+
+    /**
+     * <p>Removes a property.</p>
+     *
+     * @param id The ID of the property to be removed
+     */
+    public void removeProperty(final long id)
+    {
         for (final Iterator i = preprops.iterator(); i.hasNext();)
             if (((Property) i.next()).getID() == id)
             {
                 i.remove();
                 break;
             }
-        preprops.add(p);
         dirty = true;
         propertyCount = preprops.size();
     }
@@ -292,6 +308,10 @@ public class MutableSection extends Section
                 size = calcSize();
                 dirty = false;
             }
+            catch (HPSFRuntimeException ex)
+            {
+                throw ex;
+            }
             catch (Exception ex)
             {
                 throw new HPSFRuntimeException(ex);
@@ -365,19 +385,55 @@ public class MutableSection extends Section
         position += 2 * LittleEndian.INT_SIZE +
                     getPropertyCount() * 2 * LittleEndian.INT_SIZE;
 
+        /* Writing the section's dictionary it tricky. If there is a dictionary
+         * (property 0) the codepage property (property 1) has to be set, too.
+         * Since HPSF supports Unicode only, the codepage must be 1200. */
+        if (getProperty(PropertyIDMap.PID_DICTIONARY) != null)
+        {
+            final Object p1 = getProperty(PropertyIDMap.PID_CODEPAGE);
+            if (p1 != null)
+            {
+                if (!(p1 instanceof Integer))
+                    throw new IllegalPropertySetDataException
+                        ("The codepage property (ID = 1) must be an " +
+                         "Integer object.");
+                else if (((Integer) p1).intValue() != Property.CP_UNICODE)
+                    throw new IllegalPropertySetDataException
+                        ("The codepage property (ID = 1) must be " +
+                         "1200 (Unicode).");
+            }
+            else
+                throw new IllegalPropertySetDataException
+                    ("The codepage property (ID = 1) must be set.");
+        }
+
         /* 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();
+            final long id = p.getID();
             
             /* 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);
+
+            /* If the property ID is not equal 0 we write the property and all
+             * is fine. However, if it equals 0 we have to write the section's
+             * dictionary which does not have a type but just a value. */
+            if (id != 0)
+                /* Write the property and update the position to the next
+                 * property. */
+                position += p.write(propertyStream);
+            else
+            {
+                final Integer codepage =
+                    (Integer) getProperty(PropertyIDMap.PID_CODEPAGE);
+                if (codepage == null)
+                    throw new IllegalPropertySetDataException
+                        ("Codepage (property 1) is undefined.");
+                position += writeDictionary(propertyStream, dictionary);
+            }
         }
         propertyStream.close();
         propertyListStream.close();
@@ -405,6 +461,52 @@ public class MutableSection extends Section
 
 
 
+    /**
+     * <p>Writes the section's dictionary.</p>
+     *
+     * @param out The output stream to write to.
+     * @param dictionary The dictionary.
+     * @return The number of bytes written
+     * @exception IOException if an I/O exception occurs.
+     */
+    private static int writeDictionary(final OutputStream out,
+                                       final Map dictionary)
+        throws IOException
+    {
+        int length = 0;
+        length += TypeWriter.writeUIntToStream(out, dictionary.size());
+        for (final Iterator i = dictionary.keySet().iterator(); i.hasNext();)
+        {
+            final Long key = (Long) i.next();
+            final String value = (String) dictionary.get(key);
+            int sLength = value.length() + 1;
+            if (sLength % 2 == 1)
+                sLength++;
+            length += TypeWriter.writeUIntToStream(out, key.longValue());
+            length += TypeWriter.writeUIntToStream(out, sLength);
+            final char[] ca = value.toCharArray();
+            for (int j = 0; j < ca.length; j++)
+            {
+                int high = (ca[j] & 0x0ff00) >> 8;
+                int low  = (ca[j] & 0x000ff);
+                out.write(low);
+                out.write(high);
+                length += 2;
+                sLength--;
+            }
+            while (sLength > 0)
+            {
+                out.write(0x00);
+                out.write(0x00);
+                length += 2;
+                sLength--;
+            }
+        }
+        return length;
+    }
+
+
+
     /**
      * <p>Overwrites the super class' method to cope with a redundancy:
      * the property count is maintained in a separate member variable, but
@@ -426,7 +528,77 @@ public class MutableSection extends Section
      */
     public Property[] getProperties()
     {
-        return (Property[]) preprops.toArray(new Property[0]);
+        properties = (Property[]) preprops.toArray(new Property[0]);
+        return properties;
+    }
+
+
+
+    /**
+     * <p>Gets a property.</p>
+     * 
+     * <p><strong>FIXME (2):</strong> This method ensures that properties and
+     * preprops are in sync. Cleanup this awful stuff!</p>
+     * 
+     * @param id The ID of the property to get
+     * @return The property or <code>null</code> if there is no such property
+     */
+    public Object getProperty(final long id)
+    {
+        getProperties();
+        return super.getProperty(id);
+    }
+
+
+
+    /**
+     * <p>Sets the section's dictionary. All keys in the dictionary must be
+     * {@see java.lang.Long} instances, all values must be
+     * {@see java.lang.String}s. This method overwrites the properties with IDs
+     * 0 and 1 since they are reserved for the dictionary and the dictionary's
+     * codepage. Setting these properties explicitly might have surprising
+     * effects. An application should never do this but always use this
+     * method.</p>
+     *
+     * @param dictionary The dictionary
+     * 
+     * @exception IllegalPropertySetDataException if the dictionary's key and
+     * value types are not correct.
+     * 
+     * @see Section#getDictionary()
+     */
+    public void setDictionary(final Map dictionary)
+        throws IllegalPropertySetDataException
+    {
+        if (dictionary != null)
+        {
+            for (final Iterator i = dictionary.keySet().iterator();
+                 i.hasNext();)
+                if (!(i.next() instanceof Long))
+                    throw new IllegalPropertySetDataException
+                        ("Dictionary keys must be of type Long.");
+            for (final Iterator i = dictionary.values().iterator();
+                 i.hasNext();)
+                if (!(i.next() instanceof String))
+                    throw new IllegalPropertySetDataException
+                        ("Dictionary values must be of type String.");
+            this.dictionary = dictionary;
+
+            /* Set the dictionary property (ID 0). Please note that the second
+             * parameter in the method call below is unused because dictionaries
+             * don't have a type. */
+            setProperty(PropertyIDMap.PID_DICTIONARY, -1, dictionary);
+
+            /* Set the codepage property (ID 1) for the strings used in the 
+             * dictionary. HPSF always writes Unicode strings to the
+             * dictionary. */
+            setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2,
+                        new Integer(Property.CP_UNICODE));
+        }
+        else
+            /* Setting the dictionary to null means to remove property 0.
+             * However, it does not mean to remove property 1 (codepage). */
+            removeProperty(PropertyIDMap.PID_DICTIONARY);
     }
 
 }
index 0a3bc97fa464c60a3e31ced4de6a07b7a8999c60..e4d70bd1c317446a9566cdb9856ef73b9d25f9f4 100644 (file)
@@ -100,7 +100,7 @@ public class Property
 {
 
     /** <p>Codepage 1200 denotes Unicode.</p> */
-    private static final int CP_UNICODE = 1200;
+    public static final int CP_UNICODE = 1200;
 
     /** <p>The property's ID.</p> */
     protected long id;
@@ -318,6 +318,10 @@ public class Property
 
 
     /**
+     * <p>Compares two properties. Please beware that a property with ID == 0 is
+     * a special case: It does not have a type, and its value is the section's
+     * dictionary.</p>
+     * 
      * @see Object#equals(java.lang.Object)
      */
     public boolean equals(final Object o)
@@ -326,13 +330,14 @@ public class Property
             return false;
         final Property p = (Property) o;
         final Object pValue = p.getValue();
-        if (id != p.getID() || type != p.getType())
+        final long pId = p.getID();
+        if (id != pId || (id != 0 && 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();
index 6f6d8e6ed25b5726d5cb7abc72f325c2762313f4..e399bceee8ffcf29cff990a4b1265528fdd10334 100644 (file)
@@ -84,8 +84,6 @@ public class PropertySetFactory
      * contain a property set.
      * @throws MarkUnsupportedException if the stream does not support
      * the <code>mark</code> operation.
-     * @throws UnexpectedPropertySetTypeException if the property
-     * set's type is unexpected.
      * @throws IOException if some I/O problem occurs.
      */
     public static PropertySet create(final InputStream stream)
index 9a27a3dedc67f8794a7b6db49a3f8a12a6b697d3..efe74015c3de3fcf0437c04bcc06ac03485d8190 100644 (file)
@@ -93,8 +93,7 @@ public class Section
      * section. For example, if the format ID of the first {@link
      * Section} contains the bytes specified by
      * <code>org.apache.poi.hpsf.wellknown.SectionIDMap.SUMMARY_INFORMATION_ID</code>
-     * the section (and thus the property set) is a
-     * SummaryInformation.</p>
+     * the section (and thus the property set) is a SummaryInformation.</p>
      *
      * @return The format ID
      */
@@ -554,4 +553,21 @@ public class Section
         return b.toString();
     }
 
+
+
+    /**
+     * <p>Gets the section's dictionary. A dictionary allows an application to
+     * use human-readable property names instead of numeric property IDs. It
+     * contains mappings from property IDs to their associated string
+     * values. The dictionary is stored as the property with ID 0. The codepage
+     * for the strings in the dictionary is defined by property with ID 1.</p>
+     *
+     * @return the dictionary or <code>null</code> if the section does not have
+     * a dictionary.
+     */
+    public Map getDictionary()
+    {
+        return dictionary;
+    }
+
 }
index 6e9d96c60abb974fcf81e527958148384038701a..3bc0c39c38c46bbe95f1e5e385e48a26d2a460c3 100644 (file)
@@ -252,7 +252,7 @@ public class VariantSupport extends Variant
                     final int i1 = o1 + (i * 2);
                     final int i2 = i1 + 1;
                     final int high = src[i2] << 8;
-                    final int low = src[i1] & 0xff;
+                    final int low = src[i1] & 0x00ff;
                     final char c = (char) (high | low);
                     b.append(c);
                 }
@@ -352,8 +352,8 @@ public class VariantSupport extends Variant
                 char[] s = Util.pad4((String) value);
                 for (int i = 0; i < s.length; i++)
                 {
-                    final int high = (int) ((s[i] & 0xff00) >> 8);
-                    final int low = (int) (s[i] & 0x00ff);
+                    final int high = (int) ((s[i] & 0x0000ff00) >> 8);
+                    final int low = (int) (s[i] & 0x000000ff);
                     final byte highb = (byte) high;
                     final byte lowb = (byte) low;
                     out.write(lowb);
@@ -386,13 +386,14 @@ public class VariantSupport extends Variant
             }
             case Variant.VT_I4:
             {
-                length += TypeWriter.writeToStream(out, ((Long) value).intValue());
+                length += TypeWriter.writeToStream(out, 
+                          ((Long) value).intValue());
                 break;
             }
             case Variant.VT_FILETIME:
             {
                 long filetime = Util.dateToFileTime((Date) value);
-                int high = (int) ((filetime >> 32) & 0xFFFFFFFFL);
+                int high = (int) ((filetime >> 32) & 0x00000000FFFFFFFFL);
                 int low = (int) (filetime & 0x00000000FFFFFFFFL);
                 length += TypeWriter.writeUIntToStream
                     (out, 0x0000000FFFFFFFFL & low);
index 30cb43e8255d28117b3ddf7111b490d959decb36..855e0c94eb01cc9a40c8b678f776e20743ab875b 100644 (file)
@@ -141,7 +141,7 @@ public class PropertyIDMap extends HashMap
      * document</p> */
     public static final int PID_APPNAME = 18;
 
-    /** <p>ID of the property that denotes... FIXME (2)</p> */
+    /** <p>FIXME (2): ID of the property that denotes...</p> */
     public static final int PID_SECURITY = 19;
 
 
index 5d7ff30e76215a1226b3a48cb36d9cddaab66347..4e6d2a2129b915778a7442efd1853d292f48dd89 100644 (file)
@@ -65,7 +65,6 @@ import java.util.List;
 import junit.framework.Assert;
 import junit.framework.TestCase;
 
-import org.apache.poi.hpsf.ClassID;
 import org.apache.poi.hpsf.DocumentSummaryInformation;
 import org.apache.poi.hpsf.HPSFException;
 import org.apache.poi.hpsf.MarkUnsupportedException;
@@ -288,7 +287,7 @@ public class TestBasic extends TestCase
                 {
                     final InputStream in =
                         new ByteArrayInputStream(psf1[j].getBytes());
-                    final PropertySet psIn = PropertySetFactory.create(in);
+                    PropertySetFactory.create(in);
                 }
             }
         }
index 9d8df67d8755331af2170fb9562c0d727edd25f9..7ca404f2db334fc23bf498ac2b8b0d72255b92ec 100644 (file)
@@ -15,7 +15,6 @@ import org.apache.poi.hpsf.NoPropertySetStreamException;
 import org.apache.poi.hpsf.PropertySet;
 import org.apache.poi.hpsf.PropertySetFactory;
 import org.apache.poi.hpsf.SummaryInformation;
-import org.apache.poi.hpsf.UnexpectedPropertySetTypeException;
 
 /**
  * <p>Test case for OLE2 files with empty properties. An empty property's type
index 75f941d80d8de2a1f9fb40a6977faf62f0f20113..d62378dffdc7d01c091f01ca386c858eda81adc8 100644 (file)
@@ -66,12 +66,14 @@ import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.Date;
-import java.util.Iterator;
+import java.util.HashMap;
+import java.util.Map;
 
 import junit.framework.Assert;
 import junit.framework.TestCase;
 
 import org.apache.poi.hpsf.HPSFRuntimeException;
+import org.apache.poi.hpsf.IllegalPropertySetDataException;
 import org.apache.poi.hpsf.MutableProperty;
 import org.apache.poi.hpsf.MutablePropertySet;
 import org.apache.poi.hpsf.MutableSection;
@@ -570,7 +572,7 @@ public class TestWrite extends TestCase
                 final InputStream in =
                     new ByteArrayInputStream(psf1[i].getBytes());
                 final PropertySet psIn = PropertySetFactory.create(in);
-                final MutablePropertySet psOut = copy(psIn);
+                final MutablePropertySet psOut = new MutablePropertySet(psIn);
                 final ByteArrayOutputStream psStream =
                     new ByteArrayOutputStream();
                 psOut.write(psStream);
@@ -602,75 +604,134 @@ public class TestWrite extends TestCase
         }
         catch (Exception ex)
         {
-            StringWriter sw = new StringWriter();
-            PrintWriter pw = new PrintWriter(sw);
-            Throwable t = ex;
-            while (t != null)
-            {
-                t.printStackTrace(pw);
-                if (t instanceof HPSFRuntimeException)
-                    t = ((HPSFRuntimeException) t).getReason();
-                else
-                    t = null;
-                if (t != null)
-                    pw.println("Caused by:");
-            }
-            pw.close();
-            try
-            {
-                sw.close();
-            }
-            catch (IOException ex2)
-            {
-                ex.printStackTrace();
-            }
-            String msg = sw.toString();
-            fail(msg);
+            handle(ex);
         }
     }
 
 
 
     /**
-     * <p>Creates a copy of a {@link PropertySet}.</p>
-     *
-     * @param ps the property set to copy
-     * @return the copy
+     * <p>Tests writing and reading back a proper dictionary.</p>
      */
-    private MutablePropertySet copy(final PropertySet ps)
+    public void testDictionary()
     {
-        MutablePropertySet copy = new MutablePropertySet();
-        copy.setByteOrder(ps.getByteOrder());
-        copy.setClassID(ps.getClassID());
-        copy.setFormat(ps.getFormat());
-        copy.setOSVersion(ps.getOSVersion());
-        copy.clearSections();
-
-        /* Copy the sections. */
-        for (final Iterator i1 = ps.getSections().iterator(); i1.hasNext();)
+        try
         {
-            final Section s1 = (Section) i1.next();
-            final MutableSection s2 = new MutableSection();
-            s2.setFormatID(s1.getFormatID());
+            final File copy = File.createTempFile("Test-HPSF", "ole2");
+            copy.deleteOnExit();
 
-            /* Copy the properties. */
-            final Property[] pa = s1.getProperties();
-            for (int i2 = 0; i2 < pa.length; i2++)
-            {
-                final Property p1 = pa[i2];
-                final MutableProperty p2 = new MutableProperty();
-                p2.setID(p1.getID());
-                p2.setType(p1.getType());
-                p2.setValue(p1.getValue());
-                s2.setProperty(p2);
-            }
-            copy.addSection(s2);
+            /* Write: */
+            final OutputStream out = new FileOutputStream(copy);
+            final POIFSFileSystem poiFs = new POIFSFileSystem();
+            final MutablePropertySet ps1 = new MutablePropertySet();
+            final MutableSection s = (MutableSection) ps1.getSections().get(0);
+            final Map m = new HashMap(3, 1.0f);
+            m.put(new Long(1), "String 1");
+            m.put(new Long(2), "String 2");
+            m.put(new Long(3), "String 3");
+            s.setDictionary(m);
+            s.setFormatID(SectionIDMap.DOCUMENT_SUMMARY_INFORMATION_ID);
+            int codepage = Property.CP_UNICODE;
+            s.setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2,
+                          new Integer(codepage));
+            poiFs.createDocument(ps1.toInputStream(), "Test");
+            poiFs.writeFilesystem(out);
+            out.close();
+
+            /* Read back: */
+            final POIFile[] psf = Util.readPropertySets(copy);
+            Assert.assertEquals(1, psf.length);
+            final byte[] bytes = psf[0].getBytes();
+            final InputStream in = new ByteArrayInputStream(bytes);
+            final PropertySet ps2 = PropertySetFactory.create(in);
+
+            /* Compare the property set stream with the corresponding one
+             * from the origin file and check whether they are equal. */
+            assertEquals(ps1, ps2);
+        }
+        catch (Exception ex)
+        {
+            handle(ex);
+        }
+    }
+
+
+
+    /**
+     * <p>Tests writing and reading back a proper dictionary with an invalid
+     * codepage. (HPSF writes Unicode dictionaries only.)</p>
+     */
+    public void testDictionaryWithInvalidCodepage()
+    {
+        try
+        {
+            final File copy = File.createTempFile("Test-HPSF", "ole2");
+            copy.deleteOnExit();
+
+            /* Write: */
+            final OutputStream out = new FileOutputStream(copy);
+            final POIFSFileSystem poiFs = new POIFSFileSystem();
+            final MutablePropertySet ps1 = new MutablePropertySet();
+            final MutableSection s = (MutableSection) ps1.getSections().get(0);
+            final Map m = new HashMap(3, 1.0f);
+            m.put(new Long(1), "String 1");
+            m.put(new Long(2), "String 2");
+            m.put(new Long(3), "String 3");
+            s.setDictionary(m);
+            s.setFormatID(SectionIDMap.DOCUMENT_SUMMARY_INFORMATION_ID);
+            int codepage = 12345;
+            s.setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2,
+                          new Integer(codepage));
+            poiFs.createDocument(ps1.toInputStream(), "Test");
+            poiFs.writeFilesystem(out);
+            out.close();
+            fail("This testcase did not detect the invalid codepage value.");
+        }
+        catch (IllegalPropertySetDataException ex)
+        {
+            assertTrue(true);
+        }
+        catch (Exception ex)
+        {
+            handle(ex);
         }
-        return copy;
     }
 
 
 
+    /**
+     * <p>Handles unexpected exceptions in testcases.</p>
+     *
+     * @param ex The exception that has been thrown.
+     */
+    private void handle(final Exception ex)
+    {
+        final StringWriter sw = new StringWriter();
+        final PrintWriter pw = new PrintWriter(sw);
+        Throwable t = ex;
+        while (t != null)
+        {
+            t.printStackTrace(pw);
+            if (t instanceof HPSFRuntimeException)
+                t = ((HPSFRuntimeException) t).getReason();
+            else
+                t = null;
+            if (t != null)
+                pw.println("Caused by:");
+        }
+        pw.close();
+        try
+        {
+            sw.close();
+        }
+        catch (IOException ex2)
+        {
+            ex.printStackTrace();
+        }
+        fail(sw.toString());
+    }
+
+
     /**
      * <p>Runs the test cases stand-alone.</p>
      */
diff --git a/src/testcases/org/apache/poi/hpsf/data/TestSectionDictionary.doc b/src/testcases/org/apache/poi/hpsf/data/TestSectionDictionary.doc
new file mode 100644 (file)
index 0000000..6114a76
Binary files /dev/null and b/src/testcases/org/apache/poi/hpsf/data/TestSectionDictionary.doc differ