Return-Path: Delivered-To: apmail-jakarta-poi-dev-archive@www.apache.org Received: (qmail 52011 invoked from network); 30 Aug 2003 09:14:01 -0000 Received: from daedalus.apache.org (HELO apache.org) (208.185.179.12) by minotaur-2.apache.org with SMTP; 30 Aug 2003 09:14:01 -0000 Received: (qmail 94844 invoked by uid 500); 30 Aug 2003 09:13:31 -0000 Delivered-To: apmail-jakarta-poi-dev-archive@jakarta.apache.org Received: (qmail 94810 invoked by uid 500); 30 Aug 2003 09:13:31 -0000 Mailing-List: contact poi-dev-help@jakarta.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Subscribe: List-Help: List-Post: List-Id: "POI Developers List" Reply-To: "POI Developers List" Delivered-To: mailing list poi-dev@jakarta.apache.org Received: (qmail 94780 invoked by uid 500); 30 Aug 2003 09:13:31 -0000 Received: (qmail 94776 invoked from network); 30 Aug 2003 09:13:30 -0000 Received: from unknown (HELO minotaur.apache.org) (209.237.227.194) by daedalus.apache.org with SMTP; 30 Aug 2003 09:13:30 -0000 Received: (qmail 52000 invoked by uid 1458); 30 Aug 2003 09:13:53 -0000 Date: 30 Aug 2003 09:13:53 -0000 Message-ID: <20030830091353.51999.qmail@minotaur.apache.org> From: klute@apache.org To: jakarta-poi-cvs@apache.org Subject: cvs commit: jakarta-poi/src/java/org/apache/poi/hpsf/wellknown PropertyIDMap.java X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N X-Spam-Rating: minotaur-2.apache.org 1.6.2 0/1000/N klute 2003/08/30 02:13:53 Modified: src/java/org/apache/poi/hpsf ClassID.java DocumentSummaryInformation.java HPSFException.java HPSFRuntimeException.java MarkUnsupportedException.java NoPropertySetStreamException.java NoSingleSectionException.java Property.java PropertySet.java PropertySetFactory.java ReadingNotSupportedException.java Section.java SpecialPropertySet.java SummaryInformation.java TypeWriter.java UnexpectedPropertySetTypeException.java UnsupportedVariantTypeException.java Util.java Variant.java VariantSupport.java WritingNotSupportedException.java src/java/org/apache/poi/hpsf/wellknown PropertyIDMap.java Added: src/java/org/apache/poi/hpsf MutableProperty.java MutablePropertySet.java MutableSection.java Log: HPSF writing capability added. Revision Changes Path 1.8 +15 -4 jakarta-poi/src/java/org/apache/poi/hpsf/ClassID.java Index: ClassID.java =================================================================== RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/ClassID.java,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- ClassID.java 3 Aug 2003 20:16:46 -0000 1.7 +++ ClassID.java 30 Aug 2003 09:13:52 -0000 1.8 @@ -61,7 +61,8 @@ * order. Instead, it is a double word (4 bytes) followed by two * words (2 bytes each) followed by 8 bytes.

* - * @author Rainer Klute (klute@rainer-klute.de) + * @author Rainer Klute <klute@rainer-klute.de> * @version $Id$ * @since 2002-02-09 */ @@ -120,7 +121,7 @@ /** *

Gets the bytes making out the class ID. They are returned in * correct order, i.e. big-endian.

- * + * * @return the bytes making out the class ID. */ public byte[] getBytes() @@ -175,7 +176,7 @@ * * @param offset The offset within the dst byte array. * - * @exception ArrayStoreException if there is not enough room for the class + * @exception ArrayStoreException if there is not enough room for the class * ID 16 bytes in the byte array after the offset position. */ public void write(final byte[] dst, final int offset) @@ -226,6 +227,16 @@ if (bytes[i] != cid.bytes[i]) return false; return true; + } + + + + /** + * @see Object#hashCode() + */ + public int hashCode() + { + throw new UnsupportedOperationException("FIXME: Not yet implemented."); } } 1.11 +4 -3 jakarta-poi/src/java/org/apache/poi/hpsf/DocumentSummaryInformation.java Index: DocumentSummaryInformation.java =================================================================== RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/DocumentSummaryInformation.java,v retrieving revision 1.10 retrieving revision 1.11 diff -u -r1.10 -r1.11 --- DocumentSummaryInformation.java 2 Aug 2003 19:02:28 -0000 1.10 +++ DocumentSummaryInformation.java 30 Aug 2003 09:13:52 -0000 1.11 @@ -60,7 +60,8 @@ *

Convenience class representing a DocumentSummary Information stream in a * Microsoft Office document.

* - * @author Rainer Klute (klute@rainer-klute.de) + * @author Rainer Klute <klute@rainer-klute.de> * @author Drew Varner (Drew.Varner closeTo sc.edu) * @see SummaryInformation * @version $Id$ @@ -289,7 +290,7 @@ *

Returns true if the custom links are hampered * by excessive noise, for all applications.

* - * FIXME: Explain this some more! I (Rainer) + * FIXME (3): Explain this some more! I (Rainer) * don't understand it.

* * @return The linksDirty value 1.8 +3 -2 jakarta-poi/src/java/org/apache/poi/hpsf/HPSFException.java Index: HPSFException.java =================================================================== RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/HPSFException.java,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- HPSFException.java 2 Aug 2003 19:02:28 -0000 1.7 +++ HPSFException.java 30 Aug 2003 09:13:52 -0000 1.8 @@ -59,7 +59,8 @@ * thrown in this package. It supports a nested "reason" throwable, * i.e. an exception that caused this one to be thrown.

* - * @author Rainer Klute (klute@rainer-klute.de) + * @author Rainer Klute <klute@rainer-klute.de> * @version $Id$ * @since 2002-02-09 */ 1.8 +48 -2 jakarta-poi/src/java/org/apache/poi/hpsf/HPSFRuntimeException.java Index: HPSFRuntimeException.java =================================================================== RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/HPSFRuntimeException.java,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- HPSFRuntimeException.java 2 Aug 2003 19:02:28 -0000 1.7 +++ HPSFRuntimeException.java 30 Aug 2003 09:13:52 -0000 1.8 @@ -54,12 +54,16 @@ */ package org.apache.poi.hpsf; +import java.io.PrintStream; +import java.io.PrintWriter; + /** *

This exception is the superclass of all other unchecked * exceptions thrown in this package. It supports a nested "reason" * throwable, i.e. an exception that caused this one to be thrown.

* - * @author Rainer Klute (klute@rainer-klute.de) + * @author Rainer Klute <klute@rainer-klute.de> * @version $Id$ * @since 2002-02-09 */ @@ -136,6 +140,48 @@ public Throwable getReason() { 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); + } } } 1.8 +7 -6 jakarta-poi/src/java/org/apache/poi/hpsf/MarkUnsupportedException.java Index: MarkUnsupportedException.java =================================================================== RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/MarkUnsupportedException.java,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- MarkUnsupportedException.java 2 Aug 2003 19:02:28 -0000 1.7 +++ MarkUnsupportedException.java 30 Aug 2003 09:13:52 -0000 1.8 @@ -58,7 +58,8 @@ *

This exception is thrown if an {@link java.io.InputStream} does * not support the {@link java.io.InputStream#mark} operation.

* - * @author Rainer Klute (klute@rainer-klute.de) + * @author Rainer Klute <klute@rainer-klute.de> * @version $Id$ * @since 2002-02-09 */ @@ -76,7 +77,7 @@ /** *

Constructor

- * + * * @param msg The exception's message string */ public MarkUnsupportedException(final String msg) @@ -87,7 +88,7 @@ /** *

Constructor

- * + * * @param reason This exception's underlying reason */ public MarkUnsupportedException(final Throwable reason) @@ -98,7 +99,7 @@ /** *

Constructor

- * + * * @param msg The exception's message string * @param reason This exception's underlying reason */ @@ -107,4 +108,4 @@ super(msg, reason); } -} \ No newline at end of file +} 1.8 +12 -11 jakarta-poi/src/java/org/apache/poi/hpsf/NoPropertySetStreamException.java Index: NoPropertySetStreamException.java =================================================================== RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/NoPropertySetStreamException.java,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- NoPropertySetStreamException.java 2 Aug 2003 19:02:28 -0000 1.7 +++ NoPropertySetStreamException.java 30 Aug 2003 09:13:52 -0000 1.8 @@ -55,18 +55,16 @@ package org.apache.poi.hpsf; /** - *

+ *

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.

+ * + *

The constructors of this class are analogous to those of its superclass + * and are documented there.

* - * 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.

- *

- * - * The constructors of this class are analogous to those of its superclass and - * documented there.

- * - *@author Rainer Klute (klute@rainer-klute.de) - *@version $Id$ - *@since 2002-02-09 + * @author Rainer Klute <klute@rainer-klute.de> + * @version $Id$ + * @since 2002-02-09 */ public class NoPropertySetStreamException extends HPSFException { @@ -80,6 +78,7 @@ } + /** *

Constructor

* @@ -91,6 +90,7 @@ } + /** *

Constructor

* @@ -100,6 +100,7 @@ { super(reason); } + /** 1.8 +3 -2 jakarta-poi/src/java/org/apache/poi/hpsf/NoSingleSectionException.java Index: NoSingleSectionException.java =================================================================== RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/NoSingleSectionException.java,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- NoSingleSectionException.java 2 Aug 2003 19:02:28 -0000 1.7 +++ NoSingleSectionException.java 30 Aug 2003 09:13:52 -0000 1.8 @@ -63,7 +63,8 @@ *

The constructors of this class are analogous to those of its * superclass and documented there.

* - * @author Rainer Klute (klute@rainer-klute.de) + * @author Rainer Klute <klute@rainer-klute.de> * @version $Id$ * @since 2002-02-09 */ 1.14 +75 -33 jakarta-poi/src/java/org/apache/poi/hpsf/Property.java Index: Property.java =================================================================== RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/Property.java,v retrieving revision 1.13 retrieving revision 1.14 diff -u -r1.13 -r1.14 --- Property.java 23 Aug 2003 15:12:22 -0000 1.13 +++ Property.java 30 Aug 2003 09:13:52 -0000 1.14 @@ -63,8 +63,6 @@ package org.apache.poi.hpsf; import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; import java.util.Map; import org.apache.poi.util.LittleEndian; @@ -85,11 +83,13 @@ * value, {@link Variant#VT_FILETIME} some date and time (of a * file).

* - *

FIXME: Reading is not implemented for all - * {@link Variant} types yet. Feel free to submit error reports or - * patches for the types you need.

+ *

Please note that not all {@link Variant} types yet. This might change + * over time but largely depends on your feedback so that the POI team knows + * which variant types are really needed. So please feel free to submit error + * reports or patches for the types you need.

* - * @author Rainer Klute (klute@rainer-klute.de) + * @author Rainer Klute <klute@rainer-klute.de> * @author Drew Varner (Drew.Varner InAndAround sc.edu) * @see Section * @see Variant @@ -103,7 +103,7 @@ private static final int CP_UNICODE = 1200; /**

The property's ID.

*/ - protected int id; + protected long id; /** @@ -111,7 +111,7 @@ * * @return The ID value */ - public int getID() + public long getID() { return id; } @@ -162,7 +162,7 @@ * @param codepage The section's and thus the property's * 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) { this.id = id; @@ -187,7 +187,7 @@ } catch (UnsupportedVariantTypeException ex) { - logUnsupported(ex); + VariantSupport.writeUnsupportedTypeMessage(ex); value = ex.getValue(); } } @@ -281,15 +281,21 @@ * 4.

* * @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. */ - if (type > Integer.MAX_VALUE) - throw new HPSFRuntimeException - ("Variant type " + type + " is greater than " + - Integer.MAX_VALUE + "."); switch ((int) type) { case Variant.VT_LPSTR: @@ -304,9 +310,7 @@ case Variant.VT_EMPTY: break; default: - throw new HPSFRuntimeException - ("Writing is not yet implemented for variant type " + - type + ". Please report this problem to the POI team!"); + throw new WritingNotSupportedException(type, value); } return length; } @@ -318,27 +322,65 @@ */ 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); } /** - *

Keeps a list of those variant types for those an "unsupported" message - * has already been issued.

+ * @see Object#hashCode() */ - protected static List unsupportedMessage; + public int hashCode() + { + long hashCode = 0; + hashCode += id; + hashCode += type; + if (value != null) + hashCode += value.hashCode(); + final int returnHashCode = (int) (hashCode & 0x0ffffffffL ); + return returnHashCode; + + } - private static void logUnsupported(final UnsupportedVariantTypeException ex) + + + /** + * @see Object#toString() + */ + public String toString() { - if (unsupportedMessage == null) - unsupportedMessage = new LinkedList(); - Long vt = new Long(ex.getVariantType()); - if (!unsupportedMessage.contains(vt)) - { - System.err.println(ex.getMessage()); - unsupportedMessage.add(vt); - } + 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(); } } 1.12 +47 -5 jakarta-poi/src/java/org/apache/poi/hpsf/PropertySet.java Index: PropertySet.java =================================================================== RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/PropertySet.java,v retrieving revision 1.11 retrieving revision 1.12 diff -u -r1.11 -r1.12 --- PropertySet.java 3 Aug 2003 20:16:46 -0000 1.11 +++ PropertySet.java 30 Aug 2003 09:13:52 -0000 1.12 @@ -57,7 +57,6 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; -import java.util.LinkedList; import java.util.List; import org.apache.poi.hpsf.wellknown.SectionIDMap; @@ -91,7 +90,8 @@ * NoSingleSectionException} if the {@link PropertySet} contains more * (or less) than exactly one {@link Section}).

* - * @author Rainer Klute (klute@rainer-klute.de) + * @author Rainer Klute <klute@rainer-klute.de> * @author Drew Varner (Drew.Varner hanginIn sc.edu) * @version $Id$ * @since 2002-02-09 @@ -397,7 +397,7 @@ 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 header fields of the stream. They must always be @@ -442,7 +442,7 @@ */ 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. @@ -645,6 +645,9 @@ * to the specified parameter, else false.

* * @param o the object to compare this PropertySet with + * + * @return true if the objects are equal, false + * if not */ public boolean equals(final Object o) { @@ -672,4 +675,43 @@ 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(); + } } 1.8 +3 -2 jakarta-poi/src/java/org/apache/poi/hpsf/PropertySetFactory.java Index: PropertySetFactory.java =================================================================== RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/PropertySetFactory.java,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- PropertySetFactory.java 2 Aug 2003 19:02:28 -0000 1.7 +++ PropertySetFactory.java 30 Aug 2003 09:13:52 -0000 1.8 @@ -61,7 +61,8 @@ *

Factory class to create instances of {@link SummaryInformation}, * {@link DocumentSummaryInformation} and {@link PropertySet}.

* - * @author Rainer Klute (klute@rainer-klute.de) + * @author Rainer Klute <klute@rainer-klute.de> * @version $Id$ * @since 2002-02-09 */ 1.3 +10 -6 jakarta-poi/src/java/org/apache/poi/hpsf/ReadingNotSupportedException.java Index: ReadingNotSupportedException.java =================================================================== RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/ReadingNotSupportedException.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- ReadingNotSupportedException.java 25 Aug 2003 19:46:00 -0000 1.2 +++ ReadingNotSupportedException.java 30 Aug 2003 09:13:52 -0000 1.3 @@ -63,8 +63,11 @@ package org.apache.poi.hpsf; /** - *

This exception is thrown when trying to read a (yet) unsupported variant - * type.

+ *

This exception is thrown when HPSF tries to read a (yet) unsupported + * variant type.

+ * + * @see WritingNotSupportedException + * @see UnsupportedVariantTypeException * * @author Rainer Klute <klute@rainer-klute.de> @@ -78,10 +81,11 @@ /** *

Constructor

* - * @param variantType - * @param value + * @param variantType The unsupported variant type. + * @param value The value. */ - public ReadingNotSupportedException(long variantType, Object value) + public ReadingNotSupportedException(final long variantType, + final Object value) { super(variantType, value); } 1.14 +50 -3 jakarta-poi/src/java/org/apache/poi/hpsf/Section.java Index: Section.java =================================================================== RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/Section.java,v retrieving revision 1.13 retrieving revision 1.14 diff -u -r1.13 -r1.14 --- Section.java 23 Aug 2003 15:12:22 -0000 1.13 +++ Section.java 30 Aug 2003 09:13:52 -0000 1.14 @@ -67,7 +67,8 @@ /** *

Represents a section in a {@link PropertySet}.

* - * @author Rainer Klute (klute@rainer-klute.de) + * @author Rainer Klute <klute@rainer-klute.de> * @author Drew Varner (Drew.Varner allUpIn sc.edu) * @version $Id$ * @since 2002-02-09 @@ -493,7 +494,7 @@ /** *

Checks whether this section is equal to another object.

* - * @param o The object to cpmpare this section with + * @param o The object to compare this section with * @return true if the objects are equal, false if * not */ @@ -507,6 +508,52 @@ if (s.getPropertyCount() != getPropertyCount()) return false; 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(); } } 1.10 +3 -2 jakarta-poi/src/java/org/apache/poi/hpsf/SpecialPropertySet.java Index: SpecialPropertySet.java =================================================================== RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/SpecialPropertySet.java,v retrieving revision 1.9 retrieving revision 1.10 diff -u -r1.9 -r1.10 --- SpecialPropertySet.java 2 Aug 2003 19:02:28 -0000 1.9 +++ SpecialPropertySet.java 30 Aug 2003 09:13:52 -0000 1.10 @@ -82,7 +82,8 @@ * went the other way round historically: the convenience classes came * only late to my mind.

* - * @author Rainer Klute (klute@rainer-klute.de) + * @author Rainer Klute <klute@rainer-klute.de> * @version $Id$ * @since 2002-02-09 */ 1.12 +4 -3 jakarta-poi/src/java/org/apache/poi/hpsf/SummaryInformation.java Index: SummaryInformation.java =================================================================== RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/SummaryInformation.java,v retrieving revision 1.11 retrieving revision 1.12 diff -u -r1.11 -r1.12 --- SummaryInformation.java 2 Aug 2003 19:02:28 -0000 1.11 +++ SummaryInformation.java 30 Aug 2003 09:13:52 -0000 1.12 @@ -69,7 +69,8 @@ * 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 * for documentation from That Redmond Company.

* - * @author Rainer Klute (klute@rainer-klute.de) + * @author Rainer Klute <klute@rainer-klute.de> * @see DocumentSummaryInformation * @version $Id$ * @since 2002-02-09 @@ -297,7 +298,7 @@ * when this method is implemented. Please note that the * return type is likely to change!

* - *

FIXME / Hint to developers: Drew Varner + *

FIXME (3) / Hint to developers: Drew Varner * <Drew.Varner -at- sc.edu> said that this is an image in * WMF or Clipboard (BMP?) format. He also provided two links that * might be helpful: Class for writing little-endian data and more.

* - * @author Rainer Klute (klute@rainer-klute.de) + * @author Rainer Klute <klute@rainer-klute.de> * @version $Id$ * @since 2003-02-20 */ @@ -81,8 +81,9 @@ /** *

Writes a two-byte value (short) to an output stream.

* - * @param out The stream to write to - * @param n The value to write + * @param out The stream to write to. + * @param n The value to write. + * @return The number of bytes that have been written. * @exception IOException if an I/O error occurs */ public static int writeToStream(final OutputStream out, final short n) @@ -149,7 +150,7 @@ throws IOException { long high = n & 0xFFFFFFFF00000000L; - if (high != 0) + if (high != 0 && high != 0xFFFFFFFF00000000L) throw new IllegalPropertySetDataException ("Value " + n + " cannot be represented by 4 bytes."); return writeToStream(out, (int) n); 1.8 +3 -2 jakarta-poi/src/java/org/apache/poi/hpsf/UnexpectedPropertySetTypeException.java Index: UnexpectedPropertySetTypeException.java =================================================================== RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/UnexpectedPropertySetTypeException.java,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- UnexpectedPropertySetTypeException.java 2 Aug 2003 19:02:28 -0000 1.7 +++ UnexpectedPropertySetTypeException.java 30 Aug 2003 09:13:52 -0000 1.8 @@ -62,7 +62,8 @@ *

The constructors of this class are analogous to those of its * superclass and documented there.

* - * @author Rainer Klute (klute@rainer-klute.de) + * @author Rainer Klute <klute@rainer-klute.de> * @version $Id$ * @since 2002-02-09 */ 1.2 +2 -2 jakarta-poi/src/java/org/apache/poi/hpsf/UnsupportedVariantTypeException.java Index: UnsupportedVariantTypeException.java =================================================================== RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/UnsupportedVariantTypeException.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- UnsupportedVariantTypeException.java 23 Aug 2003 15:12:22 -0000 1.1 +++ UnsupportedVariantTypeException.java 30 Aug 2003 09:13:52 -0000 1.2 @@ -88,7 +88,7 @@ { super("HPSF does not yet support the variant type " + 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 " + "submit a request for enhancement (RFE) to " + "! Thank you!"); 1.11 +87 -2 jakarta-poi/src/java/org/apache/poi/hpsf/Util.java Index: Util.java =================================================================== RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/Util.java,v retrieving revision 1.10 retrieving revision 1.11 diff -u -r1.10 -r1.11 --- Util.java 23 Aug 2003 15:12:22 -0000 1.10 +++ Util.java 30 Aug 2003 09:13:52 -0000 1.11 @@ -78,7 +78,7 @@ *
  • if for each i with * i >= 0 and * i < a.length holds - * a[i] == b[i].

  • + * a[i] == b[i].

    * * * @@ -191,6 +191,16 @@ return new Date(ms_since_19700101); } + + + /** + *

    Converts a {@link Date} into a filetime.

    + * + * @param date The date to be converted + * @return The filetime + * + * @see #filetimeToDate + */ public static long dateToFileTime(final Date date) { long ms_since_19700101 = date.getTime(); @@ -228,6 +238,17 @@ return internalEquals(o1, o2); } + + + /** + *

    Compares to object arrays with regarding the objects' order. For + * example, [1, 2, 3] and [2, 1, 3] are equal.

    + * + * @param c1 The first object array. + * @param c2 The second object array. + * @return true if the object arrays are equal, + * false if they are not. + */ public static boolean equals(final Object[] c1, final Object[] c2) { final Object[] o1 = (Object[]) c1.clone(); @@ -250,6 +271,70 @@ return false; } return true; + } + + + + /** + *

    Pads a byte array with 0x00 bytes so that its length is a multiple of + * 4.

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

    Pads a character array with 0x0000 characters so that its length is a + * multiple of 4.

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

    Pads a string with 0x0000 characters so that its length is a + * multiple of 4.

    + * + * @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()); } } 1.9 +163 -48 jakarta-poi/src/java/org/apache/poi/hpsf/Variant.java Index: Variant.java =================================================================== RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/Variant.java,v retrieving revision 1.8 retrieving revision 1.9 diff -u -r1.8 -r1.9 --- Variant.java 23 Aug 2003 15:12:22 -0000 1.8 +++ Variant.java 30 Aug 2003 09:13:52 -0000 1.9 @@ -54,6 +54,7 @@ */ package org.apache.poi.hpsf; +import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -357,79 +358,193 @@ public static final int VT_BYREF = 0x4000; /** - *

    FIXME: Document this!

    + *

    FIXME (3): Document this!

    */ public static final int VT_RESERVED = 0x8000; /** - *

    FIXME: Document this!

    + *

    FIXME (3): Document this!

    */ public static final int VT_ILLEGAL = 0xFFFF; /** - *

    FIXME: Document this!

    + *

    FIXME (3): Document this!

    */ public static final int VT_ILLEGALMASKED = 0xFFF; /** - *

    FIXME: Document this!

    + *

    FIXME (3): Document this!

    */ public static final int VT_TYPEMASK = 0xFFF; - public static final Map m = new HashMap(); + /** + *

    Maps the numbers denoting the variant types to their corresponding + * variant type names.

    + */ + private static Map numberToName; + + private static Map numberToLength; + + /** + *

    Denotes a variant type with a length that is unknown to HPSF yet.

    + */ + public static final Integer LENGTH_UNKNOWN = new Integer(-2); + + /** + *

    Denotes a variant type with a variable length.

    + */ + public static final Integer LENGTH_VARIABLE = new Integer(-1); + + /** + *

    Denotes a variant type with a length of 0 bytes.

    + */ + public static final Integer LENGTH_0 = new Integer(0); + + /** + *

    Denotes a variant type with a length of 2 bytes.

    + */ + public static final Integer LENGTH_2 = new Integer(2); + + /** + *

    Denotes a variant type with a length of 4 bytes.

    + */ + public static final Integer LENGTH_4 = new Integer(4); + + /** + *

    Denotes a variant type with a length of 8 bytes.

    + */ + public static final Integer LENGTH_8 = new Integer(8); + + static { - m.put(new Integer(0), "VT_EMPTY"); - m.put(new Integer(1), "VT_NULL"); - m.put(new Integer(2), "VT_I2"); - m.put(new Integer(3), "VT_I4"); - m.put(new Integer(4), "VT_R4"); - m.put(new Integer(5), "VT_R8"); - m.put(new Integer(6), "VT_CY"); - m.put(new Integer(7), "VT_DATE"); - m.put(new Integer(8), "VT_BSTR"); - m.put(new Integer(9), "VT_DISPATCH"); - m.put(new Integer(10), "VT_ERROR"); - m.put(new Integer(11), "VT_BOOL"); - m.put(new Integer(12), "VT_VARIANT"); - m.put(new Integer(13), "VT_UNKNOWN"); - m.put(new Integer(14), "VT_DECIMAL"); - m.put(new Integer(16), "VT_I1"); - m.put(new Integer(17), "VT_UI1"); - m.put(new Integer(18), "VT_UI2"); - m.put(new Integer(19), "VT_UI4"); - m.put(new Integer(20), "VT_I8"); - m.put(new Integer(21), "VT_UI8"); - m.put(new Integer(22), "VT_INT"); - m.put(new Integer(23), "VT_UINT"); - m.put(new Integer(24), "VT_VOID"); - m.put(new Integer(25), "VT_HRESULT"); - m.put(new Integer(26), "VT_PTR"); - m.put(new Integer(27), "VT_SAFEARRAY"); - m.put(new Integer(28), "VT_CARRAY"); - m.put(new Integer(29), "VT_USERDEFINED"); - m.put(new Integer(30), "VT_LPSTR"); - m.put(new Integer(31), "VT_LPWSTR"); - m.put(new Integer(64), "VT_FILETIME"); - m.put(new Integer(65), "VT_BLOB"); - m.put(new Integer(66), "VT_STREAM"); - m.put(new Integer(67), "VT_STORAGE"); - m.put(new Integer(68), "VT_STREAMED_OBJECT"); - m.put(new Integer(69), "VT_STORED_OBJECT"); - m.put(new Integer(70), "VT_BLOB_OBJECT"); - m.put(new Integer(71), "VT_CF"); - m.put(new Integer(72), "VT_CLSID"); + /* Initialize the number-to-name map: */ + Map tm1 = new HashMap(); + tm1.put(new Long(0), "VT_EMPTY"); + tm1.put(new Long(1), "VT_NULL"); + tm1.put(new Long(2), "VT_I2"); + tm1.put(new Long(3), "VT_I4"); + tm1.put(new Long(4), "VT_R4"); + tm1.put(new Long(5), "VT_R8"); + tm1.put(new Long(6), "VT_CY"); + tm1.put(new Long(7), "VT_DATE"); + tm1.put(new Long(8), "VT_BSTR"); + tm1.put(new Long(9), "VT_DISPATCH"); + tm1.put(new Long(10), "VT_ERROR"); + tm1.put(new Long(11), "VT_BOOL"); + tm1.put(new Long(12), "VT_VARIANT"); + tm1.put(new Long(13), "VT_UNKNOWN"); + tm1.put(new Long(14), "VT_DECIMAL"); + tm1.put(new Long(16), "VT_I1"); + tm1.put(new Long(17), "VT_UI1"); + tm1.put(new Long(18), "VT_UI2"); + tm1.put(new Long(19), "VT_UI4"); + tm1.put(new Long(20), "VT_I8"); + tm1.put(new Long(21), "VT_UI8"); + tm1.put(new Long(22), "VT_INT"); + tm1.put(new Long(23), "VT_UINT"); + tm1.put(new Long(24), "VT_VOID"); + tm1.put(new Long(25), "VT_HRESULT"); + tm1.put(new Long(26), "VT_PTR"); + tm1.put(new Long(27), "VT_SAFEARRAY"); + tm1.put(new Long(28), "VT_CARRAY"); + tm1.put(new Long(29), "VT_USERDEFINED"); + tm1.put(new Long(30), "VT_LPSTR"); + tm1.put(new Long(31), "VT_LPWSTR"); + tm1.put(new Long(64), "VT_FILETIME"); + tm1.put(new Long(65), "VT_BLOB"); + tm1.put(new Long(66), "VT_STREAM"); + tm1.put(new Long(67), "VT_STORAGE"); + tm1.put(new Long(68), "VT_STREAMED_OBJECT"); + tm1.put(new Long(69), "VT_STORED_OBJECT"); + 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); } + /** + *

    Returns the variant type name associated with a variant type + * number.

    + * + * @param variantType The variant type number + * @return The variant type name or the string "unknown variant type" + */ 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"; } -} \ No newline at end of file + /** + *

    Returns a variant type's length.

    + * + * @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(); + } + +} 1.2 +126 -65 jakarta-poi/src/java/org/apache/poi/hpsf/VariantSupport.java Index: VariantSupport.java =================================================================== RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/VariantSupport.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- VariantSupport.java 23 Aug 2003 15:12:22 -0000 1.1 +++ VariantSupport.java 30 Aug 2003 09:13:52 -0000 1.2 @@ -65,6 +65,8 @@ import java.io.IOException; import java.io.OutputStream; import java.util.Date; +import java.util.LinkedList; +import java.util.List; import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndianConsts; @@ -72,8 +74,8 @@ /** *

    Supports reading and writing of variant data.

    * - *

    FIXME: Reading and writing must be made more uniform than - * it is now. The following items should be resolved: + *

    FIXME (3): Reading and writing should be made more + * uniform than it is now. The following items should be resolved: * *

      * @@ -87,14 +89,73 @@ * * @author Rainer Klute <klute@rainer-klute.de> - * @since 08.08.2003 + * @since 2003-08-08 * @version $Id$ */ public class VariantSupport extends Variant { + private static boolean logUnsupportedTypes = false; + + /** + *

      Specifies whether warnings about unsupported variant types are to be + * written to System.err or not.

      + * + * @param logUnsupportedTypes If true warnings will be written, + * if false they won't. + */ + public static void setLogUnsupportedTypes(final boolean logUnsupportedTypes) + { + VariantSupport.logUnsupportedTypes = logUnsupportedTypes; + } + /** - *

      Reads a variant data type from a byte array.

      + *

      Checks whether logging of unsupported variant types warning is turned + * on or off.

      + * + * @return true if logging is turned on, else + * false. + */ + public static boolean isLogUnsupportedTypes() + { + return logUnsupportedTypes; + } + + + + /** + *

      Keeps a list of the variant types an "unsupported" message has already + * been issued for.

      + */ + protected static List unsupportedMessage; + + /** + *

      Writes a warning to System.err 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

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

      Reads a variant type from a byte array.

      * * @param src The byte array * @param offset The offset in the byte array where the variant @@ -105,8 +166,8 @@ * @return A Java object that corresponds best to the variant * field. For example, a VT_I4 is returned as a {@link Long}, a * VT_LPSTR as a {@link String}. - * @exception UnsupportedVariantTypeException if HPSF does not (yet) - * support the variant type which is to be read + * @exception ReadingNotSupportedException if a property is to be written + * who's variant type HPSF does not yet support * * @see Variant */ @@ -161,7 +222,7 @@ * String object. The 0x00 bytes at the end must be * 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 * property's value are interpreted according to the * platform's default character set. @@ -238,51 +299,57 @@ /** - *

      Writes a variant value to an output stream.

      + *

      Writes a variant value to an output stream. This method ensures that + * always a multiple of 4 bytes is written.

      * * @param out The stream to write the value to. * @param type The variant's type. * @param value The variant's value. * @return The number of entities that have been written. In many cases an * "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, - final Object value) + final Object value) throws IOException, WritingNotSupportedException { + int length = 0; switch ((int) type) { case Variant.VT_BOOL: { int trueOrFalse; - int length = 0; if (((Boolean) value).booleanValue()) trueOrFalse = 1; else trueOrFalse = 0; - length += TypeWriter.writeUIntToStream(out, trueOrFalse); - return length; + length = TypeWriter.writeUIntToStream(out, trueOrFalse); + break; } case Variant.VT_LPSTR: { - TypeWriter.writeUIntToStream + length = TypeWriter.writeUIntToStream (out, ((String) value).length() + 1); - char[] s = toPaddedCharArray((String) value); - /* FIXME: The following line forces characters to bytes. This - * is generally wrong and should only be done according to a - * codepage. Alternatively Unicode could be written (see + char[] s = Util.pad4((String) value); + /* FIXME (2): The following line forces characters to bytes. + * This is generally wrong and should only be done according to + * a codepage. Alternatively Unicode could be written (see * Variant.VT_LPWSTR). */ - byte[] b = new byte[s.length]; + byte[] b = new byte[s.length + 1]; for (int i = 0; i < s.length; i++) b[i] = (byte) s[i]; + b[b.length - 1] = 0x00; out.write(b); - return b.length; + length += b.length; + break; } case Variant.VT_LPWSTR: { final int nrOfChars = ((String) value).length() + 1; TypeWriter.writeUIntToStream(out, nrOfChars); - char[] s = toPaddedCharArray((String) value); + char[] s = Util.pad4((String) value); for (int i = 0; i < s.length; i++) { final int high = (int) ((s[i] & 0xff00) >> 8); @@ -292,79 +359,73 @@ out.write(lowb); out.write(highb); } - return nrOfChars * 2; + length = nrOfChars * 2; + out.write(0x00); + out.write(0x00); + length += 2; + break; } case Variant.VT_CF: { final byte[] b = (byte[]) value; out.write(b); - return b.length; + length = b.length; + break; } case Variant.VT_EMPTY: { TypeWriter.writeUIntToStream(out, Variant.VT_EMPTY); - return LittleEndianConsts.INT_SIZE; + length = LittleEndianConsts.INT_SIZE; + break; } case Variant.VT_I2: { TypeWriter.writeToStream(out, ((Integer) value).shortValue()); - return LittleEndianConsts.SHORT_SIZE; + length = LittleEndianConsts.SHORT_SIZE; + break; } case Variant.VT_I4: { TypeWriter.writeToStream(out, ((Long) value).intValue()); - return LittleEndianConsts.INT_SIZE; + length = LittleEndianConsts.INT_SIZE; + break; } case Variant.VT_FILETIME: { - int length = 0; long filetime = Util.dateToFileTime((Date) value); int high = (int) ((filetime >> 32) & 0xFFFFFFFFL); int low = (int) (filetime & 0x00000000FFFFFFFFL); - length += TypeWriter.writeUIntToStream(out, 0x0000000FFFFFFFFL & low); - length += TypeWriter.writeUIntToStream(out, 0x0000000FFFFFFFFL & high); - return length; + length += TypeWriter.writeUIntToStream + (out, 0x0000000FFFFFFFFL & low); + length += TypeWriter.writeUIntToStream + (out, 0x0000000FFFFFFFFL & high); + break; } 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; + } } - } - - - - /** - *

      Converts a string into a 0x00-terminated character sequence padded - * with 0x00 bytes to a multiple of 4.

      - * - * @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) + /* Add 0x00 character to write a multiple of four bytes: */ + while (length % 4 != 0) { - case VT_LPWSTR: - return lengthInBytes / 2; - default: - return lengthInBytes; + out.write(0); + length++; } + return length; } + } 1.3 +8 -4 jakarta-poi/src/java/org/apache/poi/hpsf/WritingNotSupportedException.java Index: WritingNotSupportedException.java =================================================================== RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/WritingNotSupportedException.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- WritingNotSupportedException.java 25 Aug 2003 19:46:00 -0000 1.2 +++ WritingNotSupportedException.java 30 Aug 2003 09:13:52 -0000 1.3 @@ -65,6 +65,9 @@ /** *

      This exception is thrown when trying to write a (yet) unsupported variant * type.

      + * + * @see ReadingNotSupportedException + * @see UnsupportedVariantTypeException * * @author Rainer Klute <klute@rainer-klute.de> @@ -78,10 +81,11 @@ /** *

      Constructor

      * - * @param variantType - * @param value + * @param variantType The unsupported varian type. + * @param value The value. */ - public WritingNotSupportedException(long variantType, Object value) + public WritingNotSupportedException(final long variantType, + final Object value) { super(variantType, value); } 1.1 jakarta-poi/src/java/org/apache/poi/hpsf/MutableProperty.java Index: MutableProperty.java =================================================================== package org.apache.poi.hpsf; import java.io.IOException; import java.io.OutputStream; /** *

      Adds writing capability to the {@link Property} class.

      * *

      Please be aware that this class' functionality will be merged into the * {@link Property} class at a later time, so the API will change.

      * * @author Rainer Klute <klute@rainer-klute.de> * @since 2003-08-03 * @version $Id: MutableProperty.java,v 1.1 2003/08/30 09:13:52 klute Exp $ */ public class MutableProperty extends Property { /** *

      Creates an empty property. It must be filled using the set method to * be usable.

      */ public MutableProperty() { } /** *

      Sets the property's ID.

      * * @param id the ID */ public void setID(final long id) { this.id = id; } /** *

      Sets the property's type.

      * * @param type the property's type */ public void setType(final long type) { this.type = type; } /** *

      Sets the property's value.

      * * @param value the property's value */ public void setValue(final Object value) { this.value = value; } /** *

      Writes the property to an output stream.

      * * @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; } } 1.1 jakarta-poi/src/java/org/apache/poi/hpsf/MutablePropertySet.java Index: MutablePropertySet.java =================================================================== /* * ==================================================================== * 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 * . */ 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; /** *

      Adds writing support to the {@link PropertySet} class.

      * *

      Please be aware that this class' functionality will be merged into the * {@link PropertySet} class at a later time, so the API will change.

      * * @author Rainer Klute <klute@rainer-klute.de> * @version $Id: MutablePropertySet.java,v 1.1 2003/08/30 09:13:52 klute Exp $ * @since 2003-02-19 */ public class MutablePropertySet extends PropertySet { /** *

      Constructs a MutablePropertySet instance. Its * primary task is to initialize the immutable field with their proper * values. It also sets fields that might change to reasonable defaults.

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

      The length of the property set stream header.

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

      Sets the "byteOrder" property.

      * * @param byteOrder the byteOrder value to set */ public void setByteOrder(final int byteOrder) { this.byteOrder = byteOrder; } /** *

      Sets the "format" property.

      * * @param format the format value to set */ public void setFormat(final int format) { this.format = format; } /** *

      Sets the "osVersion" property.

      * * @param osVersion the osVersion value to set */ public void setOSVersion(final int osVersion) { this.osVersion = osVersion; } /** *

      Sets the property set stream's low-level "class ID" * field.

      * * @param classID The property set stream's low-level "class ID" field. * * @see #getClassID */ public void setClassID(final ClassID classID) { this.classID = classID; } /** *

      Removes all sections from this property set.

      */ public void clearSections() { sections = null; } /** *

      Adds a section to this property set.

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

      Writes the property set to an output stream.

      * * @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); } } } 1.1 jakarta-poi/src/java/org/apache/poi/hpsf/MutableSection.java Index: MutableSection.java =================================================================== /* * ==================================================================== * 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 * . */ 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; /** *

      Adds writing capability to the {@link Section} class.

      * *

      Please be aware that this class' functionality will be merged into the * {@link Section} class at a later time, so the API will change.

      * * @author Rainer Klute <klute@rainer-klute.de> * @version $Id: MutableSection.java,v 1.1 2003/08/30 09:13:52 klute Exp $ * @since 2002-02-20 */ public class MutableSection extends Section { /** *

      If the "dirty" flag is true, the section's size must be * (re-)calculated before the section is written.

      */ private boolean dirty = true; /** *

      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}.

      */ private List preprops; /** *

      Creates an empty mutable section.

      */ public MutableSection() { dirty = true; formatID = null; offset = -1; preprops = new LinkedList(); } /** *

      Sets the section's format ID.

      * * @param formatID The section's format ID * * @see #setFormatID(byte[]) * @see #getFormatID */ public void setFormatID(final ClassID formatID) { this.formatID = formatID; } /** *

      Sets the section's format ID.

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

      Sets this section's properties. Any former values are overwritten.

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

      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.

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

      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.

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

      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.

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

      Sets the value of the boolean property with the specified * ID.

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

      Returns the section's size.

      * * @return the section's size. */ public int getSize() { if (dirty) { size = calcSize(); dirty = false; } return size; } /** *

      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.

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

      Writes this section into an output stream.

      * *

      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.

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

      Overwrites the super class' method to cope with a redundancy: * the property count is maintained in a separate member variable, but * shouldn't.

      * * @return The number of properties in this section */ public int getPropertyCount() { return preprops.size(); } /** *

      Returns this section's properties.

      * * @return this section's properties. */ public Property[] getProperties() { return (Property[]) preprops.toArray(new Property[0]); } } 1.9 +4 -4 jakarta-poi/src/java/org/apache/poi/hpsf/wellknown/PropertyIDMap.java Index: PropertyIDMap.java =================================================================== RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hpsf/wellknown/PropertyIDMap.java,v retrieving revision 1.8 retrieving revision 1.9 diff -u -r1.8 -r1.9 --- PropertyIDMap.java 2 Aug 2003 19:02:28 -0000 1.8 +++ PropertyIDMap.java 30 Aug 2003 09:13:53 -0000 1.9 @@ -66,9 +66,9 @@ * should treat them as unmodifiable, copy them and modifiy the * copies.

      * - *

      FIXME: Make the singletons unmodifiable. However, + *

      FIXME (3): Make the singletons unmodifiable. However, * 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.

      * * @author Rainer Klute (klute@rainer-klute.de) @@ -141,7 +141,7 @@ * document

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

      ID of the property that denotes... FIXME

      */ + /**

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

      */ public static final int PID_SECURITY = 19; --------------------------------------------------------------------- To unsubscribe, e-mail: poi-dev-unsubscribe@jakarta.apache.org For additional commands, e-mail: poi-dev-help@jakarta.apache.org