You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by fa...@apache.org on 2022/10/18 19:10:32 UTC
svn commit: r1904685 - in /poi/trunk/poi-scratchpad/src: main/java/org/apache/poi/hsmf/datatypes/PropertiesChunk.java main/java/org/apache/poi/hsmf/datatypes/StoragePropertiesChunk.java test/java/org/apache/poi/hsmf/datatypes/TestChunkData.java
Author: fanningpj
Date: Tue Oct 18 19:10:32 2022
New Revision: 1904685
URL: http://svn.apache.org/viewvc?rev=1904685&view=rev
Log:
[bug-66301] Add a method to properly write the header necessary for a MSG attachment. Thanks to Lyn Evans.
Modified:
poi/trunk/poi-scratchpad/src/main/java/org/apache/poi/hsmf/datatypes/PropertiesChunk.java
poi/trunk/poi-scratchpad/src/main/java/org/apache/poi/hsmf/datatypes/StoragePropertiesChunk.java
poi/trunk/poi-scratchpad/src/test/java/org/apache/poi/hsmf/datatypes/TestChunkData.java
Modified: poi/trunk/poi-scratchpad/src/main/java/org/apache/poi/hsmf/datatypes/PropertiesChunk.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi-scratchpad/src/main/java/org/apache/poi/hsmf/datatypes/PropertiesChunk.java?rev=1904685&r1=1904684&r2=1904685&view=diff
==============================================================================
--- poi/trunk/poi-scratchpad/src/main/java/org/apache/poi/hsmf/datatypes/PropertiesChunk.java (original)
+++ poi/trunk/poi-scratchpad/src/main/java/org/apache/poi/hsmf/datatypes/PropertiesChunk.java Tue Oct 18 19:10:32 2022
@@ -218,7 +218,8 @@ public abstract class PropertiesChunk ex
prop = MAPIProperty.createCustom(id, type, "Unknown " + id);
}
if (type == null) {
- LOG.atWarn().log("Invalid type found, expected {} but got {} for property {}", prop.usualType, box(typeID),prop);
+ LOG.atWarn().log("Invalid type found, expected {} but got {} for property {}",
+ prop.usualType, box(typeID), prop);
going = false;
break;
}
@@ -391,6 +392,47 @@ public abstract class PropertiesChunk ex
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<PropertyValue> writePreCalculatedProperties(OutputStream out) throws IOException {
+ List<PropertyValue> variableLengthProperties = new ArrayList<>();
+ for (Entry<MAPIProperty, PropertyValue> 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 +444,19 @@ public abstract class PropertiesChunk ex
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 +474,15 @@ public abstract class PropertiesChunk ex
LittleEndian.putUInt(0, out);
}
+ private String getActualTypeTag(MAPIProperty property, MAPIType actualType) {
+ StringBuilder buffer = new StringBuilder(Integer.toHexString(property.id).toUpperCase(Locale.ROOT));
+ while (buffer.length() < 4) {
+ buffer.insert(0, "0");
+ }
+ buffer.append(actualType.asFileEnding());
+ return buffer.toString();
+ }
+
private String getFileName(MAPIProperty property, MAPIType actualType) {
StringBuilder str = new StringBuilder(Integer.toHexString(property.id).toUpperCase(Locale.ROOT));
int need0count = 4 - str.length();
Modified: poi/trunk/poi-scratchpad/src/main/java/org/apache/poi/hsmf/datatypes/StoragePropertiesChunk.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi-scratchpad/src/main/java/org/apache/poi/hsmf/datatypes/StoragePropertiesChunk.java?rev=1904685&r1=1904684&r2=1904685&view=diff
==============================================================================
--- poi/trunk/poi-scratchpad/src/main/java/org/apache/poi/hsmf/datatypes/StoragePropertiesChunk.java (original)
+++ poi/trunk/poi-scratchpad/src/main/java/org/apache/poi/hsmf/datatypes/StoragePropertiesChunk.java Tue Oct 18 19:10:32 2022
@@ -25,7 +25,7 @@ import org.apache.poi.util.LittleEndian;
/**
* A {@link PropertiesChunk} for a Storage Properties, such as Attachments and
- * Recipients. This only has a 8 byte header
+ * Recipients. This only has an 8 byte header.
*/
public class StoragePropertiesChunk extends PropertiesChunk {
public StoragePropertiesChunk(ChunkGroup parentGroup) {
@@ -49,4 +49,18 @@ public class StoragePropertiesChunk exte
// 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 output stream (calling code must close this stream)
+ * @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
Modified: poi/trunk/poi-scratchpad/src/test/java/org/apache/poi/hsmf/datatypes/TestChunkData.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi-scratchpad/src/test/java/org/apache/poi/hsmf/datatypes/TestChunkData.java?rev=1904685&r1=1904684&r2=1904685&view=diff
==============================================================================
--- poi/trunk/poi-scratchpad/src/test/java/org/apache/poi/hsmf/datatypes/TestChunkData.java (original)
+++ poi/trunk/poi-scratchpad/src/test/java/org/apache/poi/hsmf/datatypes/TestChunkData.java Tue Oct 18 19:10:32 2022
@@ -17,10 +17,14 @@
package org.apache.poi.hsmf.datatypes;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
import org.junit.jupiter.api.Test;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
/**
* Verifies that the Chunks class is actually setup properly and hasn't been changed in ways
* that will break the library.
@@ -28,22 +32,22 @@ import org.junit.jupiter.api.Test;
public final class TestChunkData {
@Test
void testChunkCreate() {
- Chunk chunk;
+ Chunk chunk;
chunk = new StringChunk(0x0200, Types.createCustom(0x001E));
assertEquals("__substg1.0_0200001E", chunk.getEntryName());
assertEquals(0x0200, chunk.getChunkId());
assertEquals(0x001E, chunk.getType().getId());
- chunk = new StringChunk("__substg1.0_", 0x0200, Types.createCustom(0x001E));
- assertEquals("__substg1.0_0200001E", chunk.getEntryName());
- assertEquals(0x0200, chunk.getChunkId());
- assertEquals(0x001E, chunk.getType().getId());
-
- chunk = new StringChunk("__substg1.0_", 0x0200, Types.getById(0x001E));
- assertEquals("__substg1.0_0200001E", chunk.getEntryName());
- assertEquals(0x0200, chunk.getChunkId());
- assertEquals(0x001E, chunk.getType().getId());
+ chunk = new StringChunk("__substg1.0_", 0x0200, Types.createCustom(0x001E));
+ assertEquals("__substg1.0_0200001E", chunk.getEntryName());
+ assertEquals(0x0200, chunk.getChunkId());
+ assertEquals(0x001E, chunk.getType().getId());
+
+ chunk = new StringChunk("__substg1.0_", 0x0200, Types.getById(0x001E));
+ assertEquals("__substg1.0_0200001E", chunk.getEntryName());
+ assertEquals(0x0200, chunk.getChunkId());
+ assertEquals(0x001E, chunk.getType().getId());
/* test the lower and upper limits of the chunk ids */
chunk = new StringChunk(0x0000, Types.createCustom(0x001E));
@@ -65,26 +69,40 @@ public final class TestChunkData {
@Test
void testDisplayToChunk() {
StringChunk chunk = new StringChunk(0x0E04, Types.UNICODE_STRING);
- assertEquals(chunk.getChunkId(), MAPIProperty.DISPLAY_TO.id);
+ assertEquals(chunk.getChunkId(), MAPIProperty.DISPLAY_TO.id);
}
@Test
void testDisplayCCChunk() {
StringChunk chunk = new StringChunk(0x0E03, Types.UNICODE_STRING);
- assertEquals(chunk.getChunkId(), MAPIProperty.DISPLAY_CC.id);
+ assertEquals(chunk.getChunkId(), MAPIProperty.DISPLAY_CC.id);
}
@Test
void testDisplayBCCChunk() {
StringChunk chunk = new StringChunk(0x0E02, Types.UNICODE_STRING);
- assertEquals(chunk.getChunkId(), MAPIProperty.DISPLAY_BCC.id);
+ assertEquals(chunk.getChunkId(), MAPIProperty.DISPLAY_BCC.id);
}
@Test
void testSubjectChunk() {
Chunk chunk = new StringChunk(0x0037, Types.UNICODE_STRING);
- assertEquals(chunk.getChunkId(), MAPIProperty.SUBJECT.id);
+ assertEquals(chunk.getChunkId(), MAPIProperty.SUBJECT.id);
}
+ @Test
+ void testWritePreCalculatedProperties() throws IOException {
+ try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) {
+ StoragePropertiesChunk storagePropertiesChunk = new StoragePropertiesChunk(null);
+ PropertyValue.LongPropertyValue attachSize =
+ new PropertyValue.LongPropertyValue(MAPIProperty.ATTACH_SIZE, 6L, new byte[0]);
+ PropertyValue currentValue = new PropertyValue(MAPIProperty.DISPLAY_BCC, 6L, new byte[0]);
+ attachSize.setValue(3934266);
+ storagePropertiesChunk.setProperty(attachSize);
+ storagePropertiesChunk.setProperty(currentValue);
+ List<PropertyValue> propertyValue= storagePropertiesChunk.writePreCalculatedProperties(stream);
+ assertEquals(propertyValue.size(),1);
+ }
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org