HPSF writing capability added.
git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@353321 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
aeaa6a0856
commit
f85ef3c94e
@ -61,7 +61,8 @@ package org.apache.poi.hpsf;
|
|||||||
* order. Instead, it is a double word (4 bytes) followed by two
|
* order. Instead, it is a double word (4 bytes) followed by two
|
||||||
* words (2 bytes each) followed by 8 bytes.</p>
|
* words (2 bytes each) followed by 8 bytes.</p>
|
||||||
*
|
*
|
||||||
* @author Rainer Klute (klute@rainer-klute.de)
|
* @author Rainer Klute <a
|
||||||
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
* @since 2002-02-09
|
* @since 2002-02-09
|
||||||
*/
|
*/
|
||||||
@ -228,4 +229,14 @@ public class ClassID
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Object#hashCode()
|
||||||
|
*/
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException("FIXME: Not yet implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,8 @@ import org.apache.poi.hpsf.wellknown.PropertyIDMap;
|
|||||||
* <p>Convenience class representing a DocumentSummary Information stream in a
|
* <p>Convenience class representing a DocumentSummary Information stream in a
|
||||||
* Microsoft Office document.</p>
|
* Microsoft Office document.</p>
|
||||||
*
|
*
|
||||||
* @author Rainer Klute (klute@rainer-klute.de)
|
* @author Rainer Klute <a
|
||||||
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
* @author Drew Varner (Drew.Varner closeTo sc.edu)
|
* @author Drew Varner (Drew.Varner closeTo sc.edu)
|
||||||
* @see SummaryInformation
|
* @see SummaryInformation
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
@ -289,7 +290,7 @@ public class DocumentSummaryInformation extends SpecialPropertySet
|
|||||||
* <p>Returns <code>true</code> if the custom links are hampered
|
* <p>Returns <code>true</code> if the custom links are hampered
|
||||||
* by excessive noise, for all applications.</p> <p>
|
* by excessive noise, for all applications.</p> <p>
|
||||||
*
|
*
|
||||||
* <strong>FIXME:</strong> Explain this some more! I (Rainer)
|
* <strong>FIXME (3):</strong> Explain this some more! I (Rainer)
|
||||||
* don't understand it.</p>
|
* don't understand it.</p>
|
||||||
*
|
*
|
||||||
* @return The linksDirty value
|
* @return The linksDirty value
|
||||||
|
@ -59,7 +59,8 @@ package org.apache.poi.hpsf;
|
|||||||
* thrown in this package. It supports a nested "reason" throwable,
|
* thrown in this package. It supports a nested "reason" throwable,
|
||||||
* i.e. an exception that caused this one to be thrown.</p>
|
* i.e. an exception that caused this one to be thrown.</p>
|
||||||
*
|
*
|
||||||
* @author Rainer Klute (klute@rainer-klute.de)
|
* @author Rainer Klute <a
|
||||||
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
* @since 2002-02-09
|
* @since 2002-02-09
|
||||||
*/
|
*/
|
||||||
|
@ -54,12 +54,16 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.poi.hpsf;
|
package org.apache.poi.hpsf;
|
||||||
|
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>This exception is the superclass of all other unchecked
|
* <p>This exception is the superclass of all other unchecked
|
||||||
* exceptions thrown in this package. It supports a nested "reason"
|
* exceptions thrown in this package. It supports a nested "reason"
|
||||||
* throwable, i.e. an exception that caused this one to be thrown.</p>
|
* throwable, i.e. an exception that caused this one to be thrown.</p>
|
||||||
*
|
*
|
||||||
* @author Rainer Klute (klute@rainer-klute.de)
|
* @author Rainer Klute <a
|
||||||
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
* @since 2002-02-09
|
* @since 2002-02-09
|
||||||
*/
|
*/
|
||||||
@ -138,4 +142,46 @@ public class HPSFRuntimeException extends RuntimeException
|
|||||||
return reason;
|
return reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Throwable#printStackTrace()
|
||||||
|
*/
|
||||||
|
public void printStackTrace()
|
||||||
|
{
|
||||||
|
printStackTrace(System.err);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Throwable#printStackTrace(java.io.PrintStream)
|
||||||
|
*/
|
||||||
|
public void printStackTrace(final PrintStream p)
|
||||||
|
{
|
||||||
|
final Throwable reason = getReason();
|
||||||
|
super.printStackTrace(p);
|
||||||
|
if (reason != null)
|
||||||
|
{
|
||||||
|
p.println("Caused by:");
|
||||||
|
reason.printStackTrace(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Throwable#printStackTrace(java.io.PrintWriter)
|
||||||
|
*/
|
||||||
|
public void printStackTrace(final PrintWriter p)
|
||||||
|
{
|
||||||
|
final Throwable reason = getReason();
|
||||||
|
super.printStackTrace(p);
|
||||||
|
if (reason != null)
|
||||||
|
{
|
||||||
|
p.println("Caused by:");
|
||||||
|
reason.printStackTrace(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,8 @@ package org.apache.poi.hpsf;
|
|||||||
* <p>This exception is thrown if an {@link java.io.InputStream} does
|
* <p>This exception is thrown if an {@link java.io.InputStream} does
|
||||||
* not support the {@link java.io.InputStream#mark} operation.</p>
|
* not support the {@link java.io.InputStream#mark} operation.</p>
|
||||||
*
|
*
|
||||||
* @author Rainer Klute (klute@rainer-klute.de)
|
* @author Rainer Klute <a
|
||||||
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
* @since 2002-02-09
|
* @since 2002-02-09
|
||||||
*/
|
*/
|
||||||
|
85
src/java/org/apache/poi/hpsf/MutableProperty.java
Normal file
85
src/java/org/apache/poi/hpsf/MutableProperty.java
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
package org.apache.poi.hpsf;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Adds writing capability to the {@link Property} class.</p>
|
||||||
|
*
|
||||||
|
* <p>Please be aware that this class' functionality will be merged into the
|
||||||
|
* {@link Property} class at a later time, so the API will change.</p>
|
||||||
|
*
|
||||||
|
* @author Rainer Klute <a
|
||||||
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
|
* @since 2003-08-03
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class MutableProperty extends Property
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Creates an empty property. It must be filled using the set method to
|
||||||
|
* be usable.</p>
|
||||||
|
*/
|
||||||
|
public MutableProperty()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the property's ID.</p>
|
||||||
|
*
|
||||||
|
* @param id the ID
|
||||||
|
*/
|
||||||
|
public void setID(final long id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the property's type.</p>
|
||||||
|
*
|
||||||
|
* @param type the property's type
|
||||||
|
*/
|
||||||
|
public void setType(final long type)
|
||||||
|
{
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the property's value.</p>
|
||||||
|
*
|
||||||
|
* @param value the property's value
|
||||||
|
*/
|
||||||
|
public void setValue(final Object value)
|
||||||
|
{
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Writes the property to an output stream.</p>
|
||||||
|
*
|
||||||
|
* @param out The output stream to write to.
|
||||||
|
* @return the number of bytes written to the stream
|
||||||
|
*
|
||||||
|
* @exception IOException if an I/O error occurs
|
||||||
|
* @exception WritingNotSupportedException if a variant type is to be
|
||||||
|
* written that is not yet supported
|
||||||
|
*/
|
||||||
|
public int write(final OutputStream out)
|
||||||
|
throws IOException, WritingNotSupportedException
|
||||||
|
{
|
||||||
|
int length = 0;
|
||||||
|
long variantType = getType();
|
||||||
|
length += TypeWriter.writeUIntToStream(out, variantType);
|
||||||
|
length += VariantSupport.write(out, variantType, getValue());
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
243
src/java/org/apache/poi/hpsf/MutablePropertySet.java
Normal file
243
src/java/org/apache/poi/hpsf/MutablePropertySet.java
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
/*
|
||||||
|
* ====================================================================
|
||||||
|
* The Apache Software License, Version 1.1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003 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;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.ListIterator;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.util.LittleEndianConsts;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Adds writing support to the {@link PropertySet} class.</p>
|
||||||
|
*
|
||||||
|
* <p>Please be aware that this class' functionality will be merged into the
|
||||||
|
* {@link PropertySet} class at a later time, so the API will change.</p>
|
||||||
|
*
|
||||||
|
* @author Rainer Klute <a
|
||||||
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
|
* @version $Id$
|
||||||
|
* @since 2003-02-19
|
||||||
|
*/
|
||||||
|
public class MutablePropertySet extends PropertySet
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Constructs a <code>MutablePropertySet</code> instance. Its
|
||||||
|
* primary task is to initialize the immutable field with their proper
|
||||||
|
* values. It also sets fields that might change to reasonable defaults.</p>
|
||||||
|
*/
|
||||||
|
public MutablePropertySet()
|
||||||
|
{
|
||||||
|
/* Initialize the "byteOrder" field. */
|
||||||
|
byteOrder = LittleEndian.getUShort(BYTE_ORDER_ASSERTION);
|
||||||
|
|
||||||
|
/* Initialize the "format" field. */
|
||||||
|
format = LittleEndian.getUShort(FORMAT_ASSERTION);
|
||||||
|
|
||||||
|
/* Initialize "osVersion" field as if the property has been created on
|
||||||
|
* a Win32 platform, whether this is the case or not. */
|
||||||
|
osVersion = (OS_WIN32 << 16) | 0x0A04;
|
||||||
|
|
||||||
|
/* Initailize the "classID" field. */
|
||||||
|
classID = new ClassID();
|
||||||
|
|
||||||
|
/* Initialize the sections. Since property set must have at least
|
||||||
|
* one section it is added right here. */
|
||||||
|
sections = new LinkedList();
|
||||||
|
sections.add(new MutableSection());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>The length of the property set stream header.</p>
|
||||||
|
*/
|
||||||
|
private final int OFFSET_HEADER =
|
||||||
|
BYTE_ORDER_ASSERTION.length + /* Byte order */
|
||||||
|
FORMAT_ASSERTION.length + /* Format */
|
||||||
|
LittleEndianConsts.INT_SIZE + /* OS version */
|
||||||
|
ClassID.LENGTH + /* Class ID */
|
||||||
|
LittleEndianConsts.INT_SIZE; /* Section count */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the "byteOrder" property.</p>
|
||||||
|
*
|
||||||
|
* @param byteOrder the byteOrder value to set
|
||||||
|
*/
|
||||||
|
public void setByteOrder(final int byteOrder)
|
||||||
|
{
|
||||||
|
this.byteOrder = byteOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the "format" property.</p>
|
||||||
|
*
|
||||||
|
* @param format the format value to set
|
||||||
|
*/
|
||||||
|
public void setFormat(final int format)
|
||||||
|
{
|
||||||
|
this.format = format;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the "osVersion" property.</p>
|
||||||
|
*
|
||||||
|
* @param osVersion the osVersion value to set
|
||||||
|
*/
|
||||||
|
public void setOSVersion(final int osVersion)
|
||||||
|
{
|
||||||
|
this.osVersion = osVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the property set stream's low-level "class ID"
|
||||||
|
* field.</p>
|
||||||
|
*
|
||||||
|
* @param classID The property set stream's low-level "class ID" field.
|
||||||
|
*
|
||||||
|
* @see #getClassID
|
||||||
|
*/
|
||||||
|
public void setClassID(final ClassID classID)
|
||||||
|
{
|
||||||
|
this.classID = classID;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes all sections from this property set.</p>
|
||||||
|
*/
|
||||||
|
public void clearSections()
|
||||||
|
{
|
||||||
|
sections = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Adds a section to this property set.</p>
|
||||||
|
*
|
||||||
|
* @param section The {@link Section} to add. It will be appended
|
||||||
|
* after any sections that are already present in the property set
|
||||||
|
* and thus become the last section.
|
||||||
|
*/
|
||||||
|
public void addSection(final Section section)
|
||||||
|
{
|
||||||
|
if (sections == null)
|
||||||
|
sections = new LinkedList();
|
||||||
|
sections.add(section);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Writes the property set to an output stream.</p>
|
||||||
|
*
|
||||||
|
* @param out the output stream to write the section to
|
||||||
|
* @exception IOException if an error when writing to the output stream
|
||||||
|
* occurs
|
||||||
|
* @exception WritingNotSupportedException if HPSF does not yet support
|
||||||
|
* writing a property's variant type.
|
||||||
|
*/
|
||||||
|
public void write(final OutputStream out)
|
||||||
|
throws WritingNotSupportedException, IOException
|
||||||
|
{
|
||||||
|
/* Write the number of sections in this property set stream. */
|
||||||
|
final int nrSections = sections.size();
|
||||||
|
int length = 0;
|
||||||
|
|
||||||
|
/* Write the property set's header. */
|
||||||
|
length += TypeWriter.writeToStream(out, (short) getByteOrder());
|
||||||
|
length += TypeWriter.writeToStream(out, (short) getFormat());
|
||||||
|
length += TypeWriter.writeToStream(out, (int) getOSVersion());
|
||||||
|
length += TypeWriter.writeToStream(out, getClassID());
|
||||||
|
length += TypeWriter.writeToStream(out, (int) nrSections);
|
||||||
|
int offset = OFFSET_HEADER;
|
||||||
|
|
||||||
|
/* Write the section list, i.e. the references to the sections. Each
|
||||||
|
* entry in the section list consist of a class ID and the offset to the
|
||||||
|
* section's begin. */
|
||||||
|
offset += nrSections * (ClassID.LENGTH + LittleEndian.INT_SIZE);
|
||||||
|
final int sectionsBegin = offset;
|
||||||
|
for (final ListIterator i = sections.listIterator(); i.hasNext();)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) i.next();
|
||||||
|
length += TypeWriter.writeToStream(out, s.getFormatID());
|
||||||
|
length += TypeWriter.writeUIntToStream(out, offset);
|
||||||
|
offset += s.getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the sections themselves. */
|
||||||
|
offset = sectionsBegin;
|
||||||
|
for (final ListIterator i = sections.listIterator(); i.hasNext();)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) i.next();
|
||||||
|
offset = s.write(out, offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
426
src/java/org/apache/poi/hpsf/MutableSection.java
Normal file
426
src/java/org/apache/poi/hpsf/MutableSection.java
Normal file
@ -0,0 +1,426 @@
|
|||||||
|
/*
|
||||||
|
* ====================================================================
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.util.LittleEndianConsts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Adds writing capability to the {@link Section} class.</p>
|
||||||
|
*
|
||||||
|
* <p>Please be aware that this class' functionality will be merged into the
|
||||||
|
* {@link Section} class at a later time, so the API will change.</p>
|
||||||
|
*
|
||||||
|
* @author Rainer Klute <a
|
||||||
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
|
* @version $Id$
|
||||||
|
* @since 2002-02-20
|
||||||
|
*/
|
||||||
|
public class MutableSection extends Section
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>If the "dirty" flag is true, the section's size must be
|
||||||
|
* (re-)calculated before the section is written.</p>
|
||||||
|
*/
|
||||||
|
private boolean dirty = true;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>List to assemble the properties. Unfortunately a wrong
|
||||||
|
* decision has been taken when specifying the "properties" field
|
||||||
|
* as an Property[]. It should have been a {@link java.util.List}.</p>
|
||||||
|
*/
|
||||||
|
private List preprops;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Creates an empty mutable section.</p>
|
||||||
|
*/
|
||||||
|
public MutableSection()
|
||||||
|
{
|
||||||
|
dirty = true;
|
||||||
|
formatID = null;
|
||||||
|
offset = -1;
|
||||||
|
preprops = new LinkedList();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the section's format ID.</p>
|
||||||
|
*
|
||||||
|
* @param formatID The section's format ID
|
||||||
|
*
|
||||||
|
* @see #setFormatID(byte[])
|
||||||
|
* @see #getFormatID
|
||||||
|
*/
|
||||||
|
public void setFormatID(final ClassID formatID)
|
||||||
|
{
|
||||||
|
this.formatID = formatID;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the section's format ID.</p>
|
||||||
|
*
|
||||||
|
* @param formatID The section's format ID as a byte array. It components
|
||||||
|
* are in big-endian format.
|
||||||
|
*
|
||||||
|
* @see #setFormatID(ClassID)
|
||||||
|
* @see #getFormatID
|
||||||
|
*/
|
||||||
|
public void setFormatID(final byte[] formatID)
|
||||||
|
{
|
||||||
|
setFormatID(new ClassID(formatID, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets this section's properties. Any former values are overwritten.</p>
|
||||||
|
*
|
||||||
|
* @param properties This section's new properties.
|
||||||
|
*/
|
||||||
|
public void setProperties(final Property[] properties)
|
||||||
|
{
|
||||||
|
preprops = new LinkedList();
|
||||||
|
for (int i = 0; i < properties.length; i++)
|
||||||
|
preprops.add(properties[i]);
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the value of the property with the specified ID. If a
|
||||||
|
* property with this ID is not yet present in the section, it
|
||||||
|
* will be added. An already present property with the specified
|
||||||
|
* ID will be overwritten.</p>
|
||||||
|
*
|
||||||
|
* @param id The property's ID
|
||||||
|
* @param value The property's value. It will be written as a Unicode
|
||||||
|
* string.
|
||||||
|
*
|
||||||
|
* @see #setProperty(int, int, Object)
|
||||||
|
* @see #getProperty
|
||||||
|
*/
|
||||||
|
public void setProperty(final int id, final String value)
|
||||||
|
{
|
||||||
|
setProperty(id, Variant.VT_LPWSTR, value);
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the value and the variant type of the property with the
|
||||||
|
* specified ID. If a property with this ID is not yet present in
|
||||||
|
* the section, it will be added. An already present property with
|
||||||
|
* the specified ID will be overwritten. A default mapping will be
|
||||||
|
* used to choose the property's type.</p>
|
||||||
|
*
|
||||||
|
* @param id The property's ID.
|
||||||
|
* @param variantType The property's variant type.
|
||||||
|
* @param value The property's value.
|
||||||
|
*
|
||||||
|
* @see #setProperty(int, Object)
|
||||||
|
* @see #getProperty
|
||||||
|
* @see Variant
|
||||||
|
*/
|
||||||
|
public void setProperty(final int id, final long variantType,
|
||||||
|
final Object value)
|
||||||
|
{
|
||||||
|
final MutableProperty p = new MutableProperty();
|
||||||
|
p.setID(id);
|
||||||
|
p.setType(variantType);
|
||||||
|
p.setValue(value);
|
||||||
|
setProperty(p);
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets a property. If a property with the same ID is not yet present in
|
||||||
|
* the section, the property will be added to the section. If there is
|
||||||
|
* already a property with the same ID present in the section, it will be
|
||||||
|
* overwritten.</p>
|
||||||
|
*
|
||||||
|
* @param p The property to be added to the section
|
||||||
|
*
|
||||||
|
* @see #setProperty(int, int, Object)
|
||||||
|
* @see #setProperty(int, String)
|
||||||
|
* @see #getProperty
|
||||||
|
* @see Variant
|
||||||
|
*/
|
||||||
|
public void setProperty(final Property p)
|
||||||
|
{
|
||||||
|
final long id = p.getID();
|
||||||
|
for (final Iterator i = preprops.iterator(); i.hasNext();)
|
||||||
|
if (((Property) i.next()).getID() == id)
|
||||||
|
{
|
||||||
|
i.remove();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
preprops.add(p);
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the value of the boolean property with the specified
|
||||||
|
* ID.</p>
|
||||||
|
*
|
||||||
|
* @param id The property's ID
|
||||||
|
* @param value The property's value
|
||||||
|
*
|
||||||
|
* @see #setProperty(int, int, Object)
|
||||||
|
* @see #getProperty
|
||||||
|
* @see Variant
|
||||||
|
*/
|
||||||
|
protected void setPropertyBooleanValue(final int id, final boolean value)
|
||||||
|
{
|
||||||
|
setProperty(id, (long) Variant.VT_BOOL, new Boolean(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns the section's size.</p>
|
||||||
|
*
|
||||||
|
* @return the section's size.
|
||||||
|
*/
|
||||||
|
public int getSize()
|
||||||
|
{
|
||||||
|
if (dirty)
|
||||||
|
{
|
||||||
|
size = calcSize();
|
||||||
|
dirty = false;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Calculates the section's size. It is the sum of the lengths of the
|
||||||
|
* section's header (8), the properties list (16 times the number of
|
||||||
|
* properties) and the properties themselves.</p>
|
||||||
|
*
|
||||||
|
* @return the section's length in bytes.
|
||||||
|
*/
|
||||||
|
private int calcSize()
|
||||||
|
{
|
||||||
|
int length = 0;
|
||||||
|
|
||||||
|
/* The section header. */
|
||||||
|
length += LittleEndianConsts.INT_SIZE * 2;
|
||||||
|
|
||||||
|
/* The length of the property list. */
|
||||||
|
Property[] psa = getProperties();
|
||||||
|
if (psa == null)
|
||||||
|
psa = new MutableProperty[0];
|
||||||
|
length += psa.length * LittleEndianConsts.INT_SIZE * 3;
|
||||||
|
|
||||||
|
/* The sum of the lengths of the properties - it is calculated by simply
|
||||||
|
* writing the properties to a temporary byte array output stream: */
|
||||||
|
final ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||||
|
for (int i = 0; i < psa.length; i++)
|
||||||
|
{
|
||||||
|
final MutableProperty mp = new MutableProperty();
|
||||||
|
mp.setID(psa[i].getID());
|
||||||
|
mp.setType(psa[i].getType());
|
||||||
|
mp.setValue(psa[i].getValue());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
length += mp.write(b);
|
||||||
|
}
|
||||||
|
catch (WritingNotSupportedException ex)
|
||||||
|
{
|
||||||
|
/* It was not possible to write the property, not even as a
|
||||||
|
* byte array. We cannot do anything about that. Instead of the
|
||||||
|
* property we insert an empty one into the stream. */
|
||||||
|
mp.setType(Variant.VT_EMPTY);
|
||||||
|
mp.setValue(null);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
length += mp.write(b);
|
||||||
|
}
|
||||||
|
catch (Exception ex2)
|
||||||
|
{
|
||||||
|
/* Even writing an empty property went awfully wrong.
|
||||||
|
* Let's give up. */
|
||||||
|
throw new HPSFRuntimeException(ex2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
/* Should never occur. */
|
||||||
|
throw new HPSFRuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Writes this section into an output stream.</p>
|
||||||
|
*
|
||||||
|
* <p>Internally this is done by writing into three byte array output
|
||||||
|
* streams: one for the properties, one for the property list and one for
|
||||||
|
* the section as such. The two former are appended to the latter when they
|
||||||
|
* have received all their data.</p>
|
||||||
|
*
|
||||||
|
* @param out The stream to write into
|
||||||
|
* @param offset The offset from the beginning of the property set
|
||||||
|
* stream this section begins at
|
||||||
|
*
|
||||||
|
* @return The offset of the first byte following this section in
|
||||||
|
* the property set stream.
|
||||||
|
* @exception IOException if an I/O error occurs
|
||||||
|
* @exception WritingNotSupportedException if HPSF does not yet support
|
||||||
|
* writing a property's variant type.
|
||||||
|
*/
|
||||||
|
public int write(final OutputStream out, final int offset)
|
||||||
|
throws WritingNotSupportedException, IOException
|
||||||
|
{
|
||||||
|
/* The properties are written to this stream. */
|
||||||
|
final ByteArrayOutputStream propertyStream =
|
||||||
|
new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
/* The property list is established here. After each property that has
|
||||||
|
* been written to "propertyStream", a property list entry is written to
|
||||||
|
* "propertyListStream". */
|
||||||
|
final ByteArrayOutputStream propertyListStream =
|
||||||
|
new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
/* Maintain the current position in the list. */
|
||||||
|
int position = 0;
|
||||||
|
|
||||||
|
/* Increase the position variable by the size of the property list so
|
||||||
|
* that it points to the beginning of the properties themselves. */
|
||||||
|
position += 2 * LittleEndian.INT_SIZE +
|
||||||
|
getPropertyCount() * 2 * LittleEndian.INT_SIZE;
|
||||||
|
|
||||||
|
/* 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();
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
propertyStream.close();
|
||||||
|
propertyListStream.close();
|
||||||
|
|
||||||
|
/* Write the section: */
|
||||||
|
byte[] pb1 = propertyListStream.toByteArray();
|
||||||
|
byte[] pb2 = propertyStream.toByteArray();
|
||||||
|
TypeWriter.writeToStream(out, LittleEndian.INT_SIZE * 2 + pb1.length +
|
||||||
|
pb2.length);
|
||||||
|
TypeWriter.writeToStream(out, getPropertyCount());
|
||||||
|
out.write(pb1);
|
||||||
|
out.write(pb2);
|
||||||
|
|
||||||
|
return offset + position;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Overwrites the super class' method to cope with a redundancy:
|
||||||
|
* the property count is maintained in a separate member variable, but
|
||||||
|
* shouldn't.</p>
|
||||||
|
*
|
||||||
|
* @return The number of properties in this section
|
||||||
|
*/
|
||||||
|
public int getPropertyCount()
|
||||||
|
{
|
||||||
|
return preprops.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns this section's properties.</p>
|
||||||
|
*
|
||||||
|
* @return this section's properties.
|
||||||
|
*/
|
||||||
|
public Property[] getProperties()
|
||||||
|
{
|
||||||
|
return (Property[]) preprops.toArray(new Property[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -55,18 +55,16 @@
|
|||||||
package org.apache.poi.hpsf;
|
package org.apache.poi.hpsf;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>This exception is thrown if a format error in a property set stream is
|
||||||
|
* detected or when the input data do not constitute a property set stream.</p>
|
||||||
*
|
*
|
||||||
* This exception is thrown if a format error in a property set stream is
|
* <p>The constructors of this class are analogous to those of its superclass
|
||||||
* detected or when the input data do not constitute a property set stream.</p>
|
* and are documented there.</p>
|
||||||
* <p>
|
|
||||||
*
|
*
|
||||||
* The constructors of this class are analogous to those of its superclass and
|
* @author Rainer Klute <a
|
||||||
* documented there.</p>
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
*
|
* @version $Id$
|
||||||
*@author Rainer Klute (klute@rainer-klute.de)
|
* @since 2002-02-09
|
||||||
*@version $Id$
|
|
||||||
*@since 2002-02-09
|
|
||||||
*/
|
*/
|
||||||
public class NoPropertySetStreamException extends HPSFException
|
public class NoPropertySetStreamException extends HPSFException
|
||||||
{
|
{
|
||||||
@ -80,6 +78,7 @@ public class NoPropertySetStreamException extends HPSFException
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Constructor</p>
|
* <p>Constructor</p>
|
||||||
*
|
*
|
||||||
@ -91,6 +90,7 @@ public class NoPropertySetStreamException extends HPSFException
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Constructor</p>
|
* <p>Constructor</p>
|
||||||
*
|
*
|
||||||
@ -102,6 +102,7 @@ public class NoPropertySetStreamException extends HPSFException
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Constructor</p>
|
* <p>Constructor</p>
|
||||||
*
|
*
|
||||||
|
@ -63,7 +63,8 @@ package org.apache.poi.hpsf;
|
|||||||
* <p>The constructors of this class are analogous to those of its
|
* <p>The constructors of this class are analogous to those of its
|
||||||
* superclass and documented there.</p>
|
* superclass and documented there.</p>
|
||||||
*
|
*
|
||||||
* @author Rainer Klute (klute@rainer-klute.de)
|
* @author Rainer Klute <a
|
||||||
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
* @since 2002-02-09
|
* @since 2002-02-09
|
||||||
*/
|
*/
|
||||||
|
@ -63,8 +63,6 @@
|
|||||||
package org.apache.poi.hpsf;
|
package org.apache.poi.hpsf;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
@ -85,11 +83,13 @@ import org.apache.poi.util.LittleEndian;
|
|||||||
* value, {@link Variant#VT_FILETIME} some date and time (of a
|
* value, {@link Variant#VT_FILETIME} some date and time (of a
|
||||||
* file).</p>
|
* file).</p>
|
||||||
*
|
*
|
||||||
* <p><strong>FIXME:</strong> Reading is not implemented for all
|
* <p>Please note that not all {@link Variant} types yet. This might change
|
||||||
* {@link Variant} types yet. Feel free to submit error reports or
|
* over time but largely depends on your feedback so that the POI team knows
|
||||||
* patches for the types you need.</p>
|
* which variant types are really needed. So please feel free to submit error
|
||||||
|
* reports or patches for the types you need.</p>
|
||||||
*
|
*
|
||||||
* @author Rainer Klute (klute@rainer-klute.de)
|
* @author Rainer Klute <a
|
||||||
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
* @author Drew Varner (Drew.Varner InAndAround sc.edu)
|
* @author Drew Varner (Drew.Varner InAndAround sc.edu)
|
||||||
* @see Section
|
* @see Section
|
||||||
* @see Variant
|
* @see Variant
|
||||||
@ -103,7 +103,7 @@ public class Property
|
|||||||
private static final int CP_UNICODE = 1200;
|
private static final int CP_UNICODE = 1200;
|
||||||
|
|
||||||
/** <p>The property's ID.</p> */
|
/** <p>The property's ID.</p> */
|
||||||
protected int id;
|
protected long id;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -111,7 +111,7 @@ public class Property
|
|||||||
*
|
*
|
||||||
* @return The ID value
|
* @return The ID value
|
||||||
*/
|
*/
|
||||||
public int getID()
|
public long getID()
|
||||||
{
|
{
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@ -162,7 +162,7 @@ public class Property
|
|||||||
* @param codepage The section's and thus the property's
|
* @param codepage The section's and thus the property's
|
||||||
* codepage. It is needed only when reading string values.
|
* codepage. It is needed only when reading string values.
|
||||||
*/
|
*/
|
||||||
public Property(final int id, final byte[] src, final long offset,
|
public Property(final long id, final byte[] src, final long offset,
|
||||||
final int length, final int codepage)
|
final int length, final int codepage)
|
||||||
{
|
{
|
||||||
this.id = id;
|
this.id = id;
|
||||||
@ -187,7 +187,7 @@ public class Property
|
|||||||
}
|
}
|
||||||
catch (UnsupportedVariantTypeException ex)
|
catch (UnsupportedVariantTypeException ex)
|
||||||
{
|
{
|
||||||
logUnsupported(ex);
|
VariantSupport.writeUnsupportedTypeMessage(ex);
|
||||||
value = ex.getValue();
|
value = ex.getValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -281,15 +281,21 @@ public class Property
|
|||||||
* 4.</p>
|
* 4.</p>
|
||||||
*
|
*
|
||||||
* @return the property's size in bytes
|
* @return the property's size in bytes
|
||||||
|
*
|
||||||
|
* @exception WritingNotSupportedException if HPSF does not yet support the
|
||||||
|
* property's variant type.
|
||||||
*/
|
*/
|
||||||
protected int getSize()
|
protected int getSize() throws WritingNotSupportedException
|
||||||
{
|
{
|
||||||
int length = LittleEndian.INT_SIZE;
|
int length = VariantSupport.getVariantLength(type);
|
||||||
|
if (length >= 0)
|
||||||
|
return length; /* Fixed length */
|
||||||
|
if (length == -2)
|
||||||
|
/* Unknown length */
|
||||||
|
throw new WritingNotSupportedException(type, null);
|
||||||
|
|
||||||
|
/* Variable length: */
|
||||||
final int PADDING = 4; /* Pad to multiples of 4. */
|
final int PADDING = 4; /* Pad to multiples of 4. */
|
||||||
if (type > Integer.MAX_VALUE)
|
|
||||||
throw new HPSFRuntimeException
|
|
||||||
("Variant type " + type + " is greater than " +
|
|
||||||
Integer.MAX_VALUE + ".");
|
|
||||||
switch ((int) type)
|
switch ((int) type)
|
||||||
{
|
{
|
||||||
case Variant.VT_LPSTR:
|
case Variant.VT_LPSTR:
|
||||||
@ -304,9 +310,7 @@ public class Property
|
|||||||
case Variant.VT_EMPTY:
|
case Variant.VT_EMPTY:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new HPSFRuntimeException
|
throw new WritingNotSupportedException(type, value);
|
||||||
("Writing is not yet implemented for variant type " +
|
|
||||||
type + ". Please report this problem to the POI team!");
|
|
||||||
}
|
}
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
@ -318,27 +322,65 @@ public class Property
|
|||||||
*/
|
*/
|
||||||
public boolean equals(final Object o)
|
public boolean equals(final Object o)
|
||||||
{
|
{
|
||||||
throw new UnsupportedOperationException("FIXME: Not yet implemented.");
|
if (!(o instanceof Property))
|
||||||
|
return false;
|
||||||
|
final Property p = (Property) o;
|
||||||
|
final Object pValue = p.getValue();
|
||||||
|
if (id != p.getID() || 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();
|
||||||
|
if (!(valueClass.isAssignableFrom(pValueClass)) &&
|
||||||
|
!(pValueClass.isAssignableFrom(valueClass)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (value instanceof byte[])
|
||||||
|
return Util.equal((byte[]) value, (byte[]) pValue);
|
||||||
|
|
||||||
|
return value.equals(pValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Keeps a list of those variant types for those an "unsupported" message
|
* @see Object#hashCode()
|
||||||
* has already been issued.</p>
|
|
||||||
*/
|
*/
|
||||||
protected static List unsupportedMessage;
|
public int hashCode()
|
||||||
|
|
||||||
private static void logUnsupported(final UnsupportedVariantTypeException ex)
|
|
||||||
{
|
{
|
||||||
if (unsupportedMessage == null)
|
long hashCode = 0;
|
||||||
unsupportedMessage = new LinkedList();
|
hashCode += id;
|
||||||
Long vt = new Long(ex.getVariantType());
|
hashCode += type;
|
||||||
if (!unsupportedMessage.contains(vt))
|
if (value != null)
|
||||||
{
|
hashCode += value.hashCode();
|
||||||
System.err.println(ex.getMessage());
|
final int returnHashCode = (int) (hashCode & 0x0ffffffffL );
|
||||||
unsupportedMessage.add(vt);
|
return returnHashCode;
|
||||||
}
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
final StringBuffer b = new StringBuffer();
|
||||||
|
b.append(getClass().getName());
|
||||||
|
b.append('[');
|
||||||
|
b.append("id: ");
|
||||||
|
b.append(getID());
|
||||||
|
b.append(", type: ");
|
||||||
|
b.append(getType());
|
||||||
|
b.append(", value: ");
|
||||||
|
b.append(getValue());
|
||||||
|
b.append(']');
|
||||||
|
return b.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,6 @@ package org.apache.poi.hpsf;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.poi.hpsf.wellknown.SectionIDMap;
|
import org.apache.poi.hpsf.wellknown.SectionIDMap;
|
||||||
@ -91,7 +90,8 @@ import org.apache.poi.util.LittleEndian;
|
|||||||
* NoSingleSectionException} if the {@link PropertySet} contains more
|
* NoSingleSectionException} if the {@link PropertySet} contains more
|
||||||
* (or less) than exactly one {@link Section}).</p>
|
* (or less) than exactly one {@link Section}).</p>
|
||||||
*
|
*
|
||||||
* @author Rainer Klute (klute@rainer-klute.de)
|
* @author Rainer Klute <a
|
||||||
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
* @author Drew Varner (Drew.Varner hanginIn sc.edu)
|
* @author Drew Varner (Drew.Varner hanginIn sc.edu)
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
* @since 2002-02-09
|
* @since 2002-02-09
|
||||||
@ -397,7 +397,7 @@ public class PropertySet
|
|||||||
final int offset,
|
final int offset,
|
||||||
final int length)
|
final int length)
|
||||||
{
|
{
|
||||||
/* FIXME: Ensure that at most "length" bytes are read. */
|
/* FIXME (3): Ensure that at most "length" bytes are read. */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read the header fields of the stream. They must always be
|
* Read the header fields of the stream. They must always be
|
||||||
@ -442,7 +442,7 @@ public class PropertySet
|
|||||||
*/
|
*/
|
||||||
private void init(final byte[] src, final int offset, final int length)
|
private void init(final byte[] src, final int offset, final int length)
|
||||||
{
|
{
|
||||||
/* FIXME: Ensure that at most "length" bytes are read. */
|
/* FIXME (3): Ensure that at most "length" bytes are read. */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read the stream's header fields.
|
* Read the stream's header fields.
|
||||||
@ -645,6 +645,9 @@ public class PropertySet
|
|||||||
* to the specified parameter, else <code>false</code>.</p>
|
* to the specified parameter, else <code>false</code>.</p>
|
||||||
*
|
*
|
||||||
* @param o the object to compare this <code>PropertySet</code> with
|
* @param o the object to compare this <code>PropertySet</code> with
|
||||||
|
*
|
||||||
|
* @return <code>true</code> if the objects are equal, <code>false</code>
|
||||||
|
* if not
|
||||||
*/
|
*/
|
||||||
public boolean equals(final Object o)
|
public boolean equals(final Object o)
|
||||||
{
|
{
|
||||||
@ -672,4 +675,43 @@ public class PropertySet
|
|||||||
return Util.equals(getSections(), ps.getSections());
|
return Util.equals(getSections(), ps.getSections());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Object#hashCode()
|
||||||
|
*/
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException("FIXME: Not yet implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
final StringBuffer b = new StringBuffer();
|
||||||
|
final int sectionCount = getSectionCount();
|
||||||
|
b.append(getClass().getName());
|
||||||
|
b.append('[');
|
||||||
|
b.append("byteOrder: ");
|
||||||
|
b.append(getByteOrder());
|
||||||
|
b.append(", classID: ");
|
||||||
|
b.append(getClassID());
|
||||||
|
b.append(", format: ");
|
||||||
|
b.append(getFormat());
|
||||||
|
b.append(", OSVersion: ");
|
||||||
|
b.append(getOSVersion());
|
||||||
|
b.append(", sectionCount: ");
|
||||||
|
b.append(sectionCount);
|
||||||
|
b.append(", sections: [");
|
||||||
|
final List sections = getSections();
|
||||||
|
for (int i = 0; i < sectionCount; i++)
|
||||||
|
b.append(((Section) sections.get(0)).toString());
|
||||||
|
b.append(']');
|
||||||
|
b.append(']');
|
||||||
|
return b.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,8 @@ import java.io.IOException;
|
|||||||
* <p>Factory class to create instances of {@link SummaryInformation},
|
* <p>Factory class to create instances of {@link SummaryInformation},
|
||||||
* {@link DocumentSummaryInformation} and {@link PropertySet}.</p>
|
* {@link DocumentSummaryInformation} and {@link PropertySet}.</p>
|
||||||
*
|
*
|
||||||
* @author Rainer Klute (klute@rainer-klute.de)
|
* @author Rainer Klute <a
|
||||||
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
* @since 2002-02-09
|
* @since 2002-02-09
|
||||||
*/
|
*/
|
||||||
|
@ -63,8 +63,11 @@
|
|||||||
package org.apache.poi.hpsf;
|
package org.apache.poi.hpsf;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>This exception is thrown when trying to read a (yet) unsupported variant
|
* <p>This exception is thrown when HPSF tries to read a (yet) unsupported
|
||||||
* type.</p>
|
* variant type.</p>
|
||||||
|
*
|
||||||
|
* @see WritingNotSupportedException
|
||||||
|
* @see UnsupportedVariantTypeException
|
||||||
*
|
*
|
||||||
* @author Rainer Klute <a
|
* @author Rainer Klute <a
|
||||||
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
@ -78,10 +81,11 @@ public class ReadingNotSupportedException
|
|||||||
/**
|
/**
|
||||||
* <p>Constructor</p>
|
* <p>Constructor</p>
|
||||||
*
|
*
|
||||||
* @param variantType
|
* @param variantType The unsupported variant type.
|
||||||
* @param value
|
* @param value The value.
|
||||||
*/
|
*/
|
||||||
public ReadingNotSupportedException(long variantType, Object value)
|
public ReadingNotSupportedException(final long variantType,
|
||||||
|
final Object value)
|
||||||
{
|
{
|
||||||
super(variantType, value);
|
super(variantType, value);
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,8 @@ import org.apache.poi.util.LittleEndian;
|
|||||||
/**
|
/**
|
||||||
* <p>Represents a section in a {@link PropertySet}.</p>
|
* <p>Represents a section in a {@link PropertySet}.</p>
|
||||||
*
|
*
|
||||||
* @author Rainer Klute (klute@rainer-klute.de)
|
* @author Rainer Klute <a
|
||||||
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
* @author Drew Varner (Drew.Varner allUpIn sc.edu)
|
* @author Drew Varner (Drew.Varner allUpIn sc.edu)
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
* @since 2002-02-09
|
* @since 2002-02-09
|
||||||
@ -493,7 +494,7 @@ public class Section
|
|||||||
/**
|
/**
|
||||||
* <p>Checks whether this section is equal to another object.</p>
|
* <p>Checks whether this section is equal to another object.</p>
|
||||||
*
|
*
|
||||||
* @param o The object to cpmpare this section with
|
* @param o The object to compare this section with
|
||||||
* @return <code>true</code> if the objects are equal, <code>false</code> if
|
* @return <code>true</code> if the objects are equal, <code>false</code> if
|
||||||
* not
|
* not
|
||||||
*/
|
*/
|
||||||
@ -509,4 +510,50 @@ public class Section
|
|||||||
return Util.equals(s.getProperties(), getProperties());
|
return Util.equals(s.getProperties(), getProperties());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Object#hashCode()
|
||||||
|
*/
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
long hashCode = 0;
|
||||||
|
hashCode += getFormatID().hashCode();
|
||||||
|
final Property[] pa = getProperties();
|
||||||
|
for (int i = 0; i < pa.length; i++)
|
||||||
|
hashCode += pa[i].hashCode();
|
||||||
|
final int returnHashCode = (int) (hashCode & 0x0ffffffffL);
|
||||||
|
return returnHashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
final StringBuffer b = new StringBuffer();
|
||||||
|
final Property[] pa = getProperties();
|
||||||
|
b.append(getClass().getName());
|
||||||
|
b.append('[');
|
||||||
|
b.append("formatID: ");
|
||||||
|
b.append(getFormatID());
|
||||||
|
b.append(", offset: ");
|
||||||
|
b.append(getOffset());
|
||||||
|
b.append(", propertyCount: ");
|
||||||
|
b.append(getPropertyCount());
|
||||||
|
b.append(", size: ");
|
||||||
|
b.append(getSize());
|
||||||
|
b.append(", properties: [\n");
|
||||||
|
for (int i = 0; i < pa.length; i++)
|
||||||
|
{
|
||||||
|
b.append(pa[i].toString());
|
||||||
|
b.append(",\n");
|
||||||
|
}
|
||||||
|
b.append(']');
|
||||||
|
b.append(']');
|
||||||
|
return b.toString();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,8 @@ import java.util.List;
|
|||||||
* went the other way round historically: the convenience classes came
|
* went the other way round historically: the convenience classes came
|
||||||
* only late to my mind.</p>
|
* only late to my mind.</p>
|
||||||
*
|
*
|
||||||
* @author Rainer Klute (klute@rainer-klute.de)
|
* @author Rainer Klute <a
|
||||||
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
* @since 2002-02-09
|
* @since 2002-02-09
|
||||||
*/
|
*/
|
||||||
|
@ -69,7 +69,8 @@ import org.apache.poi.hpsf.wellknown.PropertyIDMap;
|
|||||||
* href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/stgu_8910.asp">http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/stgu_8910.asp</a>
|
* href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/stgu_8910.asp">http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/stgu_8910.asp</a>
|
||||||
* for documentation from That Redmond Company.</p>
|
* for documentation from That Redmond Company.</p>
|
||||||
*
|
*
|
||||||
* @author Rainer Klute (klute@rainer-klute.de)
|
* @author Rainer Klute <a
|
||||||
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
* @see DocumentSummaryInformation
|
* @see DocumentSummaryInformation
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
* @since 2002-02-09
|
* @since 2002-02-09
|
||||||
@ -297,7 +298,7 @@ public class SummaryInformation extends SpecialPropertySet
|
|||||||
* <strong>when this method is implemented. Please note that the
|
* <strong>when this method is implemented. Please note that the
|
||||||
* return type is likely to change!</strong></p>
|
* return type is likely to change!</strong></p>
|
||||||
*
|
*
|
||||||
* <p><strong>FIXME / Hint to developers:</strong> Drew Varner
|
* <p><strong>FIXME (3) / Hint to developers:</strong> Drew Varner
|
||||||
* <Drew.Varner -at- sc.edu> said that this is an image in
|
* <Drew.Varner -at- sc.edu> said that this is an image in
|
||||||
* WMF or Clipboard (BMP?) format. He also provided two links that
|
* WMF or Clipboard (BMP?) format. He also provided two links that
|
||||||
* might be helpful: <a
|
* might be helpful: <a
|
||||||
|
@ -66,12 +66,12 @@ import java.io.IOException;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
import org.apache.poi.util.LittleEndianConsts;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Class for writing little-endian data and more.</p>
|
* <p>Class for writing little-endian data and more.</p>
|
||||||
*
|
*
|
||||||
* @author Rainer Klute (klute@rainer-klute.de)
|
* @author Rainer Klute <a
|
||||||
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
* @since 2003-02-20
|
* @since 2003-02-20
|
||||||
*/
|
*/
|
||||||
@ -81,8 +81,9 @@ public class TypeWriter
|
|||||||
/**
|
/**
|
||||||
* <p>Writes a two-byte value (short) to an output stream.</p>
|
* <p>Writes a two-byte value (short) to an output stream.</p>
|
||||||
*
|
*
|
||||||
* @param out The stream to write to
|
* @param out The stream to write to.
|
||||||
* @param n The value to write
|
* @param n The value to write.
|
||||||
|
* @return The number of bytes that have been written.
|
||||||
* @exception IOException if an I/O error occurs
|
* @exception IOException if an I/O error occurs
|
||||||
*/
|
*/
|
||||||
public static int writeToStream(final OutputStream out, final short n)
|
public static int writeToStream(final OutputStream out, final short n)
|
||||||
@ -149,7 +150,7 @@ public class TypeWriter
|
|||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
long high = n & 0xFFFFFFFF00000000L;
|
long high = n & 0xFFFFFFFF00000000L;
|
||||||
if (high != 0)
|
if (high != 0 && high != 0xFFFFFFFF00000000L)
|
||||||
throw new IllegalPropertySetDataException
|
throw new IllegalPropertySetDataException
|
||||||
("Value " + n + " cannot be represented by 4 bytes.");
|
("Value " + n + " cannot be represented by 4 bytes.");
|
||||||
return writeToStream(out, (int) n);
|
return writeToStream(out, (int) n);
|
||||||
|
@ -62,7 +62,8 @@ package org.apache.poi.hpsf;
|
|||||||
* <p>The constructors of this class are analogous to those of its
|
* <p>The constructors of this class are analogous to those of its
|
||||||
* superclass and documented there.</p>
|
* superclass and documented there.</p>
|
||||||
*
|
*
|
||||||
* @author Rainer Klute (klute@rainer-klute.de)
|
* @author Rainer Klute <a
|
||||||
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
* @since 2002-02-09
|
* @since 2002-02-09
|
||||||
*/
|
*/
|
||||||
|
@ -88,7 +88,7 @@ public abstract class UnsupportedVariantTypeException extends HPSFException
|
|||||||
{
|
{
|
||||||
super("HPSF does not yet support the variant type " + variantType +
|
super("HPSF does not yet support the variant type " + variantType +
|
||||||
" (" + Variant.getVariantName(variantType) + ", " +
|
" (" + Variant.getVariantName(variantType) + ", " +
|
||||||
HexDump.toHex((int) variantType) + "). If you want support for " +
|
HexDump.toHex(variantType) + "). If you want support for " +
|
||||||
"this variant type in one of the next POI releases please " +
|
"this variant type in one of the next POI releases please " +
|
||||||
"submit a request for enhancement (RFE) to " +
|
"submit a request for enhancement (RFE) to " +
|
||||||
"<http://nagoya.apache.org/bugzilla/>! Thank you!");
|
"<http://nagoya.apache.org/bugzilla/>! Thank you!");
|
||||||
|
@ -78,7 +78,7 @@ public class Util
|
|||||||
* <li><p>if for each <var>i</var> with
|
* <li><p>if for each <var>i</var> with
|
||||||
* <var>i</var> >= 0 and
|
* <var>i</var> >= 0 and
|
||||||
* <var>i</var> < <var>a.length</var> holds
|
* <var>i</var> < <var>a.length</var> holds
|
||||||
* <var>a</var>[<var>i</var>] == <var>b</var>[<var>i</var>].</p></li>
|
* <var>a</var>[<var>i</var>] == <var>b</var>[<var>i</var>].</p></li>
|
||||||
*
|
*
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
@ -191,6 +191,16 @@ public class Util
|
|||||||
return new Date(ms_since_19700101);
|
return new Date(ms_since_19700101);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Converts a {@link Date} into a filetime.</p>
|
||||||
|
*
|
||||||
|
* @param date The date to be converted
|
||||||
|
* @return The filetime
|
||||||
|
*
|
||||||
|
* @see #filetimeToDate
|
||||||
|
*/
|
||||||
public static long dateToFileTime(final Date date)
|
public static long dateToFileTime(final Date date)
|
||||||
{
|
{
|
||||||
long ms_since_19700101 = date.getTime();
|
long ms_since_19700101 = date.getTime();
|
||||||
@ -228,6 +238,17 @@ public class Util
|
|||||||
return internalEquals(o1, o2);
|
return internalEquals(o1, o2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Compares to object arrays with regarding the objects' order. For
|
||||||
|
* example, [1, 2, 3] and [2, 1, 3] are equal.</p>
|
||||||
|
*
|
||||||
|
* @param c1 The first object array.
|
||||||
|
* @param c2 The second object array.
|
||||||
|
* @return <code>true</code> if the object arrays are equal,
|
||||||
|
* <code>false</code> if they are not.
|
||||||
|
*/
|
||||||
public static boolean equals(final Object[] c1, final Object[] c2)
|
public static boolean equals(final Object[] c1, final Object[] c2)
|
||||||
{
|
{
|
||||||
final Object[] o1 = (Object[]) c1.clone();
|
final Object[] o1 = (Object[]) c1.clone();
|
||||||
@ -252,4 +273,68 @@ public class Util
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Pads a byte array with 0x00 bytes so that its length is a multiple of
|
||||||
|
* 4.</p>
|
||||||
|
*
|
||||||
|
* @param ba The byte array to pad.
|
||||||
|
* @return The padded byte array.
|
||||||
|
*/
|
||||||
|
public static byte[] pad4(final byte[] ba)
|
||||||
|
{
|
||||||
|
final int PAD = 4;
|
||||||
|
final byte[] result;
|
||||||
|
int l = ba.length % PAD;
|
||||||
|
if (l == 0)
|
||||||
|
result = ba;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
l = PAD - l;
|
||||||
|
result = new byte[ba.length + l];
|
||||||
|
System.arraycopy(ba, 0, result, 0, ba.length);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Pads a character array with 0x0000 characters so that its length is a
|
||||||
|
* multiple of 4.</p>
|
||||||
|
*
|
||||||
|
* @param ca The character array to pad.
|
||||||
|
* @return The padded character array.
|
||||||
|
*/
|
||||||
|
public static char[] pad4(final char[] ca)
|
||||||
|
{
|
||||||
|
final int PAD = 4;
|
||||||
|
final char[] result;
|
||||||
|
int l = ca.length % PAD;
|
||||||
|
if (l == 0)
|
||||||
|
result = ca;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
l = PAD - l;
|
||||||
|
result = new char[ca.length + l];
|
||||||
|
System.arraycopy(ca, 0, result, 0, ca.length);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Pads a string with 0x0000 characters so that its length is a
|
||||||
|
* multiple of 4.</p>
|
||||||
|
*
|
||||||
|
* @param s The string to pad.
|
||||||
|
* @return The padded string as a character array.
|
||||||
|
*/
|
||||||
|
public static char[] pad4(final String s)
|
||||||
|
{
|
||||||
|
return pad4(s.toCharArray());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.poi.hpsf;
|
package org.apache.poi.hpsf;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -357,79 +358,193 @@ public class Variant
|
|||||||
public static final int VT_BYREF = 0x4000;
|
public static final int VT_BYREF = 0x4000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>FIXME: Document this!</p>
|
* <p>FIXME (3): Document this!</p>
|
||||||
*/
|
*/
|
||||||
public static final int VT_RESERVED = 0x8000;
|
public static final int VT_RESERVED = 0x8000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>FIXME: Document this!</p>
|
* <p>FIXME (3): Document this!</p>
|
||||||
*/
|
*/
|
||||||
public static final int VT_ILLEGAL = 0xFFFF;
|
public static final int VT_ILLEGAL = 0xFFFF;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>FIXME: Document this!</p>
|
* <p>FIXME (3): Document this!</p>
|
||||||
*/
|
*/
|
||||||
public static final int VT_ILLEGALMASKED = 0xFFF;
|
public static final int VT_ILLEGALMASKED = 0xFFF;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>FIXME: Document this!</p>
|
* <p>FIXME (3): Document this!</p>
|
||||||
*/
|
*/
|
||||||
public static final int VT_TYPEMASK = 0xFFF;
|
public static final int VT_TYPEMASK = 0xFFF;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static final Map m = new HashMap();
|
/**
|
||||||
|
* <p>Maps the numbers denoting the variant types to their corresponding
|
||||||
|
* variant type names.</p>
|
||||||
|
*/
|
||||||
|
private static Map numberToName;
|
||||||
|
|
||||||
|
private static Map numberToLength;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Denotes a variant type with a length that is unknown to HPSF yet.</p>
|
||||||
|
*/
|
||||||
|
public static final Integer LENGTH_UNKNOWN = new Integer(-2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Denotes a variant type with a variable length.</p>
|
||||||
|
*/
|
||||||
|
public static final Integer LENGTH_VARIABLE = new Integer(-1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Denotes a variant type with a length of 0 bytes.</p>
|
||||||
|
*/
|
||||||
|
public static final Integer LENGTH_0 = new Integer(0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Denotes a variant type with a length of 2 bytes.</p>
|
||||||
|
*/
|
||||||
|
public static final Integer LENGTH_2 = new Integer(2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Denotes a variant type with a length of 4 bytes.</p>
|
||||||
|
*/
|
||||||
|
public static final Integer LENGTH_4 = new Integer(4);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Denotes a variant type with a length of 8 bytes.</p>
|
||||||
|
*/
|
||||||
|
public static final Integer LENGTH_8 = new Integer(8);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static
|
static
|
||||||
{
|
{
|
||||||
m.put(new Integer(0), "VT_EMPTY");
|
/* Initialize the number-to-name map: */
|
||||||
m.put(new Integer(1), "VT_NULL");
|
Map tm1 = new HashMap();
|
||||||
m.put(new Integer(2), "VT_I2");
|
tm1.put(new Long(0), "VT_EMPTY");
|
||||||
m.put(new Integer(3), "VT_I4");
|
tm1.put(new Long(1), "VT_NULL");
|
||||||
m.put(new Integer(4), "VT_R4");
|
tm1.put(new Long(2), "VT_I2");
|
||||||
m.put(new Integer(5), "VT_R8");
|
tm1.put(new Long(3), "VT_I4");
|
||||||
m.put(new Integer(6), "VT_CY");
|
tm1.put(new Long(4), "VT_R4");
|
||||||
m.put(new Integer(7), "VT_DATE");
|
tm1.put(new Long(5), "VT_R8");
|
||||||
m.put(new Integer(8), "VT_BSTR");
|
tm1.put(new Long(6), "VT_CY");
|
||||||
m.put(new Integer(9), "VT_DISPATCH");
|
tm1.put(new Long(7), "VT_DATE");
|
||||||
m.put(new Integer(10), "VT_ERROR");
|
tm1.put(new Long(8), "VT_BSTR");
|
||||||
m.put(new Integer(11), "VT_BOOL");
|
tm1.put(new Long(9), "VT_DISPATCH");
|
||||||
m.put(new Integer(12), "VT_VARIANT");
|
tm1.put(new Long(10), "VT_ERROR");
|
||||||
m.put(new Integer(13), "VT_UNKNOWN");
|
tm1.put(new Long(11), "VT_BOOL");
|
||||||
m.put(new Integer(14), "VT_DECIMAL");
|
tm1.put(new Long(12), "VT_VARIANT");
|
||||||
m.put(new Integer(16), "VT_I1");
|
tm1.put(new Long(13), "VT_UNKNOWN");
|
||||||
m.put(new Integer(17), "VT_UI1");
|
tm1.put(new Long(14), "VT_DECIMAL");
|
||||||
m.put(new Integer(18), "VT_UI2");
|
tm1.put(new Long(16), "VT_I1");
|
||||||
m.put(new Integer(19), "VT_UI4");
|
tm1.put(new Long(17), "VT_UI1");
|
||||||
m.put(new Integer(20), "VT_I8");
|
tm1.put(new Long(18), "VT_UI2");
|
||||||
m.put(new Integer(21), "VT_UI8");
|
tm1.put(new Long(19), "VT_UI4");
|
||||||
m.put(new Integer(22), "VT_INT");
|
tm1.put(new Long(20), "VT_I8");
|
||||||
m.put(new Integer(23), "VT_UINT");
|
tm1.put(new Long(21), "VT_UI8");
|
||||||
m.put(new Integer(24), "VT_VOID");
|
tm1.put(new Long(22), "VT_INT");
|
||||||
m.put(new Integer(25), "VT_HRESULT");
|
tm1.put(new Long(23), "VT_UINT");
|
||||||
m.put(new Integer(26), "VT_PTR");
|
tm1.put(new Long(24), "VT_VOID");
|
||||||
m.put(new Integer(27), "VT_SAFEARRAY");
|
tm1.put(new Long(25), "VT_HRESULT");
|
||||||
m.put(new Integer(28), "VT_CARRAY");
|
tm1.put(new Long(26), "VT_PTR");
|
||||||
m.put(new Integer(29), "VT_USERDEFINED");
|
tm1.put(new Long(27), "VT_SAFEARRAY");
|
||||||
m.put(new Integer(30), "VT_LPSTR");
|
tm1.put(new Long(28), "VT_CARRAY");
|
||||||
m.put(new Integer(31), "VT_LPWSTR");
|
tm1.put(new Long(29), "VT_USERDEFINED");
|
||||||
m.put(new Integer(64), "VT_FILETIME");
|
tm1.put(new Long(30), "VT_LPSTR");
|
||||||
m.put(new Integer(65), "VT_BLOB");
|
tm1.put(new Long(31), "VT_LPWSTR");
|
||||||
m.put(new Integer(66), "VT_STREAM");
|
tm1.put(new Long(64), "VT_FILETIME");
|
||||||
m.put(new Integer(67), "VT_STORAGE");
|
tm1.put(new Long(65), "VT_BLOB");
|
||||||
m.put(new Integer(68), "VT_STREAMED_OBJECT");
|
tm1.put(new Long(66), "VT_STREAM");
|
||||||
m.put(new Integer(69), "VT_STORED_OBJECT");
|
tm1.put(new Long(67), "VT_STORAGE");
|
||||||
m.put(new Integer(70), "VT_BLOB_OBJECT");
|
tm1.put(new Long(68), "VT_STREAMED_OBJECT");
|
||||||
m.put(new Integer(71), "VT_CF");
|
tm1.put(new Long(69), "VT_STORED_OBJECT");
|
||||||
m.put(new Integer(72), "VT_CLSID");
|
tm1.put(new Long(70), "VT_BLOB_OBJECT");
|
||||||
|
tm1.put(new Long(71), "VT_CF");
|
||||||
|
tm1.put(new Long(72), "VT_CLSID");
|
||||||
|
Map tm2 = new HashMap(tm1.size(), 1.0F);
|
||||||
|
tm2.putAll(tm1);
|
||||||
|
numberToName = Collections.unmodifiableMap(tm2);
|
||||||
|
|
||||||
|
/* Initialize the number-to-length map: */
|
||||||
|
tm1.clear();
|
||||||
|
tm1.put(new Long(0), LENGTH_0);
|
||||||
|
tm1.put(new Long(1), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(2), LENGTH_2);
|
||||||
|
tm1.put(new Long(3), LENGTH_4);
|
||||||
|
tm1.put(new Long(4), LENGTH_4);
|
||||||
|
tm1.put(new Long(5), LENGTH_8);
|
||||||
|
tm1.put(new Long(6), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(7), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(8), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(9), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(10), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(11), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(12), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(13), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(14), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(16), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(17), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(18), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(19), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(20), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(21), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(22), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(23), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(24), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(25), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(26), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(27), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(28), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(29), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(30), LENGTH_VARIABLE);
|
||||||
|
tm1.put(new Long(31), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(64), LENGTH_8);
|
||||||
|
tm1.put(new Long(65), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(66), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(67), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(68), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(69), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(70), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(71), LENGTH_UNKNOWN);
|
||||||
|
tm1.put(new Long(72), LENGTH_UNKNOWN);
|
||||||
|
tm2 = new HashMap(tm1.size(), 1.0F);
|
||||||
|
tm2.putAll(tm1);
|
||||||
|
numberToLength = Collections.unmodifiableMap(tm2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns the variant type name associated with a variant type
|
||||||
|
* number.</p>
|
||||||
|
*
|
||||||
|
* @param variantType The variant type number
|
||||||
|
* @return The variant type name or the string "unknown variant type"
|
||||||
|
*/
|
||||||
public static String getVariantName(final long variantType)
|
public static String getVariantName(final long variantType)
|
||||||
{
|
{
|
||||||
String name = (String) m.get(new Integer((int) variantType));
|
final String name = (String) numberToName.get(new Long(variantType));
|
||||||
return name != null ? name : "unknown variant type";
|
return name != null ? name : "unknown variant type";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns a variant type's length.</p>
|
||||||
|
*
|
||||||
|
* @param variantType The variant type number
|
||||||
|
* @return The length of the variant type's data in bytes. If the length is
|
||||||
|
* variable, i.e. the length of a string, -1 is returned. If HPSF does not
|
||||||
|
* know the length, -2 is returned. The latter usually indicates an
|
||||||
|
* unsupported variant type.
|
||||||
|
*/
|
||||||
|
public static int getVariantLength(final long variantType)
|
||||||
|
{
|
||||||
|
final Long key = new Long((int) variantType);
|
||||||
|
final Long length = (Long) numberToLength.get(key);
|
||||||
|
if (length == null)
|
||||||
|
return -2;
|
||||||
|
return length.intValue();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -65,6 +65,8 @@ package org.apache.poi.hpsf;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
import org.apache.poi.util.LittleEndianConsts;
|
import org.apache.poi.util.LittleEndianConsts;
|
||||||
@ -72,8 +74,8 @@ import org.apache.poi.util.LittleEndianConsts;
|
|||||||
/**
|
/**
|
||||||
* <p>Supports reading and writing of variant data.</p>
|
* <p>Supports reading and writing of variant data.</p>
|
||||||
*
|
*
|
||||||
* <p><strong>FIXME:</strong> Reading and writing must be made more uniform than
|
* <p><strong>FIXME (3):</strong> Reading and writing should be made more
|
||||||
* it is now. The following items should be resolved:
|
* uniform than it is now. The following items should be resolved:
|
||||||
*
|
*
|
||||||
* <ul>
|
* <ul>
|
||||||
*
|
*
|
||||||
@ -87,14 +89,73 @@ import org.apache.poi.util.LittleEndianConsts;
|
|||||||
*
|
*
|
||||||
* @author Rainer Klute <a
|
* @author Rainer Klute <a
|
||||||
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
* @since 08.08.2003
|
* @since 2003-08-08
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
*/
|
*/
|
||||||
public class VariantSupport extends Variant
|
public class VariantSupport extends Variant
|
||||||
{
|
{
|
||||||
|
|
||||||
|
private static boolean logUnsupportedTypes = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Reads a variant data type from a byte array.</p>
|
* <p>Specifies whether warnings about unsupported variant types are to be
|
||||||
|
* written to <code>System.err</code> or not.</p>
|
||||||
|
*
|
||||||
|
* @param logUnsupportedTypes If <code>true</code> warnings will be written,
|
||||||
|
* if <code>false</code> they won't.
|
||||||
|
*/
|
||||||
|
public static void setLogUnsupportedTypes(final boolean logUnsupportedTypes)
|
||||||
|
{
|
||||||
|
VariantSupport.logUnsupportedTypes = logUnsupportedTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Checks whether logging of unsupported variant types warning is turned
|
||||||
|
* on or off.</p>
|
||||||
|
*
|
||||||
|
* @return <code>true</code> if logging is turned on, else
|
||||||
|
* <code>false</code>.
|
||||||
|
*/
|
||||||
|
public static boolean isLogUnsupportedTypes()
|
||||||
|
{
|
||||||
|
return logUnsupportedTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Keeps a list of the variant types an "unsupported" message has already
|
||||||
|
* been issued for.</p>
|
||||||
|
*/
|
||||||
|
protected static List unsupportedMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Writes a warning to <code>System.err</code> that a variant type is
|
||||||
|
* unsupported by HPSF. Such a warning is written only once for each variant
|
||||||
|
* type. Log messages can be turned on or off by </p>
|
||||||
|
*
|
||||||
|
* @param ex The exception to log
|
||||||
|
*/
|
||||||
|
protected static void writeUnsupportedTypeMessage
|
||||||
|
(final UnsupportedVariantTypeException ex)
|
||||||
|
{
|
||||||
|
if (isLogUnsupportedTypes())
|
||||||
|
{
|
||||||
|
if (unsupportedMessage == null)
|
||||||
|
unsupportedMessage = new LinkedList();
|
||||||
|
Long vt = new Long(ex.getVariantType());
|
||||||
|
if (!unsupportedMessage.contains(vt))
|
||||||
|
{
|
||||||
|
System.err.println(ex.getMessage());
|
||||||
|
unsupportedMessage.add(vt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Reads a variant type from a byte array.</p>
|
||||||
*
|
*
|
||||||
* @param src The byte array
|
* @param src The byte array
|
||||||
* @param offset The offset in the byte array where the variant
|
* @param offset The offset in the byte array where the variant
|
||||||
@ -105,8 +166,8 @@ public class VariantSupport extends Variant
|
|||||||
* @return A Java object that corresponds best to the variant
|
* @return A Java object that corresponds best to the variant
|
||||||
* field. For example, a VT_I4 is returned as a {@link Long}, a
|
* field. For example, a VT_I4 is returned as a {@link Long}, a
|
||||||
* VT_LPSTR as a {@link String}.
|
* VT_LPSTR as a {@link String}.
|
||||||
* @exception UnsupportedVariantTypeException if HPSF does not (yet)
|
* @exception ReadingNotSupportedException if a property is to be written
|
||||||
* support the variant type which is to be read
|
* who's variant type HPSF does not yet support
|
||||||
*
|
*
|
||||||
* @see Variant
|
* @see Variant
|
||||||
*/
|
*/
|
||||||
@ -161,7 +222,7 @@ public class VariantSupport extends Variant
|
|||||||
* String object. The 0x00 bytes at the end must be
|
* String object. The 0x00 bytes at the end must be
|
||||||
* stripped.
|
* stripped.
|
||||||
*
|
*
|
||||||
* FIXME: Reading an 8-bit string should pay attention
|
* FIXME (2): Reading an 8-bit string should pay attention
|
||||||
* to the codepage. Currently the byte making out the
|
* to the codepage. Currently the byte making out the
|
||||||
* property's value are interpreted according to the
|
* property's value are interpreted according to the
|
||||||
* platform's default character set.
|
* platform's default character set.
|
||||||
@ -238,51 +299,57 @@ public class VariantSupport extends Variant
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Writes a variant value to an output stream.</p>
|
* <p>Writes a variant value to an output stream. This method ensures that
|
||||||
|
* always a multiple of 4 bytes is written.</p>
|
||||||
*
|
*
|
||||||
* @param out The stream to write the value to.
|
* @param out The stream to write the value to.
|
||||||
* @param type The variant's type.
|
* @param type The variant's type.
|
||||||
* @param value The variant's value.
|
* @param value The variant's value.
|
||||||
* @return The number of entities that have been written. In many cases an
|
* @return The number of entities that have been written. In many cases an
|
||||||
* "entity" is a byte but this is not always the case.
|
* "entity" is a byte but this is not always the case.
|
||||||
|
* @exception IOException if an I/O exceptions occurs
|
||||||
|
* @exception WritingNotSupportedException if a property is to be written
|
||||||
|
* who's variant type HPSF does not yet support
|
||||||
*/
|
*/
|
||||||
public static int write(final OutputStream out, final long type,
|
public static int write(final OutputStream out, final long type,
|
||||||
final Object value)
|
final Object value)
|
||||||
throws IOException, WritingNotSupportedException
|
throws IOException, WritingNotSupportedException
|
||||||
{
|
{
|
||||||
|
int length = 0;
|
||||||
switch ((int) type)
|
switch ((int) type)
|
||||||
{
|
{
|
||||||
case Variant.VT_BOOL:
|
case Variant.VT_BOOL:
|
||||||
{
|
{
|
||||||
int trueOrFalse;
|
int trueOrFalse;
|
||||||
int length = 0;
|
|
||||||
if (((Boolean) value).booleanValue())
|
if (((Boolean) value).booleanValue())
|
||||||
trueOrFalse = 1;
|
trueOrFalse = 1;
|
||||||
else
|
else
|
||||||
trueOrFalse = 0;
|
trueOrFalse = 0;
|
||||||
length += TypeWriter.writeUIntToStream(out, trueOrFalse);
|
length = TypeWriter.writeUIntToStream(out, trueOrFalse);
|
||||||
return length;
|
break;
|
||||||
}
|
}
|
||||||
case Variant.VT_LPSTR:
|
case Variant.VT_LPSTR:
|
||||||
{
|
{
|
||||||
TypeWriter.writeUIntToStream
|
length = TypeWriter.writeUIntToStream
|
||||||
(out, ((String) value).length() + 1);
|
(out, ((String) value).length() + 1);
|
||||||
char[] s = toPaddedCharArray((String) value);
|
char[] s = Util.pad4((String) value);
|
||||||
/* FIXME: The following line forces characters to bytes. This
|
/* FIXME (2): The following line forces characters to bytes.
|
||||||
* is generally wrong and should only be done according to a
|
* This is generally wrong and should only be done according to
|
||||||
* codepage. Alternatively Unicode could be written (see
|
* a codepage. Alternatively Unicode could be written (see
|
||||||
* Variant.VT_LPWSTR). */
|
* Variant.VT_LPWSTR). */
|
||||||
byte[] b = new byte[s.length];
|
byte[] b = new byte[s.length + 1];
|
||||||
for (int i = 0; i < s.length; i++)
|
for (int i = 0; i < s.length; i++)
|
||||||
b[i] = (byte) s[i];
|
b[i] = (byte) s[i];
|
||||||
|
b[b.length - 1] = 0x00;
|
||||||
out.write(b);
|
out.write(b);
|
||||||
return b.length;
|
length += b.length;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case Variant.VT_LPWSTR:
|
case Variant.VT_LPWSTR:
|
||||||
{
|
{
|
||||||
final int nrOfChars = ((String) value).length() + 1;
|
final int nrOfChars = ((String) value).length() + 1;
|
||||||
TypeWriter.writeUIntToStream(out, nrOfChars);
|
TypeWriter.writeUIntToStream(out, nrOfChars);
|
||||||
char[] s = toPaddedCharArray((String) value);
|
char[] s = Util.pad4((String) value);
|
||||||
for (int i = 0; i < s.length; i++)
|
for (int i = 0; i < s.length; i++)
|
||||||
{
|
{
|
||||||
final int high = (int) ((s[i] & 0xff00) >> 8);
|
final int high = (int) ((s[i] & 0xff00) >> 8);
|
||||||
@ -292,79 +359,73 @@ public class VariantSupport extends Variant
|
|||||||
out.write(lowb);
|
out.write(lowb);
|
||||||
out.write(highb);
|
out.write(highb);
|
||||||
}
|
}
|
||||||
return nrOfChars * 2;
|
length = nrOfChars * 2;
|
||||||
|
out.write(0x00);
|
||||||
|
out.write(0x00);
|
||||||
|
length += 2;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case Variant.VT_CF:
|
case Variant.VT_CF:
|
||||||
{
|
{
|
||||||
final byte[] b = (byte[]) value;
|
final byte[] b = (byte[]) value;
|
||||||
out.write(b);
|
out.write(b);
|
||||||
return b.length;
|
length = b.length;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case Variant.VT_EMPTY:
|
case Variant.VT_EMPTY:
|
||||||
{
|
{
|
||||||
TypeWriter.writeUIntToStream(out, Variant.VT_EMPTY);
|
TypeWriter.writeUIntToStream(out, Variant.VT_EMPTY);
|
||||||
return LittleEndianConsts.INT_SIZE;
|
length = LittleEndianConsts.INT_SIZE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case Variant.VT_I2:
|
case Variant.VT_I2:
|
||||||
{
|
{
|
||||||
TypeWriter.writeToStream(out, ((Integer) value).shortValue());
|
TypeWriter.writeToStream(out, ((Integer) value).shortValue());
|
||||||
return LittleEndianConsts.SHORT_SIZE;
|
length = LittleEndianConsts.SHORT_SIZE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case Variant.VT_I4:
|
case Variant.VT_I4:
|
||||||
{
|
{
|
||||||
TypeWriter.writeToStream(out, ((Long) value).intValue());
|
TypeWriter.writeToStream(out, ((Long) value).intValue());
|
||||||
return LittleEndianConsts.INT_SIZE;
|
length = LittleEndianConsts.INT_SIZE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case Variant.VT_FILETIME:
|
case Variant.VT_FILETIME:
|
||||||
{
|
{
|
||||||
int length = 0;
|
|
||||||
long filetime = Util.dateToFileTime((Date) value);
|
long filetime = Util.dateToFileTime((Date) value);
|
||||||
int high = (int) ((filetime >> 32) & 0xFFFFFFFFL);
|
int high = (int) ((filetime >> 32) & 0xFFFFFFFFL);
|
||||||
int low = (int) (filetime & 0x00000000FFFFFFFFL);
|
int low = (int) (filetime & 0x00000000FFFFFFFFL);
|
||||||
length += TypeWriter.writeUIntToStream(out, 0x0000000FFFFFFFFL & low);
|
length += TypeWriter.writeUIntToStream
|
||||||
length += TypeWriter.writeUIntToStream(out, 0x0000000FFFFFFFFL & high);
|
(out, 0x0000000FFFFFFFFL & low);
|
||||||
return length;
|
length += TypeWriter.writeUIntToStream
|
||||||
|
(out, 0x0000000FFFFFFFFL & high);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
throw new WritingNotSupportedException(type, value);
|
/* The variant type is not supported yet. However, if the value
|
||||||
}
|
* is a byte array we can write it nevertheless. */
|
||||||
|
if (value instanceof byte[])
|
||||||
|
{
|
||||||
|
final byte[] b = (byte[]) value;
|
||||||
|
out.write(b);
|
||||||
|
length = b.length;
|
||||||
|
writeUnsupportedTypeMessage
|
||||||
|
(new WritingNotSupportedException(type, value));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new WritingNotSupportedException(type, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Add 0x00 character to write a multiple of four bytes: */
|
||||||
|
while (length % 4 != 0)
|
||||||
/**
|
|
||||||
* <p>Converts a string into a 0x00-terminated character sequence padded
|
|
||||||
* with 0x00 bytes to a multiple of 4.</p>
|
|
||||||
*
|
|
||||||
* @param value The string to convert
|
|
||||||
* @return The padded character array
|
|
||||||
*/
|
|
||||||
private static char[] toPaddedCharArray(final String s)
|
|
||||||
{
|
|
||||||
final int PADDING = 4;
|
|
||||||
int dl = s.length() + 1;
|
|
||||||
final int r = dl % 4;
|
|
||||||
if (r > 0)
|
|
||||||
dl += PADDING - r;
|
|
||||||
char[] buffer = new char[dl];
|
|
||||||
s.getChars(0, s.length(), buffer, 0);
|
|
||||||
for (int i = s.length(); i < dl; i++)
|
|
||||||
buffer[i] = (char) 0;
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static int getLength(final long variantType, final int lengthInBytes)
|
|
||||||
{
|
|
||||||
switch ((int) variantType)
|
|
||||||
{
|
{
|
||||||
case VT_LPWSTR:
|
out.write(0);
|
||||||
return lengthInBytes / 2;
|
length++;
|
||||||
default:
|
|
||||||
return lengthInBytes;
|
|
||||||
}
|
}
|
||||||
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -66,6 +66,9 @@ package org.apache.poi.hpsf;
|
|||||||
* <p>This exception is thrown when trying to write a (yet) unsupported variant
|
* <p>This exception is thrown when trying to write a (yet) unsupported variant
|
||||||
* type.</p>
|
* type.</p>
|
||||||
*
|
*
|
||||||
|
* @see ReadingNotSupportedException
|
||||||
|
* @see UnsupportedVariantTypeException
|
||||||
|
*
|
||||||
* @author Rainer Klute <a
|
* @author Rainer Klute <a
|
||||||
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
* @since 2003-08-08
|
* @since 2003-08-08
|
||||||
@ -78,10 +81,11 @@ public class WritingNotSupportedException
|
|||||||
/**
|
/**
|
||||||
* <p>Constructor</p>
|
* <p>Constructor</p>
|
||||||
*
|
*
|
||||||
* @param variantType
|
* @param variantType The unsupported varian type.
|
||||||
* @param value
|
* @param value The value.
|
||||||
*/
|
*/
|
||||||
public WritingNotSupportedException(long variantType, Object value)
|
public WritingNotSupportedException(final long variantType,
|
||||||
|
final Object value)
|
||||||
{
|
{
|
||||||
super(variantType, value);
|
super(variantType, value);
|
||||||
}
|
}
|
||||||
|
@ -66,9 +66,9 @@ import java.util.HashMap;
|
|||||||
* should treat them as unmodifiable, copy them and modifiy the
|
* should treat them as unmodifiable, copy them and modifiy the
|
||||||
* copies.</p>
|
* copies.</p>
|
||||||
*
|
*
|
||||||
* <p><strong>FIXME:</strong> Make the singletons unmodifiable. However,
|
* <p><strong>FIXME (3):</strong> Make the singletons unmodifiable. However,
|
||||||
* since this requires to use a {@link HashMap} delegate instead of
|
* since this requires to use a {@link HashMap} delegate instead of
|
||||||
* extending {@link HashMap} and thus requires a lot of stupid typing. I won't
|
* extending {@link HashMap} and thus requires a lot of stupid typing, I won't
|
||||||
* do that for the time being.</p>
|
* do that for the time being.</p>
|
||||||
*
|
*
|
||||||
* @author Rainer Klute (klute@rainer-klute.de)
|
* @author Rainer Klute (klute@rainer-klute.de)
|
||||||
@ -141,7 +141,7 @@ public class PropertyIDMap extends HashMap
|
|||||||
* document</p> */
|
* document</p> */
|
||||||
public static final int PID_APPNAME = 18;
|
public static final int PID_APPNAME = 18;
|
||||||
|
|
||||||
/** <p>ID of the property that denotes... FIXME</p> */
|
/** <p>ID of the property that denotes... FIXME (2)</p> */
|
||||||
public static final int PID_SECURITY = 19;
|
public static final int PID_SECURITY = 19;
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user