diff --git a/src/java/org/apache/poi/hpsf/Property.java b/src/java/org/apache/poi/hpsf/Property.java index 3cfb58e6d1..16b4f7e41b 100644 --- a/src/java/org/apache/poi/hpsf/Property.java +++ b/src/java/org/apache/poi/hpsf/Property.java @@ -23,6 +23,8 @@ import java.util.Map; import org.apache.poi.util.HexDump; import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; /** *

A property in a {@link Section} of a {@link PropertySet}.

@@ -113,7 +115,8 @@ public class Property * * @param id the property's ID. * @param type the property's type, see {@link Variant}. - * @param value the property's value. Only certain types are allowed, see {@link Variant}. + * @param value the property's value. Only certain types are allowed, see + * {@link Variant}. */ public Property(final long id, final long type, final Object value) { @@ -210,68 +213,80 @@ public class Property o += LittleEndian.INT_SIZE; final Map m = new HashMap((int) nrEntries, (float) 1.0); - for (int i = 0; i < nrEntries; i++) + + try { - /* The key. */ - final Long id = new Long(LittleEndian.getUInt(src, o)); - o += LittleEndian.INT_SIZE; - - /* The value (a string). The length is the either the - * number of (two-byte) characters if the character set is Unicode - * or the number of bytes if the character set is not Unicode. - * The length includes terminating 0x00 bytes which we have to strip - * off to create a Java string. */ - long sLength = LittleEndian.getUInt(src, o); - o += LittleEndian.INT_SIZE; - - /* Read the string. */ - final StringBuffer b = new StringBuffer(); - switch (codepage) + for (int i = 0; i < nrEntries; i++) { - case -1: + /* The key. */ + final Long id = new Long(LittleEndian.getUInt(src, o)); + o += LittleEndian.INT_SIZE; + + /* The value (a string). The length is the either the + * number of (two-byte) characters if the character set is Unicode + * or the number of bytes if the character set is not Unicode. + * The length includes terminating 0x00 bytes which we have to strip + * off to create a Java string. */ + long sLength = LittleEndian.getUInt(src, o); + o += LittleEndian.INT_SIZE; + + /* Read the string. */ + final StringBuffer b = new StringBuffer(); + switch (codepage) { - /* Without a codepage the length is equal to the number of - * bytes. */ - b.append(new String(src, o, (int) sLength)); - break; - } - case Constants.CP_UNICODE: - { - /* The length is the number of characters, i.e. the number - * of bytes is twice the number of the characters. */ - final int nrBytes = (int) (sLength * 2); - final byte[] h = new byte[nrBytes]; - for (int i2 = 0; i2 < nrBytes; i2 += 2) + case -1: { - h[i2] = src[o + i2 + 1]; - h[i2 + 1] = src[o + i2]; + /* Without a codepage the length is equal to the number of + * bytes. */ + b.append(new String(src, o, (int) sLength)); + break; + } + case Constants.CP_UNICODE: + { + /* The length is the number of characters, i.e. the number + * of bytes is twice the number of the characters. */ + final int nrBytes = (int) (sLength * 2); + final byte[] h = new byte[nrBytes]; + for (int i2 = 0; i2 < nrBytes; i2 += 2) + { + h[i2] = src[o + i2 + 1]; + h[i2 + 1] = src[o + i2]; + } + b.append(new String(h, 0, nrBytes, + VariantSupport.codepageToEncoding(codepage))); + break; + } + default: + { + /* For encodings other than Unicode the length is the number + * of bytes. */ + b.append(new String(src, o, (int) sLength, + VariantSupport.codepageToEncoding(codepage))); + break; } - b.append(new String(h, 0, nrBytes, - VariantSupport.codepageToEncoding(codepage))); - break; } - default: - { - /* For encodings other than Unicode the length is the number - * of bytes. */ - b.append(new String(src, o, (int) sLength, - VariantSupport.codepageToEncoding(codepage))); - break; - } - } - /* Strip 0x00 characters from the end of the string: */ - while (b.length() > 0 && b.charAt(b.length() - 1) == 0x00) - b.setLength(b.length() - 1); - if (codepage == Constants.CP_UNICODE) - { - if (sLength % 2 == 1) - sLength++; - o += (sLength + sLength); + /* Strip 0x00 characters from the end of the string: */ + while (b.length() > 0 && b.charAt(b.length() - 1) == 0x00) + b.setLength(b.length() - 1); + if (codepage == Constants.CP_UNICODE) + { + if (sLength % 2 == 1) + sLength++; + o += (sLength + sLength); + } + else + o += sLength; + m.put(id, b.toString()); } - else - o += sLength; - m.put(id, b.toString()); + } + catch (RuntimeException ex) + { + final POILogger l = POILogFactory.getLogger(getClass()); + l.log(POILogger.WARN, + "The property set's dictionary contains bogus data. " + + "All dictionary entries starting with the one with ID " + + id + " will be ignored.", ex); } return m; } @@ -320,11 +335,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. Another special case are strings: Two properties may have - * the different types Variant.VT_LPSTR and Variant.VT_LPWSTR;

+ *

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. Another special case are strings: Two properties + * may have the different types Variant.VT_LPSTR and Variant.VT_LPWSTR;

* * @see Object#equals(java.lang.Object) */ diff --git a/src/java/org/apache/poi/hpsf/Section.java b/src/java/org/apache/poi/hpsf/Section.java index 3b041ed9c2..76824e7b7e 100644 --- a/src/java/org/apache/poi/hpsf/Section.java +++ b/src/java/org/apache/poi/hpsf/Section.java @@ -210,7 +210,7 @@ public class Section /* Pass 1: Read the property list. */ int pass1Offset = o1; - List propertyList = new ArrayList(propertyCount); + final List propertyList = new ArrayList(propertyCount); PropertyListEntry ple; for (int i = 0; i < properties.length; i++) { diff --git a/src/java/org/apache/poi/hpsf/VariantSupport.java b/src/java/org/apache/poi/hpsf/VariantSupport.java index 1986cac30c..703e8abe8d 100644 --- a/src/java/org/apache/poi/hpsf/VariantSupport.java +++ b/src/java/org/apache/poi/hpsf/VariantSupport.java @@ -109,25 +109,51 @@ public class VariantSupport extends Variant } + /** + *

HPSF is able to read these {@link Variant} types.

+ */ + final static public int[] SUPPORTED_TYPES = { Variant.VT_EMPTY, + Variant.VT_I2, Variant.VT_I4, Variant.VT_I8, Variant.VT_R8, + Variant.VT_FILETIME, Variant.VT_LPSTR, Variant.VT_LPWSTR, + Variant.VT_CF, Variant.VT_BOOL }; + + + + /** + *

Checks whether HPSF supports the specified variant type. Unsupported + * types should be implemented included in the {@link #SUPPORTED_TYPES} + * array.

+ * + * @see Variant + * @param variantType the variant type to check + * @return true if HPFS supports this type, else + * false + */ + public boolean isSupportedType(final int variantType) + { + for (int i = 0; i < SUPPORTED_TYPES.length; i++) + if (variantType == SUPPORTED_TYPES[i]) + return true; + return false; + } + + /** *

Reads a variant type from a byte array.

- * + * * @param src The byte array - * @param offset The offset in the byte array where the variant - * starts - * @param length The length of the variant including the variant - * type field + * @param offset The offset in the byte array where the variant starts + * @param length The length of the variant including the variant type field * @param type The variant type to read - * @param codepage The codepage to use to write non-wide strings - * @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}. + * @param codepage The codepage to use for non-wide strings + * @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 ReadingNotSupportedException if a property is to be written - * who's variant type HPSF does not yet support + * who's variant type HPSF does not yet support * @exception UnsupportedEncodingException if the specified codepage is not - * supported. - * + * supported. * @see Variant */ public static Object read(final byte[] src, final int offset, diff --git a/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java b/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java index 521ce819e8..1932f0f11b 100644 --- a/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java +++ b/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java @@ -20,7 +20,6 @@ package org.apache.poi.hpsf.basic; import java.io.ByteArrayInputStream; import java.io.File; -import java.io.FileFilter; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -227,46 +226,6 @@ public class TestBasic extends TestCase - /** - *

This test methods reads all property set streams from all POI - * filesystems in the "data" directory.

- */ - public void testReadAllFiles() - { - final File dataDir = - new File(System.getProperty("HPSF.testdata.path")); - final File[] fileList = dataDir.listFiles(new FileFilter() - { - public boolean accept(final File f) - { - return f.isFile(); - } - }); - try - { - for (int i = 0; i < fileList.length; i++) - { - File f = fileList[i]; - /* Read the POI filesystem's property set streams: */ - final POIFile[] psf1 = Util.readPropertySets(f); - - for (int j = 0; j < psf1.length; j++) - { - final InputStream in = - new ByteArrayInputStream(psf1[j].getBytes()); - PropertySetFactory.create(in); - } - } - } - catch (Throwable t) - { - final String s = org.apache.poi.hpsf.Util.toString(t); - fail(s); - } - } - - - /** *

Runs the test cases stand-alone.

* diff --git a/src/testcases/org/apache/poi/hpsf/basic/TestBugs.java b/src/testcases/org/apache/poi/hpsf/basic/TestBugs.java deleted file mode 100644 index 0d2b55d5f8..0000000000 --- a/src/testcases/org/apache/poi/hpsf/basic/TestBugs.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.apache.poi.hpsf.basic; - -import java.io.File; -import java.io.FileInputStream; - -import org.apache.poi.hpsf.DocumentSummaryInformation; -import org.apache.poi.hpsf.PropertySet; -import org.apache.poi.hpsf.PropertySetFactory; -import org.apache.poi.hpsf.SummaryInformation; -import org.apache.poi.poifs.filesystem.DocumentInputStream; -import org.apache.poi.poifs.filesystem.POIFSFileSystem; - -import junit.framework.TestCase; - -public class TestBugs extends TestCase { - private String dirname; - - protected void setUp() throws Exception { - dirname = System.getProperty("HPSF.testdata.path"); - } - - public void BROKENtestBug44375() throws Exception { - POIFSFileSystem fs = new POIFSFileSystem( - new FileInputStream(new File(dirname,"Bug44375.xls")) - ); - - DocumentInputStream dis; - PropertySet set; - - dis = fs.createDocumentInputStream(DocumentSummaryInformation.DEFAULT_STREAM_NAME); - set = PropertySetFactory.create(dis); - - dis = fs.createDocumentInputStream(SummaryInformation.DEFAULT_STREAM_NAME); - // This currently fails - set = PropertySetFactory.create(dis); - } - -} diff --git a/src/testcases/org/apache/poi/hpsf/basic/TestReadAllFiles.java b/src/testcases/org/apache/poi/hpsf/basic/TestReadAllFiles.java new file mode 100644 index 0000000000..f68b4c3cc9 --- /dev/null +++ b/src/testcases/org/apache/poi/hpsf/basic/TestReadAllFiles.java @@ -0,0 +1,110 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + + +package org.apache.poi.hpsf.basic; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileFilter; +import java.io.InputStream; + +import junit.framework.TestCase; + +import org.apache.poi.hpsf.PropertySetFactory; + + + +/** + *

Tests some HPSF functionality by reading all property sets from all files + * in the "data" directory. If you want to ensure HPSF can deal with a certain + * OLE2 file, just add it to the "data" directory and run this test case.

+ * + * @author Rainer Klute (klute@rainer-klute.de) + * @since 2008-02-08 + * @version $Id: TestBasic.java 489730 2006-12-22 19:18:16Z bayard $ + */ +public class TestReadAllFiles extends TestCase +{ + + /** + *

Test case constructor.

+ * + * @param name The test case's name. + */ + public TestReadAllFiles(final String name) + { + super(name); + } + + + + /** + *

This test methods reads all property set streams from all POI + * filesystems in the "data" directory.

+ */ + public void testReadAllFiles() + { + final File dataDir = + new File(System.getProperty("HPSF.testdata.path")); + final File[] fileList = dataDir.listFiles(new FileFilter() + { + public boolean accept(final File f) + { + return f.isFile(); + } + }); + try + { + for (int i = 0; i < fileList.length; i++) + { + final File f = fileList[i]; + /* Read the POI filesystem's property set streams: */ + final POIFile[] psf1 = Util.readPropertySets(f); + + for (int j = 0; j < psf1.length; j++) + { + final InputStream in = + new ByteArrayInputStream(psf1[j].getBytes()); + PropertySetFactory.create(in); + } + } + } + catch (Throwable t) + { + final String s = org.apache.poi.hpsf.Util.toString(t); + fail(s); + } + } + + + + /** + *

Runs the test cases stand-alone.

+ * + * @param args Command-line arguments (ignored) + * + * @exception Throwable if any sort of exception or error occurs + */ + public static void main(final String[] args) throws Throwable + { + System.setProperty("HPSF.testdata.path", + "./src/testcases/org/apache/poi/hpsf/data"); + junit.textui.TestRunner.run(TestReadAllFiles.class); + } + +} diff --git a/src/testcases/org/apache/poi/hpsf/data/Bug44375.xls b/src/testcases/org/apache/poi/hpsf/data/TestBug44375.xls similarity index 99% rename from src/testcases/org/apache/poi/hpsf/data/Bug44375.xls rename to src/testcases/org/apache/poi/hpsf/data/TestBug44375.xls index 1e253d175c..0ebd762934 100644 Binary files a/src/testcases/org/apache/poi/hpsf/data/Bug44375.xls and b/src/testcases/org/apache/poi/hpsf/data/TestBug44375.xls differ