Methods Summary |
---|
private int | calcSize()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.
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;
|
public void | clear()Removes all properties from the section including 0 (dictionary) and
1 (codepage).
final Property[] properties = getProperties();
for (int i = 0; i < properties.length; i++)
{
final Property p = properties[i];
removeProperty(p.getID());
}
|
public org.apache.poi.hpsf.Property[] | getProperties()Gets this section's properties.
properties = (Property[]) preprops.toArray(new Property[0]);
return properties;
|
public java.lang.Object | getProperty(long id)Gets a property.
/* Calling getProperties() ensures that properties and preprops are in
* sync.</p> */
getProperties();
return super.getProperty(id);
|
public int | getPropertyCount()Overwrites the super class' method to cope with a redundancy:
the property count is maintained in a separate member variable, but
shouldn't.
return preprops.size();
|
public int | getSize()Returns the section's size.
if (dirty)
{
try
{
size = calcSize();
dirty = false;
}
catch (HPSFRuntimeException ex)
{
throw ex;
}
catch (Exception ex)
{
throw new HPSFRuntimeException(ex);
}
}
return size;
|
public void | removeProperty(long id)Removes a property.
for (final Iterator i = preprops.iterator(); i.hasNext();)
if (((Property) i.next()).getID() == id)
{
i.remove();
break;
}
dirty = true;
|
public void | setCodepage(int codepage)Sets the codepage.
setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2,
new Integer(codepage));
|
public void | setDictionary(java.util.Map dictionary)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.
if (dictionary != null)
{
for (final Iterator i = dictionary.keySet().iterator();
i.hasNext();)
if (!(i.next() instanceof Long))
throw new IllegalPropertySetDataException
("Dictionary keys must be of type Long.");
for (final Iterator i = dictionary.values().iterator();
i.hasNext();)
if (!(i.next() instanceof String))
throw new IllegalPropertySetDataException
("Dictionary values must be of type String.");
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,
new Integer(Constants.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);
|
public void | setFormatID(org.apache.poi.hpsf.ClassID formatID)Sets the section's format ID.
this.formatID = formatID;
|
public void | setFormatID(byte[] formatID)Sets the section's format ID.
ClassID fid = getFormatID();
if (fid == null)
{
fid = new ClassID();
setFormatID(fid);
}
fid.setBytes(formatID);
|
public void | setProperties(org.apache.poi.hpsf.Property[] properties)Sets this section's properties. Any former values are overwritten.
this.properties = properties;
preprops = new LinkedList();
for (int i = 0; i < properties.length; i++)
preprops.add(properties[i]);
dirty = true;
|
public void | setProperty(int id, long variantType, java.lang.Object 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.
final MutableProperty p = new MutableProperty();
p.setID(id);
p.setType(variantType);
p.setValue(value);
setProperty(p);
dirty = true;
|
public void | setProperty(org.apache.poi.hpsf.Property p)Sets a property.
final long id = p.getID();
removeProperty(id);
preprops.add(p);
dirty = true;
|
public void | setProperty(int id, java.lang.Object value)Sets a property.
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() + ".");
|
public void | setProperty(int id, java.lang.String value)Sets the string value of the property with the specified ID.
setProperty(id, Variant.VT_LPWSTR, value);
dirty = true;
|
public void | setProperty(int id, int value)Sets the int value of the property with the specified ID.
setProperty(id, Variant.VT_I4, new Integer(value));
dirty = true;
|
public void | setProperty(int id, long value)Sets the long value of the property with the specified ID.
setProperty(id, Variant.VT_I8, new Long(value));
dirty = true;
|
public void | setProperty(int id, boolean value)Sets the boolean value of the property with the specified ID.
setProperty(id, Variant.VT_BOOL, new Boolean(value));
dirty = true;
|
protected void | setPropertyBooleanValue(int id, boolean value)Sets the value of the boolean property with the specified
ID.
setProperty(id, Variant.VT_BOOL, new Boolean(value));
|
public int | write(java.io.OutputStream out)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.
/* 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,
new Integer(Constants.CP_UNICODE));
codepage = getCodepage();
}
/* Sort the property list by their property IDs: */
Collections.sort(preprops, new Comparator()
{
public int compare(final Object o1, final Object o2)
{
final Property p1 = (Property) o1;
final Property p2 = (Property) o2;
if (p1.getID() < p2.getID())
return -1;
else if (p1.getID() == p2.getID())
return 0;
else
return 1;
}
});
/* Write the properties and the property list into their respective
* streams: */
for (final ListIterator i = preprops.listIterator(); i.hasNext();)
{
final MutableProperty p = (MutableProperty) i.next();
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;
|
private static int | writeDictionary(java.io.OutputStream out, java.util.Map dictionary, int codepage)Writes the section's dictionary.
int length = TypeWriter.writeUIntToStream(out, dictionary.size());
for (final Iterator i = dictionary.keySet().iterator(); i.hasNext();)
{
final Long key = (Long) i.next();
final String value = (String) dictionary.get(key);
if (codepage == Constants.CP_UNICODE)
{
/* Write the dictionary item in Unicode. */
int sLength = value.length() + 1;
if (sLength % 2 == 1)
sLength++;
length += TypeWriter.writeUIntToStream(out, key.longValue());
length += TypeWriter.writeUIntToStream(out, sLength);
final byte[] ca =
value.getBytes(VariantSupport.codepageToEncoding(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 =
value.getBytes(VariantSupport.codepageToEncoding(codepage));
for (int j = 0; j < ba.length; j++)
{
out.write(ba[j]);
length++;
}
out.write(0x00);
length++;
}
}
return length;
|