]> source.dussan.org Git - poi.git/commitdiff
Add support for custom MAPI Properties (0x8000 and above, plus unknown lower ones)
authorNick Burch <nick@apache.org>
Wed, 12 Jan 2011 18:14:49 +0000 (18:14 +0000)
committerNick Burch <nick@apache.org>
Wed, 12 Jan 2011 18:14:49 +0000 (18:14 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1058262 13f79535-47bb-0310-9956-ffa450edef68

src/scratchpad/src/org/apache/poi/hmef/MAPIAttribute.java
src/scratchpad/src/org/apache/poi/hsmf/datatypes/MAPIProperty.java
src/scratchpad/testcases/org/apache/poi/hsmf/datatypes/TestMAPIProperty.java [new file with mode: 0644]
src/scratchpad/testcases/org/apache/poi/hsmf/datatypes/TestTypes.java

index badf25ce717883b36e57e6477fb276995c23303c..3014f48d2d0a2a0b10016d8c19ca2bace8dcb429 100644 (file)
@@ -28,6 +28,7 @@ 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;
+import org.apache.poi.util.StringUtil;
 
 /**
  * A pure-MAPI attribute which applies to a {@link HMEFMessage}
@@ -103,9 +104,31 @@ public class MAPIAttribute {
          //  MAPI property, grab the details of it
          MAPIProperty prop = MAPIProperty.get(id);
          if(id >= 0x8000 && id <= 0xFFFF) {
-            // TODO
-            System.err.println("Not yet implemented for id " + id);
-            break;
+            byte[] guid = new byte[16];
+            IOUtils.readFully(inp, guid);
+            int mptype = LittleEndian.readInt(inp);
+            
+            // Get the name of it
+            String name;
+            if(mptype == 0) {
+               // It's based on a normal one
+               int mpid = LittleEndian.readInt(inp);
+               MAPIProperty base = MAPIProperty.get(mpid);
+               name = base.name;
+            } else {
+               // Custom name was stored
+               int mplen = LittleEndian.readInt(inp);
+               byte[] mpdata = new byte[mplen];
+               IOUtils.readFully(inp, mpdata);
+               name = StringUtil.getFromUnicodeLE(mpdata, 0, (mplen/2)-1);
+               skipToBoundary(mplen, inp);
+            }
+            
+            // Now create
+            prop = MAPIProperty.createCustom(id, type, name);
+         }
+         if(prop == MAPIProperty.UNKNOWN) {
+            prop = MAPIProperty.createCustom(id, type, "(unknown " + Integer.toHexString(id) + ")");
          }
          
          // Now read in the value(s)
@@ -117,6 +140,7 @@ public class MAPIAttribute {
             int len = getLength(type, inp);
             byte[] data = new byte[len];
             IOUtils.readFully(inp, data);
+            skipToBoundary(len, inp);
             
             // Create
             MAPIAttribute attr;
@@ -126,12 +150,6 @@ public class MAPIAttribute {
                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[4 - (len % 4)];
-               IOUtils.readFully(inp, padding);
-            }
          }
       }
       
@@ -167,4 +185,12 @@ public class MAPIAttribute {
             throw new IllegalArgumentException("Unknown type " + type);
       }
    }
+   private static void skipToBoundary(int length, InputStream inp) throws IOException {
+      // Data is always padded out to a 4 byte boundary
+      if(length % 4 != 0) {
+         int skip = 4 - (length % 4);
+         byte[] padding = new byte[skip];
+         IOUtils.readFully(inp, padding);
+      }
+   }
 }
index d5301c92821bddb5abe8b091dbf2c15a224247e5..d5b274a498711039b40b3d7eee128fe2cc957838 100644 (file)
@@ -37,7 +37,7 @@ import java.util.Map;
  *  http://msdn.microsoft.com/en-us/library/microsoft.exchange.data.contenttypes.tnef.tnefpropertyid%28v=EXCHG.140%29.aspx
  *  http://msdn.microsoft.com/en-us/library/ms526356%28v=exchg.10%29.aspx
  */
-public final class MAPIProperty {
+public class MAPIProperty {
    private static Map<Integer, MAPIProperty> attributes = new HashMap<Integer, MAPIProperty>();
    
    public static final MAPIProperty AB_DEFAULT_DIR =
@@ -1021,6 +1021,8 @@ public final class MAPIProperty {
       new MAPIProperty(-1, -1, "Unknown", null);
    
    // 0x8??? ones are outlook specific, and not standard MAPI
+   private static final int ID_FIRST_CUSTOM = 0x8000;
+   private static final int ID_LAST_CUSTOM = 0xFFFE;
    
    /* ---------------------------------------------------------------------  */
    
@@ -1035,14 +1037,19 @@ public final class MAPIProperty {
       this.name = name;
       this.mapiProperty = mapiProperty;
       
-      // Store it for lookup
-      if(attributes.containsKey(id)) {
-         throw new IllegalArgumentException(
-               "Duplicate MAPI Property with ID " + id + " : " +
-               toString() + " vs " + attributes.get(id).toString()
-         );
+      // If it isn't unknown or custom, store it for lookup
+      if(id == -1 || (id >= ID_FIRST_CUSTOM && id <= ID_LAST_CUSTOM) 
+            || (this instanceof CustomMAPIProperty)) {
+         // Custom/Unknown, skip
+      } else {
+         if(attributes.containsKey(id)) {
+            throw new IllegalArgumentException(
+                  "Duplicate MAPI Property with ID " + id + " : " +
+                  toString() + " vs " + attributes.get(id).toString()
+            );
+         }
+         attributes.put(id, this);
       }
-      attributes.put(id, this);
    }
    public String toString() {
       StringBuffer str = new StringBuffer();
@@ -1057,6 +1064,7 @@ public final class MAPIProperty {
       }
       return str.toString();
    }
+   
    public static MAPIProperty get(int id) {
       MAPIProperty attr = attributes.get(id);
       if(attr != null) {
@@ -1068,4 +1076,14 @@ public final class MAPIProperty {
    public static Collection<MAPIProperty> getAll() {
       return Collections.unmodifiableCollection( attributes.values() );
    }
+   
+   public static MAPIProperty createCustom(int id, int type, String name) {
+      return new CustomMAPIProperty(id, type, name, null);
+   }
+   
+   private static class CustomMAPIProperty extends MAPIProperty {
+      private CustomMAPIProperty(int id, int usualType, String name, String mapiProperty) {
+         super(id, usualType, name, mapiProperty);
+      }
+   }
 }
diff --git a/src/scratchpad/testcases/org/apache/poi/hsmf/datatypes/TestMAPIProperty.java b/src/scratchpad/testcases/org/apache/poi/hsmf/datatypes/TestMAPIProperty.java
new file mode 100644 (file)
index 0000000..8304d40
--- /dev/null
@@ -0,0 +1,63 @@
+/* ====================================================================
+   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.util.Collection;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+/**
+ * Checks various MAPIProperty related logic
+ */
+public final class TestMAPIProperty extends TestCase {
+   public void testGet() throws Exception {
+      assertEquals(MAPIProperty.DISPLAY_NAME, MAPIProperty.get(MAPIProperty.DISPLAY_NAME.id));
+      assertEquals(MAPIProperty.DISPLAY_BCC, MAPIProperty.get(MAPIProperty.DISPLAY_BCC.id));
+      assertNotSame(MAPIProperty.DISPLAY_BCC, MAPIProperty.get(MAPIProperty.DISPLAY_CC.id));
+   }
+   
+   public void testGetAll() throws Exception {
+      Collection<MAPIProperty> all = MAPIProperty.getAll();
+      assertEquals(true, all.contains(MAPIProperty.DISPLAY_NAME));
+      assertEquals(true, all.contains(MAPIProperty.DISPLAY_CC));
+      
+      // Won't contain custom
+      assertEquals(false, all.contains(MAPIProperty.createCustom(1, 1, "")));
+      
+      // Won't contain unknown
+      assertEquals(false, all.contains(MAPIProperty.UNKNOWN));
+   }
+   
+   public void testCustom() throws Exception {
+      MAPIProperty c1 = MAPIProperty.createCustom(1, 1, "");
+      MAPIProperty c2a = MAPIProperty.createCustom(2, 1, "2");
+      MAPIProperty c2b = MAPIProperty.createCustom(2, 1, "2");
+      
+      // New object each time
+      assertNotSame(c1, c2a);
+      assertNotSame(c1, c2b);
+      assertNotSame(c2a, c2b);
+      
+      // Won't be in all list
+      Collection<MAPIProperty> all = MAPIProperty.getAll();
+      assertEquals(false, all.contains(c1));
+      assertEquals(false, all.contains(c2a));
+      assertEquals(false, all.contains(c2b));
+   }
+}
index 0a2de38ac375505be121e4c2e4ece9fb3e3e30b3..152ca4dee06eab6bea5ef1a54d682d123ed96b69 100644 (file)
@@ -43,4 +43,9 @@ public final class TestTypes extends TestCase {
       assertEquals("0102", Types.asFileEnding(0x0102));
       assertEquals("FEDC", Types.asFileEnding(0xfedc));
    }
+   
+   public void testName() {
+      assertEquals("ASCII String", Types.asName(Types.ASCII_STRING));
+      assertEquals("Boolean", Types.asName(Types.BOOLEAN));
+   }
 }