diff --git a/build.xml b/build.xml
index 5012001fb3..ce1cf7ff47 100644
--- a/build.xml
+++ b/build.xml
@@ -503,6 +503,7 @@ under the License.
+
@@ -536,6 +537,7 @@ under the License.
+
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java b/src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java
new file mode 100644
index 0000000000..ed215f6382
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java
@@ -0,0 +1,146 @@
+/* ====================================================================
+ 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.hsmf;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.hsmf.datatypes.Chunk;
+import org.apache.poi.hsmf.datatypes.Chunks;
+import org.apache.poi.hsmf.datatypes.StringChunk;
+import org.apache.poi.hsmf.exceptions.ChunkNotFoundException;
+import org.apache.poi.hsmf.parsers.POIFSChunkParser;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+
+/**
+ * Reads an Outlook MSG File in and provides hooks into its data structure.
+ *
+ * @author Travis Ferguson
+ */
+public class MAPIMessage {
+ private POIFSChunkParser chunkParser;
+ private POIFSFileSystem fs;
+
+ /**
+ * Constructor for creating new files.
+ *
+ */
+ public MAPIMessage() {
+ //TODO make writing possible
+ }
+
+
+ /**
+ * Constructor for reading MSG Files.
+ * @param filename
+ * @throws IOException
+ */
+ public MAPIMessage(String filename) throws IOException {
+ InputStream in = new FileInputStream(new File(filename));
+ this.fs = new POIFSFileSystem(in);
+ chunkParser = new POIFSChunkParser(this.fs);
+ }
+
+ /**
+ * Gets a string value based on the passed chunk.
+ * @param chunk
+ * @return
+ * @throws ChunkNotFoundException
+ */
+ public String getStringFromChunk(StringChunk chunk) throws ChunkNotFoundException {
+ Chunk out = this.chunkParser.getDocumentNode(chunk);
+ StringChunk strchunk = (StringChunk)out;
+ return strchunk.toString();
+ }
+
+
+ /**
+ * Gets the plain text body of this Outlook Message
+ * @return The string representation of the 'text' version of the body, if available.
+ * @throws IOException
+ * @throws ChunkNotFoundException
+ */
+ public String getTextBody() throws IOException, ChunkNotFoundException {
+ return getStringFromChunk(Chunks.getInstance().textBodyChunk);
+ }
+
+ /**
+ * Gets the subject line of the Outlook Message
+ * @return
+ * @throws ChunkNotFoundException
+ */
+ public String getSubject() throws ChunkNotFoundException {
+ return getStringFromChunk(Chunks.getInstance().subjectChunk);
+ }
+
+
+ /**
+ * Gets the display value of the "TO" line of the outlook message
+ * This is not the actual list of addresses/values that will be sent to if you click Reply in the email.
+ * @return
+ * @throws ChunkNotFoundException
+ */
+ public String getDisplayTo() throws ChunkNotFoundException {
+ return getStringFromChunk(Chunks.getInstance().displayToChunk);
+ }
+
+ /**
+ * Gets the display value of the "TO" line of the outlook message
+ * This is not the actual list of addresses/values that will be sent to if you click Reply in the email.
+ * @return
+ * @throws ChunkNotFoundException
+ */
+ public String getDisplayCC() throws ChunkNotFoundException {
+ return getStringFromChunk(Chunks.getInstance().displayCCChunk);
+ }
+
+ /**
+ * Gets the display value of the "TO" line of the outlook message
+ * This is not the actual list of addresses/values that will be sent to if you click Reply in the email.
+ * @return
+ * @throws ChunkNotFoundException
+ */
+ public String getDisplayBCC() throws ChunkNotFoundException {
+ return getStringFromChunk(Chunks.getInstance().displayBCCChunk);
+ }
+
+
+ /**
+ * Gets the conversation topic of the parsed Outlook Message.
+ * This is the part of the subject line that is after the RE: and FWD:
+ * @return
+ * @throws ChunkNotFoundException
+ */
+ public String getConversationTopic() throws ChunkNotFoundException {
+ return getStringFromChunk(Chunks.getInstance().conversationTopic);
+ }
+
+ /**
+ * Gets the message class of the parsed Outlook Message.
+ * (Yes, you can use this to determine if a message is a calendar item, note, or actual outlook Message)
+ * For emails the class will be IPM.Note
+ *
+ * @return
+ * @throws ChunkNotFoundException
+ */
+ public String getMessageClass() throws ChunkNotFoundException {
+ return getStringFromChunk(Chunks.getInstance().messageClass);
+ }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunk.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunk.java
new file mode 100644
index 0000000000..785a336fac
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunk.java
@@ -0,0 +1,68 @@
+/* ====================================================================
+ 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.hsmf.datatypes;
+
+import java.io.ByteArrayOutputStream;
+
+abstract public class Chunk {
+ protected int chunkId;
+ protected int type;
+ protected String namePrefix = "__substg1.0_";
+
+ /**
+ * Gets the id of this chunk
+ * @return
+ */
+ public int getChunkId() {
+ return this.chunkId;
+ }
+
+ /**
+ * Gets the numeric type of this chunk.
+ * @return
+ */
+ public int getType() {
+ return this.type;
+ }
+
+ /**
+ * Creates a string to use to identify this chunk in the POI file system object.
+ * @return
+ */
+ public String getEntryName() {
+ String type = Integer.toHexString(this.type);
+ while(type.length() < 4) type = "0" + type;
+
+ String chunkId = Integer.toHexString(this.chunkId);
+ while(chunkId.length() < 4) chunkId = "0" + chunkId;
+
+ return this.namePrefix + chunkId.toUpperCase() + type.toUpperCase();
+ }
+
+ /**
+ * Gets a reference to a ByteArrayOutputStream that contains the value of this chunk.
+ * @return
+ */
+ public abstract ByteArrayOutputStream getValueByteArray();
+
+ /**
+ * Sets the value of this chunk using a OutputStream
+ * @param value
+ */
+ public abstract void setValue(ByteArrayOutputStream value);
+}
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunks.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunks.java
new file mode 100644
index 0000000000..309efeac9d
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunks.java
@@ -0,0 +1,40 @@
+/* ====================================================================
+ 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.hsmf.datatypes;
+
+
+/**
+ * Collection of convenence chunks for standard parts of the MSG file.
+ *
+ * @author Travis Ferguson
+ */
+public class Chunks {
+ /* String parts of Outlook Messages that are currently known */
+ public StringChunk messageClass = new StringChunk(0x001A); //Type of message that the MSG represents (ie. IPM.Note)
+ public StringChunk textBodyChunk = new StringChunk(0x1000); //BODY Chunk, for plain/text messages
+ public StringChunk subjectChunk = new StringChunk(0x0037); //Subject link chunk, in plain/text
+ public StringChunk displayToChunk = new StringChunk(0x0E04); //Value that is in the TO field (not actually the addresses as they are stored in recip directory nodes
+ public StringChunk displayCCChunk = new StringChunk(0x0E03); //value that shows in the CC field
+ public StringChunk displayBCCChunk = new StringChunk(0x0E02); //Value that shows in the BCC field
+ public StringChunk conversationTopic = new StringChunk(0x0070); //Sort of like the subject line, but without the RE: and FWD: parts.
+ public StringChunk sentByServerType = new StringChunk(0x0075); //Type of server that the message originated from (SMTP, etc).
+
+ public static Chunks getInstance() {
+ return new Chunks();
+ }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/StringChunk.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/StringChunk.java
new file mode 100644
index 0000000000..2058b8ac58
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/StringChunk.java
@@ -0,0 +1,53 @@
+/* ====================================================================
+ 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.hsmf.datatypes;
+
+import java.io.ByteArrayOutputStream;
+
+/**
+ * A Chunk made up of a single string.
+ * @author Travis Ferguson
+ */
+public class StringChunk extends Chunk {
+
+ private String value;
+
+ public StringChunk(int chunkId) {
+ this.chunkId = chunkId;
+ this.type = Types.STRING;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.poi.hsmf.Chunk.Chunk#getValueByteArray()
+ */
+ public ByteArrayOutputStream getValueByteArray() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.poi.hsmf.Chunk.Chunk#setValue(java.io.ByteArrayOutputStream)
+ */
+ public void setValue(ByteArrayOutputStream value) {
+ this.value = value.toString().replaceAll("\0", "");
+ }
+
+ public String toString() {
+ return this.value;
+ }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Types.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Types.java
new file mode 100644
index 0000000000..9297666af7
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Types.java
@@ -0,0 +1,26 @@
+/* ====================================================================
+ 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.hsmf.datatypes;
+
+public class Types {
+ public static int BINARY = 0x0102;
+ public static int STRING = 0x001E;
+ public static int LONG = 0x0003;
+ public static int TIME = 0x0040;
+ public static int BOOLEAN = 0x000B;
+}
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/exceptions/ChunkNotFoundException.java b/src/scratchpad/src/org/apache/poi/hsmf/exceptions/ChunkNotFoundException.java
new file mode 100644
index 0000000000..5c04518cb4
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hsmf/exceptions/ChunkNotFoundException.java
@@ -0,0 +1,26 @@
+/* ====================================================================
+ 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.hsmf.exceptions;
+
+public class ChunkNotFoundException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public ChunkNotFoundException(String chunkName) {
+ super(chunkName + " was named, but not found in POIFS object");
+ }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/exceptions/DirectoryChunkNotFoundException.java b/src/scratchpad/src/org/apache/poi/hsmf/exceptions/DirectoryChunkNotFoundException.java
new file mode 100644
index 0000000000..308d0c6704
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hsmf/exceptions/DirectoryChunkNotFoundException.java
@@ -0,0 +1,30 @@
+/* ====================================================================
+ 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.hsmf.exceptions;
+
+/**
+ * Exception for when a directory chunk is not found but is expected.
+ * @author Travis Ferguson
+ */
+public class DirectoryChunkNotFoundException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public DirectoryChunkNotFoundException(String directory) {
+ super("Directory Chunk " + directory + " was not found!");
+ }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/parsers/POIFSChunkParser.java b/src/scratchpad/src/org/apache/poi/hsmf/parsers/POIFSChunkParser.java
new file mode 100644
index 0000000000..bdfb29e2a2
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hsmf/parsers/POIFSChunkParser.java
@@ -0,0 +1,232 @@
+/* ====================================================================
+ 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.hsmf.parsers;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.apache.poi.hsmf.datatypes.Chunk;
+import org.apache.poi.hsmf.exceptions.ChunkNotFoundException;
+import org.apache.poi.hsmf.exceptions.DirectoryChunkNotFoundException;
+import org.apache.poi.poifs.filesystem.DirectoryEntry;
+import org.apache.poi.poifs.filesystem.DirectoryNode;
+import org.apache.poi.poifs.filesystem.DocumentNode;
+import org.apache.poi.poifs.filesystem.POIFSDocument;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.poifs.property.DirectoryProperty;
+import org.apache.poi.poifs.property.DocumentProperty;
+import org.apache.poi.poifs.storage.BlockWritable;
+
+/**
+ * Provides a HashMap with the ability to parse a PIOFS object and provide
+ * an 'easy to access' hashmap structure for the document chunks inside it.
+ *
+ * @author Travis Ferguson
+ */
+public class POIFSChunkParser {
+ /**
+ * Constructor
+ * @param fs
+ * @throws IOException
+ */
+ public POIFSChunkParser(POIFSFileSystem fs) throws IOException {
+ this.setFileSystem(fs);
+ }
+
+
+ /**
+ * Set the POIFileSystem object that this object is using.
+ * @param fs
+ * @throws IOException
+ */
+ public void setFileSystem(POIFSFileSystem fs) throws IOException {
+ this.fs = fs;
+ this.reparseFileSystem();
+ }
+
+ /**
+ * Get a reference to the FileSystem object that this object is currently using.
+ * @return
+ */
+ public POIFSFileSystem getFileSystem() {
+ return this.fs;
+ }
+
+ /**
+ * Reparse the FileSystem object, resetting all the chunks stored in this object
+ * @throws IOException
+ *
+ */
+ public void reparseFileSystem() throws IOException {
+ // first clear this object of all chunks
+ DirectoryEntry root = this.fs.getRoot();
+ Iterator iter = root.getEntries();
+
+ this.directoryMap = this.processPOIIterator(iter);
+ }
+
+ /**
+ * Pull the chunk data that's stored in this object's hashmap out and return it as a HashMap.
+ * @param entryName
+ * @return
+ */
+ public Object getChunk(HashMap dirMap, String entryName) {
+ if(dirMap == null) return null;
+ else {
+ return dirMap.get(entryName);
+ }
+ }
+
+ /**
+ * Pull a directory/hashmap out of this hashmap and return it
+ * @param directoryName
+ * @return HashMap containing the chunks stored in the named directoryChunk
+ * @throws DirectoryChunkNotFoundException This is thrown should the directoryMap HashMap on this object be null
+ * or for some reason the directory is not found, is equal to null, or is for some reason not a HashMap/aka Directory Node.
+ */
+ public HashMap getDirectoryChunk(String directoryName) throws DirectoryChunkNotFoundException {
+ DirectoryChunkNotFoundException excep = new DirectoryChunkNotFoundException(directoryName);
+ Object obj = getChunk(this.directoryMap, directoryName);
+ if(obj == null || !(obj instanceof HashMap)) throw excep;
+
+ return (HashMap)obj;
+ }
+
+ /**
+ * Pulls a ByteArrayOutputStream from this objects HashMap, this can be used to read a byte array of the contents of the given chunk.
+ * @param directoryMap, chunk
+ * @return
+ * @throws ChunkNotFoundException
+ */
+ public Chunk getDocumentNode(HashMap dirNode, Chunk chunk) throws ChunkNotFoundException {
+ String entryName = chunk.getEntryName();
+ ChunkNotFoundException excep = new ChunkNotFoundException(entryName);
+ Object obj = getChunk(dirNode, entryName);
+ if(obj == null || !(obj instanceof ByteArrayOutputStream)) throw excep;
+
+ chunk.setValue((ByteArrayOutputStream)obj);
+
+ return chunk;
+ }
+
+ /**
+ * Pulls a Chunk out of this objects root Node tree.
+ * @param chunk
+ * @return
+ * @throws ChunkNotFoundException
+ */
+ public Chunk getDocumentNode(Chunk chunk) throws ChunkNotFoundException {
+ return getDocumentNode(this.directoryMap, chunk);
+ }
+
+
+ /**
+ * Processes an iterator returned by a POIFS call to getRoot().getEntries()
+ * @param iter
+ * @return
+ * @throws IOException
+ */
+ private HashMap processPOIIterator(Iterator iter) throws IOException {
+ HashMap currentNode = new HashMap();
+
+ while(iter.hasNext()) {
+ Object obj = iter.next();
+ if(obj instanceof DocumentNode) {
+ this.processDocumentNode((DocumentNode)obj, currentNode);
+ } else if(obj instanceof DirectoryNode) {
+ String blockName = ((DirectoryNode)obj).getName();
+ Iterator viewIt = null;
+ if( ((DirectoryNode)obj).preferArray()) {
+ Object[] arr = ((DirectoryNode)obj).getViewableArray();
+ ArrayList viewList = new ArrayList(arr.length);
+
+ for(int i = 0; i < arr.length; i++) {
+ viewList.add(arr[i]);
+ }
+ viewIt = viewList.iterator();
+ } else {
+ viewIt = ((DirectoryNode)obj).getViewableIterator();
+ }
+ //store the next node on the hashmap
+ currentNode.put(blockName, processPOIIterator(viewIt));
+ } else if(obj instanceof DirectoryProperty) {
+ //don't do anything with the directory property chunk...
+ } else {
+ System.err.println("Unknown node: " + obj.toString());
+ }
+ }
+ return currentNode;
+ }
+
+ /**
+ * Processes a document node and adds it to the current directory HashMap
+ * @param obj
+ * @throws java.io.IOException
+ */
+ private void processDocumentNode(DocumentNode obj, HashMap currentObj) throws IOException {
+ String blockName = ((DocumentNode)obj).getName();
+
+ Iterator viewIt = null;
+ if( ((DocumentNode)obj).preferArray()) {
+ Object[] arr = ((DocumentNode)obj).getViewableArray();
+ ArrayList viewList = new ArrayList(arr.length);
+
+ for(int i = 0; i < arr.length; i++) {
+ viewList.add(arr[i]);
+ }
+ viewIt = viewList.iterator();
+ } else {
+ viewIt = ((DocumentNode)obj).getViewableIterator();
+ }
+
+ while(viewIt.hasNext()) {
+ Object view = viewIt.next();
+
+ if(view instanceof DocumentProperty) {
+ //we don't care about the properties
+ } else if(view instanceof POIFSDocument) {
+ //check if our node has blocks or if it can just be read raw.
+ int blockCount = ((POIFSDocument)view).countBlocks();
+ //System.out.println("Block Name: " + blockName);
+ if(blockCount <= 0) {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ BlockWritable[] bws = ((POIFSDocument)view).getSmallBlocks();
+ for(int i = 0; i < bws.length; i++) {
+ bws[i].writeBlocks(out);
+ }
+ currentObj.put(blockName, out);
+ } else {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ((POIFSDocument)view).writeBlocks(out);
+ currentObj.put(blockName, out);
+ }
+ } else {
+ System.err.println("Unknown View Type: " + view.toString());
+ }
+ }
+ }
+
+ /* private instance variables */
+ private static final long serialVersionUID = 1L;
+ private POIFSFileSystem fs;
+ private HashMap directoryMap;
+}
diff --git a/src/scratchpad/testcases/org/apache/poi/hsmf/AllTests.java b/src/scratchpad/testcases/org/apache/poi/hsmf/AllTests.java
new file mode 100644
index 0000000000..18a622c32b
--- /dev/null
+++ b/src/scratchpad/testcases/org/apache/poi/hsmf/AllTests.java
@@ -0,0 +1,40 @@
+/* ====================================================================
+ 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.hsmf;
+
+import junit.framework.*;
+
+public class AllTests
+ extends TestCase
+{
+
+ public AllTests(String s)
+ {
+ super(s);
+ }
+
+ public static Test suite()
+ {
+ TestSuite suite = new TestSuite();
+ suite.addTestSuite(org.apache.poi.hsmf.model.TestBlankFileRead.class);
+ suite.addTestSuite(org.apache.poi.hsmf.model.TestSimpleFileRead.class);
+ suite.addTestSuite(org.apache.poi.hsmf.model.TestChunkData.class);
+
+ return suite;
+ }
+}
diff --git a/src/scratchpad/testcases/org/apache/poi/hsmf/data/blank.msg b/src/scratchpad/testcases/org/apache/poi/hsmf/data/blank.msg
new file mode 100644
index 0000000000..0bdb812401
Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hsmf/data/blank.msg differ
diff --git a/src/scratchpad/testcases/org/apache/poi/hsmf/data/simple_test_msg.msg b/src/scratchpad/testcases/org/apache/poi/hsmf/data/simple_test_msg.msg
new file mode 100644
index 0000000000..731fecc236
Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hsmf/data/simple_test_msg.msg differ
diff --git a/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestBlankFileRead.java b/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestBlankFileRead.java
new file mode 100644
index 0000000000..05735870b4
--- /dev/null
+++ b/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestBlankFileRead.java
@@ -0,0 +1,125 @@
+/* ====================================================================
+ 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.hsmf.model;
+
+import java.io.IOException;
+
+import org.apache.poi.hsmf.MAPIMessage;
+import org.apache.poi.hsmf.exceptions.ChunkNotFoundException;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests to verify that the library can read blank msg files.
+ *
+ * @author Travis Ferguson
+ *
+ */
+public class TestBlankFileRead extends TestCase {
+ private MAPIMessage mapiMessage;
+
+ /**
+ * Initialize this test, load up the blank.msg mapi message.
+ * @throws IOException
+ */
+ public TestBlankFileRead() throws IOException {
+ String dirname = System.getProperty("HSMF.testdata.path");
+ this.mapiMessage = new MAPIMessage(dirname + "/blank.msg");
+ }
+
+ /**
+ * Check if we can read the body of the blank message, we expect "".
+ *
+ * @throws Exception
+ */
+ public void testReadBody() throws Exception {
+ try {
+ mapiMessage.getTextBody();
+ } catch(ChunkNotFoundException exp) {
+ return;
+ }
+
+ TestCase.fail("Should have thrown a ChunkNotFoundException but didn't");
+ }
+
+
+ /**
+ * Test to see if we can read the CC Chunk.
+ * @throws ChunkNotFoundException
+ *
+ */
+ public void testReadDisplayCC() throws ChunkNotFoundException {
+ String obtained = mapiMessage.getDisplayCC();
+ String expected = "";
+
+ TestCase.assertEquals(obtained, expected);
+ }
+
+ /**
+ * Test to see if we can read the CC Chunk.
+ * @throws ChunkNotFoundException
+ *
+ */
+ public void testReadDisplayTo() throws ChunkNotFoundException {
+ String obtained = mapiMessage.getDisplayTo();
+ String expected = "";
+
+ TestCase.assertEquals(obtained, expected);
+ }
+
+ /**
+ * Test to see if we can read the CC Chunk.
+ * @throws ChunkNotFoundException
+ *
+ */
+ public void testReadDisplayBCC() throws ChunkNotFoundException {
+ String obtained = mapiMessage.getDisplayBCC();
+ String expected = "";
+
+ TestCase.assertEquals(obtained, expected);
+ }
+
+
+ /**
+ * Check if we can read the subject line of the blank message, we expect ""
+ *
+ * @throws Exception
+ */
+ public void testReadSubject() throws Exception {
+ String obtained = mapiMessage.getSubject();
+ TestCase.assertEquals("", obtained);
+ }
+
+
+ /**
+ * Check if we can read the subject line of the blank message, we expect ""
+ *
+ * @throws Exception
+ */
+ public void testReadConversationTopic() throws Exception {
+ try {
+ mapiMessage.getConversationTopic();
+ } catch(ChunkNotFoundException exp) {
+ return;
+ }
+ TestCase.fail("We shouldn't have a ConversationTopic node on the blank.msg file.");
+ }
+
+
+}
diff --git a/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestChunkData.java b/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestChunkData.java
new file mode 100644
index 0000000000..dc4b531294
--- /dev/null
+++ b/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestChunkData.java
@@ -0,0 +1,72 @@
+/* ====================================================================
+ 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.hsmf.model;
+
+import org.apache.poi.hsmf.datatypes.Chunk;
+import org.apache.poi.hsmf.datatypes.Chunks;
+import org.apache.poi.hsmf.datatypes.StringChunk;
+
+import junit.framework.TestCase;
+
+/**
+ * Verifies that the Chunks class is actually setup properly and hasn't been changed in ways
+ * that will break the library.
+ *
+ * @author Travis Ferguson
+ *
+ */
+public class TestChunkData extends TestCase {
+ public void testChunkCreate() {
+ StringChunk chunk = new StringChunk(0x0200);
+ TestCase.assertEquals("__substg1.0_0200001E", chunk.getEntryName());
+
+ /* test the lower and upper limits of the chunk ids */
+ chunk = new StringChunk(0x0000);
+ TestCase.assertEquals("__substg1.0_0000001E", chunk.getEntryName());
+
+ chunk = new StringChunk(0xFFFF);
+ TestCase.assertEquals("__substg1.0_FFFF001E", chunk.getEntryName());
+ }
+
+ public void testTextBodyChunk() {
+ StringChunk chunk = new StringChunk(0x1000);
+ TestCase.assertEquals(chunk.getEntryName(), Chunks.getInstance().textBodyChunk.getEntryName());
+ }
+
+ public void testDisplayToChunk() {
+ StringChunk chunk = new StringChunk(0x0E04);
+ TestCase.assertEquals(chunk.getEntryName(), Chunks.getInstance().displayToChunk.getEntryName());
+ }
+
+
+ public void testDisplayCCChunk() {
+ StringChunk chunk = new StringChunk(0x0E03);
+ TestCase.assertEquals(chunk.getEntryName(), Chunks.getInstance().displayCCChunk.getEntryName());
+ }
+
+ public void testDisplayBCCChunk() {
+ StringChunk chunk = new StringChunk(0x0E02);
+ TestCase.assertEquals(chunk.getEntryName(), Chunks.getInstance().displayBCCChunk.getEntryName());
+ }
+
+ public void testSubjectChunk() {
+ Chunk chunk = new StringChunk(0x0037);
+ TestCase.assertEquals(chunk.getEntryName(), Chunks.getInstance().subjectChunk.getEntryName());
+ }
+
+}
diff --git a/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestSimpleFileRead.java b/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestSimpleFileRead.java
new file mode 100644
index 0000000000..0ede68965a
--- /dev/null
+++ b/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestSimpleFileRead.java
@@ -0,0 +1,129 @@
+/* ====================================================================
+ 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.hsmf.model;
+
+import java.io.IOException;
+
+import org.apache.poi.hsmf.MAPIMessage;
+import org.apache.poi.hsmf.exceptions.ChunkNotFoundException;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests to verify that we can read a simple msg file, that is in plain/text format with no attachments
+ * or extra recipents.
+ *
+ * @author Travis Ferguson
+ */
+public class TestSimpleFileRead extends TestCase {
+private MAPIMessage mapiMessage;
+
+ /**
+ * Initialize this test, load up the blank.msg mapi message.
+ * @throws Exception
+ */
+ public TestSimpleFileRead() throws IOException {
+ String dirname = System.getProperty("HSMF.testdata.path");
+ this.mapiMessage = new MAPIMessage(dirname + "/simple_test_msg.msg");
+ }
+
+ /**
+ * Test to see if we can read the CC Chunk.
+ * @throws ChunkNotFoundException
+ *
+ */
+ public void testReadDisplayCC() throws ChunkNotFoundException {
+ String obtained = mapiMessage.getDisplayCC();
+ String expected = "";
+
+ TestCase.assertEquals(obtained, expected);
+ }
+
+ /**
+ * Test to see if we can read the CC Chunk.
+ * @throws ChunkNotFoundException
+ *
+ */
+ public void testReadDisplayTo() throws ChunkNotFoundException {
+ String obtained = mapiMessage.getDisplayTo();
+ String expected = "travis@overwrittenstack.com";
+
+ TestCase.assertEquals(obtained, expected);
+ }
+
+ /**
+ * Test to see if we can read the CC Chunk.
+ * @throws ChunkNotFoundException
+ *
+ */
+ public void testReadDisplayBCC() throws ChunkNotFoundException {
+ String obtained = mapiMessage.getDisplayBCC();
+ String expected = "";
+
+ TestCase.assertEquals(obtained, expected);
+ }
+
+
+ /**
+ * Check if we can read the body of the blank message, we expect "".
+ *
+ * @throws Exception
+ */
+ public void testReadBody() throws Exception {
+ String obtained = mapiMessage.getTextBody();
+ String expected = "This is a test message.";
+
+ TestCase.assertEquals(obtained, expected);
+ }
+
+ /**
+ * Check if we can read the subject line of the blank message, we expect ""
+ *
+ * @throws Exception
+ */
+ public void testReadSubject() throws Exception {
+ String obtained = mapiMessage.getSubject();
+ String expected = "test message";
+
+ TestCase.assertEquals(expected, obtained);
+ }
+
+ /**
+ * Check if we can read the subject line of the blank message, we expect ""
+ *
+ * @throws Exception
+ */
+ public void testReadConversationTopic() throws Exception {
+ String obtained = mapiMessage.getConversationTopic();
+ TestCase.assertEquals("test message", obtained);
+ }
+
+
+ /**
+ * Check if we can read the subject line of the blank message, we expect ""
+ *
+ * @throws Exception
+ */
+ public void testReadMessageClass() throws Exception {
+ String obtained = mapiMessage.getMessageClass();
+ TestCase.assertEquals("IPM.Note", obtained);
+ }
+
+
+
+}