aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDominik Stadler <centic@apache.org>2023-08-06 14:57:47 +0000
committerDominik Stadler <centic@apache.org>2023-08-06 14:57:47 +0000
commit1e8e95c3a659e88c3303f6247298c3b865229122 (patch)
tree9781b598b3f9c90c35189a52680b575f3fc7ec08
parente5ff0e4eb6abd50e3cbd4a44a5477be94450d702 (diff)
downloadpoi-1e8e95c3a659e88c3303f6247298c3b865229122.tar.gz
poi-1e8e95c3a659e88c3303f6247298c3b865229122.zip
Bug 66425: Avoid a ClassCastException found via oss-fuzz
We try to avoid throwing ClassCastException, but it was possible to trigger one here with a specially crafted input-file Also rework test a bit to use try-with-resources and proper formatting Should fix https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=61221 git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1911494 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--poi-scratchpad/src/main/java/org/apache/poi/hsmf/datatypes/Chunks.java110
-rw-r--r--poi-scratchpad/src/test/java/org/apache/poi/hsmf/parsers/TestPOIFSChunkParser.java581
-rw-r--r--test-data/hsmf/clusterfuzz-testcase-minimized-POIHSMFFuzzer-4848576776503296.msgbin0 -> 21504 bytes
-rw-r--r--test-data/spreadsheet/stress.xlsbin39936 -> 39936 bytes
4 files changed, 345 insertions, 346 deletions
diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hsmf/datatypes/Chunks.java b/poi-scratchpad/src/main/java/org/apache/poi/hsmf/datatypes/Chunks.java
index 041ab37556..2ffcb3f3b2 100644
--- a/poi-scratchpad/src/main/java/org/apache/poi/hsmf/datatypes/Chunks.java
+++ b/poi-scratchpad/src/main/java/org/apache/poi/hsmf/datatypes/Chunks.java
@@ -194,67 +194,65 @@ public final class Chunks implements ChunkGroupWithProperties {
public void record(Chunk chunk) {
// Work out what MAPIProperty this corresponds to
MAPIProperty prop = MAPIProperty.get(chunk.getChunkId());
- if (prop == MAPIProperty.UNKNOWN) {
- long id = (chunk.getChunkId() << 16) + (long)chunk.getType().getId();
- prop = unknownProperties.get(id);
- if (prop == null) {
- prop = MAPIProperty.createCustom(chunk.getChunkId(), chunk.getType(), chunk.getEntryName());
- unknownProperties.put(id, prop);
+ try {
+ if (prop == MAPIProperty.UNKNOWN) {
+ long id = (chunk.getChunkId() << 16) + (long) chunk.getType().getId();
+ prop = unknownProperties.get(id);
+ if (prop == null) {
+ prop = MAPIProperty.createCustom(chunk.getChunkId(), chunk.getType(), chunk.getEntryName());
+ unknownProperties.put(id, prop);
+ }
}
- }
-
- // Assign it for easy lookup, as best we can
- if (prop == MAPIProperty.MESSAGE_CLASS) {
- messageClass = (StringChunk) chunk;
- } else if (prop == MAPIProperty.INTERNET_MESSAGE_ID) {
- messageId = (StringChunk) chunk;
- } else if (prop == MAPIProperty.MESSAGE_SUBMISSION_ID) {
- // TODO - parse
- submissionChunk = (MessageSubmissionChunk) chunk;
- } else if (prop == MAPIProperty.RECEIVED_BY_ADDRTYPE) {
- sentByServerType = (StringChunk) chunk;
- } else if (prop == MAPIProperty.TRANSPORT_MESSAGE_HEADERS) {
- messageHeaders = (StringChunk) chunk;
- }
- else if (prop == MAPIProperty.CONVERSATION_TOPIC) {
- conversationTopic = (StringChunk) chunk;
- } else if (prop == MAPIProperty.SUBJECT) {
- subjectChunk = (StringChunk) chunk;
- } /*else if (prop == MAPIProperty.ORIGINAL_SUBJECT) {
+ // Assign it for easy lookup, as best we can
+ if (prop == MAPIProperty.MESSAGE_CLASS) {
+ messageClass = (StringChunk) chunk;
+ } else if (prop == MAPIProperty.INTERNET_MESSAGE_ID) {
+ messageId = (StringChunk) chunk;
+ } else if (prop == MAPIProperty.MESSAGE_SUBMISSION_ID) {
+ // TODO - parse
+ submissionChunk = (MessageSubmissionChunk) chunk;
+ } else if (prop == MAPIProperty.RECEIVED_BY_ADDRTYPE) {
+ sentByServerType = (StringChunk) chunk;
+ } else if (prop == MAPIProperty.TRANSPORT_MESSAGE_HEADERS) {
+ messageHeaders = (StringChunk) chunk;
+ } else if (prop == MAPIProperty.CONVERSATION_TOPIC) {
+ conversationTopic = (StringChunk) chunk;
+ } else if (prop == MAPIProperty.SUBJECT) {
+ subjectChunk = (StringChunk) chunk;
+ } /*else if (prop == MAPIProperty.ORIGINAL_SUBJECT) {
// TODO
- }*/
-
- else if (prop == MAPIProperty.DISPLAY_TO) {
- displayToChunk = (StringChunk) chunk;
- } else if (prop == MAPIProperty.DISPLAY_CC) {
- displayCCChunk = (StringChunk) chunk;
- } else if (prop == MAPIProperty.DISPLAY_BCC) {
- displayBCCChunk = (StringChunk) chunk;
- }
-
- else if (prop == MAPIProperty.SENDER_EMAIL_ADDRESS) {
- emailFromChunk = (StringChunk) chunk;
- } else if (prop == MAPIProperty.SENDER_NAME) {
- displayFromChunk = (StringChunk) chunk;
- } else if (prop == MAPIProperty.BODY) {
- textBodyChunk = (StringChunk) chunk;
- } else if (prop == MAPIProperty.BODY_HTML) {
- if (chunk instanceof StringChunk) {
- htmlBodyChunkString = (StringChunk) chunk;
- }
- if (chunk instanceof ByteChunk) {
- htmlBodyChunkBinary = (ByteChunk) chunk;
+ }*/ else if (prop == MAPIProperty.DISPLAY_TO) {
+ displayToChunk = (StringChunk) chunk;
+ } else if (prop == MAPIProperty.DISPLAY_CC) {
+ displayCCChunk = (StringChunk) chunk;
+ } else if (prop == MAPIProperty.DISPLAY_BCC) {
+ displayBCCChunk = (StringChunk) chunk;
+ } else if (prop == MAPIProperty.SENDER_EMAIL_ADDRESS) {
+ emailFromChunk = (StringChunk) chunk;
+ } else if (prop == MAPIProperty.SENDER_NAME) {
+ displayFromChunk = (StringChunk) chunk;
+ } else if (prop == MAPIProperty.BODY) {
+ textBodyChunk = (StringChunk) chunk;
+ } else if (prop == MAPIProperty.BODY_HTML) {
+ if (chunk instanceof StringChunk) {
+ htmlBodyChunkString = (StringChunk) chunk;
+ }
+ if (chunk instanceof ByteChunk) {
+ htmlBodyChunkBinary = (ByteChunk) chunk;
+ }
+ } else if (prop == MAPIProperty.RTF_COMPRESSED) {
+ rtfBodyChunk = (ByteChunk) chunk;
+ } else if (chunk instanceof MessagePropertiesChunk) {
+ messageProperties = (MessagePropertiesChunk) chunk;
}
- } else if (prop == MAPIProperty.RTF_COMPRESSED) {
- rtfBodyChunk = (ByteChunk) chunk;
- } else if (chunk instanceof MessagePropertiesChunk) {
- messageProperties = (MessagePropertiesChunk) chunk;
- }
- // And add to the main list
- allChunks.computeIfAbsent(prop, k -> new ArrayList<>());
- allChunks.get(prop).add(chunk);
+ // And add to the main list
+ allChunks.computeIfAbsent(prop, k -> new ArrayList<>());
+ allChunks.get(prop).add(chunk);
+ } catch (ClassCastException e) {
+ throw new IllegalArgumentException("Property and type of chunk did not match, had property " + prop + " and type of chunk: " + chunk.getClass());
+ }
}
@Override
diff --git a/poi-scratchpad/src/test/java/org/apache/poi/hsmf/parsers/TestPOIFSChunkParser.java b/poi-scratchpad/src/test/java/org/apache/poi/hsmf/parsers/TestPOIFSChunkParser.java
index 528fefd548..f93ff19f0f 100644
--- a/poi-scratchpad/src/test/java/org/apache/poi/hsmf/parsers/TestPOIFSChunkParser.java
+++ b/poi-scratchpad/src/test/java/org/apache/poi/hsmf/parsers/TestPOIFSChunkParser.java
@@ -21,6 +21,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.IOException;
@@ -48,294 +49,294 @@ import org.junit.jupiter.api.Test;
* Tests to verify that the chunk parser works properly
*/
public final class TestPOIFSChunkParser {
- private final POIDataSamples samples = POIDataSamples.getHSMFInstance();
-
- @Test
- void testFindsCore() throws IOException, ChunkNotFoundException {
- POIFSFileSystem simple = new POIFSFileSystem(samples.getFile("quick.msg"), true);
-
- // Check a few core things are present
- simple.getRoot().getEntry(
- (new StringChunk(MAPIProperty.SUBJECT.id, Types.ASCII_STRING)).getEntryName()
- );
- simple.getRoot().getEntry(
- (new StringChunk(MAPIProperty.SENDER_NAME.id, Types.ASCII_STRING)).getEntryName()
- );
-
- // Now load the file
- MAPIMessage msg = new MAPIMessage(simple);
- assertEquals("Kevin Roast", msg.getDisplayTo());
- assertEquals("Kevin Roast", msg.getDisplayFrom());
- assertEquals("Test the content transformer", msg.getSubject());
-
- // Check date too
- Calendar calExp = LocaleUtil.getLocaleCalendar(2007,5,14,9,42,55);
- Calendar calAct = msg.getMessageDate();
- assertEquals( calExp, calAct );
-
- msg.close();
- simple.close();
- }
-
- @Test
- void testFindsRecips() throws IOException, ChunkNotFoundException {
- POIFSFileSystem simple = new POIFSFileSystem(samples.getFile("quick.msg"), true);
-
- simple.getRoot().getEntry("__recip_version1.0_#00000000");
-
- ChunkGroup[] groups = POIFSChunkParser.parse(simple.getRoot());
- assertEquals(3, groups.length);
- assertTrue(groups[0] instanceof Chunks);
- assertTrue(groups[1] instanceof RecipientChunks);
- assertTrue(groups[2] instanceof NameIdChunks);
-
- RecipientChunks recips = (RecipientChunks)groups[1];
- assertEquals("kevin.roast@alfresco.org", recips.getRecipientSMTPChunk().getValue());
- assertEquals("/O=HOSTEDSERVICE2/OU=FIRST ADMINISTRATIVE GROUP/CN=RECIPIENTS/CN=Kevin.roast@ben",
- recips.getRecipientEmailChunk().getValue());
-
- String search = new String(recips.getRecipientSearchChunk().getValue(), StandardCharsets.US_ASCII);
- assertEquals("CN=KEVIN.ROAST@BEN\0", search.substring(search.length()-19));
-
- // Now via MAPIMessage
- MAPIMessage msg = new MAPIMessage(simple);
- assertNotNull(msg.getRecipientDetailsChunks());
- assertEquals(1, msg.getRecipientDetailsChunks().length);
-
- assertEquals("kevin.roast@alfresco.org", msg.getRecipientDetailsChunks()[0].getRecipientSMTPChunk().getValue());
- assertEquals("kevin.roast@alfresco.org", msg.getRecipientDetailsChunks()[0].getRecipientEmailAddress());
- assertEquals("Kevin Roast", msg.getRecipientDetailsChunks()[0].getRecipientName());
- assertEquals("kevin.roast@alfresco.org", msg.getRecipientEmailAddress());
-
-
- // Try both SMTP and EX files for recipient
- assertEquals("EX", msg.getRecipientDetailsChunks()[0].getDeliveryTypeChunk().getValue());
- assertEquals("kevin.roast@alfresco.org", msg.getRecipientDetailsChunks()[0].getRecipientSMTPChunk().getValue());
- assertEquals("/O=HOSTEDSERVICE2/OU=FIRST ADMINISTRATIVE GROUP/CN=RECIPIENTS/CN=Kevin.roast@ben",
- msg.getRecipientDetailsChunks()[0].getRecipientEmailChunk().getValue());
- msg.close();
- simple.close();
-
-
- // Now look at another message
- simple = new POIFSFileSystem(samples.getFile("simple_test_msg.msg"), true);
- msg = new MAPIMessage(simple);
- assertNotNull(msg.getRecipientDetailsChunks());
- assertEquals(1, msg.getRecipientDetailsChunks().length);
-
- assertEquals("SMTP", msg.getRecipientDetailsChunks()[0].getDeliveryTypeChunk().getValue());
- assertNull(msg.getRecipientDetailsChunks()[0].getRecipientSMTPChunk());
- assertNull(msg.getRecipientDetailsChunks()[0].getRecipientNameChunk());
- assertEquals("travis@overwrittenstack.com", msg.getRecipientDetailsChunks()[0].getRecipientEmailChunk().getValue());
- assertEquals("travis@overwrittenstack.com", msg.getRecipientEmailAddress());
-
- msg.close();
- simple.close();
- }
-
- @Test
- void testFindsMultipleRecipients() throws IOException, ChunkNotFoundException {
- POIFSFileSystem multiple = new POIFSFileSystem(samples.getFile("example_received_unicode.msg"), true);
-
- multiple.getRoot().getEntry("__recip_version1.0_#00000000");
- multiple.getRoot().getEntry("__recip_version1.0_#00000001");
- multiple.getRoot().getEntry("__recip_version1.0_#00000002");
- multiple.getRoot().getEntry("__recip_version1.0_#00000003");
- multiple.getRoot().getEntry("__recip_version1.0_#00000004");
- multiple.getRoot().getEntry("__recip_version1.0_#00000005");
-
- ChunkGroup[] groups = POIFSChunkParser.parse(multiple.getRoot());
- assertEquals(9, groups.length);
- assertTrue(groups[0] instanceof Chunks);
- assertTrue(groups[1] instanceof RecipientChunks);
- assertTrue(groups[2] instanceof RecipientChunks);
- assertTrue(groups[3] instanceof RecipientChunks);
- assertTrue(groups[4] instanceof RecipientChunks);
- assertTrue(groups[5] instanceof AttachmentChunks);
- assertTrue(groups[6] instanceof RecipientChunks);
- assertTrue(groups[7] instanceof RecipientChunks);
- assertTrue(groups[8] instanceof NameIdChunks);
-
- // In FS order initially
- RecipientChunks[] chunks = new RecipientChunks[] {
- (RecipientChunks)groups[1],
- (RecipientChunks)groups[2],
- (RecipientChunks)groups[3],
- (RecipientChunks)groups[4],
- (RecipientChunks)groups[6],
- (RecipientChunks)groups[7],
- };
- assertEquals(6, chunks.length);
- assertEquals(0, chunks[0].getRecipientNumber());
- assertEquals(2, chunks[1].getRecipientNumber());
- assertEquals(4, chunks[2].getRecipientNumber());
- assertEquals(5, chunks[3].getRecipientNumber());
- assertEquals(3, chunks[4].getRecipientNumber());
- assertEquals(1, chunks[5].getRecipientNumber());
-
- // Check
- assertEquals("'Ashutosh Dandavate'", chunks[0].getRecipientName());
- assertEquals("ashutosh.dandavate@alfresco.com", chunks[0].getRecipientEmailAddress());
- assertEquals("'Mike Farman'", chunks[1].getRecipientName());
- assertEquals("mikef@alfresco.com", chunks[1].getRecipientEmailAddress());
- assertEquals("nick.burch@alfresco.com", chunks[2].getRecipientName());
- assertEquals("nick.burch@alfresco.com", chunks[2].getRecipientEmailAddress());
- assertEquals("'Roy Wetherall'", chunks[3].getRecipientName());
- assertEquals("roy.wetherall@alfresco.com", chunks[3].getRecipientEmailAddress());
- assertEquals("nickb@alfresco.com", chunks[4].getRecipientName());
- assertEquals("nickb@alfresco.com", chunks[4].getRecipientEmailAddress());
- assertEquals("'Paul Holmes-Higgin'", chunks[5].getRecipientName());
- assertEquals("paul.hh@alfresco.com", chunks[5].getRecipientEmailAddress());
-
- // Now sort, and re-check
- Arrays.sort(chunks, new RecipientChunksSorter());
-
- assertEquals("'Ashutosh Dandavate'", chunks[0].getRecipientName());
- assertEquals("ashutosh.dandavate@alfresco.com", chunks[0].getRecipientEmailAddress());
- assertEquals("'Paul Holmes-Higgin'", chunks[1].getRecipientName());
- assertEquals("paul.hh@alfresco.com", chunks[1].getRecipientEmailAddress());
- assertEquals("'Mike Farman'", chunks[2].getRecipientName());
- assertEquals("mikef@alfresco.com", chunks[2].getRecipientEmailAddress());
- assertEquals("nickb@alfresco.com", chunks[3].getRecipientName());
- assertEquals("nickb@alfresco.com", chunks[3].getRecipientEmailAddress());
- assertEquals("nick.burch@alfresco.com", chunks[4].getRecipientName());
- assertEquals("nick.burch@alfresco.com", chunks[4].getRecipientEmailAddress());
- assertEquals("'Roy Wetherall'", chunks[5].getRecipientName());
- assertEquals("roy.wetherall@alfresco.com", chunks[5].getRecipientEmailAddress());
-
- // Finally check on message
- MAPIMessage msg = new MAPIMessage(multiple);
- assertEquals(6, msg.getRecipientEmailAddressList().length);
- assertEquals(6, msg.getRecipientNamesList().length);
-
- assertEquals("'Ashutosh Dandavate'", msg.getRecipientNamesList()[0]);
- assertEquals("'Paul Holmes-Higgin'", msg.getRecipientNamesList()[1]);
- assertEquals("'Mike Farman'", msg.getRecipientNamesList()[2]);
- assertEquals("nickb@alfresco.com", msg.getRecipientNamesList()[3]);
- assertEquals("nick.burch@alfresco.com", msg.getRecipientNamesList()[4]);
- assertEquals("'Roy Wetherall'", msg.getRecipientNamesList()[5]);
-
- assertEquals("ashutosh.dandavate@alfresco.com", msg.getRecipientEmailAddressList()[0]);
- assertEquals("paul.hh@alfresco.com", msg.getRecipientEmailAddressList()[1]);
- assertEquals("mikef@alfresco.com", msg.getRecipientEmailAddressList()[2]);
- assertEquals("nickb@alfresco.com", msg.getRecipientEmailAddressList()[3]);
- assertEquals("nick.burch@alfresco.com", msg.getRecipientEmailAddressList()[4]);
- assertEquals("roy.wetherall@alfresco.com", msg.getRecipientEmailAddressList()[5]);
-
- msg.close();
- multiple.close();
- }
-
- @Test
- void testFindsNameId() throws IOException {
- POIFSFileSystem simple = new POIFSFileSystem(samples.getFile("quick.msg"), true);
-
- simple.getRoot().getEntry("__nameid_version1.0");
-
- ChunkGroup[] groups = POIFSChunkParser.parse(simple.getRoot());
- assertEquals(3, groups.length);
- assertTrue(groups[0] instanceof Chunks);
- assertTrue(groups[1] instanceof RecipientChunks);
- assertTrue(groups[2] instanceof NameIdChunks);
-
- NameIdChunks nameId = (NameIdChunks)groups[2];
- assertEquals(10, nameId.getAll().length);
-
- // Now via MAPIMessage
- MAPIMessage msg = new MAPIMessage(simple);
- assertNotNull(msg.getNameIdChunks());
- assertEquals(10, msg.getNameIdChunks().getAll().length);
-
- msg.close();
- simple.close();
- }
-
- @Test
- void testFindsAttachments() throws IOException, ChunkNotFoundException {
- POIFSFileSystem with = new POIFSFileSystem(samples.getFile("attachment_test_msg.msg"), true);
- POIFSFileSystem without = new POIFSFileSystem(samples.getFile("quick.msg"), true);
- AttachmentChunks attachment;
-
-
- // Check raw details on the one with
- with.getRoot().getEntry("__attach_version1.0_#00000000");
- with.getRoot().getEntry("__attach_version1.0_#00000001");
- POIFSChunkParser.parse(with.getRoot());
-
- ChunkGroup[] groups = POIFSChunkParser.parse(with.getRoot());
- assertEquals(5, groups.length);
- assertTrue(groups[0] instanceof Chunks);
- assertTrue(groups[1] instanceof RecipientChunks);
- assertTrue(groups[2] instanceof AttachmentChunks);
- assertTrue(groups[3] instanceof AttachmentChunks);
- assertTrue(groups[4] instanceof NameIdChunks);
-
- attachment = (AttachmentChunks)groups[2];
- assertEquals("TEST-U~1.DOC", attachment.getAttachFileName().toString());
- assertEquals("test-unicode.doc", attachment.getAttachLongFileName().toString());
- assertEquals(24064, attachment.getAttachData().getValue().length);
-
- attachment = (AttachmentChunks)groups[3];
- assertEquals("pj1.txt", attachment.getAttachFileName().toString());
- assertEquals("pj1.txt", attachment.getAttachLongFileName().toString());
- assertEquals(89, attachment.getAttachData().getValue().length);
-
-
- // Check raw details on one without
- assertFalse(without.getRoot().hasEntry("__attach_version1.0_#00000000"));
- assertFalse(without.getRoot().hasEntry("__attach_version1.0_#00000001"));
-
- // One with, from the top
- MAPIMessage msgWith = new MAPIMessage(with);
- assertEquals(2, msgWith.getAttachmentFiles().length);
-
- attachment = msgWith.getAttachmentFiles()[0];
- assertEquals("TEST-U~1.DOC", attachment.getAttachFileName().toString());
- assertEquals("test-unicode.doc", attachment.getAttachLongFileName().toString());
- assertEquals(24064, attachment.getAttachData().getValue().length);
-
- attachment = msgWith.getAttachmentFiles()[1];
- assertEquals("pj1.txt", attachment.getAttachFileName().toString());
- assertEquals("pj1.txt", attachment.getAttachLongFileName().toString());
- assertEquals(89, attachment.getAttachData().getValue().length);
-
- // Plus check core details are there
- assertEquals("'nicolas1.23456@free.fr'", msgWith.getDisplayTo());
- assertEquals("Nicolas1 23456", msgWith.getDisplayFrom());
- assertEquals("test pi\u00e8ce jointe 1", msgWith.getSubject());
-
- // One without, from the top
- MAPIMessage msgWithout = new MAPIMessage(without);
-
- // No attachments
- assertEquals(0, msgWithout.getAttachmentFiles().length);
-
- // But has core details
- assertEquals("Kevin Roast", msgWithout.getDisplayTo());
- assertEquals("Kevin Roast", msgWithout.getDisplayFrom());
- assertEquals("Test the content transformer", msgWithout.getSubject());
-
- msgWithout.close();
- msgWith.close();
- without.close();
- with.close();
- }
-
- /**
- * Bugzilla #51873 - Outlook 2002 files created with dragging and
- * dropping files to the disk include a non-standard named streams
- * such as "Olk10SideProps_0001"
- */
- @Test
- void testOlk10SideProps() throws IOException, ChunkNotFoundException {
- POIFSFileSystem poifs = new POIFSFileSystem(samples.getFile("51873.msg"), true);
- MAPIMessage msg = new MAPIMessage(poifs);
-
- // Check core details came through
- assertEquals("bubba@bubbasmith.com", msg.getDisplayTo());
- assertEquals("Test with Olk10SideProps_ Chunk", msg.getSubject());
-
- msg.close();
- poifs.close();
- }
+
+ private final POIDataSamples samples = POIDataSamples.getHSMFInstance();
+
+ @Test
+ void testFindsCore() throws IOException, ChunkNotFoundException {
+ try (POIFSFileSystem simple = new POIFSFileSystem(samples.getFile("quick.msg"), true)) {
+
+ // Check a few core things are present
+ simple.getRoot().getEntry(
+ (new StringChunk(MAPIProperty.SUBJECT.id, Types.ASCII_STRING)).getEntryName()
+ );
+ simple.getRoot().getEntry(
+ (new StringChunk(MAPIProperty.SENDER_NAME.id, Types.ASCII_STRING)).getEntryName()
+ );
+
+ // Now load the file
+ try (MAPIMessage msg = new MAPIMessage(simple)) {
+ assertEquals("Kevin Roast", msg.getDisplayTo());
+ assertEquals("Kevin Roast", msg.getDisplayFrom());
+ assertEquals("Test the content transformer", msg.getSubject());
+
+ // Check date too
+ Calendar calExp = LocaleUtil.getLocaleCalendar(2007, 5, 14, 9, 42, 55);
+ Calendar calAct = msg.getMessageDate();
+ assertEquals(calExp, calAct);
+ }
+ }
+ }
+
+ @Test
+ void testFindsRecips() throws IOException, ChunkNotFoundException {
+ try (POIFSFileSystem simple = new POIFSFileSystem(samples.getFile("quick.msg"), true)) {
+
+ simple.getRoot().getEntry("__recip_version1.0_#00000000");
+
+ ChunkGroup[] groups = POIFSChunkParser.parse(simple.getRoot());
+ assertEquals(3, groups.length);
+ assertTrue(groups[0] instanceof Chunks);
+ assertTrue(groups[1] instanceof RecipientChunks);
+ assertTrue(groups[2] instanceof NameIdChunks);
+
+ RecipientChunks recips = (RecipientChunks) groups[1];
+ assertEquals("kevin.roast@alfresco.org", recips.getRecipientSMTPChunk().getValue());
+ assertEquals("/O=HOSTEDSERVICE2/OU=FIRST ADMINISTRATIVE GROUP/CN=RECIPIENTS/CN=Kevin.roast@ben",
+ recips.getRecipientEmailChunk().getValue());
+
+ String search = new String(recips.getRecipientSearchChunk().getValue(), StandardCharsets.US_ASCII);
+ assertEquals("CN=KEVIN.ROAST@BEN\0", search.substring(search.length() - 19));
+
+ // Now via MAPIMessage
+ try (MAPIMessage msg = new MAPIMessage(simple)) {
+ assertNotNull(msg.getRecipientDetailsChunks());
+ assertEquals(1, msg.getRecipientDetailsChunks().length);
+
+ assertEquals("kevin.roast@alfresco.org", msg.getRecipientDetailsChunks()[0].getRecipientSMTPChunk().getValue());
+ assertEquals("kevin.roast@alfresco.org", msg.getRecipientDetailsChunks()[0].getRecipientEmailAddress());
+ assertEquals("Kevin Roast", msg.getRecipientDetailsChunks()[0].getRecipientName());
+ assertEquals("kevin.roast@alfresco.org", msg.getRecipientEmailAddress());
+
+ // Try both SMTP and EX files for recipient
+ assertEquals("EX", msg.getRecipientDetailsChunks()[0].getDeliveryTypeChunk().getValue());
+ assertEquals("kevin.roast@alfresco.org", msg.getRecipientDetailsChunks()[0].getRecipientSMTPChunk().getValue());
+ assertEquals("/O=HOSTEDSERVICE2/OU=FIRST ADMINISTRATIVE GROUP/CN=RECIPIENTS/CN=Kevin.roast@ben",
+ msg.getRecipientDetailsChunks()[0].getRecipientEmailChunk().getValue());
+ }
+ }
+
+ // Now look at another message
+ try (POIFSFileSystem simple = new POIFSFileSystem(samples.getFile("simple_test_msg.msg"), true)) {
+ try (MAPIMessage msg = new MAPIMessage(simple)) {
+ assertNotNull(msg.getRecipientDetailsChunks());
+ assertEquals(1, msg.getRecipientDetailsChunks().length);
+
+ assertEquals("SMTP", msg.getRecipientDetailsChunks()[0].getDeliveryTypeChunk().getValue());
+ assertNull(msg.getRecipientDetailsChunks()[0].getRecipientSMTPChunk());
+ assertNull(msg.getRecipientDetailsChunks()[0].getRecipientNameChunk());
+ assertEquals("travis@overwrittenstack.com",
+ msg.getRecipientDetailsChunks()[0].getRecipientEmailChunk().getValue());
+ assertEquals("travis@overwrittenstack.com", msg.getRecipientEmailAddress());
+ }
+ }
+ }
+
+ @Test
+ void testFindsMultipleRecipients() throws IOException, ChunkNotFoundException {
+ try (POIFSFileSystem multiple = new POIFSFileSystem(samples.getFile("example_received_unicode.msg"), true)) {
+
+ multiple.getRoot().getEntry("__recip_version1.0_#00000000");
+ multiple.getRoot().getEntry("__recip_version1.0_#00000001");
+ multiple.getRoot().getEntry("__recip_version1.0_#00000002");
+ multiple.getRoot().getEntry("__recip_version1.0_#00000003");
+ multiple.getRoot().getEntry("__recip_version1.0_#00000004");
+ multiple.getRoot().getEntry("__recip_version1.0_#00000005");
+
+ ChunkGroup[] groups = POIFSChunkParser.parse(multiple.getRoot());
+ assertEquals(9, groups.length);
+ assertTrue(groups[0] instanceof Chunks);
+ assertTrue(groups[1] instanceof RecipientChunks);
+ assertTrue(groups[2] instanceof RecipientChunks);
+ assertTrue(groups[3] instanceof RecipientChunks);
+ assertTrue(groups[4] instanceof RecipientChunks);
+ assertTrue(groups[5] instanceof AttachmentChunks);
+ assertTrue(groups[6] instanceof RecipientChunks);
+ assertTrue(groups[7] instanceof RecipientChunks);
+ assertTrue(groups[8] instanceof NameIdChunks);
+
+ // In FS order initially
+ RecipientChunks[] chunks = new RecipientChunks[] {
+ (RecipientChunks) groups[1],
+ (RecipientChunks) groups[2],
+ (RecipientChunks) groups[3],
+ (RecipientChunks) groups[4],
+ (RecipientChunks) groups[6],
+ (RecipientChunks) groups[7],
+ };
+ assertEquals(6, chunks.length);
+ assertEquals(0, chunks[0].getRecipientNumber());
+ assertEquals(2, chunks[1].getRecipientNumber());
+ assertEquals(4, chunks[2].getRecipientNumber());
+ assertEquals(5, chunks[3].getRecipientNumber());
+ assertEquals(3, chunks[4].getRecipientNumber());
+ assertEquals(1, chunks[5].getRecipientNumber());
+
+ // Check
+ assertEquals("'Ashutosh Dandavate'", chunks[0].getRecipientName());
+ assertEquals("ashutosh.dandavate@alfresco.com", chunks[0].getRecipientEmailAddress());
+ assertEquals("'Mike Farman'", chunks[1].getRecipientName());
+ assertEquals("mikef@alfresco.com", chunks[1].getRecipientEmailAddress());
+ assertEquals("nick.burch@alfresco.com", chunks[2].getRecipientName());
+ assertEquals("nick.burch@alfresco.com", chunks[2].getRecipientEmailAddress());
+ assertEquals("'Roy Wetherall'", chunks[3].getRecipientName());
+ assertEquals("roy.wetherall@alfresco.com", chunks[3].getRecipientEmailAddress());
+ assertEquals("nickb@alfresco.com", chunks[4].getRecipientName());
+ assertEquals("nickb@alfresco.com", chunks[4].getRecipientEmailAddress());
+ assertEquals("'Paul Holmes-Higgin'", chunks[5].getRecipientName());
+ assertEquals("paul.hh@alfresco.com", chunks[5].getRecipientEmailAddress());
+
+ // Now sort, and re-check
+ Arrays.sort(chunks, new RecipientChunksSorter());
+
+ assertEquals("'Ashutosh Dandavate'", chunks[0].getRecipientName());
+ assertEquals("ashutosh.dandavate@alfresco.com", chunks[0].getRecipientEmailAddress());
+ assertEquals("'Paul Holmes-Higgin'", chunks[1].getRecipientName());
+ assertEquals("paul.hh@alfresco.com", chunks[1].getRecipientEmailAddress());
+ assertEquals("'Mike Farman'", chunks[2].getRecipientName());
+ assertEquals("mikef@alfresco.com", chunks[2].getRecipientEmailAddress());
+ assertEquals("nickb@alfresco.com", chunks[3].getRecipientName());
+ assertEquals("nickb@alfresco.com", chunks[3].getRecipientEmailAddress());
+ assertEquals("nick.burch@alfresco.com", chunks[4].getRecipientName());
+ assertEquals("nick.burch@alfresco.com", chunks[4].getRecipientEmailAddress());
+ assertEquals("'Roy Wetherall'", chunks[5].getRecipientName());
+ assertEquals("roy.wetherall@alfresco.com", chunks[5].getRecipientEmailAddress());
+
+ // Finally check on message
+ try (MAPIMessage msg = new MAPIMessage(multiple)) {
+ assertEquals(6, msg.getRecipientEmailAddressList().length);
+ assertEquals(6, msg.getRecipientNamesList().length);
+
+ assertEquals("'Ashutosh Dandavate'", msg.getRecipientNamesList()[0]);
+ assertEquals("'Paul Holmes-Higgin'", msg.getRecipientNamesList()[1]);
+ assertEquals("'Mike Farman'", msg.getRecipientNamesList()[2]);
+ assertEquals("nickb@alfresco.com", msg.getRecipientNamesList()[3]);
+ assertEquals("nick.burch@alfresco.com", msg.getRecipientNamesList()[4]);
+ assertEquals("'Roy Wetherall'", msg.getRecipientNamesList()[5]);
+
+ assertEquals("ashutosh.dandavate@alfresco.com", msg.getRecipientEmailAddressList()[0]);
+ assertEquals("paul.hh@alfresco.com", msg.getRecipientEmailAddressList()[1]);
+ assertEquals("mikef@alfresco.com", msg.getRecipientEmailAddressList()[2]);
+ assertEquals("nickb@alfresco.com", msg.getRecipientEmailAddressList()[3]);
+ assertEquals("nick.burch@alfresco.com", msg.getRecipientEmailAddressList()[4]);
+ assertEquals("roy.wetherall@alfresco.com", msg.getRecipientEmailAddressList()[5]);
+ }
+ }
+ }
+
+ @Test
+ void testFindsNameId() throws IOException {
+ try (POIFSFileSystem simple = new POIFSFileSystem(samples.getFile("quick.msg"), true)) {
+
+ simple.getRoot().getEntry("__nameid_version1.0");
+
+ ChunkGroup[] groups = POIFSChunkParser.parse(simple.getRoot());
+ assertEquals(3, groups.length);
+ assertTrue(groups[0] instanceof Chunks);
+ assertTrue(groups[1] instanceof RecipientChunks);
+ assertTrue(groups[2] instanceof NameIdChunks);
+
+ NameIdChunks nameId = (NameIdChunks) groups[2];
+ assertEquals(10, nameId.getAll().length);
+
+ // Now via MAPIMessage
+ try (MAPIMessage msg = new MAPIMessage(simple)) {
+ assertNotNull(msg.getNameIdChunks());
+ assertEquals(10, msg.getNameIdChunks().getAll().length);
+ }
+ }
+ }
+
+ @Test
+ void testFindsAttachments() throws IOException, ChunkNotFoundException {
+ try (POIFSFileSystem with = new POIFSFileSystem(samples.getFile("attachment_test_msg.msg"), true);
+ POIFSFileSystem without = new POIFSFileSystem(samples.getFile("quick.msg"), true)) {
+ AttachmentChunks attachment;
+
+ // Check raw details on the one with
+ with.getRoot().getEntry("__attach_version1.0_#00000000");
+ with.getRoot().getEntry("__attach_version1.0_#00000001");
+ POIFSChunkParser.parse(with.getRoot());
+
+ ChunkGroup[] groups = POIFSChunkParser.parse(with.getRoot());
+ assertEquals(5, groups.length);
+ assertTrue(groups[0] instanceof Chunks);
+ assertTrue(groups[1] instanceof RecipientChunks);
+ assertTrue(groups[2] instanceof AttachmentChunks);
+ assertTrue(groups[3] instanceof AttachmentChunks);
+ assertTrue(groups[4] instanceof NameIdChunks);
+
+ attachment = (AttachmentChunks) groups[2];
+ assertEquals("TEST-U~1.DOC", attachment.getAttachFileName().toString());
+ assertEquals("test-unicode.doc", attachment.getAttachLongFileName().toString());
+ assertEquals(24064, attachment.getAttachData().getValue().length);
+
+ attachment = (AttachmentChunks) groups[3];
+ assertEquals("pj1.txt", attachment.getAttachFileName().toString());
+ assertEquals("pj1.txt", attachment.getAttachLongFileName().toString());
+ assertEquals(89, attachment.getAttachData().getValue().length);
+
+ // Check raw details on one without
+ assertFalse(without.getRoot().hasEntry("__attach_version1.0_#00000000"));
+ assertFalse(without.getRoot().hasEntry("__attach_version1.0_#00000001"));
+
+ // One with, from the top
+ try (MAPIMessage msgWith = new MAPIMessage(with)) {
+ assertEquals(2, msgWith.getAttachmentFiles().length);
+
+ attachment = msgWith.getAttachmentFiles()[0];
+ assertEquals("TEST-U~1.DOC", attachment.getAttachFileName().toString());
+ assertEquals("test-unicode.doc", attachment.getAttachLongFileName().toString());
+ assertEquals(24064, attachment.getAttachData().getValue().length);
+
+ attachment = msgWith.getAttachmentFiles()[1];
+ assertEquals("pj1.txt", attachment.getAttachFileName().toString());
+ assertEquals("pj1.txt", attachment.getAttachLongFileName().toString());
+ assertEquals(89, attachment.getAttachData().getValue().length);
+
+ // Plus check core details are there
+ assertEquals("'nicolas1.23456@free.fr'", msgWith.getDisplayTo());
+ assertEquals("Nicolas1 23456", msgWith.getDisplayFrom());
+ assertEquals("test pi\u00e8ce jointe 1", msgWith.getSubject());
+
+ // One without, from the top
+ try (MAPIMessage msgWithout = new MAPIMessage(without)) {
+
+ // No attachments
+ assertEquals(0, msgWithout.getAttachmentFiles().length);
+
+ // But has core details
+ assertEquals("Kevin Roast", msgWithout.getDisplayTo());
+ assertEquals("Kevin Roast", msgWithout.getDisplayFrom());
+ assertEquals("Test the content transformer", msgWithout.getSubject());
+ }
+ }
+
+ }
+ }
+
+ /**
+ * Bugzilla #51873 - Outlook 2002 files created with dragging and
+ * dropping files to the disk include a non-standard named streams
+ * such as "Olk10SideProps_0001"
+ */
+ @Test
+ void testOlk10SideProps() throws IOException, ChunkNotFoundException {
+ try (POIFSFileSystem poifs = new POIFSFileSystem(samples.getFile("51873.msg"), true)) {
+ try (MAPIMessage msg = new MAPIMessage(poifs)) {
+ // Check core details came through
+ assertEquals("bubba@bubbasmith.com", msg.getDisplayTo());
+ assertEquals("Test with Olk10SideProps_ Chunk", msg.getSubject());
+ }
+ }
+ }
+
+ @Test
+ void testInvalidChunk() throws IOException {
+ try (POIFSFileSystem poifs =
+ new POIFSFileSystem(samples.getFile("clusterfuzz-testcase-minimized-POIHSMFFuzzer-4848576776503296.msg"), true)) {
+ assertThrows(IllegalArgumentException.class,
+ () -> new MAPIMessage(poifs));
+ }
+ }
}
diff --git a/test-data/hsmf/clusterfuzz-testcase-minimized-POIHSMFFuzzer-4848576776503296.msg b/test-data/hsmf/clusterfuzz-testcase-minimized-POIHSMFFuzzer-4848576776503296.msg
new file mode 100644
index 0000000000..fc86ac083a
--- /dev/null
+++ b/test-data/hsmf/clusterfuzz-testcase-minimized-POIHSMFFuzzer-4848576776503296.msg
Binary files differ
diff --git a/test-data/spreadsheet/stress.xls b/test-data/spreadsheet/stress.xls
index 1032a86a92..bd7aa3bcc7 100644
--- a/test-data/spreadsheet/stress.xls
+++ b/test-data/spreadsheet/stress.xls
Binary files differ