#63955 - HMEFContentsExtractor fails to extract content from winmail.dat

added example file - optimized junit tests

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1872480 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2020-01-08 00:49:39 +00:00
parent 5a5c074471
commit f7fe4b0d59
6 changed files with 129 additions and 154 deletions

View File

@ -17,7 +17,9 @@
package org.apache.poi.hmef;
import static org.apache.poi.hmef.TestHMEFMessage.openSample;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.io.IOException;
import java.text.DateFormat;
@ -25,29 +27,23 @@ import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Locale;
import org.apache.poi.POIDataSamples;
import org.apache.poi.util.LocaleUtil;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
public final class TestAttachments {
protected static final POIDataSamples _samples = POIDataSamples.getHMEFInstance();
private static HMEFMessage quick;
private HMEFMessage quick;
@Before
public void setUp() throws Exception {
quick = new HMEFMessage(
_samples.openResourceAsStream("quick-winmail.dat")
);
@BeforeClass
public static void setUp() throws IOException {
quick = openSample("quick-winmail.dat");
}
/**
* Check the file is as we expect
*/
@Test
public void testCounts() throws Exception {
public void testCounts() {
// Should have 5 attachments
assertEquals(5, quick.getAttachments().size());
}
@ -56,7 +52,7 @@ public final class TestAttachments {
* Check some basic bits about the attachments
*/
@Test
public void testBasicAttachments() throws Exception {
public void testBasicAttachments() {
List<Attachment> attachments = quick.getAttachments();
// Word first
@ -90,26 +86,22 @@ public final class TestAttachments {
* the right values for key things
*/
@Test
public void testAttachmentDetails() throws Exception {
public void testAttachmentDetails() {
List<Attachment> attachments = quick.getAttachments();
assertEquals(5, attachments.size());
// Pick a predictable date format + timezone
DateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy hh:mm:ss", Locale.UK);
fmt.setTimeZone(LocaleUtil.TIMEZONE_UTC);
// They should all have the same date on them
assertEquals("28-Apr-2010 12:40:56", fmt.format(attachments.get(0).getModifiedDate()));
assertEquals("28-Apr-2010 12:40:56", fmt.format(attachments.get(1).getModifiedDate()));
assertEquals("28-Apr-2010 12:40:56", fmt.format(attachments.get(2).getModifiedDate()));
assertEquals("28-Apr-2010 12:40:56", fmt.format(attachments.get(3).getModifiedDate()));
assertEquals("28-Apr-2010 12:40:56", fmt.format(attachments.get(4).getModifiedDate()));
// They should all have a 3512 byte metafile rendered version
assertEquals(3512, attachments.get(0).getRenderedMetaFile().length);
assertEquals(3512, attachments.get(1).getRenderedMetaFile().length);
assertEquals(3512, attachments.get(2).getRenderedMetaFile().length);
assertEquals(3512, attachments.get(3).getRenderedMetaFile().length);
assertEquals(3512, attachments.get(4).getRenderedMetaFile().length);
for (Attachment attachment : attachments) {
// They should all have the same date on them
assertEquals("28-Apr-2010 12:40:56", fmt.format(attachment.getModifiedDate()));
// They should all have a 3512 byte metafile rendered version
byte[] meta = attachment.getRenderedMetaFile();
assertNotNull(meta);
assertEquals(3512, meta.length);
}
}
/**

View File

@ -16,40 +16,41 @@
==================================================================== */
package org.apache.poi.hmef;
import static org.apache.poi.hmef.TestHMEFMessage.openSample;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import org.apache.poi.POIDataSamples;
import java.io.IOException;
import java.util.List;
import org.apache.poi.hmef.attribute.MAPIAttribute;
import org.apache.poi.hmef.attribute.TNEFAttribute;
import org.apache.poi.hmef.attribute.TNEFProperty;
import org.apache.poi.hsmf.datatypes.MAPIProperty;
import org.apache.poi.util.LittleEndian;
import org.junit.Test;
public class TestBugs {
@Test
public void test52400ReadSimpleTNEF() throws Exception {
POIDataSamples samples = POIDataSamples.getHMEFInstance();
String testFile = "bug52400-winmail-simple.dat";
HMEFMessage tnefDat = new HMEFMessage(samples.openResourceAsStream(testFile));
public void test52400ReadSimpleTNEF() throws IOException {
HMEFMessage tnefDat = openSample("bug52400-winmail-simple.dat");
MAPIAttribute bodyHtml = tnefDat.getMessageMAPIAttribute(MAPIProperty.BODY_HTML);
assertNotNull(bodyHtml);
String bodyStr = new String(bodyHtml.getData(), getEncoding(tnefDat));
assertTrue(bodyStr.contains("This is the message body."));
}
@Test
public void test52400ReadAttachedTNEF() throws Exception {
POIDataSamples samples = POIDataSamples.getHMEFInstance();
String testFile = "bug52400-winmail-with-attachments.dat";
HMEFMessage tnefDat = new HMEFMessage(samples.openResourceAsStream(testFile));
public void test52400ReadAttachedTNEF() throws IOException {
HMEFMessage tnefDat = openSample("bug52400-winmail-with-attachments.dat");
MAPIAttribute bodyHtml = tnefDat.getMessageMAPIAttribute(MAPIProperty.BODY_HTML);
assertNotNull(bodyHtml);
String bodyStr = new String(bodyHtml.getData(), getEncoding(tnefDat));
assertTrue(bodyStr.contains("There are also two attachments."));
assertEquals(2, tnefDat.getAttachments().size());
}
private String getEncoding(HMEFMessage tnefDat) {
TNEFAttribute oemCP = tnefDat.getMessageAttribute(TNEFProperty.ID_OEMCODEPAGE);
MAPIAttribute cpId = tnefDat.getMessageMAPIAttribute(MAPIProperty.INTERNET_CPID);
@ -66,4 +67,15 @@ public class TestBugs {
default: return "cp"+codePage;
}
}
@Test
public void bug63955() throws IOException {
HMEFMessage tnefDat = openSample("bug63955-winmail.dat");
List<MAPIAttribute> atts = tnefDat.getMessageMAPIAttributes();
assertEquals(96, atts.size());
MAPIAttribute bodyHtml = tnefDat.getMessageMAPIAttribute(MAPIProperty.BODY_HTML);
assertNotNull(bodyHtml);
String bodyStr = new String(bodyHtml.getData(), getEncoding(tnefDat));
assertEquals(1697, bodyStr.length());
}
}

View File

@ -17,6 +17,7 @@
package org.apache.poi.hmef;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@ -24,6 +25,7 @@ import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import org.apache.poi.POIDataSamples;
import org.apache.poi.hmef.attribute.MAPIAttribute;
@ -69,32 +71,36 @@ public final class TestCompressedRTF {
// Now Look at the code
assertEquals((byte) 0x07, data[16 + 0]); // Flag: cccUUUUU
assertEquals((byte) 0x00, data[16 + 1]); // c1a: offset 0 / 0x000
assertEquals((byte) 0x06, data[16 + 2]); // c1b: length 6+2 -> {\rtf1\a
assertEquals((byte) 0x01, data[16 + 3]); // c2a: offset 16 / 0x010
assertEquals((byte) 0x01, data[16 + 4]); // c2b: length 1+2 -> def
assertEquals((byte) 0x0b, data[16 + 5]); // c3a: offset 182 / 0xb6
assertEquals((byte) 0x60, data[16 + 6]); // c3b: length 0+2 -> la
assertEquals((byte) 0x6e, data[16 + 7]); // n
assertEquals((byte) 0x67, data[16 + 8]); // g
assertEquals((byte) 0x31, data[16 + 9]); // 1
assertEquals((byte) 0x30, data[16 + 10]); // 0
assertEquals((byte) 0x32, data[16 + 11]); // 2
byte[] exp = {
(byte) 0x07, // Flag: cccUUUUU
(byte) 0x00, // c1a: offset 0 / 0x000
(byte) 0x06, // c1b: length 6+2 -> {\rtf1\a
(byte) 0x01, // c2a: offset 16 / 0x010
(byte) 0x01, // c2b: length 1+2 -> def
(byte) 0x0b, // c3a: offset 182 / 0xb6
(byte) 0x60, // c3b: length 0+2 -> la
(byte) 0x6e, // n
(byte) 0x67, // g
(byte) 0x31, // 1
(byte) 0x30, // 0
(byte) 0x32, // 2
assertEquals((byte) 0x66, data[16 + 12]); // Flag: UccUUccU
assertEquals((byte) 0x35, data[16 + 13]); // 5
assertEquals((byte) 0x00, data[16 + 14]); // c2a: offset 6 / 0x006
assertEquals((byte) 0x64, data[16 + 15]); // c2b: length 4+2 -> \ansi\a
assertEquals((byte) 0x00, data[16 + 16]); // c3a: offset 7 / 0x007
assertEquals((byte) 0x72, data[16 + 17]); // c3b: length 2+2 -> nsi
assertEquals((byte) 0x63, data[16 + 18]); // c
assertEquals((byte) 0x70, data[16 + 19]); // p
assertEquals((byte) 0x0d, data[16 + 20]); // c6a: offset 221 / 0x0dd
assertEquals((byte) 0xd0, data[16 + 21]); // c6b: length 0+2 -> g1
assertEquals((byte) 0x0e, data[16 + 22]); // c7a: offset 224 / 0x0e0
assertEquals((byte) 0x00, data[16 + 23]); // c7b: length 0+2 -> 25
assertEquals((byte) 0x32, data[16 + 24]); // 2
(byte) 0x66, // Flag: UccUUccU
(byte) 0x35, // 5
(byte) 0x00, // c2a: offset 6 / 0x006
(byte) 0x64, // c2b: length 4+2 -> \ansi\a
(byte) 0x00, // c3a: offset 7 / 0x007
(byte) 0x72, // c3b: length 2+2 -> nsi
(byte) 0x63, // c
(byte) 0x70, // p
(byte) 0x0d, // c6a: offset 221 / 0x0dd
(byte) 0xd0, // c6b: length 0+2 -> g1
(byte) 0x0e, // c7a: offset 224 / 0x0e0
(byte) 0x00, // c7b: length 0+2 -> 25
(byte) 0x32, // 2
};
assertArrayEquals(exp, Arrays.copyOfRange(data, 16, 16+25));
}
/**
@ -119,7 +125,7 @@ public final class TestCompressedRTF {
// Decompress it
CompressedRTF comp = new CompressedRTF();
byte[] decomp = comp.decompress(new ByteArrayInputStream(data));
String decompStr = new String(decomp, StandardCharsets.US_ASCII);
String decompStr = new String(decomp, StandardCharsets.US_ASCII);
// Test
assertEquals(block1.length(), decomp.length);
@ -142,16 +148,14 @@ public final class TestCompressedRTF {
MAPIRtfAttribute rtfAttr = (MAPIRtfAttribute) attr;
// Truncate to header + flag + data for flag + flag + data
byte[] data = new byte[16 + 12 + 13];
System.arraycopy(rtfAttr.getRawData(), 0, data, 0, data.length);
byte[] data = Arrays.copyOf(rtfAttr.getRawData(), 16 + 12 + 13);
// Decompress it
CompressedRTF comp = new CompressedRTF();
byte[] decomp = comp.decompress(new ByteArrayInputStream(data));
String decompStr = new String(decomp, StandardCharsets.US_ASCII);
String decompStr = new String(decomp, StandardCharsets.US_ASCII);
// Test
assertEquals(block2.length(), decomp.length);
assertEquals(block2, decompStr);
}
@ -185,20 +189,13 @@ public final class TestCompressedRTF {
// Will have been padded though
assertEquals(expected.length + 2, decomp.length);
byte[] tmp = new byte[expected.length];
System.arraycopy(decomp, 0, tmp, 0, tmp.length);
decomp = tmp;
// By byte
assertEquals(expected.length, decomp.length);
for (int i = 0; i < expected.length; i++) {
assertEquals(expected[i], decomp[i]);
}
assertArrayEquals(expected, Arrays.copyOf(decomp, expected.length));
// By String
String expString = new String(expected, StandardCharsets.US_ASCII);
String decompStr = rtfAttr.getDataString();
assertEquals(expString.length(), decompStr.length());
assertEquals(expString, decompStr);
}
}

View File

@ -17,11 +17,11 @@
package org.apache.poi.hmef;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@ -33,30 +33,25 @@ import org.apache.poi.POIDataSamples;
import org.apache.poi.hmef.attribute.MAPIAttribute;
import org.apache.poi.hmef.attribute.MAPIRtfAttribute;
import org.apache.poi.hmef.attribute.MAPIStringAttribute;
import org.apache.poi.hmef.attribute.TNEFAttribute;
import org.apache.poi.hmef.attribute.TNEFProperty;
import org.apache.poi.hsmf.datatypes.MAPIProperty;
import org.apache.poi.hsmf.datatypes.Types;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public final class TestHMEFMessage {
protected static final POIDataSamples _samples = POIDataSamples.getHMEFInstance();
private static final POIDataSamples _samples = POIDataSamples.getHMEFInstance();
@Test
public void testOpen() throws Exception {
HMEFMessage msg = new HMEFMessage(
_samples.openResourceAsStream("quick-winmail.dat")
);
assertNotNull(msg);
}
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void testCounts() throws Exception {
HMEFMessage msg = new HMEFMessage(
_samples.openResourceAsStream("quick-winmail.dat")
);
HMEFMessage msg = openSample("quick-winmail.dat");
// Should have 4 attributes on the message
assertEquals(4, msg.getMessageAttributes().size());
@ -82,9 +77,7 @@ public final class TestHMEFMessage {
@Test
public void testBasicMessageAttributes() throws Exception {
HMEFMessage msg = new HMEFMessage(
_samples.openResourceAsStream("quick-winmail.dat")
);
HMEFMessage msg = openSample("quick-winmail.dat");
// Should have version, codepage, class and MAPI
assertEquals(4, msg.getMessageAttributes().size());
@ -104,21 +97,18 @@ public final class TestHMEFMessage {
assertNull(msg.getMessageAttribute(TNEFProperty.ID_ATTACHDATA));
// Now check the details of one or two
assertEquals(
0x010000,
LittleEndian.getInt(msg.getMessageAttribute(TNEFProperty.ID_TNEFVERSION).getData())
);
assertEquals(
"IPM.Microsoft Mail.Note\0",
new String(msg.getMessageAttribute(TNEFProperty.ID_MESSAGECLASS).getData(), StandardCharsets.US_ASCII)
);
TNEFAttribute version = msg.getMessageAttribute(TNEFProperty.ID_TNEFVERSION);
assertNotNull(version);
assertEquals(0x010000, LittleEndian.getInt(version.getData()));
TNEFAttribute msgCls = msg.getMessageAttribute(TNEFProperty.ID_MESSAGECLASS);
assertNotNull(msgCls);
assertEquals("IPM.Microsoft Mail.Note\0", new String(msgCls.getData(), StandardCharsets.US_ASCII));
}
@Test
public void testBasicMessageMAPIAttributes() throws Exception {
HMEFMessage msg = new HMEFMessage(
_samples.openResourceAsStream("quick-winmail.dat")
);
HMEFMessage msg = openSample("quick-winmail.dat");
assertEquals("This is a test message", msg.getSubject());
assertEquals("{\\rtf1", msg.getBody().substring(0, 6));
@ -130,19 +120,18 @@ public final class TestHMEFMessage {
*/
@Test
public void testMessageContents() throws Exception {
HMEFMessage msg = new HMEFMessage(
_samples.openResourceAsStream("quick-winmail.dat")
);
HMEFMessage msg = openSample("quick-winmail.dat");
// Firstly by byte
MAPIRtfAttribute rtf = (MAPIRtfAttribute)
msg.getMessageMAPIAttribute(MAPIProperty.RTF_COMPRESSED);
assertNotNull(rtf);
assertContents("message.rtf", rtf.getData());
// Then by String
String contents = msg.getBody();
// It's all low bytes
byte[] contentsBytes = contents.getBytes(StandardCharsets.US_ASCII);
byte[] contentsBytes = contents.getBytes(StandardCharsets.US_ASCII);
assertContents("message.rtf", contentsBytes);
// try to get a message id that does not exist
@ -151,8 +140,7 @@ public final class TestHMEFMessage {
@Test
public void testMessageSample1() throws Exception {
HMEFMessage msg = new HMEFMessage(
_samples.openResourceAsStream("winmail-sample1.dat"));
HMEFMessage msg = openSample("winmail-sample1.dat");
// Firstly by byte
MAPIRtfAttribute rtf = (MAPIRtfAttribute) msg
@ -164,7 +152,7 @@ public final class TestHMEFMessage {
String contents = msg.getBody();
//System.out.println(contents);
// It's all low bytes
byte[] contentsBytes = contents.getBytes(StandardCharsets.US_ASCII);
byte[] contentsBytes = contents.getBytes(StandardCharsets.US_ASCII);
// assertContents("message.rtf", contentsBytes);
assertNotNull(contentsBytes);
@ -174,13 +162,11 @@ public final class TestHMEFMessage {
@Test
public void testInvalidMessage() throws Exception {
InputStream str = new ByteArrayInputStream(new byte[]{0, 0, 0, 0});
try {
assertNotNull(new HMEFMessage(str));
fail("Should catch an exception here");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("TNEF signature not detected in file, expected 574529400 but got 0"));
}
InputStream str = new ByteArrayInputStream(new byte[4]);
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("TNEF signature not detected in file, expected 574529400 but got 0");
new HMEFMessage(str);
}
@Test
@ -213,21 +199,16 @@ public final class TestHMEFMessage {
// invalid level
LittleEndian.putUShort(90, out);
byte[] bytes = out.toByteArray();
InputStream str = new ByteArrayInputStream(bytes);
try {
assertNotNull(new HMEFMessage(str));
fail("Should catch an exception here");
} catch (IllegalStateException e) {
assertTrue(e.getMessage().contains("Unhandled level 90"));
}
InputStream str = new ByteArrayInputStream(out.toByteArray());
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Unhandled level 90");
new HMEFMessage(str);
}
@Test
public void testCustomProperty() throws Exception {
HMEFMessage msg = new HMEFMessage(
_samples.openResourceAsStream("quick-winmail.dat")
);
public void testCustomProperty() throws IOException {
HMEFMessage msg = openSample("quick-winmail.dat");
// Should have non-standard properties with IDs 0xE28 and 0xE29
boolean hasE28 = false;
@ -236,8 +217,8 @@ public final class TestHMEFMessage {
if (attr.getProperty().id == 0xe28) hasE28 = true;
if (attr.getProperty().id == 0xe29) hasE29 = true;
}
assertTrue(hasE28);
assertTrue(hasE29);
assertTrue(hasE28);
assertTrue(hasE29);
// Ensure we can fetch those as custom ones
MAPIProperty propE28 = MAPIProperty.createCustom(0xe28, Types.ASCII_STRING, "Custom E28");
@ -245,22 +226,22 @@ public final class TestHMEFMessage {
assertNotNull(msg.getMessageMAPIAttribute(propE28));
assertNotNull(msg.getMessageMAPIAttribute(propE29));
assertEquals(MAPIStringAttribute.class, msg.getMessageMAPIAttribute(propE28).getClass());
assertEquals(
"Zimbra - Mark Rogers",
((MAPIStringAttribute) msg.getMessageMAPIAttribute(propE28)).getDataString().substring(10)
);
MAPIStringAttribute propE28b = (MAPIStringAttribute)msg.getMessageMAPIAttribute(propE28);
assertNotNull(propE28b);
assertEquals(MAPIStringAttribute.class, propE28b.getClass());
assertEquals("Zimbra - Mark Rogers", propE28b.getDataString().substring(10));
}
static void assertContents(String filename, byte[] actual)
throws IOException {
static HMEFMessage openSample(String filename) throws IOException {
try (InputStream is = _samples.openResourceAsStream(filename)) {
return new HMEFMessage(is);
}
}
static void assertContents(String filename, byte[] actual) throws IOException {
try (InputStream stream = _samples.openResourceAsStream("quick-contents/" + filename)) {
byte[] expected = IOUtils.toByteArray(stream);
assertEquals(expected.length, actual.length);
for (int i = 0; i < expected.length; i++) {
assertEquals("Byte " + i + " wrong", expected[i], actual[i]);
}
assertArrayEquals(expected, actual);
}
}

View File

@ -31,27 +31,20 @@ import org.apache.poi.hmef.HMEFMessage;
import org.apache.poi.hsmf.datatypes.MAPIProperty;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LocaleUtil;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public final class TestMAPIAttributes {
private static final POIDataSamples _samples = POIDataSamples.getHMEFInstance();
private HMEFMessage quick;
private InputStream stream;
@Before
public void setUp() throws Exception {
stream = _samples.openResourceAsStream("quick-winmail.dat");
quick = new HMEFMessage(stream);
try (InputStream stream = _samples.openResourceAsStream("quick-winmail.dat")) {
quick = new HMEFMessage(stream);
}
}
@After
public void tearDown() throws Exception {
stream.close();
}
/**
* Test counts
*/

Binary file not shown.