Compares this {@link PropertyListEntry} with another one by their
- * offsets. A {@link PropertyListEntry} is "smaller" than another one if
- * its offset from the section's begin is smaller.
- *
- * @see Comparable#compareTo(java.lang.Object)
- */
- public int compareTo(final PropertyListEntry o)
- {
- final int otherOffset = o.offset;
- if (offset < otherOffset)
- return -1;
- else if (offset == otherOffset)
- return 0;
- else
- return 1;
- }
-
-
-
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + id;
- result = prime * result + length;
- result = prime * result + offset;
- return result;
- }
-
-
-
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- PropertyListEntry other = (PropertyListEntry) obj;
- if (id != other.id) {
- return false;
- }
- if (length != other.length) {
- return false;
- }
- if (offset != other.offset) {
- return false;
- }
- return true;
- }
-
-
-
- public String toString()
- {
- final StringBuffer b = new StringBuffer();
- b.append(getClass().getName());
- b.append("[id=");
- b.append(id);
- b.append(", offset=");
- b.append(offset);
- b.append(", length=");
- b.append(length);
- b.append(']');
- return b.toString();
- }
+ private static int propLen(
+ TreeBidiMap offset2Id,
+ Long entryOffset,
+ long maxSize) {
+ Long nextKey = offset2Id.nextKey(entryOffset);
+ long begin = entryOffset;
+ long end = (nextKey != null) ? nextKey : maxSize;
+ return (int)(end - begin);
}
+ /**
+ * Returns the format ID. The format ID is the "type" of the
+ * section. For example, if the format ID of the first {@link
+ * Section} contains the bytes specified by
+ * {@code org.apache.poi.hpsf.wellknown.SectionIDMap.SUMMARY_INFORMATION_ID}
+ * the section (and thus the property set) is a SummaryInformation.
+ *
+ * @return The format ID
+ */
+ public ClassID getFormatID() {
+ return formatID;
+ }
/**
- * Returns the value of the property with the specified ID. If
- * the property is not available, null
is returned
+ * Sets the section's format ID.
+ *
+ * @param formatID The section's format ID
+ */
+ 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.
+ */
+ public void setFormatID(final byte[] formatID) {
+ ClassID fid = getFormatID();
+ if (fid == null) {
+ fid = new ClassID();
+ setFormatID(fid);
+ }
+ fid.setBytes(formatID);
+ }
+
+ /**
+ * Returns the offset of the section in the stream.
+ *
+ * @return The offset of the section in the stream.
+ */
+ public long getOffset() {
+ return offset;
+ }
+
+ /**
+ * Returns the number of properties in this section.
+ *
+ * @return The number of properties in this section.
+ */
+ public int getPropertyCount() {
+ return properties.size();
+ }
+
+ /**
+ * Returns this section's properties.
+ *
+ * @return This section's properties.
+ */
+ public Property[] getProperties() {
+ return properties.values().toArray(new Property[properties.size()]);
+ }
+
+ /**
+ * Sets this section's properties. Any former values are overwritten.
+ *
+ * @param properties This section's new properties.
+ */
+ public void setProperties(final Property[] properties) {
+ this.properties.clear();
+ for (Property p : properties) {
+ this.properties.put(p.getID(), p);
+ }
+ dirty = true;
+ }
+
+ /**
+ * Returns the value of the property with the specified ID. If
+ * the property is not available, {@code null} is returned
* and a subsequent call to {@link #wasNull} will return
- * true
.
+ * {@code true}.
*
* @param id The property's ID
*
* @return The property's value
*/
- public Object getProperty(final long id)
- {
- wasNull = false;
- for (int i = 0; i < properties.length; i++)
- if (id == properties[i].getID())
- return properties[i].getValue();
- wasNull = true;
- return null;
+ public Object getProperty(final long id) {
+ wasNull = !properties.containsKey(id);
+ return (wasNull) ? null : properties.get(id).getValue();
+ }
+
+ /**
+ * Sets the string value of the property with the specified ID.
+ *
+ * @param id The property's ID
+ * @param value The property's value. It will be written as a Unicode
+ * string.
+ */
+ public void setProperty(final int id, final String value) {
+ setProperty(id, Variant.VT_LPWSTR, value);
+ }
+
+ /**
+ * Sets the int value of the property with the specified ID.
+ *
+ * @param id The property's ID
+ * @param value The property's value.
+ *
+ * @see #setProperty(int, long, Object)
+ * @see #getProperty
+ */
+ public void setProperty(final int id, final int value) {
+ setProperty(id, Variant.VT_I4, Integer.valueOf(value));
}
/**
- * Returns the value of the numeric property with the specified
+ * Sets the long value of the property with the specified ID.
+ *
+ * @param id The property's ID
+ * @param value The property's value.
+ *
+ * @see #setProperty(int, long, Object)
+ * @see #getProperty
+ */
+ public void setProperty(final int id, final long value) {
+ setProperty(id, Variant.VT_I8, Long.valueOf(value));
+ }
+
+
+
+ /**
+ * Sets the boolean value of the property with the specified ID.
+ *
+ * @param id The property's ID
+ * @param value The property's value.
+ *
+ * @see #setProperty(int, long, Object)
+ * @see #getProperty
+ */
+ public void setProperty(final int id, final boolean value) {
+ setProperty(id, Variant.VT_BOOL, Boolean.valueOf(value));
+ }
+
+
+
+ /**
+ * 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, String)
+ * @see #getProperty
+ * @see Variant
+ */
+ public void setProperty(final int id, final long variantType, final Object value) {
+ setProperty(new Property(id, variantType, value));
+ }
+
+
+
+ /**
+ * Sets a property.
+ *
+ * @param p The property to be set.
+ *
+ * @see #setProperty(int, long, Object)
+ * @see #getProperty
+ * @see Variant
+ */
+ public void setProperty(final Property p) {
+ Property old = properties.get(p.getID());
+ if (old == null || !old.equals(p)) {
+ properties.put(p.getID(), p);
+ dirty = true;
+ }
+ }
+
+ /**
+ * Sets a property.
+ *
+ * @param id The property ID.
+ * @param value The property's value. The value's class must be one of those
+ * supported by HPSF.
+ */
+ public void setProperty(final int id, final Object value) {
+ if (value instanceof String) {
+ setProperty(id, (String) value);
+ } else if (value instanceof Long) {
+ setProperty(id, ((Long) value).longValue());
+ } else if (value instanceof Integer) {
+ setProperty(id, ((Integer) value).intValue());
+ } else if (value instanceof Short) {
+ setProperty(id, ((Short) value).intValue());
+ } else if (value instanceof Boolean) {
+ setProperty(id, ((Boolean) value).booleanValue());
+ } else if (value instanceof Date) {
+ setProperty(id, Variant.VT_FILETIME, value);
+ } else {
+ throw new HPSFRuntimeException(
+ "HPSF does not support properties of type " +
+ value.getClass().getName() + ".");
+ }
+ }
+
+ /**
+ * Returns the value of the numeric property with the specified
* ID. If the property is not available, 0 is returned. A
* subsequent call to {@link #wasNull} will return
- * true
to let the caller distinguish that case from
- * a real property value of 0.
+ * {@code true} to let the caller distinguish that case from
+ * a real property value of 0.
*
* @param id The property's ID
*
* @return The property's value
*/
- protected int getPropertyIntValue(final long id)
- {
+ protected int getPropertyIntValue(final long id) {
final Number i;
final Object o = getProperty(id);
- if (o == null)
+ if (o == null) {
return 0;
- if (!(o instanceof Long || o instanceof Integer))
+ }
+ if (!(o instanceof Long || o instanceof Integer)) {
throw new HPSFRuntimeException
("This property is not an integer type, but " +
o.getClass().getName() + ".");
+ }
i = (Number) o;
return i.intValue();
}
-
-
/**
- * Returns the value of the boolean property with the specified
- * ID. If the property is not available, false
is
+ * Returns the value of the boolean property with the specified
+ * ID. If the property is not available, {@code false} is
* returned. A subsequent call to {@link #wasNull} will return
- * true
to let the caller distinguish that case from
- * a real property value of false
.
+ * {@code true} to let the caller distinguish that case from
+ * a real property value of {@code false}.
*
* @param id The property's ID
*
* @return The property's value
*/
- protected boolean getPropertyBooleanValue(final int id)
- {
+ protected boolean getPropertyBooleanValue(final int id) {
final Boolean b = (Boolean) getProperty(id);
if (b == null) {
return false;
}
return b.booleanValue();
- }
-
-
+ }
/**
- * This member is true
if the last call to {@link
- * #getPropertyIntValue} or {@link #getProperty} tried to access a
- * property that was not available, else false
.
+ * 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, long, Object)
+ * @see #getProperty
+ * @see Variant
*/
- private boolean wasNull;
+ protected void setPropertyBooleanValue(final int id, final boolean value) {
+ setProperty(id, Variant.VT_BOOL, Boolean.valueOf(value));
+ }
+
+ /**
+ * @return the section's size in bytes.
+ */
+ public int getSize() {
+ if (dirty) {
+ try {
+ size = calcSize();
+ dirty = false;
+ } catch (HPSFRuntimeException ex) {
+ throw ex;
+ } catch (Exception ex) {
+ throw new HPSFRuntimeException(ex);
+ }
+ }
+ 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.
+ * @throws WritingNotSupportedException
+ * @throws IOException
+ */
+ private int calcSize() throws WritingNotSupportedException, IOException {
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ write(out);
+ out.close();
+ /* Pad to multiple of 4 bytes so that even the Windows shell (explorer)
+ * shows custom properties. */
+ sectionBytes = Util.pad4(out.toByteArray());
+ return sectionBytes.length;
+ }
+
+
/**
- * Checks whether the property which the last call to {@link
+ * Checks whether the property which the last call to {@link
* #getPropertyIntValue} or {@link #getProperty} tried to access
* was available or not. This information might be important for
* callers of {@link #getPropertyIntValue} since the latter
* returns 0 if the property does not exist. Using {@link
* #wasNull} the caller can distiguish this case from a property's
- * real value of 0.
+ * real value of 0.
*
- * @return true
if the last call to {@link
+ * @return {@code true} if the last call to {@link
* #getPropertyIntValue} or {@link #getProperty} tried to access a
- * property that was not available, else false
.
+ * property that was not available, else {@code false}.
*/
- public boolean wasNull()
- {
+ public boolean wasNull() {
return wasNull;
}
/**
- * Returns the PID string associated with a property ID. The ID
+ * Returns the PID string associated with a property ID. The ID
* is first looked up in the {@link Section}'s private
* dictionary. If it is not found there, the method calls {@link
- * SectionIDMap#getPIDString}.
+ * SectionIDMap#getPIDString}.
*
* @param pid The property ID
*
* @return The property ID's string value
*/
- public String getPIDString(final long pid)
- {
+ public String getPIDString(final long pid) {
String s = null;
if (dictionary != null) {
s = dictionary.get(Long.valueOf(pid));
@@ -491,39 +600,65 @@ public class Section
return s;
}
+ /**
+ * Removes all properties from the section including 0 (dictionary) and
+ * 1 (codepage).
+ */
+ public void clear()
+ {
+ final Property[] properties = getProperties();
+ for (int i = 0; i < properties.length; i++)
+ {
+ final Property p = properties[i];
+ removeProperty(p.getID());
+ }
+ }
+
+ /**
+ * Sets the codepage.
+ *
+ * @param codepage the codepage
+ */
+ public void setCodepage(final int codepage)
+ {
+ setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2,
+ Integer.valueOf(codepage));
+ }
+
/**
- * Checks whether this section is equal to another object. The result is
- * false
if one of the the following conditions holds:
+ * Checks whether this section is equal to another object. The result is
+ * {@code false} if one of the the following conditions holds:
*
*
*
- * The other object is not a {@link Section}.
+ * - The other object is not a {@link Section}.
*
- * The format IDs of the two sections are not equal.
+ * - The format IDs of the two sections are not equal.
*
- * The sections have a different number of properties. However,
- * properties with ID 1 (codepage) are not counted.
+ * - The sections have a different number of properties. However,
+ * properties with ID 1 (codepage) are not counted.
*
- * The other object is not a {@link Section}.
+ * - The other object is not a {@link Section}.
*
- * The properties have different values. The order of the properties
- * is irrelevant.
+ * - The properties have different values. The order of the properties
+ * is irrelevant.
*
*
*
* @param o The object to compare this section with
- * @return true
if the objects are equal, false
if
+ * @return {@code true} if the objects are equal, {@code false} if
* not
*/
- public boolean equals(final Object o)
- {
- if (o == null || !(o instanceof Section))
+ public boolean equals(final Object o) {
+ if (o == null || !(o instanceof Section)) {
return false;
+ }
final Section s = (Section) o;
- if (!s.getFormatID().equals(getFormatID()))
+ if (!s.getFormatID().equals(getFormatID())) {
return false;
+ }
/* Compare all properties except 0 and 1 as they must be handled
* specially. */
@@ -536,34 +671,26 @@ public class Section
* arrays. */
Property p10 = null;
Property p20 = null;
- for (int i = 0; i < pa1.length; i++)
- {
+ for (int i = 0; i < pa1.length; i++) {
final long id = pa1[i].getID();
- if (id == 0)
- {
+ if (id == 0) {
p10 = pa1[i];
pa1 = remove(pa1, i);
i--;
}
- if (id == 1)
- {
- // p11 = pa1[i];
+ if (id == 1) {
pa1 = remove(pa1, i);
i--;
}
}
- for (int i = 0; i < pa2.length; i++)
- {
+ for (int i = 0; i < pa2.length; i++) {
final long id = pa2[i].getID();
- if (id == 0)
- {
+ if (id == 0) {
p20 = pa2[i];
pa2 = remove(pa2, i);
i--;
}
- if (id == 1)
- {
- // p21 = pa2[i];
+ if (id == 1) {
pa2 = remove(pa2, i);
i--;
}
@@ -571,52 +698,266 @@ public class Section
/* If the number of properties (not counting property 1) is unequal the
* sections are unequal. */
- if (pa1.length != pa2.length)
+ if (pa1.length != pa2.length) {
return false;
+ }
/* If the dictionaries are unequal the sections are unequal. */
boolean dictionaryEqual = true;
- if (p10 != null && p20 != null)
+ if (p10 != null && p20 != null) {
dictionaryEqual = p10.getValue().equals(p20.getValue());
- else if (p10 != null || p20 != null)
+ } else if (p10 != null || p20 != null) {
dictionaryEqual = false;
+ }
if (dictionaryEqual) {
return Util.equals(pa1, pa2);
}
return false;
}
-
+ /**
+ * Removes a property.
+ *
+ * @param id The ID of the property to be removed
+ */
+ public void removeProperty(final long id) {
+ dirty |= (properties.remove(id) != null);
+ }
/**
- * Removes a field from a property array. The resulting array is
- * compactified and returned.
+ * Removes a field from a property array. The resulting array is
+ * compactified and returned.
*
* @param pa The property array.
* @param i The index of the field to be removed.
* @return the compactified array.
*/
- private Property[] remove(final Property[] pa, final int i)
- {
+ private Property[] remove(final Property[] pa, final int i) {
final Property[] h = new Property[pa.length - 1];
- if (i > 0)
+ if (i > 0) {
System.arraycopy(pa, 0, h, 0, i);
+ }
System.arraycopy(pa, i + 1, h, i, h.length - i);
return h;
}
+ /**
+ * 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.
+ *
+ * @return The number of bytes written, i.e. the section's size.
+ * @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) throws WritingNotSupportedException, IOException {
+ /* Check whether we have already generated the bytes making out the
+ * section. */
+ if (!dirty && sectionBytes != null) {
+ out.write(sectionBytes);
+ return sectionBytes.length;
+ }
+
+ /* 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 behind the property list and to the beginning of the
+ * properties themselves. */
+ position += 2 * LittleEndian.INT_SIZE + getPropertyCount() * 2 * LittleEndian.INT_SIZE;
+
+ /* Writing the section's dictionary it tricky. If there is a dictionary
+ * (property 0) the codepage property (property 1) must be set, too. */
+ int codepage = -1;
+ if (getProperty(PropertyIDMap.PID_DICTIONARY) != null) {
+ final Object p1 = getProperty(PropertyIDMap.PID_CODEPAGE);
+ if (p1 != null) {
+ if (!(p1 instanceof Integer)) {
+ throw new IllegalPropertySetDataException
+ ("The codepage property (ID = 1) must be an " +
+ "Integer object.");
+ }
+ } else {
+ /* Warning: The codepage property is not set although a
+ * dictionary is present. In order to cope with this problem we
+ * add the codepage property and set it to Unicode. */
+ setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2,
+ Integer.valueOf(CodePageUtil.CP_UNICODE));
+ }
+ codepage = getCodepage();
+ }
+
+ /* Write the properties and the property list into their respective
+ * streams: */
+ for (Property p : properties.values()) {
+ final long id = p.getID();
+
+ /* Write the property list entry. */
+ TypeWriter.writeUIntToStream(propertyListStream, p.getID());
+ TypeWriter.writeUIntToStream(propertyListStream, position);
+
+ /* If the property ID is not equal 0 we write the property and all
+ * is fine. However, if it equals 0 we have to write the section's
+ * dictionary which has an implicit type only and an explicit
+ * value. */
+ if (id != 0)
+ /* Write the property and update the position to the next
+ * property. */
+ position += p.write(propertyStream, getCodepage());
+ else
+ {
+ if (codepage == -1)
+ throw new IllegalPropertySetDataException
+ ("Codepage (property 1) is undefined.");
+ position += writeDictionary(propertyStream, dictionary,
+ codepage);
+ }
+ }
+ propertyStream.close();
+ propertyListStream.close();
+
+ /* Write the section: */
+ byte[] pb1 = propertyListStream.toByteArray();
+ byte[] pb2 = propertyStream.toByteArray();
+
+ /* Write the section's length: */
+ TypeWriter.writeToStream(out, LittleEndian.INT_SIZE * 2 +
+ pb1.length + pb2.length);
+
+ /* Write the section's number of properties: */
+ TypeWriter.writeToStream(out, getPropertyCount());
+
+ /* Write the property list: */
+ out.write(pb1);
+
+ /* Write the properties: */
+ out.write(pb2);
+
+ int streamLength = LittleEndian.INT_SIZE * 2 + pb1.length + pb2.length;
+ return streamLength;
+ }
+
+
+
+ /**
+ * Writes the section's dictionary.
+ *
+ * @param out The output stream to write to.
+ * @param dictionary The dictionary.
+ * @param codepage The codepage to be used to write the dictionary items.
+ * @return The number of bytes written
+ * @exception IOException if an I/O exception occurs.
+ */
+ private static int writeDictionary(final OutputStream out, final Map dictionary, final int codepage)
+ throws IOException {
+ int length = TypeWriter.writeUIntToStream(out, dictionary.size());
+ for (Map.Entry ls : dictionary.entrySet()) {
+ final Long key = ls.getKey();
+ final String value = ls.getValue();
+
+ if (codepage == CodePageUtil.CP_UNICODE) {
+ /* Write the dictionary item in Unicode. */
+ int sLength = value.length() + 1;
+ if ((sLength & 1) == 1) {
+ sLength++;
+ }
+ length += TypeWriter.writeUIntToStream(out, key.longValue());
+ length += TypeWriter.writeUIntToStream(out, sLength);
+ final byte[] ca = CodePageUtil.getBytesInCodePage(value, codepage);
+ for (int j = 2; j < ca.length; j += 2) {
+ out.write(ca[j+1]);
+ out.write(ca[j]);
+ length += 2;
+ }
+ sLength -= value.length();
+ while (sLength > 0) {
+ out.write(0x00);
+ out.write(0x00);
+ length += 2;
+ sLength--;
+ }
+ } else {
+ /* Write the dictionary item in another codepage than
+ * Unicode. */
+ length += TypeWriter.writeUIntToStream(out, key.longValue());
+ length += TypeWriter.writeUIntToStream(out, value.length() + 1);
+ final byte[] ba = CodePageUtil.getBytesInCodePage(value, codepage);
+ for (int j = 0; j < ba.length; j++) {
+ out.write(ba[j]);
+ length++;
+ }
+ out.write(0x00);
+ length++;
+ }
+ }
+ return length;
+ }
+
+ /**
+ * Sets the section's dictionary. All keys in the dictionary must be
+ * {@link java.lang.Long} instances, all values must be
+ * {@link java.lang.String}s. This method overwrites the properties with IDs
+ * 0 and 1 since they are reserved for the dictionary and the dictionary's
+ * codepage. Setting these properties explicitly might have surprising
+ * effects. An application should never do this but always use this
+ * method.
+ *
+ * @param dictionary The dictionary
+ *
+ * @exception IllegalPropertySetDataException if the dictionary's key and
+ * value types are not correct.
+ *
+ * @see Section#getDictionary()
+ */
+ public void setDictionary(final Map dictionary) throws IllegalPropertySetDataException {
+ if (dictionary != null) {
+ this.dictionary = dictionary;
+
+ /* Set the dictionary property (ID 0). Please note that the second
+ * parameter in the method call below is unused because dictionaries
+ * don't have a type. */
+ setProperty(PropertyIDMap.PID_DICTIONARY, -1, dictionary);
+
+ /* If the codepage property (ID 1) for the strings (keys and
+ * values) used in the dictionary is not yet defined, set it to
+ * Unicode. */
+ final Integer codepage = (Integer) getProperty(PropertyIDMap.PID_CODEPAGE);
+ if (codepage == null) {
+ setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2,
+ Integer.valueOf(CodePageUtil.CP_UNICODE));
+ }
+ } else {
+ /* Setting the dictionary to null means to remove property 0.
+ * However, it does not mean to remove property 1 (codepage). */
+ removeProperty(PropertyIDMap.PID_DICTIONARY);
+ }
+ }
/**
* @see Object#hashCode()
*/
- public int hashCode()
- {
+ public int hashCode() {
long hashCode = 0;
hashCode += getFormatID().hashCode();
final Property[] pa = getProperties();
- for (int i = 0; i < pa.length; i++)
+ for (int i = 0; i < pa.length; i++) {
hashCode += pa[i].hashCode();
+ }
final int returnHashCode = (int) (hashCode & 0x0ffffffffL);
return returnHashCode;
}
@@ -626,8 +967,7 @@ public class Section
/**
* @see Object#toString()
*/
- public String toString()
- {
+ public String toString() {
final StringBuffer b = new StringBuffer();
final Property[] pa = getProperties();
b.append(getClass().getName());
@@ -641,8 +981,7 @@ public class Section
b.append(", size: ");
b.append(getSize());
b.append(", properties: [\n");
- for (int i = 0; i < pa.length; i++)
- {
+ for (int i = 0; i < pa.length; i++) {
b.append(pa[i].toString());
b.append(",\n");
}
@@ -654,35 +993,33 @@ public class Section
/**
- * Gets the section's dictionary. A dictionary allows an application to
+ * Gets the section's dictionary. A dictionary allows an application to
* use human-readable property names instead of numeric property IDs. It
* contains mappings from property IDs to their associated string
* values. The dictionary is stored as the property with ID 0. The codepage
- * for the strings in the dictionary is defined by property with ID 1.
+ * for the strings in the dictionary is defined by property with ID 1.
*
- * @return the dictionary or null
if the section does not have
+ * @return the dictionary or {@code null} if the section does not have
* a dictionary.
*/
- public Map getDictionary()
- {
+ public Map getDictionary() {
return dictionary;
}
/**
- * Gets the section's codepage, if any.
+ * Gets the section's codepage, if any.
*
* @return The section's codepage if one is defined, else -1.
*/
public int getCodepage()
{
- final Integer codepage =
- (Integer) getProperty(PropertyIDMap.PID_CODEPAGE);
- if (codepage == null)
+ final Integer codepage = (Integer) getProperty(PropertyIDMap.PID_CODEPAGE);
+ if (codepage == null) {
return -1;
+ }
int cp = codepage.intValue();
return cp;
}
-
}
diff --git a/src/java/org/apache/poi/hpsf/SpecialPropertySet.java b/src/java/org/apache/poi/hpsf/SpecialPropertySet.java
index aa8f8051d..843d681eb 100644
--- a/src/java/org/apache/poi/hpsf/SpecialPropertySet.java
+++ b/src/java/org/apache/poi/hpsf/SpecialPropertySet.java
@@ -17,397 +17,24 @@
package org.apache.poi.hpsf;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.charset.Charset;
-import java.util.List;
-
-import org.apache.poi.hpsf.wellknown.PropertyIDMap;
-import org.apache.poi.poifs.filesystem.DirectoryEntry;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.Removal;
/**
- * Abstract superclass for the convenience classes {@link
- * SummaryInformation} and {@link DocumentSummaryInformation}.
+ * Interface for the convenience classes {@link SummaryInformation}
+ * and {@link DocumentSummaryInformation}.
*
- *
The motivation behind this class is quite nasty if you look
- * behind the scenes, but it serves the application programmer well by
- * providing him with the easy-to-use {@link SummaryInformation} and
- * {@link DocumentSummaryInformation} classes. When parsing the data a
- * property set stream consists of (possibly coming from an {@link
- * java.io.InputStream}) we want to read and process each byte only
- * once. Since we don't know in advance which kind of property set we
- * have, we can expect only the most general {@link
- * PropertySet}. Creating a special subclass should be as easy as
- * calling the special subclass' constructor and pass the general
- * {@link PropertySet} in. To make things easy internally, the special
- * class just holds a reference to the general {@link PropertySet} and
- * delegates all method calls to it.
+ * This used to be an abstract class to support late loading
+ * of the SummaryInformation classes, as their concrete instance can
+ * only be determined after the PropertySet has been loaded.
*
- * A cleaner implementation would have been like this: The {@link
- * PropertySetFactory} parses the stream data into some internal
- * object first. Then it finds out whether the stream is a {@link
- * SummaryInformation}, a {@link DocumentSummaryInformation} or a
- * general {@link PropertySet}. However, the current implementation
- * went the other way round historically: the convenience classes came
- * only late to my mind.
+ * @deprecated POI 3.16 - use PropertySet as base class instead
*/
-public abstract class SpecialPropertySet extends MutablePropertySet
-{
- /**
- * The id to name mapping of the properties in this set.
- *
- * @return the id to name mapping of the properties in this set
- */
- public abstract PropertyIDMap getPropertySetIDMap();
-
- /**
- * The "real" property set SpecialPropertySet
- * delegates to.
- */
- private final MutablePropertySet delegate;
-
-
-
- /**
- * Creates a SpecialPropertySet
.
- *
- * @param ps The property set to be encapsulated by the
- * SpecialPropertySet
- */
- public SpecialPropertySet(final PropertySet ps)
- {
- delegate = new MutablePropertySet(ps);
+@Removal(version="3.18")
+public class SpecialPropertySet extends MutablePropertySet {
+ public SpecialPropertySet() {
}
-
-
- /**
- *
Creates a SpecialPropertySet
.
- *
- * @param ps The mutable property set to be encapsulated by the
- * SpecialPropertySet
- */
- public SpecialPropertySet(final MutablePropertySet ps)
- {
- delegate = ps;
+ public SpecialPropertySet(final PropertySet ps) throws UnexpectedPropertySetTypeException {
+ super(ps);
}
-
-
-
- /**
- * @see PropertySet#getByteOrder
- */
- @Override
- public int getByteOrder()
- {
- return delegate.getByteOrder();
- }
-
-
-
- /**
- * @see PropertySet#getFormat
- */
- @Override
- public int getFormat()
- {
- return delegate.getFormat();
- }
-
-
-
- /**
- * @see PropertySet#getOSVersion
- */
- @Override
- public int getOSVersion()
- {
- return delegate.getOSVersion();
- }
-
-
-
- /**
- * @see PropertySet#getClassID
- */
- @Override
- public ClassID getClassID()
- {
- return delegate.getClassID();
- }
-
-
-
- /**
- * @see PropertySet#getSectionCount
- */
- @Override
- public int getSectionCount()
- {
- return delegate.getSectionCount();
- }
-
-
-
- /**
- * @see PropertySet#getSections
- */
- @Override
- public List getSections()
- {
- return delegate.getSections();
- }
-
-
-
- /**
- * @see PropertySet#isSummaryInformation
- */
- @Override
- public boolean isSummaryInformation()
- {
- return delegate.isSummaryInformation();
- }
-
-
-
- /**
- * @see PropertySet#isDocumentSummaryInformation
- */
- @Override
- public boolean isDocumentSummaryInformation()
- {
- return delegate.isDocumentSummaryInformation();
- }
-
-
-
- /**
- * @see PropertySet#getSingleSection
- */
- @Override
- public Section getFirstSection()
- {
- return delegate.getFirstSection();
- }
-
-
- /**
- * @see org.apache.poi.hpsf.MutablePropertySet#addSection(org.apache.poi.hpsf.Section)
- */
- @Override
- public void addSection(final Section section)
- {
- delegate.addSection(section);
- }
-
-
-
- /**
- * @see org.apache.poi.hpsf.MutablePropertySet#clearSections()
- */
- @Override
- public void clearSections()
- {
- delegate.clearSections();
- }
-
-
-
- /**
- * @see org.apache.poi.hpsf.MutablePropertySet#setByteOrder(int)
- */
- @Override
- public void setByteOrder(final int byteOrder)
- {
- delegate.setByteOrder(byteOrder);
- }
-
-
-
- /**
- * @see org.apache.poi.hpsf.MutablePropertySet#setClassID(org.apache.poi.hpsf.ClassID)
- */
- @Override
- public void setClassID(final ClassID classID)
- {
- delegate.setClassID(classID);
- }
-
-
-
- /**
- * @see org.apache.poi.hpsf.MutablePropertySet#setFormat(int)
- */
- @Override
- public void setFormat(final int format)
- {
- delegate.setFormat(format);
- }
-
-
-
- /**
- * @see org.apache.poi.hpsf.MutablePropertySet#setOSVersion(int)
- */
- @Override
- public void setOSVersion(final int osVersion)
- {
- delegate.setOSVersion(osVersion);
- }
-
-
-
- /**
- * @see org.apache.poi.hpsf.MutablePropertySet#toInputStream()
- */
- @Override
- public InputStream toInputStream() throws IOException, WritingNotSupportedException
- {
- return delegate.toInputStream();
- }
-
-
-
- /**
- * @see org.apache.poi.hpsf.MutablePropertySet#write(org.apache.poi.poifs.filesystem.DirectoryEntry, java.lang.String)
- */
- @Override
- public void write(final DirectoryEntry dir, final String name) throws WritingNotSupportedException, IOException
- {
- delegate.write(dir, name);
- }
-
- /**
- * @see org.apache.poi.hpsf.MutablePropertySet#write(java.io.OutputStream)
- */
- @Override
- public void write(final OutputStream out) throws WritingNotSupportedException, IOException
- {
- delegate.write(out);
- }
-
- /**
- * @see org.apache.poi.hpsf.PropertySet#equals(java.lang.Object)
- */
- @Override
- public boolean equals(final Object o)
- {
- return delegate.equals(o);
- }
-
- /**
- * @see org.apache.poi.hpsf.PropertySet#getProperties()
- */
- @Override
- public Property[] getProperties() throws NoSingleSectionException
- {
- return delegate.getProperties();
- }
-
- /**
- * @see org.apache.poi.hpsf.PropertySet#getProperty(int)
- */
- @Override
- protected Object getProperty(final int id) throws NoSingleSectionException
- {
- return delegate.getProperty(id);
- }
-
-
-
- /**
- * @see org.apache.poi.hpsf.PropertySet#getPropertyBooleanValue(int)
- */
- @Override
- protected boolean getPropertyBooleanValue(final int id) throws NoSingleSectionException
- {
- return delegate.getPropertyBooleanValue(id);
- }
-
-
-
- /**
- * @see org.apache.poi.hpsf.PropertySet#getPropertyIntValue(int)
- */
- @Override
- protected int getPropertyIntValue(final int id) throws NoSingleSectionException
- {
- return delegate.getPropertyIntValue(id);
- }
-
-
-
- /**
- * Fetches the property with the given ID, then does its
- * best to return it as a String
- *
- * @param propertyId the property id
- *
- * @return The property as a String, or null if unavailable
- */
- protected String getPropertyStringValue(final int propertyId) {
- Object propertyValue = getProperty(propertyId);
- return getPropertyStringValue(propertyValue);
- }
- protected static String getPropertyStringValue(final Object propertyValue) {
- // Normal cases
- if (propertyValue == null) return null;
- if (propertyValue instanceof String) return (String)propertyValue;
-
- // Do our best with some edge cases
- if (propertyValue instanceof byte[]) {
- byte[] b = (byte[])propertyValue;
- if (b.length == 0) {
- return "";
- }
- if (b.length == 1) {
- return Byte.toString(b[0]);
- }
- if (b.length == 2) {
- return Integer.toString( LittleEndian.getUShort(b) );
- }
- if (b.length == 4) {
- return Long.toString( LittleEndian.getUInt(b) );
- }
- // Maybe it's a string? who knows!
- return new String(b, Charset.forName("ASCII"));
- }
- return propertyValue.toString();
- }
-
-
- /**
- * @see org.apache.poi.hpsf.PropertySet#hashCode()
- */
- @Override
- public int hashCode()
- {
- return delegate.hashCode();
- }
-
-
-
- /**
- * @see org.apache.poi.hpsf.PropertySet#toString()
- */
- @Override
- public String toString()
- {
- return delegate.toString();
- }
-
-
-
- /**
- * @see org.apache.poi.hpsf.PropertySet#wasNull()
- */
- @Override
- public boolean wasNull() throws NoSingleSectionException
- {
- return delegate.wasNull();
- }
-
}
diff --git a/src/java/org/apache/poi/hpsf/SummaryInformation.java b/src/java/org/apache/poi/hpsf/SummaryInformation.java
index 5c260187c..856f566e7 100644
--- a/src/java/org/apache/poi/hpsf/SummaryInformation.java
+++ b/src/java/org/apache/poi/hpsf/SummaryInformation.java
@@ -20,18 +20,18 @@ package org.apache.poi.hpsf;
import java.util.Date;
import org.apache.poi.hpsf.wellknown.PropertyIDMap;
+import org.apache.poi.hpsf.wellknown.SectionIDMap;
/**
- * Convenience class representing a Summary Information stream in a
- * Microsoft Office document.
+ * Convenience class representing a Summary Information stream in a
+ * Microsoft Office document.
*
* @see DocumentSummaryInformation
*/
public final class SummaryInformation extends SpecialPropertySet {
/**
- * The document name a summary information stream usually has in a POIFS
- * filesystem.
+ * The document name a summary information stream usually has in a POIFS filesystem.
*/
public static final String DEFAULT_STREAM_NAME = "\005SummaryInformation";
@@ -39,324 +39,291 @@ public final class SummaryInformation extends SpecialPropertySet {
return PropertyIDMap.getSummaryInformationProperties();
}
-
/**
- * Creates a {@link SummaryInformation} from a given {@link
- * PropertySet}.
+ * Creates a {@link SummaryInformation} from a given {@link
+ * PropertySet}.
*
* @param ps A property set which should be created from a summary
* information stream.
- * @throws UnexpectedPropertySetTypeException if ps does not
+ * @throws UnexpectedPropertySetTypeException if {@code ps} does not
* contain a summary information stream.
*/
- public SummaryInformation(final PropertySet ps)
- throws UnexpectedPropertySetTypeException
- {
+ public SummaryInformation() {
+ getFirstSection().setFormatID(SectionIDMap.SUMMARY_INFORMATION_ID);
+ }
+
+ /**
+ * Creates a {@link SummaryInformation} from a given {@link
+ * PropertySet}.
+ *
+ * @param ps A property set which should be created from a summary
+ * information stream.
+ * @throws UnexpectedPropertySetTypeException if {@code ps} does not
+ * contain a summary information stream.
+ */
+ public SummaryInformation(final PropertySet ps) throws UnexpectedPropertySetTypeException {
super(ps);
- if (!isSummaryInformation())
- throw new UnexpectedPropertySetTypeException("Not a "
- + getClass().getName());
+ if (!isSummaryInformation()) {
+ throw new UnexpectedPropertySetTypeException("Not a " + getClass().getName());
+ }
}
/**
- * Returns the title (or null
).
- *
- * @return The title or null
+ * @return The title or {@code null}
*/
- public String getTitle()
- {
+ public String getTitle() {
return getPropertyStringValue(PropertyIDMap.PID_TITLE);
}
/**
- * Sets the title.
+ * Sets the title.
*
* @param title The title to set.
*/
- public void setTitle(final String title)
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.setProperty(PropertyIDMap.PID_TITLE, title);
+ public void setTitle(final String title) {
+ set1stProperty(PropertyIDMap.PID_TITLE, title);
}
/**
- * Removes the title.
+ * Removes the title.
*/
- public void removeTitle()
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.removeProperty(PropertyIDMap.PID_TITLE);
+ public void removeTitle() {
+ remove1stProperty(PropertyIDMap.PID_TITLE);
}
/**
- * Returns the subject (or null
).
+ * Returns the subject (or {@code null}).
*
- * @return The subject or null
+ * @return The subject or {@code null}
*/
- public String getSubject()
- {
+ public String getSubject() {
return getPropertyStringValue(PropertyIDMap.PID_SUBJECT);
}
/**
- * Sets the subject.
+ * Sets the subject.
*
* @param subject The subject to set.
*/
- public void setSubject(final String subject)
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.setProperty(PropertyIDMap.PID_SUBJECT, subject);
+ public void setSubject(final String subject) {
+ set1stProperty(PropertyIDMap.PID_SUBJECT, subject);
}
/**
- * Removes the subject.
+ * Removes the subject.
*/
- public void removeSubject()
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.removeProperty(PropertyIDMap.PID_SUBJECT);
+ public void removeSubject() {
+ remove1stProperty(PropertyIDMap.PID_SUBJECT);
}
/**
- * Returns the author (or null
).
+ * Returns the author (or {@code null}).
*
- * @return The author or null
+ * @return The author or {@code null}
*/
- public String getAuthor()
- {
+ public String getAuthor() {
return getPropertyStringValue(PropertyIDMap.PID_AUTHOR);
}
/**
- * Sets the author.
+ * Sets the author.
*
* @param author The author to set.
*/
- public void setAuthor(final String author)
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.setProperty(PropertyIDMap.PID_AUTHOR, author);
+ public void setAuthor(final String author) {
+ set1stProperty(PropertyIDMap.PID_AUTHOR, author);
}
/**
- * Removes the author.
+ * Removes the author.
*/
- public void removeAuthor()
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.removeProperty(PropertyIDMap.PID_AUTHOR);
+ public void removeAuthor() {
+ remove1stProperty(PropertyIDMap.PID_AUTHOR);
}
/**
- * Returns the keywords (or null
).
+ * Returns the keywords (or {@code null}).
*
- * @return The keywords or null
+ * @return The keywords or {@code null}
*/
- public String getKeywords()
- {
+ public String getKeywords() {
return getPropertyStringValue(PropertyIDMap.PID_KEYWORDS);
}
/**
- * Sets the keywords.
+ * Sets the keywords.
*
* @param keywords The keywords to set.
*/
- public void setKeywords(final String keywords)
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.setProperty(PropertyIDMap.PID_KEYWORDS, keywords);
+ public void setKeywords(final String keywords) {
+ set1stProperty(PropertyIDMap.PID_KEYWORDS, keywords);
}
/**
- * Removes the keywords.
+ * Removes the keywords.
*/
- public void removeKeywords()
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.removeProperty(PropertyIDMap.PID_KEYWORDS);
+ public void removeKeywords() {
+ remove1stProperty(PropertyIDMap.PID_KEYWORDS);
}
/**
- * Returns the comments (or null
).
+ * Returns the comments (or {@code null}).
*
- * @return The comments or null
+ * @return The comments or {@code null}
*/
- public String getComments()
- {
+ public String getComments() {
return getPropertyStringValue(PropertyIDMap.PID_COMMENTS);
}
/**
- * Sets the comments.
+ * Sets the comments.
*
* @param comments The comments to set.
*/
- public void setComments(final String comments)
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.setProperty(PropertyIDMap.PID_COMMENTS, comments);
+ public void setComments(final String comments) {
+ set1stProperty(PropertyIDMap.PID_COMMENTS, comments);
}
/**
- * Removes the comments.
+ * Removes the comments.
*/
- public void removeComments()
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.removeProperty(PropertyIDMap.PID_COMMENTS);
+ public void removeComments() {
+ remove1stProperty(PropertyIDMap.PID_COMMENTS);
}
/**
- * Returns the template (or null
).
+ * Returns the template (or {@code null}).
*
- * @return The template or null
+ * @return The template or {@code null}
*/
- public String getTemplate()
- {
+ public String getTemplate() {
return getPropertyStringValue(PropertyIDMap.PID_TEMPLATE);
}
/**
- * Sets the template.
+ * Sets the template.
*
* @param template The template to set.
*/
- public void setTemplate(final String template)
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.setProperty(PropertyIDMap.PID_TEMPLATE, template);
+ public void setTemplate(final String template) {
+ set1stProperty(PropertyIDMap.PID_TEMPLATE, template);
}
/**
- * Removes the template.
+ * Removes the template.
*/
- public void removeTemplate()
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.removeProperty(PropertyIDMap.PID_TEMPLATE);
+ public void removeTemplate() {
+ remove1stProperty(PropertyIDMap.PID_TEMPLATE);
}
/**
- * Returns the last author (or null
).
+ * Returns the last author (or {@code null}).
*
- * @return The last author or null
+ * @return The last author or {@code null}
*/
- public String getLastAuthor()
- {
+ public String getLastAuthor() {
return getPropertyStringValue(PropertyIDMap.PID_LASTAUTHOR);
}
/**
- * Sets the last author.
+ * Sets the last author.
*
* @param lastAuthor The last author to set.
*/
- public void setLastAuthor(final String lastAuthor)
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.setProperty(PropertyIDMap.PID_LASTAUTHOR, lastAuthor);
+ public void setLastAuthor(final String lastAuthor) {
+ set1stProperty(PropertyIDMap.PID_LASTAUTHOR, lastAuthor);
}
/**
- * Removes the last author.
+ * Removes the last author.
*/
- public void removeLastAuthor()
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.removeProperty(PropertyIDMap.PID_LASTAUTHOR);
+ public void removeLastAuthor() {
+ remove1stProperty(PropertyIDMap.PID_LASTAUTHOR);
}
/**
- * Returns the revision number (or null
).
+ * Returns the revision number (or {@code null}).
*
- * @return The revision number or null
+ * @return The revision number or {@code null}
*/
- public String getRevNumber()
- {
+ public String getRevNumber() {
return getPropertyStringValue(PropertyIDMap.PID_REVNUMBER);
}
/**
- * Sets the revision number.
+ * Sets the revision number.
*
* @param revNumber The revision number to set.
*/
- public void setRevNumber(final String revNumber)
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.setProperty(PropertyIDMap.PID_REVNUMBER, revNumber);
+ public void setRevNumber(final String revNumber) {
+ set1stProperty(PropertyIDMap.PID_REVNUMBER, revNumber);
}
/**
- * Removes the revision number.
+ * Removes the revision number.
*/
- public void removeRevNumber()
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.removeProperty(PropertyIDMap.PID_REVNUMBER);
+ public void removeRevNumber() {
+ remove1stProperty(PropertyIDMap.PID_REVNUMBER);
}
/**
- * Returns the total time spent in editing the document (or
- * 0
).
+ * Returns the total time spent in editing the document (or
+ * {@code 0}).
*
* @return The total time spent in editing the document or 0 if the {@link
* SummaryInformation} does not contain this information.
*/
- public long getEditTime()
- {
+ public long getEditTime() {
final Date d = (Date) getProperty(PropertyIDMap.PID_EDITTIME);
if (d == null) {
return 0;
@@ -367,124 +334,106 @@ public final class SummaryInformation extends SpecialPropertySet {
/**
- * Sets the total time spent in editing the document.
+ * Sets the total time spent in editing the document.
*
* @param time The time to set.
*/
- public void setEditTime(final long time)
- {
+ public void setEditTime(final long time) {
final Date d = Util.filetimeToDate(time);
- final MutableSection s = (MutableSection) getFirstSection();
- s.setProperty(PropertyIDMap.PID_EDITTIME, Variant.VT_FILETIME, d);
+ getFirstSection().setProperty(PropertyIDMap.PID_EDITTIME, Variant.VT_FILETIME, d);
}
/**
- * Remove the total time spent in editing the document.
+ * Remove the total time spent in editing the document.
*/
- public void removeEditTime()
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.removeProperty(PropertyIDMap.PID_EDITTIME);
+ public void removeEditTime() {
+ remove1stProperty(PropertyIDMap.PID_EDITTIME);
}
/**
- * Returns the last printed time (or null
).
+ * Returns the last printed time (or {@code null}).
*
- * @return The last printed time or null
+ * @return The last printed time or {@code null}
*/
- public Date getLastPrinted()
- {
+ public Date getLastPrinted() {
return (Date) getProperty(PropertyIDMap.PID_LASTPRINTED);
}
/**
- * Sets the lastPrinted.
+ * Sets the lastPrinted.
*
* @param lastPrinted The lastPrinted to set.
*/
- public void setLastPrinted(final Date lastPrinted)
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.setProperty(PropertyIDMap.PID_LASTPRINTED, Variant.VT_FILETIME,
- lastPrinted);
+ public void setLastPrinted(final Date lastPrinted) {
+ getFirstSection().setProperty(PropertyIDMap.PID_LASTPRINTED, Variant.VT_FILETIME, lastPrinted);
}
/**
- * Removes the lastPrinted.
+ * Removes the lastPrinted.
*/
- public void removeLastPrinted()
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.removeProperty(PropertyIDMap.PID_LASTPRINTED);
+ public void removeLastPrinted() {
+ remove1stProperty(PropertyIDMap.PID_LASTPRINTED);
}
/**
- * Returns the creation time (or null
).
+ * Returns the creation time (or {@code null}).
*
- * @return The creation time or null
+ * @return The creation time or {@code null}
*/
- public Date getCreateDateTime()
- {
+ public Date getCreateDateTime() {
return (Date) getProperty(PropertyIDMap.PID_CREATE_DTM);
}
/**
- * Sets the creation time.
+ * Sets the creation time.
*
* @param createDateTime The creation time to set.
*/
- public void setCreateDateTime(final Date createDateTime)
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.setProperty(PropertyIDMap.PID_CREATE_DTM, Variant.VT_FILETIME,
- createDateTime);
+ public void setCreateDateTime(final Date createDateTime) {
+ getFirstSection().setProperty(PropertyIDMap.PID_CREATE_DTM, Variant.VT_FILETIME, createDateTime);
}
/**
- * Removes the creation time.
+ * Removes the creation time.
*/
- public void removeCreateDateTime()
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.removeProperty(PropertyIDMap.PID_CREATE_DTM);
+ public void removeCreateDateTime() {
+ remove1stProperty(PropertyIDMap.PID_CREATE_DTM);
}
/**
- * Returns the last save time (or null
).
+ * Returns the last save time (or {@code null}).
*
- * @return The last save time or null
+ * @return The last save time or {@code null}
*/
- public Date getLastSaveDateTime()
- {
+ public Date getLastSaveDateTime() {
return (Date) getProperty(PropertyIDMap.PID_LASTSAVE_DTM);
}
/**
- * Sets the total time spent in editing the document.
+ * Sets the total time spent in editing the document.
*
* @param time The time to set.
*/
- public void setLastSaveDateTime(final Date time)
- {
- final MutableSection s = (MutableSection) getFirstSection();
+ public void setLastSaveDateTime(final Date time) {
+ final Section s = getFirstSection();
s
.setProperty(PropertyIDMap.PID_LASTSAVE_DTM,
Variant.VT_FILETIME, time);
@@ -493,153 +442,134 @@ public final class SummaryInformation extends SpecialPropertySet {
/**
- * Remove the total time spent in editing the document.
+ * Remove the total time spent in editing the document.
*/
- public void removeLastSaveDateTime()
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.removeProperty(PropertyIDMap.PID_LASTSAVE_DTM);
+ public void removeLastSaveDateTime() {
+ remove1stProperty(PropertyIDMap.PID_LASTSAVE_DTM);
}
/**
- * Returns the page count or 0 if the {@link SummaryInformation} does
- * not contain a page count.
+ * Returns the page count or 0 if the {@link SummaryInformation} does
+ * not contain a page count.
*
* @return The page count or 0 if the {@link SummaryInformation} does not
* contain a page count.
*/
- public int getPageCount()
- {
+ public int getPageCount() {
return getPropertyIntValue(PropertyIDMap.PID_PAGECOUNT);
}
/**
- * Sets the page count.
+ * Sets the page count.
*
* @param pageCount The page count to set.
*/
- public void setPageCount(final int pageCount)
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.setProperty(PropertyIDMap.PID_PAGECOUNT, pageCount);
+ public void setPageCount(final int pageCount) {
+ set1stProperty(PropertyIDMap.PID_PAGECOUNT, pageCount);
}
/**
- * Removes the page count.
+ * Removes the page count.
*/
- public void removePageCount()
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.removeProperty(PropertyIDMap.PID_PAGECOUNT);
+ public void removePageCount() {
+ remove1stProperty(PropertyIDMap.PID_PAGECOUNT);
}
/**
- * Returns the word count or 0 if the {@link SummaryInformation} does
- * not contain a word count.
+ * Returns the word count or 0 if the {@link SummaryInformation} does
+ * not contain a word count.
*
- * @return The word count or null
+ * @return The word count or {@code null}
*/
- public int getWordCount()
- {
+ public int getWordCount() {
return getPropertyIntValue(PropertyIDMap.PID_WORDCOUNT);
}
/**
- * Sets the word count.
+ * Sets the word count.
*
* @param wordCount The word count to set.
*/
- public void setWordCount(final int wordCount)
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.setProperty(PropertyIDMap.PID_WORDCOUNT, wordCount);
+ public void setWordCount(final int wordCount) {
+ set1stProperty(PropertyIDMap.PID_WORDCOUNT, wordCount);
}
/**
- * Removes the word count.
+ * Removes the word count.
*/
- public void removeWordCount()
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.removeProperty(PropertyIDMap.PID_WORDCOUNT);
+ public void removeWordCount() {
+ remove1stProperty(PropertyIDMap.PID_WORDCOUNT);
}
/**
- * Returns the character count or 0 if the {@link SummaryInformation}
- * does not contain a char count.
+ * Returns the character count or 0 if the {@link SummaryInformation}
+ * does not contain a char count.
*
- * @return The character count or null
+ * @return The character count or {@code null}
*/
- public int getCharCount()
- {
+ public int getCharCount() {
return getPropertyIntValue(PropertyIDMap.PID_CHARCOUNT);
}
/**
- * Sets the character count.
+ * Sets the character count.
*
* @param charCount The character count to set.
*/
- public void setCharCount(final int charCount)
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.setProperty(PropertyIDMap.PID_CHARCOUNT, charCount);
+ public void setCharCount(final int charCount) {
+ set1stProperty(PropertyIDMap.PID_CHARCOUNT, charCount);
}
/**
- * Removes the character count.
+ * Removes the character count.
*/
- public void removeCharCount()
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.removeProperty(PropertyIDMap.PID_CHARCOUNT);
+ public void removeCharCount() {
+ remove1stProperty(PropertyIDMap.PID_CHARCOUNT);
}
/**
- * Returns the thumbnail (or null
) when this
+ * Returns the thumbnail (or {@code null}) when this
* method is implemented. Please note that the return type is likely to
- * change!
+ * change!
*
- *
To process this data, you may wish to make use of the
+ * To process this data, you may wish to make use of the
* {@link Thumbnail} class. The raw data is generally
- * an image in WMF or Clipboard (BMP?) format
+ * an image in WMF or Clipboard (BMP?) format
*
- * @return The thumbnail or null
+ * @return The thumbnail or {@code null}
*/
- public byte[] getThumbnail()
- {
+ public byte[] getThumbnail() {
return (byte[]) getProperty(PropertyIDMap.PID_THUMBNAIL);
}
/**
- * Returns the thumbnail (or null
), processed
+ * Returns the thumbnail (or {@code null}), processed
* as an object which is (largely) able to unpack the thumbnail
- * image data.
+ * image data.
*
- * @return The thumbnail or null
+ * @return The thumbnail or {@code null}
*/
- public Thumbnail getThumbnailThumbnail()
- {
+ public Thumbnail getThumbnailThumbnail() {
byte[] data = getThumbnail();
if (data == null) return null;
return new Thumbnail(data);
@@ -648,115 +578,100 @@ public final class SummaryInformation extends SpecialPropertySet {
/**
- * Sets the thumbnail.
+ * Sets the thumbnail.
*
* @param thumbnail The thumbnail to set.
*/
- public void setThumbnail(final byte[] thumbnail)
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.setProperty(PropertyIDMap.PID_THUMBNAIL, /* FIXME: */
- Variant.VT_LPSTR, thumbnail);
+ public void setThumbnail(final byte[] thumbnail) {
+ getFirstSection().setProperty(PropertyIDMap.PID_THUMBNAIL, /* FIXME: */ Variant.VT_LPSTR, thumbnail);
}
/**
- * Removes the thumbnail.
+ * Removes the thumbnail.
*/
- public void removeThumbnail()
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.removeProperty(PropertyIDMap.PID_THUMBNAIL);
+ public void removeThumbnail() {
+ remove1stProperty(PropertyIDMap.PID_THUMBNAIL);
}
/**
- * Returns the application name (or null
).
+ * Returns the application name (or {@code null}).
*
- * @return The application name or null
+ * @return The application name or {@code null}
*/
- public String getApplicationName()
- {
+ public String getApplicationName() {
return getPropertyStringValue(PropertyIDMap.PID_APPNAME);
}
/**
- * Sets the application name.
+ * Sets the application name.
*
* @param applicationName The application name to set.
*/
- public void setApplicationName(final String applicationName)
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.setProperty(PropertyIDMap.PID_APPNAME, applicationName);
+ public void setApplicationName(final String applicationName) {
+ set1stProperty(PropertyIDMap.PID_APPNAME, applicationName);
}
/**
- * Removes the application name.
+ * Removes the application name.
*/
- public void removeApplicationName()
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.removeProperty(PropertyIDMap.PID_APPNAME);
+ public void removeApplicationName() {
+ remove1stProperty(PropertyIDMap.PID_APPNAME);
}
/**
- * Returns a security code which is one of the following values:
+ * Returns a security code which is one of the following values:
*
*
+ * cases!
*
- * 1 if the document is password protected
+ * 1 if the document is password protected
*
- * 2 if the document is read-only recommended
+ * 2 if the document is read-only recommended
*
- * 4 if the document is read-only enforced
+ * 4 if the document is read-only enforced
*
- * 8 if the document is locked for annotations
+ * 8 if the document is locked for annotations
*
*
*
- * @return The security code or null
+ * @return The security code or {@code null}
*/
- public int getSecurity()
- {
+ public int getSecurity() {
return getPropertyIntValue(PropertyIDMap.PID_SECURITY);
}
/**
- * Sets the security code.
+ * Sets the security code.
*
* @param security The security code to set.
*/
- public void setSecurity(final int security)
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.setProperty(PropertyIDMap.PID_SECURITY, security);
+ public void setSecurity(final int security) {
+ set1stProperty(PropertyIDMap.PID_SECURITY, security);
}
/**
- * Removes the security code.
+ * Removes the security code.
*/
- public void removeSecurity()
- {
- final MutableSection s = (MutableSection) getFirstSection();
- s.removeProperty(PropertyIDMap.PID_SECURITY);
+ public void removeSecurity() {
+ remove1stProperty(PropertyIDMap.PID_SECURITY);
}
}
diff --git a/src/java/org/apache/poi/hpsf/Util.java b/src/java/org/apache/poi/hpsf/Util.java
index 5d75cb986..d8ab7315d 100644
--- a/src/java/org/apache/poi/hpsf/Util.java
+++ b/src/java/org/apache/poi/hpsf/Util.java
@@ -20,110 +20,17 @@ package org.apache.poi.hpsf;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
-import java.util.Collection;
import java.util.Date;
+import org.apache.poi.util.Internal;
import org.apache.poi.util.SuppressForbidden;
/**
* Provides various static utility methods.
*/
+@Internal
public class Util
{
-
- /**
- * Checks whether two byte arrays a and b
- * are equal. They are equal
- *
- *
- *
- * @param a The first byte array
- * @param b The first byte array
- * @return true
if the byte arrays are equal, else
- * false
- */
- public static boolean equal(final byte[] a, final byte[] b)
- {
- if (a.length != b.length)
- return false;
- for (int i = 0; i < a.length; i++)
- if (a[i] != b[i])
- return false;
- return true;
- }
-
-
-
- /**
- * Copies a part of a byte array into another byte array.
- *
- * @param src The source byte array.
- * @param srcOffset Offset in the source byte array.
- * @param length The number of bytes to copy.
- * @param dst The destination byte array.
- * @param dstOffset Offset in the destination byte array.
- */
- public static void copy(final byte[] src, final int srcOffset,
- final int length, final byte[] dst,
- final int dstOffset)
- {
- for (int i = 0; i < length; i++)
- dst[dstOffset + i] = src[srcOffset + i];
- }
-
-
-
- /**
- * Concatenates the contents of several byte arrays into a
- * single one.
- *
- * @param byteArrays The byte arrays to be concatened.
- * @return A new byte array containing the concatenated byte
- * arrays.
- */
- public static byte[] cat(final byte[][] byteArrays)
- {
- int capacity = 0;
- for (int i = 0; i < byteArrays.length; i++)
- capacity += byteArrays[i].length;
- final byte[] result = new byte[capacity];
- int r = 0;
- for (int i = 0; i < byteArrays.length; i++)
- for (int j = 0; j < byteArrays[i].length; j++)
- result[r++] = byteArrays[i][j];
- return result;
- }
-
-
-
- /**
- * Copies bytes from a source byte array into a new byte
- * array.
- *
- * @param src Copy from this byte array.
- * @param offset Start copying here.
- * @param length Copy this many bytes.
- * @return The new byte array. Its length is number of copied bytes.
- */
- public static byte[] copy(final byte[] src, final int offset,
- final int length)
- {
- final byte[] result = new byte[length];
- copy(src, offset, length, result, 0);
- return result;
- }
-
-
-
/**
* The difference between the Windows epoch (1601-01-01
* 00:00:00) and the Unix epoch (1970-01-01 00:00:00) in
@@ -189,36 +96,6 @@ public class Util
}
- /**
- *
Checks whether two collections are equal. Two collections
- * C1 and C2 are equal, if the following conditions
- * are true:
- *
- *
- *
- * For each c1i (element of C1) there
- * is a c2j (element of C2), and
- * c1i equals c2j.
- *
- * For each c2i (element of C2) there
- * is a c1j (element of C1) and
- * c2i equals c1j.
- *
- *
- *
- * @param c1 the first collection
- * @param c2 the second collection
- * @return true
if the collections are equal, else
- * false
.
- */
- public static boolean equals(Collection> c1, Collection> c2)
- {
- Object[] o1 = c1.toArray();
- Object[] o2 = c2.toArray();
- return internalEquals(o1, o2);
- }
-
-
/**
* Compares to object arrays with regarding the objects' order. For
@@ -231,24 +108,17 @@ public class Util
*/
public static boolean equals(Object[] c1, Object[] c2)
{
- final Object[] o1 = c1.clone();
- final Object[] o2 = c2.clone();
- return internalEquals(o1, o2);
- }
-
- private static boolean internalEquals(Object[] o1, Object[] o2)
- {
- for (int i1 = 0; i1 < o1.length; i1++)
+ for (int i1 = 0; i1 < c1.length; i1++)
{
- final Object obj1 = o1[i1];
+ final Object obj1 = c1[i1];
boolean matchFound = false;
- for (int i2 = 0; !matchFound && i2 < o1.length; i2++)
+ for (int i2 = 0; !matchFound && i2 < c1.length; i2++)
{
- final Object obj2 = o2[i2];
+ final Object obj2 = c2[i2];
if (obj1.equals(obj2))
{
matchFound = true;
- o2[i2] = null;
+ c2[i2] = null;
}
}
if (!matchFound)
@@ -257,8 +127,6 @@ public class Util
return true;
}
-
-
/**
*
Pads a byte array with 0x00 bytes so that its length is a multiple of
* 4.
@@ -283,46 +151,6 @@ public class Util
}
-
- /**
- * 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());
- }
-
-
-
/**
* Returns a textual representation of a {@link Throwable}, including a
* stacktrace.
diff --git a/src/java/org/apache/poi/hpsf/VariantSupport.java b/src/java/org/apache/poi/hpsf/VariantSupport.java
index b4816eb91..61fc30d88 100644
--- a/src/java/org/apache/poi/hpsf/VariantSupport.java
+++ b/src/java/org/apache/poi/hpsf/VariantSupport.java
@@ -27,70 +27,77 @@ import java.util.List;
import org.apache.poi.util.CodePageUtil;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
+import org.apache.poi.util.Removal;
/**
- * Supports reading and writing of variant data.
+ * Supports reading and writing of variant data.
*
- *
FIXME (3): Reading and writing should 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:
*
*
*
- * Reading requires a length parameter that is 4 byte greater than the
- * actual data, because the variant type field is included.
+ * - Reading requires a length parameter that is 4 byte greater than the
+ * actual data, because the variant type field is included.
*
- *
Reading reads from a byte array while writing writes to an byte array
- * output stream.
+ * - Reading reads from a byte array while writing writes to an byte array
+ * output stream.
*
*
*/
-public class VariantSupport extends Variant
-{
- private static final POILogger logger = POILogFactory.getLogger(VariantSupport.class);
+public class VariantSupport extends Variant {
+ /**
+ * HPSF is able to read these {@link Variant} types.
+ */
+ public static final int[] SUPPORTED_TYPES = { Variant.VT_EMPTY,
+ Variant.VT_I2, Variant.VT_I4, Variant.VT_I8, Variant.VT_R8,
+ Variant.VT_FILETIME, Variant.VT_LPSTR, Variant.VT_LPWSTR,
+ Variant.VT_CF, Variant.VT_BOOL };
+
+
+ private static final POILogger logger = POILogFactory.getLogger(VariantSupport.class);
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.
+ * Keeps a list of the variant types an "unsupported" message has already
+ * been issued for.
*/
- public static void setLogUnsupportedTypes(final boolean logUnsupportedTypes)
- {
+ protected static List unsupportedMessage;
+
+
+ /**
+ * Specifies whether warnings about unsupported variant types are to be
+ * written to {@code System.err} or not.
+ *
+ * @param logUnsupportedTypes If {@code true} warnings will be written,
+ * if {@code false} they won't.
+ */
+ public static void setLogUnsupportedTypes(final boolean logUnsupportedTypes) {
VariantSupport.logUnsupportedTypes = logUnsupportedTypes;
}
/**
- * Checks whether logging of unsupported variant types warning is turned
- * on or off.
+ * Checks whether logging of unsupported variant types warning is turned
+ * on or off.
*
- * @return true
if logging is turned on, else
- * false
.
+ * @return {@code true} if logging is turned on, else
+ * {@code false}.
*/
- public static boolean isLogUnsupportedTypes()
- {
+ 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
+ * Writes a warning to {@code 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
+ * type. Log messages can be turned on or off by
*
* @param ex The exception to log
*/
protected static void writeUnsupportedTypeMessage
- (final UnsupportedVariantTypeException ex)
- {
+ (final UnsupportedVariantTypeException ex) {
if (isLogUnsupportedTypes())
{
if (unsupportedMessage == null)
@@ -105,28 +112,18 @@ public class VariantSupport extends Variant
}
- /**
- * HPSF is able to read these {@link Variant} types.
- */
- final static public int[] SUPPORTED_TYPES = { Variant.VT_EMPTY,
- Variant.VT_I2, Variant.VT_I4, Variant.VT_I8, Variant.VT_R8,
- Variant.VT_FILETIME, Variant.VT_LPSTR, Variant.VT_LPWSTR,
- Variant.VT_CF, Variant.VT_BOOL };
-
-
/**
- * Checks whether HPSF supports the specified variant type. Unsupported
+ * Checks whether HPSF supports the specified variant type. Unsupported
* types should be implemented included in the {@link #SUPPORTED_TYPES}
- * array.
+ * array.
*
* @see Variant
* @param variantType the variant type to check
- * @return true
if HPFS supports this type, else
- * false
+ * @return {@code true} if HPFS supports this type, else
+ * {@code false}
*/
- public boolean isSupportedType(final int variantType)
- {
+ public boolean isSupportedType(final int variantType) {
for (int i = 0; i < SUPPORTED_TYPES.length; i++)
if (variantType == SUPPORTED_TYPES[i])
return true;
@@ -136,7 +133,7 @@ public class VariantSupport extends Variant
/**
- * Reads a variant type from a byte array.
+ * Reads a variant type from a byte array.
*
* @param src The byte array
* @param offset The offset in the byte array where the variant starts
@@ -154,66 +151,50 @@ public class VariantSupport extends Variant
*/
public static Object read( final byte[] src, final int offset,
final int length, final long type, final int codepage )
- throws ReadingNotSupportedException, UnsupportedEncodingException
- {
- TypedPropertyValue typedPropertyValue = new TypedPropertyValue(
- (int) type, null );
+ throws ReadingNotSupportedException, UnsupportedEncodingException {
+ TypedPropertyValue typedPropertyValue = new TypedPropertyValue( (int) type, null );
int unpadded;
- try
- {
+ try {
unpadded = typedPropertyValue.readValue( src, offset );
- }
- catch ( UnsupportedOperationException exc )
- {
+ } catch ( UnsupportedOperationException exc ) {
int propLength = Math.min( length, src.length - offset );
final byte[] v = new byte[propLength];
System.arraycopy( src, offset, v, 0, propLength );
throw new ReadingNotSupportedException( type, v );
}
- switch ( (int) type )
- {
- case Variant.VT_EMPTY:
- case Variant.VT_I4:
- case Variant.VT_I8:
- case Variant.VT_R8:
+ switch ( (int) type ) {
/*
* we have more property types that can be converted into Java
* objects, but current API need to be preserved, and it returns
* other types as byte arrays. In future major versions it shall be
* changed -- sergey
*/
- return typedPropertyValue.getValue();
+ case Variant.VT_EMPTY:
+ case Variant.VT_I4:
+ case Variant.VT_I8:
+ case Variant.VT_R8:
+ return typedPropertyValue.getValue();
- case Variant.VT_I2:
- {
/*
* also for backward-compatibility with prev. versions of POI
* --sergey
*/
- return Integer.valueOf( ( (Short) typedPropertyValue.getValue() )
- .intValue() );
- }
- case Variant.VT_FILETIME:
- {
- Filetime filetime = (Filetime) typedPropertyValue.getValue();
- return Util.filetimeToDate( (int) filetime.getHigh(),
- (int) filetime.getLow() );
- }
- case Variant.VT_LPSTR:
- {
- CodePageString string = (CodePageString) typedPropertyValue
- .getValue();
- return string.getJavaValue( codepage );
- }
- case Variant.VT_LPWSTR:
- {
- UnicodeString string = (UnicodeString) typedPropertyValue
- .getValue();
- return string.toJavaString();
- }
- case Variant.VT_CF:
- {
+ case Variant.VT_I2:
+ return ( (Short) typedPropertyValue.getValue() ).intValue();
+
+ case Variant.VT_FILETIME:
+ Filetime filetime = (Filetime) typedPropertyValue.getValue();
+ return Util.filetimeToDate( (int) filetime.getHigh(), (int) filetime.getLow() );
+
+ case Variant.VT_LPSTR:
+ CodePageString cpString = (CodePageString) typedPropertyValue.getValue();
+ return cpString.getJavaValue( codepage );
+
+ case Variant.VT_LPWSTR:
+ UnicodeString uniString = (UnicodeString) typedPropertyValue.getValue();
+ return uniString.toJavaString();
+
// if(l1 < 0) {
/**
* YK: reading the ClipboardData packet (VT_CF) is not quite
@@ -223,7 +204,7 @@ public class VariantSupport extends Variant
* 45583 clearly show that this approach does not always work. The
* workaround below attempts to gracefully handle such cases instead
* of throwing exceptions.
- *
+ *
* August 20, 2009
*/
// l1 = LittleEndian.getInt(src, o1); o1 += LittleEndian.INT_SIZE;
@@ -232,33 +213,28 @@ public class VariantSupport extends Variant
// System.arraycopy(src, o1, v, 0, v.length);
// value = v;
// break;
- ClipboardData clipboardData = (ClipboardData) typedPropertyValue
- .getValue();
- return clipboardData.toByteArray();
- }
+ case Variant.VT_CF:
+ ClipboardData clipboardData = (ClipboardData) typedPropertyValue.getValue();
+ return clipboardData.toByteArray();
- case Variant.VT_BOOL:
- {
- VariantBool bool = (VariantBool) typedPropertyValue.getValue();
- return Boolean.valueOf( bool.getValue() );
- }
+ case Variant.VT_BOOL:
+ VariantBool bool = (VariantBool) typedPropertyValue.getValue();
+ return bool.getValue();
- default:
- {
/*
* it is not very good, but what can do without breaking current
* API? --sergey
*/
- final byte[] v = new byte[unpadded];
- System.arraycopy( src, offset, v, 0, unpadded );
- throw new ReadingNotSupportedException( type, v );
- }
+ default:
+ final byte[] v = new byte[unpadded];
+ System.arraycopy( src, offset, v, 0, unpadded );
+ throw new ReadingNotSupportedException( type, v );
}
}
/**
- * Turns a codepage number into the equivalent character encoding's
- * name.
+ * Turns a codepage number into the equivalent character encoding's
+ * name.
*
* @param codepage The codepage number
*
@@ -269,7 +245,10 @@ public class VariantSupport extends Variant
*
* @exception UnsupportedEncodingException if the specified codepage is
* less than zero.
+ *
+ * @deprecated POI 3.16 - use {@link CodePageUtil#codepageToEncoding(int)}
*/
+ @Removal(version="3.18")
public static String codepageToEncoding(final int codepage)
throws UnsupportedEncodingException
{
@@ -278,13 +257,13 @@ public class VariantSupport extends Variant
/**
- * Writes a variant value to an output stream. This method ensures that
- * always a multiple of 4 bytes is written.
+ * Writes a variant value to an output stream. This method ensures that
+ * always a multiple of 4 bytes is written.
*
- *
If the codepage is UTF-16, which is encouraged, strings
+ * If the codepage is UTF-16, which is encouraged, strings
* must always be written as {@link Variant#VT_LPWSTR}
* strings, not as {@link Variant#VT_LPSTR} strings. This method ensure this
- * by converting strings appropriately, if needed.
+ * by converting strings appropriately, if needed.
*
* @param out The stream to write the value to.
* @param type The variant's type.
@@ -298,42 +277,31 @@ public class VariantSupport extends Variant
*/
public static int write(final OutputStream out, final long type,
final Object value, final int codepage)
- throws IOException, WritingNotSupportedException
- {
+ throws IOException, WritingNotSupportedException {
int length = 0;
- switch ((int) type)
- {
+ switch ((int) type) {
case Variant.VT_BOOL:
- {
- if ( ( (Boolean) value ).booleanValue() )
- {
+ if ( ( (Boolean) value ).booleanValue() ) {
out.write( 0xff );
out.write( 0xff );
- }
- else
- {
+ } else {
out.write( 0x00 );
out.write( 0x00 );
}
length += 2;
break;
- }
+
case Variant.VT_LPSTR:
- {
- CodePageString codePageString = new CodePageString( (String) value,
- codepage );
+ CodePageString codePageString = new CodePageString( (String) value, codepage );
length += codePageString.write( out );
break;
- }
+
case Variant.VT_LPWSTR:
- {
final int nrOfChars = ( (String) value ).length() + 1;
length += TypeWriter.writeUIntToStream( out, nrOfChars );
- char[] s = ( (String) value ).toCharArray();
- for ( int i = 0; i < s.length; i++ )
- {
- final int high = ( ( s[i] & 0x0000ff00 ) >> 8 );
- final int low = ( s[i] & 0x000000ff );
+ for ( char s : ( (String) value ).toCharArray() ) {
+ final int high = ( ( s & 0x0000ff00 ) >> 8 );
+ final int low = ( s & 0x000000ff );
final byte highb = (byte) high;
final byte lowb = (byte) low;
out.write( lowb );
@@ -345,79 +313,63 @@ public class VariantSupport extends Variant
out.write( 0x00 );
length += 2;
break;
- }
+
case Variant.VT_CF:
- {
- final byte[] b = (byte[]) value;
- out.write(b);
- length = b.length;
+ final byte[] cf = (byte[]) value;
+ out.write(cf);
+ length = cf.length;
break;
- }
+
case Variant.VT_EMPTY:
- {
length += TypeWriter.writeUIntToStream( out, Variant.VT_EMPTY );
break;
- }
+
case Variant.VT_I2:
- {
- length += TypeWriter.writeToStream( out,
- ( (Integer) value ).shortValue() );
+ length += TypeWriter.writeToStream( out, ( (Integer) value ).shortValue() );
break;
- }
+
case Variant.VT_I4:
- {
- if (!(value instanceof Integer))
- {
+ if (!(value instanceof Integer)) {
throw new ClassCastException("Could not cast an object to "
+ Integer.class.toString() + ": "
+ value.getClass().toString() + ", "
+ value.toString());
}
- length += TypeWriter.writeToStream(out,
- ((Integer) value).intValue());
+ length += TypeWriter.writeToStream(out, ((Integer) value).intValue());
break;
- }
+
case Variant.VT_I8:
- {
length += TypeWriter.writeToStream(out, ((Long) value).longValue());
break;
- }
+
case Variant.VT_R8:
- {
- length += TypeWriter.writeToStream(out,
- ((Double) value).doubleValue());
+ length += TypeWriter.writeToStream(out, ((Double) value).doubleValue());
break;
- }
+
case Variant.VT_FILETIME:
- {
long filetime = Util.dateToFileTime((Date) value);
int high = (int) ((filetime >> 32) & 0x00000000FFFFFFFFL);
int low = (int) (filetime & 0x00000000FFFFFFFFL);
Filetime filetimeValue = new Filetime( low, high);
length += filetimeValue.write( out );
break;
- }
+
default:
- {
/* The variant type is not supported yet. However, if the value
* is a byte array we can write it nevertheless. */
- if (value instanceof byte[])
- {
+ if (value instanceof byte[]) {
final byte[] b = (byte[]) value;
out.write(b);
length = b.length;
- writeUnsupportedTypeMessage
- (new WritingNotSupportedException(type, value));
- }
- else
+ writeUnsupportedTypeMessage(new WritingNotSupportedException(type, value));
+ } else {
throw new WritingNotSupportedException(type, value);
+ }
break;
- }
}
/* pad values to 4-bytes */
- while ( ( length & 0x3 ) != 0 )
- {
+ while ( ( length & 0x3 ) != 0 ) {
out.write( 0x00 );
length++;
}
diff --git a/src/java/org/apache/poi/hpsf/extractor/HPSFPropertiesExtractor.java b/src/java/org/apache/poi/hpsf/extractor/HPSFPropertiesExtractor.java
index fc526ee61..36c3f3a9c 100644
--- a/src/java/org/apache/poi/hpsf/extractor/HPSFPropertiesExtractor.java
+++ b/src/java/org/apache/poi/hpsf/extractor/HPSFPropertiesExtractor.java
@@ -27,6 +27,7 @@ import org.apache.poi.hpsf.CustomProperties;
import org.apache.poi.hpsf.DocumentSummaryInformation;
import org.apache.poi.hpsf.HPSFPropertiesOnlyDocument;
import org.apache.poi.hpsf.Property;
+import org.apache.poi.hpsf.PropertySet;
import org.apache.poi.hpsf.SpecialPropertySet;
import org.apache.poi.hpsf.SummaryInformation;
import org.apache.poi.hpsf.wellknown.PropertyIDMap;
@@ -67,7 +68,7 @@ public class HPSFPropertiesExtractor extends POIOLE2TextExtractor {
CustomProperties cps = dsi == null ? null : dsi.getCustomProperties();
if (cps != null) {
for (String key : cps.nameSet()) {
- String val = HelperPropertySet.getPropertyValueText(cps.get(key));
+ String val = getPropertyValueText(cps.get(key));
text.append(key).append(" = ").append(val).append("\n");
}
}
@@ -86,7 +87,7 @@ public class HPSFPropertiesExtractor extends POIOLE2TextExtractor {
return getPropertiesText(si);
}
- private static String getPropertiesText(SpecialPropertySet ps) {
+ private static String getPropertiesText(PropertySet ps) {
if (ps == null) {
// Not defined, oh well
return "";
@@ -98,12 +99,12 @@ public class HPSFPropertiesExtractor extends POIOLE2TextExtractor {
Property[] props = ps.getProperties();
for (Property prop : props) {
String type = Long.toString(prop.getID());
- Object typeObj = idMap.get(prop.getID());
+ Object typeObj = (idMap == null) ? null : idMap.get(prop.getID());
if (typeObj != null) {
type = typeObj.toString();
}
- String val = HelperPropertySet.getPropertyValueText(prop.getValue());
+ String val = getPropertyValueText(prop.getValue());
text.append(type).append(" = ").append(val).append("\n");
}
@@ -125,18 +126,12 @@ public class HPSFPropertiesExtractor extends POIOLE2TextExtractor {
throw new IllegalStateException("You already have the Metadata Text Extractor, not recursing!");
}
- private static abstract class HelperPropertySet extends SpecialPropertySet {
- public HelperPropertySet() {
- super(null);
- }
- public static String getPropertyValueText(Object val) {
- if (val == null) {
- return "(not set)";
- }
- return SpecialPropertySet.getPropertyStringValue(val);
- }
+ private static String getPropertyValueText(Object val) {
+ return (val == null)
+ ? "(not set)"
+ : PropertySet.getPropertyStringValue(val);
}
-
+
@Override
public boolean equals(Object o) {
return super.equals(o);
diff --git a/src/java/org/apache/poi/util/IOUtils.java b/src/java/org/apache/poi/util/IOUtils.java
index 2f61fd1d7..929ade06c 100644
--- a/src/java/org/apache/poi/util/IOUtils.java
+++ b/src/java/org/apache/poi/util/IOUtils.java
@@ -45,26 +45,42 @@ public final class IOUtils {
* @throws EmptyFileException if the stream is empty
*/
public static byte[] peekFirst8Bytes(InputStream stream) throws IOException, EmptyFileException {
- // We want to peek at the first 8 bytes
- stream.mark(8);
+ return peekFirstNBytes(stream, 8);
+ }
- byte[] header = new byte[8];
- int read = IOUtils.readFully(stream, header);
+ /**
+ * Peeks at the first N bytes of the stream. Returns those bytes, but
+ * with the stream unaffected. Requires a stream that supports mark/reset,
+ * or a PushbackInputStream. If the stream has >0 but <N bytes,
+ * remaining bytes will be zero.
+ * @throws EmptyFileException if the stream is empty
+ */
+ public static byte[] peekFirstNBytes(InputStream stream, int limit) throws IOException, EmptyFileException {
+ stream.mark(limit);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream(limit);
+ copy(new BoundedInputStream(stream, limit), bos);
- if (read < 1)
+ int readBytes = bos.size();
+ if (readBytes == 0) {
throw new EmptyFileException();
-
- // Wind back those 8 bytes
+ }
+
+ if (readBytes < limit) {
+ bos.write(new byte[limit-readBytes]);
+ }
+ byte peekedBytes[] = bos.toByteArray();
if(stream instanceof PushbackInputStream) {
PushbackInputStream pin = (PushbackInputStream)stream;
- pin.unread(header, 0, read);
+ pin.unread(peekedBytes, 0, readBytes);
} else {
stream.reset();
}
- return header;
+ return peekedBytes;
}
-
+
+
+
/**
* Reads all the data from the input stream, and returns the bytes read.
*/
diff --git a/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java b/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java
index 8937dca58..b40e7a463 100644
--- a/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java
+++ b/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java
@@ -192,8 +192,7 @@ public final class TestBasic {
(poiFiles[0].getBytes()));
final List sections = si.getSections();
final Section s = sections.get(0);
- assertTrue(org.apache.poi.hpsf.Util.equal
- (s.getFormatID().getBytes(), SectionIDMap.SUMMARY_INFORMATION_ID));
+ assertArrayEquals(s.getFormatID().getBytes(), SectionIDMap.SUMMARY_INFORMATION_ID);
assertNotNull(s.getProperties());
assertEquals(17, s.getPropertyCount());
assertEquals("Titel", s.getProperty(2));
diff --git a/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java b/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java
index ffcaa3a79..20f7d8fae 100644
--- a/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java
+++ b/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java
@@ -216,7 +216,8 @@ public class TestWrite
final MutablePropertySet ps = new MutablePropertySet();
final MutableSection si = new MutableSection();
si.setFormatID(SectionIDMap.SUMMARY_INFORMATION_ID);
- ps.getSections().set(0, si);
+ ps.clearSections();
+ ps.addSection(si);
final MutableProperty p = new MutableProperty();
p.setID(PropertyIDMap.PID_AUTHOR);