Author: nick
Date: Wed Jan 12 16:45:02 2011
New Revision: 1058226
URL: http://svn.apache.org/viewvc?rev=1058226&view=rev
Log:
Start to decode the MAPI Properties in the TNEF stream for HMEF
Added:
poi/trunk/src/scratchpad/src/org/apache/poi/hmef/MAPIAttribute.java
poi/trunk/src/scratchpad/src/org/apache/poi/hmef/MAPIStringAttribute.java
Modified:
poi/trunk/src/scratchpad/src/org/apache/poi/hmef/Attachment.java
poi/trunk/src/scratchpad/src/org/apache/poi/hmef/HMEFMessage.java
poi/trunk/src/scratchpad/src/org/apache/poi/hmef/dev/HMEFDumper.java
poi/trunk/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Types.java
Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hmef/Attachment.java
URL:
http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hmef/Attachment.java?rev=1058226&r1=1058225&r2=1058226&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hmef/Attachment.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hmef/Attachment.java Wed Jan 12
16:45:02 2011
@@ -26,12 +26,21 @@ import java.util.List;
*/
public final class Attachment {
private final List<Attribute> attributes = new ArrayList<Attribute>();
+ private final List<MAPIAttribute> mapiAttributes = new
ArrayList<MAPIAttribute>();
protected void addAttribute(Attribute attr) {
attributes.add(attr);
}
+ protected void addAttribute(MAPIAttribute attr) {
+ mapiAttributes.add(attr);
+ }
+
public List<Attribute> getAttributes() {
return attributes;
}
+
+ public List<MAPIAttribute> getMAPIAttributes() {
+ return mapiAttributes;
+ }
}
Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hmef/HMEFMessage.java
URL:
http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hmef/HMEFMessage.java?rev=1058226&r1=1058225&r2=1058226&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hmef/HMEFMessage.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hmef/HMEFMessage.java Wed Jan
12 16:45:02 2011
@@ -37,6 +37,7 @@ public final class HMEFMessage {
private int fileId;
private List<Attribute> messageAttributes = new ArrayList<Attribute>();
+ private List<MAPIAttribute> mapiAttributes = new ArrayList<MAPIAttribute>();
private List<Attachment> attachments = new ArrayList<Attachment>();
public HMEFMessage(InputStream inp) throws IOException {
@@ -54,6 +55,24 @@ public final class HMEFMessage {
// Now begin processing the contents
process(inp, 0);
+
+ // Finally expand out the MAPI Attributes
+ for(Attribute attr : messageAttributes) {
+ if(attr.getId() == Attribute.ID_MAPIPROPERTIES) {
+ mapiAttributes.addAll(
+ MAPIAttribute.create(attr)
+ );
+ }
+ }
+ for(Attachment attachment : attachments) {
+ for(Attribute attr : attachment.getAttributes()) {
+ if(attr.getId() == Attribute.ID_MAPIPROPERTIES) {
+ attachment.getMAPIAttributes().addAll(
+ MAPIAttribute.create(attr)
+ );
+ }
+ }
+ }
}
private void process(InputStream inp, int lastLevel) throws IOException {
Added: poi/trunk/src/scratchpad/src/org/apache/poi/hmef/MAPIAttribute.java
URL:
http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hmef/MAPIAttribute.java?rev=1058226&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hmef/MAPIAttribute.java (added)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hmef/MAPIAttribute.java Wed Jan
12 16:45:02 2011
@@ -0,0 +1,170 @@
+/* ====================================================================
+ 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 java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.hsmf.datatypes.MAPIProperty;
+import org.apache.poi.hsmf.datatypes.Types;
+import org.apache.poi.util.HexDump;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.LittleEndian;
+
+/**
+ * A pure-MAPI attribute which applies to a {...@link HMEFMessage}
+ * or one of its {...@link Attachment}s.
+ */
+public class MAPIAttribute {
+ private final MAPIProperty property;
+ private final int type;
+ private final byte[] data;
+
+ /**
+ * Constructs a single new attribute from
+ * the contents of the stream
+ */
+ public MAPIAttribute(MAPIProperty property, int type, byte[] data) {
+ this.property = property;
+ this.type = type;
+ this.data = data;
+ }
+
+ public MAPIProperty getProperty() {
+ return property;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public byte[] getData() {
+ return data;
+ }
+
+ public String toString() {
+ return property.toString() + " " + HexDump.toHex(data);
+ }
+
+ /**
+ * Parses a MAPI Properties TNEF Attribute, and returns
+ * the list of MAPI Attributes contained within it
+ */
+ public static List<MAPIAttribute> create(Attribute parent) throws
IOException {
+ if(parent.getId() != Attribute.ID_MAPIPROPERTIES) {
+ throw new IllegalArgumentException(
+ "Can only create from a MAPIProperty attribute, " +
+ "instead received a " + parent.getId() + " one"
+ );
+ }
+ ByteArrayInputStream inp = new ByteArrayInputStream(parent.getData());
+
+ // First up, get the number of attributes
+ int count = LittleEndian.readInt(inp);
+ List<MAPIAttribute> attrs = new ArrayList<MAPIAttribute>();
+
+ // Now, read each one in in turn
+ for(int i=0; i<count; i++) {
+ int typeAndMV = LittleEndian.readUShort(inp);
+ int id = LittleEndian.readUShort(inp);
+
+ // Is it either Multi-Valued or Variable-Length?
+ boolean isMV = false;
+ boolean isVL = false;
+ int type = typeAndMV;
+ if( (typeAndMV & Types.MULTIVALUED_FLAG) > 0 ) {
+ isMV = true;
+ type -= Types.MULTIVALUED_FLAG;
+ }
+ if(type == Types.ASCII_STRING || type == Types.UNICODE_STRING ||
+ type == Types.BINARY || type == Types.DIRECTORY) {
+ isVL = true;
+ }
+
+ // If it's a named property, rather than a standard
+ // MAPI property, grab the details of it
+ MAPIProperty prop = MAPIProperty.get(id);
+ if(id >= 0x8000 && id <= 0xFFFF) {
+ // TODO
+ throw new UnsupportedOperationException("Not yet implemented for
id " + id);
+ }
+
+ // Now read in the value(s)
+ int values = 1;
+ if(isMV || isVL) {
+ values = LittleEndian.readInt(inp);
+ }
+ for(int j=0; j<values; j++) {
+ int len = getLength(type, inp);
+ byte[] data = new byte[len];
+ IOUtils.readFully(inp, data);
+
+ // Create
+ MAPIAttribute attr;
+ if(type == Types.UNICODE_STRING || type == Types.ASCII_STRING) {
+ attr = new MAPIStringAttribute(prop, type, data);
+ } else {
+ attr = new MAPIAttribute(prop, type, data);
+ }
+ attrs.add(attr);
+
+ // Data is always padded out to a 4 byte boundary
+ if(len % 4 != 0) {
+ byte[] padding = new byte[len % 4];
+ IOUtils.readFully(inp, padding);
+ }
+ }
+ break;
+ }
+
+ // All done
+ return attrs;
+ }
+ private static int getLength(int type, InputStream inp) throws IOException {
+ switch(type) {
+ case Types.NULL:
+ return 0;
+ case Types.BOOLEAN:
+ case Types.SHORT:
+ return 2;
+ case Types.LONG:
+ case Types.FLOAT:
+ case Types.ERROR:
+ return 4;
+ case Types.LONG_LONG:
+ case Types.DOUBLE:
+ case Types.APP_TIME:
+ case Types.TIME:
+ case Types.CURRENCY:
+ return 8;
+ case Types.CLS_ID:
+ return 16;
+ case Types.ASCII_STRING:
+ case Types.UNICODE_STRING:
+ case Types.DIRECTORY:
+ case Types.BINARY:
+ // Need to read the length, as it varies
+ return LittleEndian.readInt(inp);
+ default:
+ throw new IllegalArgumentException("Unknown type " + type);
+ }
+ }
+}
Added: poi/trunk/src/scratchpad/src/org/apache/poi/hmef/MAPIStringAttribute.java
URL:
http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hmef/MAPIStringAttribute.java?rev=1058226&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hmef/MAPIStringAttribute.java
(added)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hmef/MAPIStringAttribute.java
Wed Jan 12 16:45:02 2011
@@ -0,0 +1,71 @@
+/* ====================================================================
+ 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 java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.poi.util.HexDump;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.StringUtil;
+import org.apache.poi.hmef.Attribute.AttributeID;
+import org.apache.poi.hsmf.datatypes.MAPIProperty;
+import org.apache.poi.hsmf.datatypes.Types;
+
+/**
+ * A pure-MAPI attribute holding a String, which applies
+ * to a {...@link HMEFMessage} or one of its {...@link Attachment}s.
+ */
+public final class MAPIStringAttribute extends MAPIAttribute {
+ private static final String CODEPAGE = "CP1252";
+ private final String data;
+
+ public MAPIStringAttribute(MAPIProperty property, int type, byte[] data) {
+ super(property, type, data);
+
+ String tmpData = null;
+ if(type == Types.ASCII_STRING) {
+ try {
+ tmpData = new String(data, CODEPAGE);
+ } catch(UnsupportedEncodingException e) {
+ throw new RuntimeException("JVM Broken - core encoding " +
CODEPAGE + " missing");
+ }
+ } else if(type == Types.UNICODE_STRING) {
+ tmpData = StringUtil.getFromUnicodeLE(data);
+ } else {
+ throw new IllegalArgumentException("Not a string type " + type);
+ }
+
+ // Strip off the null terminator if present
+ if(tmpData.endsWith("\0")) {
+ tmpData = tmpData.substring(0, tmpData.length()-1);
+ }
+ this.data = tmpData;
+ }
+
+ public String toString() {
+ return getProperty().toString() + " " + data;
+ }
+}
Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hmef/dev/HMEFDumper.java
URL:
http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hmef/dev/HMEFDumper.java?rev=1058226&r1=1058225&r2=1058226&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hmef/dev/HMEFDumper.java
(original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hmef/dev/HMEFDumper.java Wed
Jan 12 16:45:02 2011
@@ -20,9 +20,11 @@ package org.apache.poi.hmef.dev;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.List;
import org.apache.poi.hmef.Attribute;
import org.apache.poi.hmef.HMEFMessage;
+import org.apache.poi.hmef.MAPIAttribute;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;
@@ -104,6 +106,14 @@ public final class HMEFDumper {
}
}
System.out.println();
+
+ if(attr.getId() == Attribute.ID_MAPIPROPERTIES) {
+ List<MAPIAttribute> attrs = MAPIAttribute.create(attr);
+ for(MAPIAttribute ma : attrs) {
+ System.out.println(indent + indent + ma);
+ }
+ System.out.println();
+ }
}
}
}
Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Types.java
URL:
http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Types.java?rev=1058226&r1=1058225&r2=1058226&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Types.java
(original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Types.java Wed
Jan 12 16:45:02 2011
@@ -65,7 +65,7 @@ public final class Types {
public static final int UNICODE_STRING = 0x001F;
/** MultiValued - Value part contains multiple values */
- public static final int MULTIVALUED_FLAT = 0x1000;
+ public static final int MULTIVALUED_FLAG = 0x1000;
public static String asFileEnding(int type) {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]