git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1538353 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_10_FINAL
@@ -39,7 +39,7 @@ import org.apache.poi.util.LittleEndian; | |||
* http://search.cpan.org/dist/Convert-TNEF/ | |||
*/ | |||
public final class HMEFMessage { | |||
public static final long HEADER_SIGNATURE = 0x223e9f78; | |||
public static final int HEADER_SIGNATURE = 0x223e9f78; | |||
private int fileId; | |||
private List<TNEFAttribute> messageAttributes = new ArrayList<TNEFAttribute>(); | |||
@@ -48,7 +48,7 @@ public final class HMEFMessage { | |||
public HMEFMessage(InputStream inp) throws IOException { | |||
// Check the signature matches | |||
long sig = LittleEndian.readInt(inp); | |||
int sig = LittleEndian.readInt(inp); | |||
if(sig != HEADER_SIGNATURE) { | |||
throw new IllegalArgumentException( | |||
"TNEF signature not detected in file, " + | |||
@@ -60,42 +60,59 @@ public final class HMEFMessage { | |||
fileId = LittleEndian.readUShort(inp); | |||
// Now begin processing the contents | |||
process(inp, 0); | |||
process(inp); | |||
} | |||
private void process(InputStream inp, int lastLevel) throws IOException { | |||
// Fetch the level | |||
int level = inp.read(); | |||
if(level == TNEFProperty.LEVEL_END_OF_FILE) { | |||
return; | |||
private void process(InputStream inp) throws IOException { | |||
int level; | |||
do { | |||
// Fetch the level | |||
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 | |||
TNEFAttribute attr = TNEFAttribute.create(inp); | |||
messageAttributes.add(attr); | |||
if (attr instanceof TNEFMAPIAttribute) { | |||
TNEFMAPIAttribute tnefMAPI = (TNEFMAPIAttribute) attr; | |||
mapiAttributes.addAll(tnefMAPI.getMAPIAttributes()); | |||
} | |||
} | |||
void processAttachment(InputStream inp) throws IOException { | |||
// Build the attribute | |||
TNEFAttribute attr = TNEFAttribute.create(inp); | |||
// Decide what to attach it to, based on the levels and IDs | |||
if(level == TNEFProperty.LEVEL_MESSAGE) { | |||
messageAttributes.add(attr); | |||
if(attr instanceof TNEFMAPIAttribute) { | |||
TNEFMAPIAttribute tnefMAPI = (TNEFMAPIAttribute)attr; | |||
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 | |||
Attachment attach = attachments.get(attachments.size()-1); | |||
attach.addAttribute(attr); | |||
} 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 | |||
process(inp, level); | |||
// Save the attribute for it | |||
Attachment attach = attachments.get(attachments.size() - 1); | |||
attach.addAttribute(attr); | |||
} | |||
/** |
@@ -23,8 +23,8 @@ import java.io.InputStream; | |||
import java.util.List; | |||
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.TNEFAttribute; | |||
import org.apache.poi.hmef.attribute.TNEFDateAttribute; | |||
import org.apache.poi.hmef.attribute.TNEFProperty; | |||
import org.apache.poi.hmef.attribute.TNEFStringAttribute; | |||
@@ -62,7 +62,7 @@ public final class HMEFDumper { | |||
this.inp = inp; | |||
// Check the signature matches | |||
long sig = LittleEndian.readInt(inp); | |||
int sig = LittleEndian.readInt(inp); | |||
if(sig != HMEFMessage.HEADER_SIGNATURE) { | |||
throw new IllegalArgumentException( | |||
"TNEF signature not detected in 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; | |||
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.TNEFProperty; | |||
import org.apache.poi.hsmf.datatypes.MAPIProperty; | |||
@@ -119,5 +123,80 @@ public final class TestHMEFMessage extends HMEFTest { | |||
// It's all low bytes | |||
byte[] contentsBytes = contents.getBytes("ASCII"); | |||
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")); | |||
} | |||
} | |||
} | |||