diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hsmf/datatypes/PropertiesChunk.java b/poi-scratchpad/src/main/java/org/apache/poi/hsmf/datatypes/PropertiesChunk.java index 5d5cde3..a9fa704 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hsmf/datatypes/PropertiesChunk.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hsmf/datatypes/PropertiesChunk.java @@ -391,6 +391,47 @@ public abstract class PropertiesChunk extends Chunk { return variableLengthProperties; } + /** + * Writes the manually pre-calculated(have header and data written manually) properties. + * + * @param out + * The {@code OutputStream}. + * @return The variable-length properties that need to be written in another + * node. + * @throws IOException + * If an I/O error occurs. + */ + protected List writePreCalculatedProperties(OutputStream out) throws IOException { + List variableLengthProperties = new ArrayList<>(); + for (Entry entry : properties.entrySet()) { + MAPIProperty property = entry.getKey(); + PropertyValue value = entry.getValue(); + if (value == null) { + continue; + } + if (property.id < 0) { + continue; + } + // generic header + // page 23, point 2.4.2 + // tag is the property id and its type + long tag = Long.parseLong(getActualTypeTag(property, value.getActualType()), 16); + LittleEndian.putUInt(tag, out); + LittleEndian.putUInt(value.getFlags(), out); // readable + writable + + MAPIType type = value.getActualType(); + if (type.isFixedLength()) { + // page 11, point 2.1.2 + writeFixedLengthValueHeader(out, property, type, value); + } else { + // page 12, point 2.1.3 + writeVariableLengthPreCalculatedValue(out, value); + variableLengthProperties.add(value); + } + } + return variableLengthProperties; + } + private void writeFixedLengthValueHeader(OutputStream out, MAPIProperty property, MAPIType type, PropertyValue value) throws IOException { // fixed type header // page 24, point 2.4.2.1.1 @@ -402,6 +443,19 @@ public abstract class PropertiesChunk extends Chunk { out.write(new byte[8 - length]); } + /** + * Writes out pre-calculated raw values which assume any variable length property `data` + * field to already have size, reserved and manually written header + * @param out + * @throws IOException + */ + private void writeVariableLengthPreCalculatedValue(OutputStream out, PropertyValue value) throws IOException { + // variable length header + // page 24, point 2.4.2.2 + byte[] bytes = value.getRawValue(); + out.write(bytes); + } + private void writeVariableLengthValueHeader(OutputStream out, MAPIProperty propertyEx, MAPIType type, PropertyValue value) throws IOException { // variable length header @@ -419,6 +473,14 @@ public abstract class PropertiesChunk extends Chunk { LittleEndian.putUInt(0, out); } + private String getActualTypeTag(MAPIProperty property, MAPIType actualType) { + String str = Integer.toHexString(property.id).toUpperCase(Locale.ROOT); + while (str.length() < 4) { + str = "0" + str; + } + return str + actualType.asFileEnding(); + } + private String getFileName(MAPIProperty property, MAPIType actualType) { StringBuilder str = new StringBuilder(Integer.toHexString(property.id).toUpperCase(Locale.ROOT)); int need0count = 4 - str.length(); diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hsmf/datatypes/StoragePropertiesChunk.java b/poi-scratchpad/src/main/java/org/apache/poi/hsmf/datatypes/StoragePropertiesChunk.java index 50b393d..cc98457 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hsmf/datatypes/StoragePropertiesChunk.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hsmf/datatypes/StoragePropertiesChunk.java @@ -49,4 +49,18 @@ public class StoragePropertiesChunk extends PropertiesChunk { // Now properties writeProperties(out); } + + /** + * Writes out pre-calculated header values which assume any variable length property `data` + * field to already have Size and Reserved + * @param out + * @throws IOException + */ + public void writePreCalculatedValue(OutputStream out) throws IOException { + // 8 bytes of reserved zeros + out.write(new byte[8]); + + // Now properties + writePreCalculatedProperties(out); + } } \ No newline at end of file