Bug 52400: fix handling some types of TNEF files, make HMEFMessage.HEADER_SIGNATURE int as it is handled as int everywhere, move .dat files to HMEF sample dir, cover some border cases in HMEFMessage, add another .dat sample file
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1538353 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
19630f1a29
commit
7014abae83
@ -39,7 +39,7 @@ import org.apache.poi.util.LittleEndian;
|
|||||||
* http://search.cpan.org/dist/Convert-TNEF/
|
* http://search.cpan.org/dist/Convert-TNEF/
|
||||||
*/
|
*/
|
||||||
public final class HMEFMessage {
|
public final class HMEFMessage {
|
||||||
public static final long HEADER_SIGNATURE = 0x223e9f78;
|
public static final int HEADER_SIGNATURE = 0x223e9f78;
|
||||||
|
|
||||||
private int fileId;
|
private int fileId;
|
||||||
private List<TNEFAttribute> messageAttributes = new ArrayList<TNEFAttribute>();
|
private List<TNEFAttribute> messageAttributes = new ArrayList<TNEFAttribute>();
|
||||||
@ -48,7 +48,7 @@ public final class HMEFMessage {
|
|||||||
|
|
||||||
public HMEFMessage(InputStream inp) throws IOException {
|
public HMEFMessage(InputStream inp) throws IOException {
|
||||||
// Check the signature matches
|
// Check the signature matches
|
||||||
long sig = LittleEndian.readInt(inp);
|
int sig = LittleEndian.readInt(inp);
|
||||||
if(sig != HEADER_SIGNATURE) {
|
if(sig != HEADER_SIGNATURE) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"TNEF signature not detected in file, " +
|
"TNEF signature not detected in file, " +
|
||||||
@ -60,42 +60,59 @@ public final class HMEFMessage {
|
|||||||
fileId = LittleEndian.readUShort(inp);
|
fileId = LittleEndian.readUShort(inp);
|
||||||
|
|
||||||
// Now begin processing the contents
|
// Now begin processing the contents
|
||||||
process(inp, 0);
|
process(inp);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void process(InputStream inp, int lastLevel) throws IOException {
|
private void process(InputStream inp) throws IOException {
|
||||||
// Fetch the level
|
int level;
|
||||||
int level = inp.read();
|
do {
|
||||||
if(level == TNEFProperty.LEVEL_END_OF_FILE) {
|
// Fetch the level
|
||||||
return;
|
level = inp.read();
|
||||||
}
|
|
||||||
|
|
||||||
|
// Decide what to attach it to, based on the levels and IDs
|
||||||
|
switch (level) {
|
||||||
|
case TNEFProperty.LEVEL_MESSAGE:
|
||||||
|
processMessage(inp);
|
||||||
|
break;
|
||||||
|
case TNEFProperty.LEVEL_ATTACHMENT:
|
||||||
|
processAttachment(inp);
|
||||||
|
break;
|
||||||
|
// ignore trailing newline
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
case TNEFProperty.LEVEL_END_OF_FILE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unhandled level " + level);
|
||||||
|
}
|
||||||
|
} while (level != TNEFProperty.LEVEL_END_OF_FILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void processMessage(InputStream inp) throws IOException {
|
||||||
// Build the attribute
|
// Build the attribute
|
||||||
TNEFAttribute attr = TNEFAttribute.create(inp);
|
TNEFAttribute attr = TNEFAttribute.create(inp);
|
||||||
|
|
||||||
// Decide what to attach it to, based on the levels and IDs
|
messageAttributes.add(attr);
|
||||||
if(level == TNEFProperty.LEVEL_MESSAGE) {
|
|
||||||
messageAttributes.add(attr);
|
|
||||||
|
|
||||||
if(attr instanceof TNEFMAPIAttribute) {
|
if (attr instanceof TNEFMAPIAttribute) {
|
||||||
TNEFMAPIAttribute tnefMAPI = (TNEFMAPIAttribute)attr;
|
TNEFMAPIAttribute tnefMAPI = (TNEFMAPIAttribute) attr;
|
||||||
mapiAttributes.addAll( tnefMAPI.getMAPIAttributes() );
|
mapiAttributes.addAll(tnefMAPI.getMAPIAttributes());
|
||||||
}
|
}
|
||||||
} else if(level == TNEFProperty.LEVEL_ATTACHMENT) {
|
}
|
||||||
// Previous attachment or a new one?
|
|
||||||
if(attachments.size() == 0 || attr.getProperty() == TNEFProperty.ID_ATTACHRENDERDATA) {
|
|
||||||
attachments.add(new Attachment());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the attribute for it
|
void processAttachment(InputStream inp) throws IOException {
|
||||||
Attachment attach = attachments.get(attachments.size()-1);
|
// Build the attribute
|
||||||
attach.addAttribute(attr);
|
TNEFAttribute attr = TNEFAttribute.create(inp);
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("Unhandled level " + level);
|
// Previous attachment or a new one?
|
||||||
|
if (attachments.isEmpty()
|
||||||
|
|| attr.getProperty() == TNEFProperty.ID_ATTACHRENDERDATA) {
|
||||||
|
attachments.add(new Attachment());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle the next one down
|
// Save the attribute for it
|
||||||
process(inp, level);
|
Attachment attach = attachments.get(attachments.size() - 1);
|
||||||
|
attach.addAttribute(attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,8 +23,8 @@ import java.io.InputStream;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.poi.hmef.HMEFMessage;
|
import org.apache.poi.hmef.HMEFMessage;
|
||||||
import org.apache.poi.hmef.attribute.TNEFAttribute;
|
|
||||||
import org.apache.poi.hmef.attribute.MAPIAttribute;
|
import org.apache.poi.hmef.attribute.MAPIAttribute;
|
||||||
|
import org.apache.poi.hmef.attribute.TNEFAttribute;
|
||||||
import org.apache.poi.hmef.attribute.TNEFDateAttribute;
|
import org.apache.poi.hmef.attribute.TNEFDateAttribute;
|
||||||
import org.apache.poi.hmef.attribute.TNEFProperty;
|
import org.apache.poi.hmef.attribute.TNEFProperty;
|
||||||
import org.apache.poi.hmef.attribute.TNEFStringAttribute;
|
import org.apache.poi.hmef.attribute.TNEFStringAttribute;
|
||||||
@ -62,7 +62,7 @@ public final class HMEFDumper {
|
|||||||
this.inp = inp;
|
this.inp = inp;
|
||||||
|
|
||||||
// Check the signature matches
|
// Check the signature matches
|
||||||
long sig = LittleEndian.readInt(inp);
|
int sig = LittleEndian.readInt(inp);
|
||||||
if(sig != HMEFMessage.HEADER_SIGNATURE) {
|
if(sig != HMEFMessage.HEADER_SIGNATURE) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"TNEF signature not detected in file, " +
|
"TNEF signature not detected in file, " +
|
||||||
|
48
src/scratchpad/testcases/org/apache/poi/hmef/TestBugs.java
Normal file
48
src/scratchpad/testcases/org/apache/poi/hmef/TestBugs.java
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package org.apache.poi.hmef;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.apache.poi.POIDataSamples;
|
||||||
|
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;
|
||||||
|
|
||||||
|
public class TestBugs extends TestCase {
|
||||||
|
public void test52400ReadSimpleTNEF() throws Exception {
|
||||||
|
POIDataSamples samples = POIDataSamples.getHMEFInstance();
|
||||||
|
String testFile = "bug52400-winmail-simple.dat";
|
||||||
|
HMEFMessage tnefDat = new HMEFMessage(samples.openResourceAsStream(testFile));
|
||||||
|
MAPIAttribute bodyHtml = tnefDat.getMessageMAPIAttribute(MAPIProperty.BODY_HTML);
|
||||||
|
String bodyStr = new String(bodyHtml.getData(), getEncoding(tnefDat));
|
||||||
|
assertTrue(bodyStr.contains("This is the message body."));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void test52400ReadAttachedTNEF() throws Exception {
|
||||||
|
POIDataSamples samples = POIDataSamples.getHMEFInstance();
|
||||||
|
String testFile = "bug52400-winmail-with-attachments.dat";
|
||||||
|
HMEFMessage tnefDat = new HMEFMessage(samples.openResourceAsStream(testFile));
|
||||||
|
MAPIAttribute bodyHtml = tnefDat.getMessageMAPIAttribute(MAPIProperty.BODY_HTML);
|
||||||
|
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);
|
||||||
|
int codePage = 1252;
|
||||||
|
if (oemCP != null) {
|
||||||
|
codePage = LittleEndian.getInt(oemCP.getData());
|
||||||
|
} else if (cpId != null) {
|
||||||
|
codePage = LittleEndian.getInt(cpId.getData());
|
||||||
|
}
|
||||||
|
switch (codePage) {
|
||||||
|
// see http://en.wikipedia.org/wiki/Code_page for more
|
||||||
|
case 1252: return "Windows-1252";
|
||||||
|
case 20127: return "US-ASCII";
|
||||||
|
default: return "cp"+codePage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -17,6 +17,10 @@
|
|||||||
|
|
||||||
package org.apache.poi.hmef;
|
package org.apache.poi.hmef;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
import org.apache.poi.hmef.attribute.MAPIRtfAttribute;
|
import org.apache.poi.hmef.attribute.MAPIRtfAttribute;
|
||||||
import org.apache.poi.hmef.attribute.TNEFProperty;
|
import org.apache.poi.hmef.attribute.TNEFProperty;
|
||||||
import org.apache.poi.hsmf.datatypes.MAPIProperty;
|
import org.apache.poi.hsmf.datatypes.MAPIProperty;
|
||||||
@ -119,5 +123,80 @@ public final class TestHMEFMessage extends HMEFTest {
|
|||||||
// It's all low bytes
|
// It's all low bytes
|
||||||
byte[] contentsBytes = contents.getBytes("ASCII");
|
byte[] contentsBytes = contents.getBytes("ASCII");
|
||||||
assertContents("message.rtf", contentsBytes);
|
assertContents("message.rtf", contentsBytes);
|
||||||
|
|
||||||
|
// try to get a message id that does not exist
|
||||||
|
assertNull(msg.getMessageMAPIAttribute(MAPIProperty.AB_DEFAULT_DIR));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMessageSample1() throws Exception {
|
||||||
|
HMEFMessage msg = new HMEFMessage(
|
||||||
|
_samples.openResourceAsStream("winmail-sample1.dat"));
|
||||||
|
|
||||||
|
// Firstly by byte
|
||||||
|
MAPIRtfAttribute rtf = (MAPIRtfAttribute) msg
|
||||||
|
.getMessageMAPIAttribute(MAPIProperty.RTF_COMPRESSED);
|
||||||
|
// assertContents("message.rtf", rtf.getData());
|
||||||
|
assertNotNull(rtf);
|
||||||
|
|
||||||
|
// Then by String
|
||||||
|
String contents = msg.getBody();
|
||||||
|
//System.out.println(contents);
|
||||||
|
// It's all low bytes
|
||||||
|
byte[] contentsBytes = contents.getBytes("ASCII");
|
||||||
|
// assertContents("message.rtf", contentsBytes);
|
||||||
|
assertNotNull(contentsBytes);
|
||||||
|
|
||||||
|
assertNotNull(msg.getSubject());
|
||||||
|
assertNotNull(msg.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testNoData() throws Exception {
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
// Header
|
||||||
|
LittleEndian.putInt(HMEFMessage.HEADER_SIGNATURE, out);
|
||||||
|
|
||||||
|
// field
|
||||||
|
LittleEndian.putUShort(0, out);
|
||||||
|
|
||||||
|
byte[] bytes = out.toByteArray();
|
||||||
|
InputStream str = new ByteArrayInputStream(bytes);
|
||||||
|
HMEFMessage msg = new HMEFMessage(str);
|
||||||
|
assertNull(msg.getSubject());
|
||||||
|
assertNull(msg.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testInvalidLevel() throws Exception {
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
// Header
|
||||||
|
LittleEndian.putInt(HMEFMessage.HEADER_SIGNATURE, out);
|
||||||
|
|
||||||
|
// field
|
||||||
|
LittleEndian.putUShort(0, out);
|
||||||
|
|
||||||
|
// 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"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BIN
test-data/hmef/bug52400-winmail-simple.dat
Normal file
BIN
test-data/hmef/bug52400-winmail-simple.dat
Normal file
Binary file not shown.
BIN
test-data/hmef/bug52400-winmail-with-attachments.dat
Normal file
BIN
test-data/hmef/bug52400-winmail-with-attachments.dat
Normal file
Binary file not shown.
BIN
test-data/hmef/winmail-sample1.dat
Normal file
BIN
test-data/hmef/winmail-sample1.dat
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user