Browse Source

#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
tags/REL_4_1_2
Andreas Beeker 4 years ago
parent
commit
f7fe4b0d59

+ 19
- 27
src/scratchpad/testcases/org/apache/poi/hmef/TestAttachments.java 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);
}
}

/**

+ 24
- 12
src/scratchpad/testcases/org/apache/poi/hmef/TestBugs.java 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());
}
}

+ 36
- 39
src/scratchpad/testcases/org/apache/poi/hmef/TestCompressedRTF.java 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

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[] 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

(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);
}
}

+ 48
- 67
src/scratchpad/testcases/org/apache/poi/hmef/TestHMEFMessage.java 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);
}
}


+ 3
- 10
src/scratchpad/testcases/org/apache/poi/hmef/attribute/TestMAPIAttributes.java 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);
}

@After
public void tearDown() throws Exception {
stream.close();
try (InputStream stream = _samples.openResourceAsStream("quick-winmail.dat")) {
quick = new HMEFMessage(stream);
}
}


/**
* Test counts
*/

BIN
test-data/hmef/bug63955-winmail.dat View File


Loading…
Cancel
Save