]> source.dussan.org Git - poi.git/commitdiff
- Comparing sections refined: For the dictionary (property 0) only the value (Map...
authorRainer Klute <klute@apache.org>
Sat, 20 Sep 2003 15:43:08 +0000 (15:43 +0000)
committerRainer Klute <klute@apache.org>
Sat, 20 Sep 2003 15:43:08 +0000 (15:43 +0000)
- New sample application CopyCompare. I'll turn that into a testcase later.

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

src/documentation/content/xdocs/hpsf/how-to.xml
src/examples/src/org/apache/poi/hpsf/examples/CopyCompare.java [new file with mode: 0644]
src/examples/src/org/apache/poi/hpsf/examples/ReadCustomPropertySets.java
src/examples/src/org/apache/poi/hpsf/examples/ReadTitle.java
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/Section.java
src/java/org/apache/poi/hpsf/Util.java
src/testcases/org/apache/poi/hpsf/data/Test0313rur.adm [new file with mode: 0644]
src/testcases/org/apache/poi/hpsf/data/TestEditTime.doc [new file with mode: 0644]
src/testcases/org/apache/poi/hpsf/data/TestMickey.doc [new file with mode: 0644]

index cc1b3ce72587980f06a3e79990d38662f35362c9..d632a4c97eaf804157cf442778493360d36a310f 100644 (file)
@@ -700,16 +700,16 @@ No property set stream: "/1Table"</source>
       <tr>
        <td>0</td>
        <td>The property's value is a <strong>dictionary</strong>, i.e. a
-       mapping from property IDs to strings.</td>
+        mapping from property IDs to strings.</td>
       </tr>
 
       <tr>
        <td>1</td>
        <td>The property's value is the number of a <strong>codepage</strong>,
-       i.e. a mapping from character codes to characters. All strings in the
-       section containing this property must be interpreted using this
-       codepage. Typical property values are 1252 (8-bit "western" characters)
-       or 1200 (16-bit Unicode characters).</td>
+        i.e. a mapping from character codes to characters. All strings in the
+        section containing this property must be interpreted using this
+        codepage. Typical property values are 1252 (8-bit "western" characters)
+        or 1200 (16-bit Unicode characters).</td>
       </tr>
      </table>
     </section>
@@ -1036,15 +1036,15 @@ final String fileName = args[0];</source>
      <p>The <code>MutableSection</code> the sample application retrieved from
       the <code>MutablePropertySet</code> is still empty. It contains no
       properties and does not have a format ID. As you have read <link
-       href="#sec3">above</link> the format ID of the first section in a property set
-       determines the property set's type. Since our property set should become
-       a SummaryInformation property set we have to set the format ID of its
-       first (and only) section to
-       <code>F29F85E0-4FF9-1068-AB-91-08-00-2B-27-B3-D9</code>. However, you
-       won't have to remember that ID: HPSF has it defined as the well-known
-       constant <code>SectionIDMap.SUMMARY_INFORMATION_ID</code>. The sample
-       application writes it to the section using the
-       <code>setFormatID(byte[])</code> method:</p>
+       href="#sec3">above</link> the format ID of the first section in a
+      property set determines the property set's type. Since our property set
+      should become a SummaryInformation property set we have to set the format
+      ID of its first (and only) section to
+      <code>F29F85E0-4FF9-1068-AB-91-08-00-2B-27-B3-D9</code>. However, you
+      won't have to remember that ID: HPSF has it defined as the well-known
+      constant <code>SectionIDMap.SUMMARY_INFORMATION_ID</code>. The sample
+      application writes it to the section using the
+      <code>setFormatID(byte[])</code> method:</p>
 
      <source>ms.setFormatID(SectionIDMap.SUMMARY_INFORMATION_ID);</source>
 
diff --git a/src/examples/src/org/apache/poi/hpsf/examples/CopyCompare.java b/src/examples/src/org/apache/poi/hpsf/examples/CopyCompare.java
new file mode 100644 (file)
index 0000000..94b3a42
--- /dev/null
@@ -0,0 +1,566 @@
+/*
+ *  ====================================================================
+ *  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.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.poi.hpsf.HPSFRuntimeException;
+import org.apache.poi.hpsf.MarkUnsupportedException;
+import org.apache.poi.hpsf.MutablePropertySet;
+import org.apache.poi.hpsf.NoPropertySetStreamException;
+import org.apache.poi.hpsf.PropertySet;
+import org.apache.poi.hpsf.PropertySetFactory;
+import org.apache.poi.hpsf.Util;
+import org.apache.poi.hpsf.WritingNotSupportedException;
+import org.apache.poi.poifs.eventfilesystem.POIFSReader;
+import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent;
+import org.apache.poi.poifs.eventfilesystem.POIFSReaderListener;
+import org.apache.poi.poifs.filesystem.DirectoryEntry;
+import org.apache.poi.poifs.filesystem.DocumentEntry;
+import org.apache.poi.poifs.filesystem.DocumentInputStream;
+import org.apache.poi.poifs.filesystem.Entry;
+import org.apache.poi.poifs.filesystem.POIFSDocumentPath;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+
+/**
+ * <p>This class copies a POI file system to a new file and compares the copy
+ * with the original.</p>
+ * 
+ * <p>Property set streams are copied logically, i.e. the application
+ * establishes a {@link org.apache.poi.hpsf.PropertySet} of an original property
+ * set, creates a {@link org.apache.poi.hpsf.MutablePropertySet} from the
+ * {@link org.apache.poi.hpsf.PropertySet} and writes the
+ * {@link org.apache.poi.hpsf.MutablePropertySet} to the destination POI file
+ * system. - Streams which are no property set streams are copied bit by
+ * bit.</p>
+ * 
+ * <p>The comparison of the POI file systems is done logically. That means that
+ * the two disk files containing the POI file systems do not need to be
+ * exactly identical. However, both POI file systems must contain the same
+ * files, and most of these files must be bitwise identical. Property set
+ * streams, however, are compared logically: they must have the same sections
+ * with the same attributs, and the sections must contain the same properties.
+ * Details like the ordering of the properties do not matter.</p>
+ *
+ * @author Rainer Klute <a
+ * href="mailto:klute@rainer-klute.de">&lt;klute@rainer-klute.de&gt;</a>
+ * @version $Id$
+ * @since 2003-09-19
+ */
+public class CopyCompare
+{
+    /**
+     * <p>Runs the example program. The application expects one or two
+     * arguments:</p>
+     * 
+     * <ol>
+     * 
+     * <li><p>The first argument is the disk file name of the POI filesystem to
+     * copy.</p></li>
+     * 
+     * <li><p>The second argument is optional. If it is given, it is the name of
+     * a disk file the copy of the POI filesystem will be written to. If it is
+     * not given, the copy will be written to a temporary file which will be
+     * deleted at the end of the program.</p></li>
+     * 
+     * </ol>
+     *
+     * @param args Command-line arguments.
+     * @exception MarkUnsupportedException if a POI document stream does not
+     * support the mark() operation.
+     * @exception NoPropertySetStreamException if the application tries to
+     * create a property set from a POI document stream that is not a property
+     * set stream.
+     * @exception IOException if any I/O exception occurs.
+     */
+    public static void main(final String[] args)
+    throws MarkUnsupportedException, NoPropertySetStreamException, IOException
+    {
+        String originalFileName = null;
+        String copyFileName = null;
+
+        /* Check the command-line arguments. */
+        if (args.length == 1)
+        {
+            originalFileName = args[0];
+            File f = File.createTempFile("CopyOfPOIFileSystem-", ".ole2");
+            f.deleteOnExit();
+            copyFileName = f.getAbsolutePath();
+        }
+        else if (args.length == 2)
+        {
+            originalFileName = args[0];
+            copyFileName = args[1];
+        }
+        else
+        {
+            System.err.println("Usage: " + CopyCompare.class.getName() +
+                               "originPOIFS [copyPOIFS]");
+            System.exit(1);
+        }
+
+        /* Read the origin POIFS using the eventing API. The real work is done
+         * in the class CopyFile which is registered here as a POIFSReader. */
+        final POIFSReader r = new POIFSReader();
+        final CopyFile cf = new CopyFile(copyFileName);
+        r.registerListener(cf);
+        r.read(new FileInputStream(originalFileName));
+        
+        /* Write the new POIFS to disk. */
+        cf.close();
+
+        /* Read all documents from the original POI file system and compare them
+         * with the equivalent document from the copy. */
+        final POIFSFileSystem opfs =
+            new POIFSFileSystem(new FileInputStream(originalFileName));
+        final POIFSFileSystem cpfs =
+            new POIFSFileSystem(new FileInputStream(copyFileName));
+
+        final DirectoryEntry oRoot = opfs.getRoot();
+        final DirectoryEntry cRoot = cpfs.getRoot();
+        final StringBuffer messages = new StringBuffer();
+        if (equal(oRoot, cRoot, messages))
+            System.out.println("Equal");
+        else
+            System.out.println("Not equal: " + messages.toString());
+    }
+
+
+
+    /**
+     * <p>Compares two {@link DirectoryEntry} instances of a POI file system.
+     * The directories must contain the same streams with the same names and
+     * contents.</p>
+     *
+     * @param d1 The first directory.
+     * @param d2 The second directory.
+     * @param msg The method may append human-readable comparison messages to
+     * this string buffer. 
+     * @return <code>true</code> if the directories are equal, else
+     * <code>false</code>.
+     * @exception MarkUnsupportedException if a POI document stream does not
+     * support the mark() operation.
+     * @exception NoPropertySetStreamException if the application tries to
+     * create a property set from a POI document stream that is not a property
+     * set stream.
+     * @exception IOException if any I/O exception occurs.
+     */
+    private static boolean equal(final DirectoryEntry d1,
+                                 final DirectoryEntry d2,
+                                 final StringBuffer msg)
+    throws MarkUnsupportedException, NoPropertySetStreamException, IOException
+    {
+        boolean equal = true;
+        /* Iterate over d1 and compare each entry with its counterpart in d2. */
+        for (final Iterator i = d1.getEntries(); equal && i.hasNext();)
+        {
+            final Entry e1 = (Entry) i.next();
+            final String n1 = e1.getName();
+            Entry e2 = null;
+            try
+            {
+                e2 = d2.getEntry(n1);
+            }
+            catch (FileNotFoundException ex)
+            {
+                msg.append("Document \"" + e1 + "\" exitsts, document \"" +
+                           e2 + "\" does not.\n");
+                equal = false;
+                break;
+            }
+
+            if (e1.isDirectoryEntry() && e2.isDirectoryEntry())
+                equal = equal((DirectoryEntry) e1, (DirectoryEntry) e2, msg);
+            else if (e1.isDocumentEntry() && e2.isDocumentEntry())
+                equal = equal((DocumentEntry) e1, (DocumentEntry) e2, msg);
+            else
+            {
+                msg.append("One of \"" + e1 + "\" and \"" + e2 + "\" is a " +
+                           "document while the other one is a directory.\n");
+                equal = false;
+            }
+        }
+
+        /* Iterate over d2 just to make sure that there are no entries in d2
+         * that are not in d1. */
+        for (final Iterator i = d2.getEntries(); equal && i.hasNext();)
+        {
+            final Entry e2 = (Entry) i.next();
+            final String n2 = e2.getName();
+            Entry e1 = null;
+            try
+            {
+                e1 = d1.getEntry(n2);
+            }
+            catch (FileNotFoundException ex)
+            {
+                msg.append("Document \"" + e2 + "\" exitsts, document \"" +
+                           e1 + "\" does not.\n");
+                equal = false;
+                break;
+            }
+        }
+        return equal;
+    }
+
+
+
+    /**
+     * <p>Compares two {@link DocumentEntry} instances of a POI file system.
+     * Documents that are not property set streams must be bitwise identical.
+     * Property set streams must be logically equal.</p>
+     *
+     * @param d1 The first document.
+     * @param d2 The second document.
+     * @param msg The method may append human-readable comparison messages to
+     * this string buffer. 
+     * @return <code>true</code> if the documents are equal, else
+     * <code>false</code>.
+     * @exception MarkUnsupportedException if a POI document stream does not
+     * support the mark() operation.
+     * @exception NoPropertySetStreamException if the application tries to
+     * create a property set from a POI document stream that is not a property
+     * set stream.
+     * @exception IOException if any I/O exception occurs.
+     */
+    private static boolean equal(final DocumentEntry d1, final DocumentEntry d2,
+                                 final StringBuffer msg)
+    throws MarkUnsupportedException, NoPropertySetStreamException, IOException
+    {
+        boolean equal = true;
+        final DocumentInputStream dis1 = new DocumentInputStream(d1);
+        final DocumentInputStream dis2 = new DocumentInputStream(d2);
+        if (PropertySet.isPropertySetStream(dis1) &&
+            PropertySet.isPropertySetStream(dis2))
+        {
+            final PropertySet ps1 = PropertySetFactory.create(dis1);
+            final PropertySet ps2 = PropertySetFactory.create(dis2);
+            equal = ps1.equals(ps2);
+            if (!equal)
+            {
+                msg.append("Property sets are not equal.\n");
+                return equal;
+            }
+        }
+        else
+        {
+            int i1;
+            int i2;
+            do
+            {
+                i1 = dis1.read();
+                i2 = dis2.read();
+                if (i1 != i2)
+                {
+                    equal = false;
+                    msg.append("Documents are not equal.\n");
+                    break;
+                }
+            }
+            while (equal && i1 == -1);
+        }
+        return true;
+    }
+
+
+
+    /**
+     * <p>This class does all the work. Its method {@link
+     * #processPOIFSReaderEvent(POIFSReaderEvent)} is called for each file in
+     * the original POI file system. Except for property set streams it copies
+     * everything unmodified to the destination POI filesystem. Property set
+     * streams are copied by creating a new {@link PropertySet} from the
+     * original property set by using the {@link
+     * MutablePropertySet#MutablePropertySet(PropertySet) constructor.</p>
+     */
+    static class CopyFile implements POIFSReaderListener
+    {
+        String dstName;
+        OutputStream out;
+        POIFSFileSystem poiFs;
+
+
+        /**
+         * <p>The constructor of a {@link CopyFile} instance creates the target
+         * POIFS. It also stores the name of the file the POIFS will be written
+         * to once it is complete.</p>
+         * 
+         * @param dstName The name of the disk file the destination POIFS is to
+         * be written to.
+         * @throws FileNotFoundException
+         */
+        public CopyFile(final String dstName)
+        {
+            this.dstName = dstName;
+            poiFs = new POIFSFileSystem();
+        }
+
+
+        /**
+         * <p>The method is called by POI's eventing API for each file in the
+         * origin POIFS.</p>
+         */
+        public void processPOIFSReaderEvent(final POIFSReaderEvent event)
+        {
+            /* The following declarations are shortcuts for accessing the
+             * "event" object. */
+            final POIFSDocumentPath path = event.getPath();
+            final String name = event.getName();
+            final DocumentInputStream stream = event.getStream();
+
+            Throwable t = null;
+
+            try
+            {
+                /* Find out whether the current document is a property set
+                 * stream or not. */
+                if (PropertySet.isPropertySetStream(stream))
+                {
+                    /* Yes, the current document is a property set stream.
+                     * Let's create a PropertySet instance from it. */
+                    PropertySet ps = null;
+                    try
+                    {
+                        ps = PropertySetFactory.create(stream);
+                    }
+                    catch (NoPropertySetStreamException ex)
+                    {
+                        /* This exception will not be thrown because we already
+                         * checked above. */
+                    }
+
+                    /* Copy the property set to the destination POI file
+                     * system. */
+                    copy(poiFs, path, name, ps);
+                }
+                else
+                    /* No, the current document is not a property set stream. We
+                     * copy it unmodified to the destination POIFS. */
+                    copy(poiFs, event.getPath(), event.getName(), stream);
+            }
+            catch (MarkUnsupportedException ex)
+            {
+                t = ex;
+            }
+            catch (IOException ex)
+            {
+                t = ex;
+            }
+            catch (WritingNotSupportedException ex)
+            {
+                t = ex;
+            }
+
+            /* According to the definition of the processPOIFSReaderEvent method
+             * we cannot pass checked exceptions to the caller. The following
+             * lines check whether a checked exception occured and throws an
+             * unchecked exception. The message of that exception is that of
+             * the underlying checked exception. */
+            if (t != null)
+            {
+                throw new HPSFRuntimeException
+                    ("Could not read file \"" + path + "/" + name +
+                     "\". Reason: " + Util.toString(t));
+            }
+        }
+
+
+
+        /**
+         * <p>Writes a {@link PropertySet} to a POI filesystem.</p>
+         *
+         * @param poiFs The POI filesystem to write to.
+         * @param path The file's path in the POI filesystem.
+         * @param name The file's name in the POI filesystem.
+         * @param ps The property set to write.
+         */
+        public void copy(final POIFSFileSystem poiFs,
+                         final POIFSDocumentPath path,
+                         final String name,
+                         final PropertySet ps)
+            throws WritingNotSupportedException, IOException
+        {
+            final DirectoryEntry de = getPath(poiFs, path);
+            final MutablePropertySet mps = new MutablePropertySet(ps);
+            de.createDocument(name, mps.toInputStream());
+        }
+
+
+
+        /**
+         * <p>Copies the bytes from a {@link DocumentInputStream} to a new
+         * stream in a POI filesystem.</p>
+         *
+         * @param poiFs The POI filesystem to write to.
+         * @param path The source document's path.
+         * @param stream The stream containing the source document.
+         */
+        public void copy(final POIFSFileSystem poiFs,
+                         final POIFSDocumentPath path,
+                         final String name,
+                         final DocumentInputStream stream) throws IOException
+        {
+            final DirectoryEntry de = getPath(poiFs, path);
+            final ByteArrayOutputStream out = new ByteArrayOutputStream();
+            int c;
+            while ((c = stream.read()) != -1)
+                out.write(c);
+            stream.close();
+            out.close();
+            final InputStream in =
+                new ByteArrayInputStream(out.toByteArray());
+            de.createDocument(name, in);
+        }
+
+
+        /**
+         * <p>Writes the POI file system to a disk file.</p>
+         *
+         * @throws FileNotFoundException
+         * @throws IOException
+         */
+        public void close() throws FileNotFoundException, IOException
+        {
+            out = new FileOutputStream(dstName);
+            poiFs.writeFilesystem(out);
+            out.close();
+        }
+
+
+
+        /** Contains the directory paths that have already been created in the
+         * output POI filesystem and maps them to their corresponding
+         * {@link org.apache.poi.poifs.filesystem.DirectoryNode}s. */
+        private final Map paths = new HashMap();
+
+
+
+        /**
+         * <p>Ensures that the directory hierarchy for a document in a POI
+         * fileystem is in place. When a document is to be created somewhere in
+         * a POI filesystem its directory must be created first. This method
+         * creates all directories between the POI filesystem root and the
+         * directory the document should belong to which do not yet exist.</p>
+         * 
+         * <p>Unfortunately POI does not offer a simple method to interrogate
+         * the POIFS whether a certain child node (file or directory) exists in
+         * a directory. However, since we always start with an empty POIFS which
+         * contains the root directory only and since each directory in the
+         * POIFS is created by this method we can maintain the POIFS's directory
+         * hierarchy ourselves: The {@link DirectoryEntry} of each directory
+         * created is stored in a {@link Map}. The directories' path names map
+         * to the corresponding {@link DirectoryEntry} instances.</p>
+         *
+         * @param poiFs The POI filesystem the directory hierarchy is created
+         * in, if needed.
+         * @param path The document's path. This method creates those directory
+         * components of this hierarchy which do not yet exist.
+         * @return The directory entry of the document path's parent. The caller
+         * should use this {@link DirectoryEntry} to create documents in it.
+         */
+        public DirectoryEntry getPath(final POIFSFileSystem poiFs,
+                                      final POIFSDocumentPath path)
+        {
+            try
+            {
+                /* Check whether this directory has already been created. */
+                final String s = path.toString();
+                DirectoryEntry de = (DirectoryEntry) paths.get(s);
+                if (de != null)
+                    /* Yes: return the corresponding DirectoryEntry. */
+                    return de;
+
+                /* No: We have to create the directory - or return the root's
+                 * DirectoryEntry. */
+                int l = path.length();
+                if (l == 0)
+                    /* Get the root directory. It does not have to be created
+                     * since it always exists in a POIFS. */
+                    de = poiFs.getRoot();
+                else
+                {
+                    /* Create a subordinate directory. The first step is to
+                     * ensure that the parent directory exists: */
+                    de = getPath(poiFs, path.getParent());
+                    /* Now create the target directory: */
+                    de = de.createDirectory(path.getComponent
+                                            (path.length() - 1));
+                }
+                paths.put(s, de);
+                return de;
+            }
+            catch (IOException ex)
+            {
+                /* This exception will be thrown if the directory already
+                 * exists. However, since we have full control about directory
+                 * creation we can ensure that this will never happen. */
+                ex.printStackTrace(System.err);
+                throw new RuntimeException(ex);
+            }
+        }
+    }
+
+}
index 93853f45adb156a9e82ef652eec43372bf00f19c..dc0376e5e6cfc0ef538df94eb61a49abc00a823f 100644 (file)
@@ -70,13 +70,13 @@ import org.apache.poi.poifs.eventfilesystem.POIFSReaderListener;
 import org.apache.poi.util.HexDump;
 
 /**
- * <p>Sample application showing how to read a custom property set of
- * a document. Call it with the document's file name as command line
- * parameter.</p>
+ * <p>Sample application showing how to read a document's custom property set.
+ * Call it with the document's file name as command-line parameter.</p>
  *
  * <p>Explanations can be found in the HPSF HOW-TO.</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-01
  */
index fcd61542e14a167a6a0db6a0e6987b0c99787e94..5d4ef3b94786f2ad94cc70be8ea4ae6f3ef547c3 100644 (file)
@@ -70,7 +70,8 @@ import org.apache.poi.poifs.eventfilesystem.POIFSReaderListener;
  *
  * <p>Explanations can be found in the HPSF HOW-TO.</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-01
  */
index d0b203dfddb726dae2c8c944aaac345e2862b700..dd550dae0166d9214a1ae67e401458f1a7040a29 100644 (file)
@@ -118,7 +118,8 @@ import org.apache.poi.poifs.filesystem.POIFSFileSystem;
  * 
  * <p>Further explanations can be found in the HPSF HOW-TO.</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-09-01
  */
index df85917e68b77eeef40485005ea0364f36c6af56..2b1367cb1926f3a456e38dd24aad63c9fc38d56f 100644 (file)
@@ -72,7 +72,8 @@ import org.apache.poi.poifs.filesystem.POIFSFileSystem;
  * <p>This class is a simple sample application showing how to create a property
  * set and write it to disk.</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-09-12
  */
index efe74015c3de3fcf0437c04bcc06ac03485d8190..dcbea1b60df2fa4606ec9617f861a1b80788aa90 100644 (file)
@@ -504,7 +504,77 @@ public class Section
             return false;
         if (s.getPropertyCount() != getPropertyCount())
             return false;
-        return Util.equals(s.getProperties(), getProperties());
+
+        /* Compare all properties except 0 and 1 as they must be handled 
+         * specially. */
+        Property[] pa1 = new Property[getProperties().length];
+        Property[] pa2 = new Property[s.getProperties().length];
+        System.arraycopy(getProperties(), 0, pa1, 0, pa1.length);
+        System.arraycopy(s.getProperties(), 0, pa2, 0, pa2.length);
+
+        /* Extract properties 0 and 1 and remove them from the copy of the
+         * arrays. */
+        Property p10 = null;
+        Property p11;
+        Property p20 = null;
+        Property p21;
+        for (int i = 0; i < pa1.length; i++)
+        {
+            final long id = pa1[i].getID();
+            if (id == 0)
+            {
+                p10 = pa1[i];
+                pa1 = remove(pa1, i);
+                i--;
+            }
+            if (id == 1)
+            {
+                p11 = pa1[i];
+                pa1 = remove(pa1, i);
+                i--;
+            }
+        }
+        for (int i = 0; i < pa2.length; i++)
+        {
+            final long id = pa2[i].getID();
+            if (id == 0)
+            {
+                p20 = pa2[i];
+                pa2 = remove(pa2, i);
+                i--;
+            }
+            if (id == 1)
+            {
+                p21 = pa2[i];
+                pa2 = remove(pa2, i);
+                i--;
+            }
+        }
+
+        boolean dictionaryEqual = true;
+        if (p10 != null && p20 != null)
+            dictionaryEqual = p10.getValue().equals(p20.getValue());
+        else if (p10 != null || p20 != null)
+            dictionaryEqual = false;
+        if (!dictionaryEqual)
+            return false;
+        else
+            return Util.equals(pa1, pa2);
+    }
+
+
+
+    /**
+     * <p>Removes a field from a property array. The resulting array is
+     * compactified and returned.</p>
+     */
+    private Property[] remove(final Property[] pa, final int i)
+    {
+        final Property[] h = new Property[pa.length - 1];
+        if (i > 0)
+            System.arraycopy(pa, 0, h, 0, i);
+        System.arraycopy(pa, i + 1, h, i, h.length - i);
+        return h;
     }
 
 
index c3ec9492470d229a0a421347feb99d8a28179b39..dc9454c2c1242bac10a47414c1729b0e219c5d4b 100644 (file)
@@ -263,13 +263,17 @@ public class Util
     {
         for (int i1 = 0; i1 < o1.length; i1++)
         {
+            final Object obj1 = o1[i1];
             boolean matchFound = false;
             for (int i2 = 0; !matchFound && i2 < o1.length; i2++)
-                if (o1[i1].equals(o2[i2]))
+            {
+                final Object obj2 = o2[i2];
+                if (obj1.equals(obj2))
                 {
                     matchFound = true;
                     o2[i2] = null;
                 }
+            }
             if (!matchFound)
                 return false;
         }
diff --git a/src/testcases/org/apache/poi/hpsf/data/Test0313rur.adm b/src/testcases/org/apache/poi/hpsf/data/Test0313rur.adm
new file mode 100644 (file)
index 0000000..1e1f954
Binary files /dev/null and b/src/testcases/org/apache/poi/hpsf/data/Test0313rur.adm differ
diff --git a/src/testcases/org/apache/poi/hpsf/data/TestEditTime.doc b/src/testcases/org/apache/poi/hpsf/data/TestEditTime.doc
new file mode 100644 (file)
index 0000000..8b30417
Binary files /dev/null and b/src/testcases/org/apache/poi/hpsf/data/TestEditTime.doc differ
diff --git a/src/testcases/org/apache/poi/hpsf/data/TestMickey.doc b/src/testcases/org/apache/poi/hpsf/data/TestMickey.doc
new file mode 100644 (file)
index 0000000..f62ade3
Binary files /dev/null and b/src/testcases/org/apache/poi/hpsf/data/TestMickey.doc differ