From: Javen O'Neal Date: Sun, 3 Jul 2016 23:13:37 +0000 (+0000) Subject: bug 59786: fix NPE from winmail.dat files if message body is null X-Git-Tag: REL_3_15_BETA3~219 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=ca39856e9106e4a03c1ffd2137d944851cd83c1c;p=poi.git bug 59786: fix NPE from winmail.dat files if message body is null git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1751180 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/scratchpad/src/org/apache/poi/hmef/extractor/HMEFContentsExtractor.java b/src/scratchpad/src/org/apache/poi/hmef/extractor/HMEFContentsExtractor.java index 38e473e81a..157856915b 100644 --- a/src/scratchpad/src/org/apache/poi/hmef/extractor/HMEFContentsExtractor.java +++ b/src/scratchpad/src/org/apache/poi/hmef/extractor/HMEFContentsExtractor.java @@ -1,18 +1,18 @@ /* ==================================================================== - Licensed to the Apache Software Foundation (ASF) under one or more - contributor license agreements. See the NOTICE file distributed with - this work for additional information regarding copyright ownership. - The ASF licenses this file to You under the Apache License, Version 2.0 - (the "License"); you may not use this file except in compliance with - the License. You may obtain a copy of the License at + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. ==================================================================== */ package org.apache.poi.hmef.extractor; @@ -34,8 +34,11 @@ import org.apache.poi.hsmf.datatypes.MAPIProperty; * from a HMEF/TNEF/winmail.dat file */ public final class HMEFContentsExtractor { - public static void main(String[] args) throws Exception { - if (args.length < 2) { + /** + * Usage: HMEFContentsExtractor <filename> <output dir> + */ + public static void main(String[] args) throws IOException { + if(args.length < 2) { System.err.println("Use:"); System.err.println(" HMEFContentsExtractor "); System.err.println(""); @@ -45,11 +48,14 @@ public final class HMEFContentsExtractor { System.exit(2); } - HMEFContentsExtractor ext = new HMEFContentsExtractor(new File(args[0])); + final String filename = args[0]; + final String outputDir = args[1]; - File dir = new File(args[1]); + HMEFContentsExtractor ext = new HMEFContentsExtractor(new File(filename)); + + File dir = new File(outputDir); File rtf = new File(dir, "message.rtf"); - if (! dir.exists()) { + if(! dir.exists()) { throw new FileNotFoundException("Output directory " + dir.getName() + " not found"); } @@ -59,7 +65,7 @@ public final class HMEFContentsExtractor { System.out.println("Extraction completed"); } - private HMEFMessage message; + private final HMEFMessage message; public HMEFContentsExtractor(File filename) throws IOException { this(new HMEFMessage(new FileInputStream(filename))); } @@ -73,14 +79,23 @@ public final class HMEFContentsExtractor { public void extractMessageBody(File dest) throws IOException { OutputStream fout = new FileOutputStream(dest); try { - MAPIRtfAttribute body = (MAPIRtfAttribute) - message.getMessageMAPIAttribute(MAPIProperty.RTF_COMPRESSED); - fout.write(body.getData()); + extractMessageBody(fout); } finally { fout.close(); } } + /** + * Extracts the RTF message body to the supplied stream + */ + public void extractMessageBody(OutputStream out) throws IOException { + MAPIRtfAttribute body = (MAPIRtfAttribute) + message.getMessageMAPIAttribute(MAPIProperty.RTF_COMPRESSED); + if (body != null) { + out.write(body.getData()); + } + } + /** * Extracts all the message attachments to the supplied directory */ diff --git a/src/scratchpad/testcases/org/apache/poi/hmef/extractor/TestHMEFContentsExtractor.java b/src/scratchpad/testcases/org/apache/poi/hmef/extractor/TestHMEFContentsExtractor.java new file mode 100644 index 0000000000..2cfd644905 --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hmef/extractor/TestHMEFContentsExtractor.java @@ -0,0 +1,78 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hmef.extractor; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertArrayEquals; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; + +import org.apache.poi.POIDataSamples; +import org.apache.poi.util.TempFile; +import org.junit.Test; + +public class TestHMEFContentsExtractor { + @Test + public void TestMain() throws IOException { + POIDataSamples samples = POIDataSamples.getHMEFInstance(); + File message = samples.getFile("quick-winmail.dat"); + File outputDirectory = TempFile.createTempDirectory("quick-winmail-main"); + String[] args = new String[] { message.getAbsolutePath(), outputDirectory.getAbsolutePath() }; + HMEFContentsExtractor.main(args); + + String[] contents = new String[] { + "message.rtf", // from extractMessageBody + "quick.txt", "quick.pdf", "quick.xml", "quick.doc", "quick.html" // from extractAttachments + }; + + for (String filename : contents) { + File f = new File(outputDirectory, filename); + assertTrue(f + " does not exist", f.exists()); + } + + outputDirectory.delete(); + } + + @Test + public void TestExtractMessageBody_OutputStream() throws IOException { + POIDataSamples samples = POIDataSamples.getHMEFInstance(); + File winmailTNEFFile = samples.getFile("quick-winmail.dat"); + HMEFContentsExtractor extractor = new HMEFContentsExtractor(winmailTNEFFile); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + extractor.extractMessageBody(out); + assertTrue(out.size() > 0); + byte[] expectedMagic = new byte[] { '{', '\\', 'r', 't', 'f' }; + byte[] magic = Arrays.copyOf(out.toByteArray(), 5); + assertArrayEquals("RTF magic number", expectedMagic, magic); + out.close(); + } + + @Test + public void TestExtractMessageBody_File() throws IOException { + POIDataSamples samples = POIDataSamples.getHMEFInstance(); + File winmailTNEFFile = samples.getFile("quick-winmail.dat"); + HMEFContentsExtractor extractor = new HMEFContentsExtractor(winmailTNEFFile); + File rtf = TempFile.createTempFile("quick-winmail-message-body", ".rtf"); + assertTrue(rtf.delete()); + extractor.extractMessageBody(rtf); + assertTrue("RTF message body is empty", rtf.length() > 0); + } +}