aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/java/org/apache/poi/util/LZWDecompresser.java12
-rw-r--r--src/scratchpad/src/org/apache/poi/hdgf/HDGFLZW.java2
-rw-r--r--src/scratchpad/src/org/apache/poi/hmef/Attribute.java5
-rw-r--r--src/scratchpad/src/org/apache/poi/hmef/CompressedRTF.java2
-rw-r--r--src/scratchpad/src/org/apache/poi/hmef/HMEFMessage.java53
-rw-r--r--src/scratchpad/testcases/org/apache/poi/hmef/TestCompressedRTF.java155
-rw-r--r--src/scratchpad/testcases/org/apache/poi/hmef/TestHMEFMessage.java103
-rw-r--r--src/testcases/org/apache/poi/POIDataSamples.java6
8 files changed, 333 insertions, 5 deletions
diff --git a/src/java/org/apache/poi/util/LZWDecompresser.java b/src/java/org/apache/poi/util/LZWDecompresser.java
index f172a01db4..51926b6c25 100644
--- a/src/java/org/apache/poi/util/LZWDecompresser.java
+++ b/src/java/org/apache/poi/util/LZWDecompresser.java
@@ -35,10 +35,16 @@ public abstract class LZWDecompresser {
/**
* Does the mask bit mean it's compressed or uncompressed?
*/
- private boolean maskMeansCompressed;
+ private final boolean maskMeansCompressed;
+ /**
+ * How much to append to the code length in the stream
+ * to get the real code length? Normally 2 or 3
+ */
+ private final int codeLengthIncrease;
- protected LZWDecompresser(boolean maskMeansCompressed) {
+ protected LZWDecompresser(boolean maskMeansCompressed, int codeLengthIncrease) {
this.maskMeansCompressed = maskMeansCompressed;
+ this.codeLengthIncrease = codeLengthIncrease;
}
/**
@@ -135,7 +141,7 @@ public abstract class LZWDecompresser {
// what position of the code to start at
// (The position is the first 12 bits, the
// length is the last 4 bits)
- len = (dataIPt2 & 15) + 3;
+ len = (dataIPt2 & 15) + codeLengthIncrease;
pntr = (dataIPt2 & 240)*16 + dataIPt1;
// Adjust the pointer as needed
diff --git a/src/scratchpad/src/org/apache/poi/hdgf/HDGFLZW.java b/src/scratchpad/src/org/apache/poi/hdgf/HDGFLZW.java
index 290c14799b..f122c40f17 100644
--- a/src/scratchpad/src/org/apache/poi/hdgf/HDGFLZW.java
+++ b/src/scratchpad/src/org/apache/poi/hdgf/HDGFLZW.java
@@ -38,7 +38,7 @@ import org.apache.poi.util.LZWDecompresser;
public class HDGFLZW extends LZWDecompresser {
public HDGFLZW() {
// We're the wrong way round!
- super(false);
+ super(false, 3);
}
/**
diff --git a/src/scratchpad/src/org/apache/poi/hmef/Attribute.java b/src/scratchpad/src/org/apache/poi/hmef/Attribute.java
index d5e5aebdd8..8f7372ef1e 100644
--- a/src/scratchpad/src/org/apache/poi/hmef/Attribute.java
+++ b/src/scratchpad/src/org/apache/poi/hmef/Attribute.java
@@ -254,4 +254,9 @@ public final class Attribute {
public byte[] getData() {
return data;
}
+
+ public String toString() {
+ return "Attachment " + getId().toString() + ", type=" + type +
+ ", data length=" + data.length;
+ }
}
diff --git a/src/scratchpad/src/org/apache/poi/hmef/CompressedRTF.java b/src/scratchpad/src/org/apache/poi/hmef/CompressedRTF.java
index aa3b41c650..81218bc9ba 100644
--- a/src/scratchpad/src/org/apache/poi/hmef/CompressedRTF.java
+++ b/src/scratchpad/src/org/apache/poi/hmef/CompressedRTF.java
@@ -54,7 +54,7 @@ public final class CompressedRTF extends LZWDecompresser {
"{\\colortbl\\red0\\green0\\blue0\n\r\\par \\pard\\plain\\f0\\fs20\\b\\i\\u\\tab\\tx";
public CompressedRTF() {
- super(true);
+ super(true, 2);
}
public void decompress(InputStream src, OutputStream res) throws IOException {
diff --git a/src/scratchpad/src/org/apache/poi/hmef/HMEFMessage.java b/src/scratchpad/src/org/apache/poi/hmef/HMEFMessage.java
index d86e6afad6..d74bcbefae 100644
--- a/src/scratchpad/src/org/apache/poi/hmef/HMEFMessage.java
+++ b/src/scratchpad/src/org/apache/poi/hmef/HMEFMessage.java
@@ -22,6 +22,8 @@ import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
+import org.apache.poi.hmef.Attribute.AttributeID;
+import org.apache.poi.hsmf.datatypes.MAPIProperty;
import org.apache.poi.util.LittleEndian;
/**
@@ -103,4 +105,55 @@ public final class HMEFMessage {
// Handle the next one down
process(inp, level);
}
+
+ /**
+ * Returns all HMEF/TNEF attributes of the message.
+ * Note - In a typical message, most of the interesting properties
+ * are stored as {@link MAPIAttribute}s - see {@link #getMessageMAPIAttributes()}
+ */
+ public List<Attribute> getMessageAttributes() {
+ return messageAttributes;
+ }
+
+ /**
+ * Returns all MAPI attributes of the message.
+ * Note - A small number of HMEF/TNEF specific attributes normally
+ * apply to most messages, see {@link #getMessageAttributes()}
+ */
+ public List<MAPIAttribute> getMessageMAPIAttributes() {
+ return mapiAttributes;
+ }
+
+ /**
+ * Returns all the Attachments of the message.
+ */
+ public List<Attachment> getAttachments() {
+ return attachments;
+ }
+
+ /**
+ * Return the message attribute with the given ID,
+ * or null if there isn't one.
+ */
+ public Attribute getMessageAttribute(AttributeID id) {
+ for(Attribute attr : messageAttributes) {
+ if(attr.getId() == id) {
+ return attr;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return the message MAPI Attribute with the given ID,
+ * or null if there isn't one.
+ */
+ public MAPIAttribute getMessageMAPIAttribute(MAPIProperty id) {
+ for(MAPIAttribute attr : mapiAttributes) {
+ if(attr.getProperty() == id) {
+ return attr;
+ }
+ }
+ return null;
+ }
}
diff --git a/src/scratchpad/testcases/org/apache/poi/hmef/TestCompressedRTF.java b/src/scratchpad/testcases/org/apache/poi/hmef/TestCompressedRTF.java
new file mode 100644
index 0000000000..f9cc09c37a
--- /dev/null
+++ b/src/scratchpad/testcases/org/apache/poi/hmef/TestCompressedRTF.java
@@ -0,0 +1,155 @@
+/* ====================================================================
+ 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;
+
+import java.io.ByteArrayInputStream;
+
+import junit.framework.TestCase;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.hmef.Attribute.AttributeID;
+import org.apache.poi.hsmf.datatypes.MAPIProperty;
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.StringUtil;
+
+public final class TestCompressedRTF extends TestCase {
+ private static final POIDataSamples _samples = POIDataSamples.getHMEFInstance();
+
+ private static final String block1 = "{\\rtf1\\adeflang102";
+ private static final String block2 = block1 + "5\\ansi\\ansicpg1252";
+
+ /**
+ * Check that things are as we expected. If this fails,
+ * then decoding has no hope...
+ */
+ public void testQuickBasics() throws Exception {
+ HMEFMessage msg = new HMEFMessage(
+ _samples.openResourceAsStream("quick-winmail.dat")
+ );
+
+ MAPIAttribute rtfAttr = msg.getMessageMAPIAttribute(MAPIProperty.RTF_COMPRESSED);
+ assertNotNull(rtfAttr);
+ assertTrue(rtfAttr instanceof MAPIRtfAttribute);
+
+ // Check the start of the compressed version
+ assertEquals(5907, rtfAttr.getData().length);
+
+ // First 16 bytes is header stuff
+ // Check it has the length + compressed marker
+ assertEquals(5907-4, LittleEndian.getShort(rtfAttr.getData()));
+ assertEquals(
+ "LZFu",
+ StringUtil.getFromCompressedUnicode(rtfAttr.getData(), 8, 4)
+ );
+
+
+ // Now Look at the code
+ assertEquals((byte)0x07, rtfAttr.getData()[16+0]); // Flag: cccUUUUU
+ assertEquals((byte)0x00, rtfAttr.getData()[16+1]); // c1a: offset 0 / 0x000
+ assertEquals((byte)0x06, rtfAttr.getData()[16+2]); // c1b: length 6+2 -> {\rtf1\a
+ assertEquals((byte)0x01, rtfAttr.getData()[16+3]); // c2a: offset 16 / 0x010
+ assertEquals((byte)0x01, rtfAttr.getData()[16+4]); // c2b: length 1+2 -> def
+ assertEquals((byte)0x0b, rtfAttr.getData()[16+5]); // c3a: offset 182 / 0xb6
+ assertEquals((byte)0x60, rtfAttr.getData()[16+6]); // c3b: length 0+2 -> la
+ assertEquals((byte)0x6e, rtfAttr.getData()[16+7]); // n
+ assertEquals((byte)0x67, rtfAttr.getData()[16+8]); // g
+ assertEquals((byte)0x31, rtfAttr.getData()[16+9]); // 1
+ assertEquals((byte)0x30, rtfAttr.getData()[16+10]); // 0
+ assertEquals((byte)0x32, rtfAttr.getData()[16+11]); // 2
+
+ assertEquals((byte)0x66, rtfAttr.getData()[16+12]); // Flag: UccUUccU
+ assertEquals((byte)0x35, rtfAttr.getData()[16+13]); // 5
+ assertEquals((byte)0x00, rtfAttr.getData()[16+14]); // c2a: offset 6 / 0x006
+ assertEquals((byte)0x64, rtfAttr.getData()[16+15]); // c2b: length 4+2 -> \ansi\a
+ assertEquals((byte)0x00, rtfAttr.getData()[16+16]); // c3a: offset 7 / 0x007
+ assertEquals((byte)0x72, rtfAttr.getData()[16+17]); // c3b: length 2+2 -> nsi
+ assertEquals((byte)0x63, rtfAttr.getData()[16+18]); // c
+ assertEquals((byte)0x70, rtfAttr.getData()[16+19]); // p
+ assertEquals((byte)0x0d, rtfAttr.getData()[16+20]); // c6a: offset 221 / 0x0dd
+ assertEquals((byte)0xd0, rtfAttr.getData()[16+21]); // c6b: length 0+2 -> g1
+ assertEquals((byte)0x0e, rtfAttr.getData()[16+22]); // c7a: offset 224 / 0x0e0
+ assertEquals((byte)0x00, rtfAttr.getData()[16+23]); // c7b: length 0+2 -> 25
+ assertEquals((byte)0x32, rtfAttr.getData()[16+24]); // 2
+ }
+
+ /**
+ * Check that we can decode the first 8 codes
+ * (1 flag byte + 8 codes)
+ */
+ public void DISABLEDtestFirstBlock() throws Exception {
+ HMEFMessage msg = new HMEFMessage(
+ _samples.openResourceAsStream("quick-winmail.dat")
+ );
+
+ MAPIAttribute rtfAttr = msg.getMessageMAPIAttribute(MAPIProperty.RTF_COMPRESSED);
+ assertNotNull(rtfAttr);
+
+ // Truncate to header + flag + data for flag
+ byte[] data = new byte[16+12];
+ System.arraycopy(rtfAttr.getData(), 0, data, 0, data.length);
+
+ // Decompress it
+ CompressedRTF comp = new CompressedRTF();
+ byte[] decomp = comp.decompress(new ByteArrayInputStream(data));
+ String decompStr = new String(decomp, "ASCII");
+
+ // Test
+System.err.println(decompStr);
+ assertEquals(block1.length(), decomp.length);
+ assertEquals(block1, decompStr);
+ }
+
+ /**
+ * Check that we can decode the first 16 codes
+ * (flag + 8 codes, flag + 8 codes)
+ */
+ public void DISABLEDtestFirstTwoBlocks() throws Exception {
+ HMEFMessage msg = new HMEFMessage(
+ _samples.openResourceAsStream("quick-winmail.dat")
+ );
+
+ MAPIAttribute rtfAttr = msg.getMessageMAPIAttribute(MAPIProperty.RTF_COMPRESSED);
+ assertNotNull(rtfAttr);
+
+ // Truncate to header + flag + data for flag + flag + data
+ byte[] data = new byte[16+12+13];
+ System.arraycopy(rtfAttr.getData(), 0, data, 0, data.length);
+
+ // Decompress it
+ CompressedRTF comp = new CompressedRTF();
+ byte[] decomp = comp.decompress(new ByteArrayInputStream(data));
+ String decompStr = new String(decomp, "ASCII");
+
+ // Test
+System.err.println(decompStr);
+ assertEquals(block2.length(), decomp.length);
+ assertEquals(block2, decompStr);
+ }
+
+ /**
+ * Check that we can correctly decode the whole file
+ * @throws Exception
+ */
+ public void testFull() throws Exception {
+ HMEFMessage msg = new HMEFMessage(
+ _samples.openResourceAsStream("quick-winmail.dat")
+ );
+
+ // TODO
+ }
+}
diff --git a/src/scratchpad/testcases/org/apache/poi/hmef/TestHMEFMessage.java b/src/scratchpad/testcases/org/apache/poi/hmef/TestHMEFMessage.java
new file mode 100644
index 0000000000..33e1edbbe3
--- /dev/null
+++ b/src/scratchpad/testcases/org/apache/poi/hmef/TestHMEFMessage.java
@@ -0,0 +1,103 @@
+/* ====================================================================
+ 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;
+
+import junit.framework.TestCase;
+
+import org.apache.poi.POIDataSamples;
+
+public final class TestHMEFMessage extends TestCase {
+ private static final POIDataSamples _samples = POIDataSamples.getHMEFInstance();
+
+ public void testOpen() throws Exception {
+ HMEFMessage msg = new HMEFMessage(
+ _samples.openResourceAsStream("quick-winmail.dat")
+ );
+
+ assertNotNull(msg);
+ }
+
+ public void testCounts() throws Exception {
+ HMEFMessage msg = new HMEFMessage(
+ _samples.openResourceAsStream("quick-winmail.dat")
+ );
+
+ // Should have 4 attributes on the message
+ assertEquals(4, msg.getMessageAttributes().size());
+
+ // And should have 54 MAPI attributes on it
+ assertEquals(54, msg.getMessageMAPIAttributes().size());
+
+
+ // Should have 5 attachments
+ assertEquals(5, msg.getAttachments().size());
+
+ // Each attachment should have 6 normal attributes, and
+ // 20 or so MAPI ones
+ for(Attachment attach : msg.getAttachments()) {
+ int attrCount = attach.getAttributes().size();
+ int mapiAttrCount = attach.getMAPIAttributes().size();
+
+ assertEquals(6, attrCount);
+ // TODO
+// assertTrue("Should be 3-4 attributes, found " + mapiAttrCount, mapiAttrCount >= 20);
+// assertTrue("Should be 3-4 attributes, found " + mapiAttrCount, mapiAttrCount <= 25);
+ }
+
+
+ // TODO
+ }
+
+ public void testBasicMessageAttributes() throws Exception {
+ HMEFMessage msg = new HMEFMessage(
+ _samples.openResourceAsStream("quick-winmail.dat")
+ );
+
+ // Should have version, codepage, class and MAPI
+ assertEquals(4, msg.getMessageAttributes().size());
+ assertNotNull(msg.getMessageAttribute(Attribute.ID_TNEFVERSION));
+ assertNotNull(msg.getMessageAttribute(Attribute.ID_OEMCODEPAGE));
+ assertNotNull(msg.getMessageAttribute(Attribute.ID_MESSAGECLASS));
+ assertNotNull(msg.getMessageAttribute(Attribute.ID_MAPIPROPERTIES));
+
+ // Check the order
+ assertEquals(Attribute.ID_TNEFVERSION, msg.getMessageAttributes().get(0).getId());
+ assertEquals(Attribute.ID_OEMCODEPAGE, msg.getMessageAttributes().get(1).getId());
+ assertEquals(Attribute.ID_MESSAGECLASS, msg.getMessageAttributes().get(2).getId());
+ assertEquals(Attribute.ID_MAPIPROPERTIES, msg.getMessageAttributes().get(3).getId());
+
+ // Check some that aren't there
+ assertNull(msg.getMessageAttribute(Attribute.ID_AIDOWNER));
+ assertNull(msg.getMessageAttribute(Attribute.ID_ATTACHDATA));
+
+ // Now check the details of one or two
+ // TODO
+ }
+
+ public void testBasicMessageMAPIAttributes() throws Exception {
+ // TODO
+ }
+
+ public void testBasicAttachments() throws Exception {
+ // TODO
+ }
+
+ public void testMessageAttributeDetails() throws Exception {
+ // TODO
+ }
+}
diff --git a/src/testcases/org/apache/poi/POIDataSamples.java b/src/testcases/org/apache/poi/POIDataSamples.java
index d4ec6d6b7d..6f60a4e184 100644
--- a/src/testcases/org/apache/poi/POIDataSamples.java
+++ b/src/testcases/org/apache/poi/POIDataSamples.java
@@ -35,6 +35,7 @@ public final class POIDataSamples {
private static POIDataSamples _instOpenxml4j;
private static POIDataSamples _instPOIFS;
private static POIDataSamples _instDDF;
+ private static POIDataSamples _instHMEF;
private static POIDataSamples _instHPSF;
private static POIDataSamples _instHPBF;
private static POIDataSamples _instHSMF;
@@ -99,6 +100,11 @@ public final class POIDataSamples {
return _instHPBF;
}
+ public static POIDataSamples getHMEFInstance(){
+ if(_instHMEF == null) _instHMEF = new POIDataSamples("hmef");
+ return _instHMEF;
+ }
+
public static POIDataSamples getHSMFInstance(){
if(_instHSMF == null) _instHSMF = new POIDataSamples("hsmf");
return _instHSMF;