- Comparing sections refined: For the dictionary (property 0) only the value (Map) is relevant. The dictionary's codepage (property 1) is disregarded.

- 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
This commit is contained in:
Rainer Klute 2003-09-20 15:43:08 +00:00
parent ac57389456
commit 8bd4b39387
11 changed files with 666 additions and 23 deletions

View File

@ -700,16 +700,16 @@ No property set stream: "/1Table"</source>
<tr> <tr>
<td>0</td> <td>0</td>
<td>The property's value is a <strong>dictionary</strong>, i.e. a <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>
<tr> <tr>
<td>1</td> <td>1</td>
<td>The property's value is the number of a <strong>codepage</strong>, <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 i.e. a mapping from character codes to characters. All strings in the
section containing this property must be interpreted using this section containing this property must be interpreted using this
codepage. Typical property values are 1252 (8-bit "western" characters) codepage. Typical property values are 1252 (8-bit "western" characters)
or 1200 (16-bit Unicode characters).</td> or 1200 (16-bit Unicode characters).</td>
</tr> </tr>
</table> </table>
</section> </section>
@ -1036,15 +1036,15 @@ final String fileName = args[0];</source>
<p>The <code>MutableSection</code> the sample application retrieved from <p>The <code>MutableSection</code> the sample application retrieved from
the <code>MutablePropertySet</code> is still empty. It contains no the <code>MutablePropertySet</code> is still empty. It contains no
properties and does not have a format ID. As you have read <link 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 href="#sec3">above</link> the format ID of the first section in a
determines the property set's type. Since our property set should become property set determines the property set's type. Since our property set
a SummaryInformation property set we have to set the format ID of its should become a SummaryInformation property set we have to set the format
first (and only) section to ID of its first (and only) section to
<code>F29F85E0-4FF9-1068-AB-91-08-00-2B-27-B3-D9</code>. However, you <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 won't have to remember that ID: HPSF has it defined as the well-known
constant <code>SectionIDMap.SUMMARY_INFORMATION_ID</code>. The sample constant <code>SectionIDMap.SUMMARY_INFORMATION_ID</code>. The sample
application writes it to the section using the application writes it to the section using the
<code>setFormatID(byte[])</code> method:</p> <code>setFormatID(byte[])</code> method:</p>
<source>ms.setFormatID(SectionIDMap.SUMMARY_INFORMATION_ID);</source> <source>ms.setFormatID(SectionIDMap.SUMMARY_INFORMATION_ID);</source>

View File

@ -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);
}
}
}
}

View File

@ -70,13 +70,13 @@ import org.apache.poi.poifs.eventfilesystem.POIFSReaderListener;
import org.apache.poi.util.HexDump; import org.apache.poi.util.HexDump;
/** /**
* <p>Sample application showing how to read a custom property set of * <p>Sample application showing how to read a document's custom property set.
* a document. Call it with the document's file name as command line * Call it with the document's file name as command-line parameter.</p>
* parameter.</p>
* *
* <p>Explanations can be found in the HPSF HOW-TO.</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$ * @version $Id$
* @since 2003-02-01 * @since 2003-02-01
*/ */

View File

@ -70,7 +70,8 @@ import org.apache.poi.poifs.eventfilesystem.POIFSReaderListener;
* *
* <p>Explanations can be found in the HPSF HOW-TO.</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$ * @version $Id$
* @since 2003-02-01 * @since 2003-02-01
*/ */

View File

@ -118,7 +118,8 @@ import org.apache.poi.poifs.filesystem.POIFSFileSystem;
* *
* <p>Further explanations can be found in the HPSF HOW-TO.</p> * <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$ * @version $Id$
* @since 2003-09-01 * @since 2003-09-01
*/ */

View 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 * <p>This class is a simple sample application showing how to create a property
* set and write it to disk.</p> * 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$ * @version $Id$
* @since 2003-09-12 * @since 2003-09-12
*/ */

View File

@ -504,7 +504,77 @@ public class Section
return false; return false;
if (s.getPropertyCount() != getPropertyCount()) if (s.getPropertyCount() != getPropertyCount())
return false; 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;
} }

View File

@ -263,13 +263,17 @@ public class Util
{ {
for (int i1 = 0; i1 < o1.length; i1++) for (int i1 = 0; i1 < o1.length; i1++)
{ {
final Object obj1 = o1[i1];
boolean matchFound = false; boolean matchFound = false;
for (int i2 = 0; !matchFound && i2 < o1.length; i2++) 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; matchFound = true;
o2[i2] = null; o2[i2] = null;
} }
}
if (!matchFound) if (!matchFound)
return false; return false;
} }

Binary file not shown.

Binary file not shown.