From 61f780dba8db34aadf827a2922443c9fd54f4ca4 Mon Sep 17 00:00:00 2001 From: Rainer Klute Date: Thu, 18 Sep 2003 18:56:35 +0000 Subject: [PATCH] These changes introduce the following HPSF enhancements and fixes: - 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 --- .../hpsf/examples/WriteAuthorAndTitle.java | 1 - .../apache/poi/hpsf/examples/WriteTitle.java | 16 +- .../hpsf/IllegalPropertySetDataException.java | 2 +- .../apache/poi/hpsf/MutablePropertySet.java | 3 +- .../org/apache/poi/hpsf/MutableSection.java | 186 +++++++++++++++++- src/java/org/apache/poi/hpsf/Property.java | 11 +- .../apache/poi/hpsf/PropertySetFactory.java | 2 - src/java/org/apache/poi/hpsf/Section.java | 20 +- .../org/apache/poi/hpsf/VariantSupport.java | 11 +- .../poi/hpsf/wellknown/PropertyIDMap.java | 2 +- .../org/apache/poi/hpsf/basic/TestBasic.java | 3 +- .../poi/hpsf/basic/TestEmptyProperties.java | 1 - .../org/apache/poi/hpsf/basic/TestWrite.java | 173 ++++++++++------ .../poi/hpsf/data/TestSectionDictionary.doc | Bin 0 -> 83456 bytes 14 files changed, 345 insertions(+), 86 deletions(-) create mode 100644 src/testcases/org/apache/poi/hpsf/data/TestSectionDictionary.doc diff --git a/src/examples/src/org/apache/poi/hpsf/examples/WriteAuthorAndTitle.java b/src/examples/src/org/apache/poi/hpsf/examples/WriteAuthorAndTitle.java index 64ea6c542..d0b203dfd 100644 --- a/src/examples/src/org/apache/poi/hpsf/examples/WriteAuthorAndTitle.java +++ b/src/examples/src/org/apache/poi/hpsf/examples/WriteAuthorAndTitle.java @@ -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; diff --git a/src/examples/src/org/apache/poi/hpsf/examples/WriteTitle.java b/src/examples/src/org/apache/poi/hpsf/examples/WriteTitle.java index c98274829..df85917e6 100644 --- a/src/examples/src/org/apache/poi/hpsf/examples/WriteTitle.java +++ b/src/examples/src/org/apache/poi/hpsf/examples/WriteTitle.java @@ -54,11 +54,19 @@ */ 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; /** *

This class is a simple sample application showing how to create a property diff --git a/src/java/org/apache/poi/hpsf/IllegalPropertySetDataException.java b/src/java/org/apache/poi/hpsf/IllegalPropertySetDataException.java index 378b1874d..3ad7de6e0 100644 --- a/src/java/org/apache/poi/hpsf/IllegalPropertySetDataException.java +++ b/src/java/org/apache/poi/hpsf/IllegalPropertySetDataException.java @@ -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 { /** diff --git a/src/java/org/apache/poi/hpsf/MutablePropertySet.java b/src/java/org/apache/poi/hpsf/MutablePropertySet.java index 8a236643d..f9f1333ee 100644 --- a/src/java/org/apache/poi/hpsf/MutablePropertySet.java +++ b/src/java/org/apache/poi/hpsf/MutablePropertySet.java @@ -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();) { diff --git a/src/java/org/apache/poi/hpsf/MutableSection.java b/src/java/org/apache/poi/hpsf/MutableSection.java index fce86980e..e60edf5bd 100644 --- a/src/java/org/apache/poi/hpsf/MutableSection.java +++ b/src/java/org/apache/poi/hpsf/MutableSection.java @@ -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(); + } + + + + /** + *

Removes a property.

+ * + * @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 + /** + *

Writes the section's dictionary.

+ * + * @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; + } + + + /** *

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; + } + + + + /** + *

Gets a property.

+ * + *

FIXME (2): This method ensures that properties and + * preprops are in sync. Cleanup this awful stuff!

+ * + * @param id The ID of the property to get + * @return The property or null if there is no such property + */ + public Object getProperty(final long id) + { + getProperties(); + return super.getProperty(id); + } + + + + /** + *

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.

+ * + * @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); } } diff --git a/src/java/org/apache/poi/hpsf/Property.java b/src/java/org/apache/poi/hpsf/Property.java index 0a3bc97fa..e4d70bd1c 100644 --- a/src/java/org/apache/poi/hpsf/Property.java +++ b/src/java/org/apache/poi/hpsf/Property.java @@ -100,7 +100,7 @@ public class Property { /**

Codepage 1200 denotes Unicode.

*/ - private static final int CP_UNICODE = 1200; + public static final int CP_UNICODE = 1200; /**

The property's ID.

*/ protected long id; @@ -318,6 +318,10 @@ public class Property /** + *

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.

+ * * @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(); diff --git a/src/java/org/apache/poi/hpsf/PropertySetFactory.java b/src/java/org/apache/poi/hpsf/PropertySetFactory.java index 6f6d8e6ed..e399bceee 100644 --- a/src/java/org/apache/poi/hpsf/PropertySetFactory.java +++ b/src/java/org/apache/poi/hpsf/PropertySetFactory.java @@ -84,8 +84,6 @@ public class PropertySetFactory * contain a property set. * @throws MarkUnsupportedException if the stream does not support * the mark 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) diff --git a/src/java/org/apache/poi/hpsf/Section.java b/src/java/org/apache/poi/hpsf/Section.java index 9a27a3ded..efe74015c 100644 --- a/src/java/org/apache/poi/hpsf/Section.java +++ b/src/java/org/apache/poi/hpsf/Section.java @@ -93,8 +93,7 @@ public class Section * section. For example, if the format ID of the first {@link * Section} contains the bytes specified by * org.apache.poi.hpsf.wellknown.SectionIDMap.SUMMARY_INFORMATION_ID - * the section (and thus the property set) is a - * SummaryInformation.

+ * the section (and thus the property set) is a SummaryInformation.

* * @return The format ID */ @@ -554,4 +553,21 @@ public class Section return b.toString(); } + + + /** + *

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.

+ * + * @return the dictionary or null if the section does not have + * a dictionary. + */ + public Map getDictionary() + { + return dictionary; + } + } diff --git a/src/java/org/apache/poi/hpsf/VariantSupport.java b/src/java/org/apache/poi/hpsf/VariantSupport.java index 6e9d96c60..3bc0c39c3 100644 --- a/src/java/org/apache/poi/hpsf/VariantSupport.java +++ b/src/java/org/apache/poi/hpsf/VariantSupport.java @@ -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); diff --git a/src/java/org/apache/poi/hpsf/wellknown/PropertyIDMap.java b/src/java/org/apache/poi/hpsf/wellknown/PropertyIDMap.java index 30cb43e82..855e0c94e 100644 --- a/src/java/org/apache/poi/hpsf/wellknown/PropertyIDMap.java +++ b/src/java/org/apache/poi/hpsf/wellknown/PropertyIDMap.java @@ -141,7 +141,7 @@ public class PropertyIDMap extends HashMap * document

*/ public static final int PID_APPNAME = 18; - /**

ID of the property that denotes... FIXME (2)

*/ + /**

FIXME (2): ID of the property that denotes...

*/ public static final int PID_SECURITY = 19; diff --git a/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java b/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java index 5d7ff30e7..4e6d2a212 100644 --- a/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java +++ b/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java @@ -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); } } } diff --git a/src/testcases/org/apache/poi/hpsf/basic/TestEmptyProperties.java b/src/testcases/org/apache/poi/hpsf/basic/TestEmptyProperties.java index 9d8df67d8..7ca404f2d 100644 --- a/src/testcases/org/apache/poi/hpsf/basic/TestEmptyProperties.java +++ b/src/testcases/org/apache/poi/hpsf/basic/TestEmptyProperties.java @@ -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; /** *

Test case for OLE2 files with empty properties. An empty property's type diff --git a/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java b/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java index 75f941d80..d62378dff 100644 --- a/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java +++ b/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java @@ -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); } } /** - *

Creates a copy of a {@link PropertySet}.

- * - * @param ps the property set to copy - * @return the copy + *

Tests writing and reading back a proper dictionary.

*/ - 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); } - return copy; } + /** + *

Tests writing and reading back a proper dictionary with an invalid + * codepage. (HPSF writes Unicode dictionaries only.)

+ */ + 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); + } + } + + + + /** + *

Handles unexpected exceptions in testcases.

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

Runs the test cases stand-alone.

*/ 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 index 0000000000000000000000000000000000000000..6114a76572d64e4c2a737eaae149246175b18854 GIT binary patch literal 83456 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 b7lbhGdj9A2nu(vAZyD<&6ukcDO5pziX9Sc% literal 0 HcmV?d00001