diff --git a/src/examples/src/org/apache/poi/hsmf/examples/Msg2txt.java b/src/examples/src/org/apache/poi/hsmf/examples/Msg2txt.java index 546334bdaf..bf018a3e41 100644 --- a/src/examples/src/org/apache/poi/hsmf/examples/Msg2txt.java +++ b/src/examples/src/org/apache/poi/hsmf/examples/Msg2txt.java @@ -17,16 +17,14 @@ package org.apache.poi.hsmf.examples; -import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; -import java.util.Iterator; -import java.util.Map; import org.apache.poi.hsmf.MAPIMessage; +import org.apache.poi.hsmf.datatypes.AttachmentChunks; import org.apache.poi.hsmf.exceptions.ChunkNotFoundException; /** @@ -35,7 +33,6 @@ import org.apache.poi.hsmf.exceptions.ChunkNotFoundException; * attachments. * * @author Bruno Girin - * */ public class Msg2txt { @@ -105,17 +102,13 @@ public class Msg2txt { } catch (ChunkNotFoundException e) { System.err.println("No message body"); } - Map attachmentMap = msg.getAttachmentFiles(); - if(attachmentMap.size() > 0) { + + AttachmentChunks[] attachments = msg.getAttachmentFiles(); + if(attachments.length > 0) { File d = new File(attDirName); if(d.mkdir()) { - for( - Iterator ii = attachmentMap.entrySet().iterator(); - ii.hasNext(); - ) { - Map.Entry entry = (Map.Entry)ii.next(); - processAttachment(d, entry.getKey().toString(), - (ByteArrayInputStream)entry.getValue()); + for(AttachmentChunks attachment : attachments) { + processAttachment(attachment, d); } } else { System.err.println("Can't create directory "+attDirName); @@ -131,33 +124,26 @@ public class Msg2txt { /** * Processes a single attachment: reads it from the Outlook MSG file and * writes it to disk as an individual file. - * + * + * @param attachment the chunk group describing the attachment * @param dir the directory in which to write the attachment file - * @param fileName the name of the attachment file - * @param fileIn the input stream that contains the attachment's data * @throws IOException when any of the file operations fails */ - public void processAttachment(File dir, String fileName, - ByteArrayInputStream fileIn) throws IOException { + public void processAttachment(AttachmentChunks attachment, + File dir) throws IOException { + String fileName = attachment.attachFileName.toString(); + if(attachment.attachLongFileName != null) { + fileName = attachment.attachLongFileName.toString(); + } + File f = new File(dir, fileName); OutputStream fileOut = null; try { fileOut = new FileOutputStream(f); - byte[] buffer = new byte[2048]; - int bNum = fileIn.read(buffer); - while(bNum > 0) { - fileOut.write(buffer); - bNum = fileIn.read(buffer); - } + fileOut.write(attachment.attachData.getValue()); } finally { - try { - if(fileIn != null) { - fileIn.close(); - } - } finally { - if(fileOut != null) { - fileOut.close(); - } + if(fileOut != null) { + fileOut.close(); } } } diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunks.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunks.java index fa9f9b5985..9f68cc1670 100644 --- a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunks.java +++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunks.java @@ -63,7 +63,7 @@ public final class Chunks implements ChunkGroup { /** Type of server that the message originated from (SMTP, etc). */ public StringChunk sentByServerType; /** TODO */ - public StringChunk dateChunk; + public ByteChunk dateChunk; /** TODO */ public StringChunk emailFromChunk; @@ -86,7 +86,7 @@ public final class Chunks implements ChunkGroup { subjectChunk = (StringChunk)chunk; break; case DATE: - dateChunk = (StringChunk)chunk; + dateChunk = (ByteChunk)chunk; break; case CONVERSATION_TOPIC: conversationTopic = (StringChunk)chunk; diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/RecipientChunks.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/RecipientChunks.java index 27a9ecca89..b5157bb2c3 100644 --- a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/RecipientChunks.java +++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/RecipientChunks.java @@ -32,7 +32,7 @@ public final class RecipientChunks implements ChunkGroup { public static final int RECIPIENT_EMAIL = 0x39FE; /** TODO */ - public StringChunk recipientSearchChunk; + public ByteChunk recipientSearchChunk; /** TODO */ public StringChunk recipientEmailChunk; @@ -53,7 +53,7 @@ public final class RecipientChunks implements ChunkGroup { public void record(Chunk chunk) { switch(chunk.getChunkId()) { case RECIPIENT_SEARCH: - recipientSearchChunk = (StringChunk)chunk; + recipientSearchChunk = (ByteChunk)chunk; break; case RECIPIENT_EMAIL: recipientEmailChunk = (StringChunk)chunk; diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/StringChunk.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/StringChunk.java index 91558ba5c8..b1f859d04f 100644 --- a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/StringChunk.java +++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/StringChunk.java @@ -55,7 +55,7 @@ public class StringChunk extends Chunk { switch(type) { case Types.ASCII_STRING: try { - tmpValue = new String(data, "UTF-16LE"); + tmpValue = new String(data, "CP1252"); } catch (UnsupportedEncodingException e) { throw new RuntimeException("Core encoding not found, JVM broken?", e); } @@ -77,7 +77,7 @@ public class StringChunk extends Chunk { switch(type) { case Types.ASCII_STRING: try { - data = value.getBytes("UTF-16LE"); + data = value.getBytes("CP1252"); } catch (UnsupportedEncodingException e) { throw new RuntimeException("Core encoding not found, JVM broken?", e); } diff --git a/src/scratchpad/src/org/apache/poi/hsmf/parsers/POIFSChunkParser.java b/src/scratchpad/src/org/apache/poi/hsmf/parsers/POIFSChunkParser.java index adbe1a7ac9..eb79ae9ad7 100644 --- a/src/scratchpad/src/org/apache/poi/hsmf/parsers/POIFSChunkParser.java +++ b/src/scratchpad/src/org/apache/poi/hsmf/parsers/POIFSChunkParser.java @@ -55,7 +55,7 @@ public final class POIFSChunkParser { // there doesn't seem to be any use of that in Outlook for(Entry entry : node) { if(entry instanceof DirectoryNode) { - DirectoryNode dir = (DirectoryNode)node; + DirectoryNode dir = (DirectoryNode)entry; ChunkGroup group = null; // Do we know what to do with it? @@ -66,7 +66,7 @@ public final class POIFSChunkParser { group = new NameIdChunks(); } if(dir.getName().startsWith(RecipientChunks.PREFIX)) { - group = new NameIdChunks(); + group = new RecipientChunks(); } if(group != null) { diff --git a/src/scratchpad/testcases/org/apache/poi/hsmf/parsers/TestPOIFSChunkParser.java b/src/scratchpad/testcases/org/apache/poi/hsmf/parsers/TestPOIFSChunkParser.java index 06bc5f9e30..a86a4cec54 100644 --- a/src/scratchpad/testcases/org/apache/poi/hsmf/parsers/TestPOIFSChunkParser.java +++ b/src/scratchpad/testcases/org/apache/poi/hsmf/parsers/TestPOIFSChunkParser.java @@ -18,8 +18,16 @@ package org.apache.poi.hsmf.parsers; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; +import org.apache.poi.hsmf.MAPIMessage; +import org.apache.poi.hsmf.datatypes.AttachmentChunks; +import org.apache.poi.hsmf.datatypes.ChunkGroup; +import org.apache.poi.hsmf.datatypes.Chunks; +import org.apache.poi.hsmf.datatypes.NameIdChunks; +import org.apache.poi.hsmf.datatypes.RecipientChunks; +import org.apache.poi.hsmf.exceptions.ChunkNotFoundException; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.POIDataSamples; @@ -44,13 +52,83 @@ public final class TestPOIFSChunkParser extends TestCase { new FileInputStream(samples.getFile("attachment_test_msg.msg")) ); POIFSFileSystem without = new POIFSFileSystem( - new FileInputStream(samples.getFile("simple_test_msg.msg")) + new FileInputStream(samples.getFile("quick.msg")) ); + AttachmentChunks attachment; - // Check details on the one with - - // One with, from the top + + // 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.attachFileName.toString()); + assertEquals("test-unicode.doc", attachment.attachLongFileName.toString()); + assertEquals(24064, attachment.attachData.getValue().length); + + attachment = (AttachmentChunks)groups[3]; + assertEquals("pj1.txt", attachment.attachFileName.toString()); + assertEquals("pj1.txt", attachment.attachLongFileName.toString()); + assertEquals(89, attachment.attachData.getValue().length); + + // Check raw details on one without + try { + without.getRoot().getEntry("__attach_version1.0_#00000000"); + fail(); + } catch(FileNotFoundException e) {} + try { + without.getRoot().getEntry("__attach_version1.0_#00000001"); + fail(); + } catch(FileNotFoundException e) {} + + + // 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.attachFileName.toString()); + assertEquals("test-unicode.doc", attachment.attachLongFileName.toString()); + assertEquals(24064, attachment.attachData.getValue().length); + + attachment = msgWith.getAttachmentFiles()[1]; + assertEquals("pj1.txt", attachment.attachFileName.toString()); + assertEquals("pj1.txt", attachment.attachLongFileName.toString()); + assertEquals(89, attachment.attachData.getValue().length); + + // Plus check core details are there + try { + assertEquals("'nicolas1.23456@free.fr'", msgWith.getDisplayTo()); + assertEquals("Nicolas1 23456", msgWith.getDisplayFrom()); + assertEquals("test pi\u00e8ce jointe 1", msgWith.getSubject()); + } catch(ChunkNotFoundException e) { + fail(); + } + + // One without, from the top + MAPIMessage msgWithout = new MAPIMessage(without); + + // No attachments + assertEquals(0, msgWithout.getAttachmentFiles().length); + + // But has core details + try { + assertEquals("Kevin Roast", msgWithout.getDisplayTo()); + assertEquals("Kevin Roast", msgWithout.getDisplayFrom()); + assertEquals("Test the content transformer", msgWithout.getSubject()); + } catch(ChunkNotFoundException e) { + fail(); + } } } diff --git a/test-data/hsmf/quick.msg b/test-data/hsmf/quick.msg new file mode 100644 index 0000000000..05326d2c84 Binary files /dev/null and b/test-data/hsmf/quick.msg differ