]> source.dussan.org Git - poi.git/commitdiff
Start on decoding fixed sized HSMF properties, and linking the variable sized ones...
authorNick Burch <nick@apache.org>
Fri, 1 Feb 2013 11:45:31 +0000 (11:45 +0000)
committerNick Burch <nick@apache.org>
Fri, 1 Feb 2013 11:45:31 +0000 (11:45 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1441398 13f79535-47bb-0310-9956-ffa450edef68

src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java
src/scratchpad/src/org/apache/poi/hsmf/datatypes/AttachmentChunks.java
src/scratchpad/src/org/apache/poi/hsmf/datatypes/ChunkBasedPropertyValue.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hsmf/datatypes/ChunkGroup.java
src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunks.java
src/scratchpad/src/org/apache/poi/hsmf/datatypes/MessagePropertiesChunk.java
src/scratchpad/src/org/apache/poi/hsmf/datatypes/NameIdChunks.java
src/scratchpad/src/org/apache/poi/hsmf/datatypes/PropertiesChunk.java
src/scratchpad/src/org/apache/poi/hsmf/datatypes/RecipientChunks.java
src/scratchpad/src/org/apache/poi/hsmf/datatypes/StoragePropertiesChunk.java
src/scratchpad/src/org/apache/poi/hsmf/parsers/POIFSChunkParser.java

index 73e6b89478ca5f191d4d096efaa970255a7ddc9e..4c5176c8bf5fd1fd215a3db9f811fafc01c52d6f 100644 (file)
@@ -418,14 +418,14 @@ public class MAPIMessage extends POIDocument {
     * @see #guess7BitEncoding()
     */
    public void set7BitEncoding(String charset) {
-      for(Chunk c : mainChunks.getAll()) {
+      for(Chunk c : mainChunks.getChunks()) {
          if(c instanceof StringChunk) {
             ((StringChunk)c).set7BitEncoding(charset);
          }
       }
 
       if (nameIdChunks!=null) {
-         for(Chunk c : nameIdChunks.getAll()) {
+         for(Chunk c : nameIdChunks.getChunks()) {
             if(c instanceof StringChunk) {
                 ((StringChunk)c).set7BitEncoding(charset);
             }
@@ -446,7 +446,7 @@ public class MAPIMessage extends POIDocument {
     *  are stored as 7 bit rather than unicode?
     */
    public boolean has7BitEncodingStrings() {
-      for(Chunk c : mainChunks.getAll()) {
+      for(Chunk c : mainChunks.getChunks()) {
          if(c instanceof StringChunk) {
             if( ((StringChunk)c).getType() == Types.ASCII_STRING ) {
                return true;
@@ -455,7 +455,7 @@ public class MAPIMessage extends POIDocument {
       }
       
       if (nameIdChunks!=null) {
-         for(Chunk c : nameIdChunks.getAll()) {
+         for(Chunk c : nameIdChunks.getChunks()) {
             if(c instanceof StringChunk) {
                if( ((StringChunk)c).getType() == Types.ASCII_STRING ) {
                   return true;
index aa17b7f7bb88e2dc14127e6350e4037c3536edc4..eddf6787d2471bc22c654a6f31ab3ee1de0dc412 100644 (file)
@@ -171,7 +171,17 @@ public class AttachmentChunks implements ChunkGroup {
       // And add to the main list
       allChunks.add(chunk);
    }
-   
+
+   /**
+    * Used to flag that all the chunks of the attachment
+    *  have now been located.
+    */
+   public void chunksComplete() {
+      // Currently, we don't need to do anything special once
+      //  all the chunks have been located
+   }
+
+
    /**
     * Orders by the attachment number.
     */
diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/ChunkBasedPropertyValue.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/ChunkBasedPropertyValue.java
new file mode 100644 (file)
index 0000000..36c723b
--- /dev/null
@@ -0,0 +1,44 @@
+/* ====================================================================
+   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;
+
+
+/**
+ * A variable length {@link PropertyValue} that is
+ *  backed by a {@link Chunk}
+ * TODO Provide a way to link these up with the chunks
+ */
+public class ChunkBasedPropertyValue extends PropertyValue {
+   public ChunkBasedPropertyValue(MAPIProperty property, long flags, byte[] offsetData) {
+      super(property, flags, offsetData);
+   }
+
+   @Override
+   public Chunk getValue() {
+      // TODO Decode the value into an offset
+      // TODO Look up the chunk based on that
+      return null;
+   }
+   
+   /**
+    * Stores the offset of the chunk as the property value
+    */
+   public void setValue(Chunk chunk) {
+      // TODO
+   }
+}
index 8f03cdda6a5fbec303a9bf87f418b871bcc71ca6..2bed67a7b206e6824f4115e7517cee4b0bce3951 100644 (file)
@@ -33,4 +33,9 @@ public interface ChunkGroup {
         * Called by the parser whenever a chunk is found.
         */
        public void record(Chunk chunk);
+       
+       /**
+        * Called by the parser when all chunks have been found.
+        */
+       public void chunksComplete();
 }
index f7e211a6ec5e0dd44b34d9134c36d8d93cf87294..b4897b4fcc685df343d3b9cf446aaa63257f2a38 100644 (file)
@@ -18,7 +18,9 @@
 package org.apache.poi.hsmf.datatypes;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 
 /**
@@ -30,8 +32,8 @@ import java.util.List;
  *  http://msdn.microsoft.com/en-us/library/ms526356%28v=exchg.10%29.aspx
  */
 public final class Chunks implements ChunkGroup {
-   /** Holds all the chunks that were found. */
-   private List<Chunk> allChunks = new ArrayList<Chunk>();
+   /** Holds all the chunks that were found, indexed by their MAPIProperty */
+   private Map<MAPIProperty,List<Chunk>> allChunks = new HashMap<MAPIProperty,List<Chunk>>();
    
    /** Type of message that the MSG represents (ie. IPM.Note) */
    public StringChunk messageClass;
@@ -70,65 +72,72 @@ public final class Chunks implements ChunkGroup {
    /** The message properties */
    public MessagePropertiesChunk messageProperties;
 
-
-   public Chunk[] getAll() {
-      return allChunks.toArray(new Chunk[allChunks.size()]);
+   public Map<MAPIProperty,List<Chunk>> getAll() {
+      return allChunks;
    }
    public Chunk[] getChunks() {
-      return getAll();
+      ArrayList<Chunk> chunks = new ArrayList<Chunk>(allChunks.size());
+      for (List<Chunk> c : allChunks.values()) {
+         chunks.addAll(c);
+      }
+      return chunks.toArray(new Chunk[chunks.size()]);
    }
        
    /**
     * Called by the parser whenever a chunk is found.
     */
    public void record(Chunk chunk) {
-      if(chunk.getChunkId() == MAPIProperty.MESSAGE_CLASS.id) {
+      // Work out what MAPIProperty this corresponds to
+      MAPIProperty prop = MAPIProperty.get(chunk.getChunkId());
+      
+      // Assign it for easy lookup, as best we can
+      if(prop == MAPIProperty.MESSAGE_CLASS) {
          messageClass = (StringChunk)chunk;
       }
-      else if(chunk.getChunkId() == MAPIProperty.INTERNET_MESSAGE_ID.id) {
+      else if(prop == MAPIProperty.INTERNET_MESSAGE_ID) {
          messageId = (StringChunk)chunk;
       }
-      else if(chunk.getChunkId() == MAPIProperty.MESSAGE_SUBMISSION_ID.id) {
+      else if(prop == MAPIProperty.MESSAGE_SUBMISSION_ID) {
          // TODO - parse
          submissionChunk = (MessageSubmissionChunk)chunk;
       }
-      else if(chunk.getChunkId() == MAPIProperty.RECEIVED_BY_ADDRTYPE.id) {
+      else if(prop == MAPIProperty.RECEIVED_BY_ADDRTYPE) {
          sentByServerType = (StringChunk)chunk;
       }
-      else if(chunk.getChunkId() == MAPIProperty.TRANSPORT_MESSAGE_HEADERS.id) {
+      else if(prop == MAPIProperty.TRANSPORT_MESSAGE_HEADERS) {
          messageHeaders = (StringChunk)chunk;
       }
       
-      else if(chunk.getChunkId() == MAPIProperty.CONVERSATION_TOPIC.id) {
+      else if(prop == MAPIProperty.CONVERSATION_TOPIC) {
          conversationTopic = (StringChunk)chunk;
       }
-      else if(chunk.getChunkId() == MAPIProperty.SUBJECT.id) {
+      else if(prop == MAPIProperty.SUBJECT) {
          subjectChunk = (StringChunk)chunk;
       }
-      else if(chunk.getChunkId() == MAPIProperty.ORIGINAL_SUBJECT.id) {
+      else if(prop == MAPIProperty.ORIGINAL_SUBJECT) {
          // TODO
       }
       
-      else if(chunk.getChunkId() == MAPIProperty.DISPLAY_TO.id) {
+      else if(prop == MAPIProperty.DISPLAY_TO) {
          displayToChunk = (StringChunk)chunk;
       }
-      else if(chunk.getChunkId() == MAPIProperty.DISPLAY_CC.id) {
+      else if(prop == MAPIProperty.DISPLAY_CC) {
          displayCCChunk = (StringChunk)chunk;
       }
-      else if(chunk.getChunkId() == MAPIProperty.DISPLAY_BCC.id) {
+      else if(prop == MAPIProperty.DISPLAY_BCC) {
          displayBCCChunk = (StringChunk)chunk;
       }
       
-      else if(chunk.getChunkId() == MAPIProperty.SENDER_EMAIL_ADDRESS.id) {
+      else if(prop == MAPIProperty.SENDER_EMAIL_ADDRESS) {
          emailFromChunk = (StringChunk)chunk;
       }
-      else if(chunk.getChunkId() == MAPIProperty.SENDER_NAME.id) {
+      else if(prop == MAPIProperty.SENDER_NAME) {
          displayFromChunk = (StringChunk)chunk;
       }
-      else if(chunk.getChunkId() == MAPIProperty.BODY.id) {
+      else if(prop == MAPIProperty.BODY) {
          textBodyChunk = (StringChunk)chunk;
       }
-      else if(chunk.getChunkId() == MAPIProperty.BODY_HTML.id) {
+      else if(prop == MAPIProperty.BODY_HTML) {
          if(chunk instanceof StringChunk) {
             htmlBodyChunkString = (StringChunk)chunk;
          }
@@ -136,16 +145,21 @@ public final class Chunks implements ChunkGroup {
             htmlBodyChunkBinary = (ByteChunk)chunk;
          }
       }
-      else if(chunk.getChunkId() == MAPIProperty.RTF_COMPRESSED.id) {
+      else if(prop == MAPIProperty.RTF_COMPRESSED) {
          rtfBodyChunk = (ByteChunk)chunk;
       }
-      else if(chunk.getChunkId() == MAPIProperty.UNKNOWN.id &&
-              chunk instanceof MessagePropertiesChunk) {
-         // TODO Should we maybe collect the contents of this?
+      else if(chunk instanceof MessagePropertiesChunk) {
          messageProperties = (MessagePropertiesChunk) chunk;
       }
       
       // And add to the main list
-      allChunks.add(chunk);
+      if (allChunks.get(prop) == null) {
+         allChunks.put(prop, new ArrayList<Chunk>());
+      }
+      allChunks.get(prop).add(chunk);
+   }
+   
+   public void chunksComplete() {
+      // TODO Match variable sized properties to their chunks + index
    }
 }
index ab9b1bfaf54dbf84aa8f7025f446cb9b57730909..dbf77c51c6ee62ce2f73613d0900ec061c8ab9e9 100644 (file)
@@ -33,8 +33,8 @@ public class MessagePropertiesChunk extends PropertiesChunk {
    private long recipientCount;
    private long attachmentCount;
 
-   public MessagePropertiesChunk() {
-      super();
+   public MessagePropertiesChunk(ChunkGroup parentGroup) {
+      super(parentGroup);
    }
    
    public long getNextRecipientId() {
index bb78ea308e9987c8c5f85555a72cf90e2500ec7d..a976d9395f2793585301b191503cf4bb88b9bcb6 100644 (file)
@@ -44,4 +44,13 @@ public final class NameIdChunks implements ChunkGroup {
    public void record(Chunk chunk) {
       allChunks.add(chunk);
    }
+   
+   /**
+    * Used to flag that all the chunks of the NameID
+    *  have now been located.
+    */
+   public void chunksComplete() {
+      // Currently, we don't need to do anything special once
+      //  all the chunks have been located
+   }
 }
index 17ff31473c61cd2779189226fa0835740d153ef2..5e57adb729293fd371dd900e79616b940728a994 100644 (file)
@@ -25,8 +25,9 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.poi.hsmf.datatypes.PropertyValue.LongLongPropertyValue;
+import org.apache.poi.hsmf.datatypes.PropertyValue.TimePropertyValue;
 import org.apache.poi.hsmf.datatypes.Types.MAPIType;
-import org.apache.poi.hsmf.datatypes.PropertyValue.*;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndian.BufferUnderrunException;
@@ -52,11 +53,19 @@ public abstract class PropertiesChunk extends Chunk {
    private Map<MAPIProperty, List<PropertyValue>> properties = 
          new HashMap<MAPIProperty, List<PropertyValue>>();
 
+   /**
+    * The ChunkGroup that these properties apply to. Used when
+    *  matching chunks to variable sized properties
+    * TODO Make use of this
+    */
+   private ChunkGroup parentGroup;
+   
        /**
         * Creates a Properties Chunk.
         */
-       protected PropertiesChunk() {
+       protected PropertiesChunk(ChunkGroup parentGroup) {
                super(NAME, -1, Types.UNKNOWN);
+               this.parentGroup = parentGroup;
        }
 
        @Override
@@ -132,7 +141,7 @@ public abstract class PropertiesChunk extends Chunk {
             // Wrap and store
             PropertyValue propVal = null;
             if (isPointer) {
-               // TODO Pointer type which can do lookup
+               propVal = new ChunkBasedPropertyValue(prop, flags, data);
             }
             else if (type == Types.LONG_LONG) {
                propVal = new LongLongPropertyValue(prop, flags, data);
index a3f57248ac5e294d39ea2a109e0d7fbdd2913c13..2ac4eee19abe708dc6f1a857546302d2225225cf 100644 (file)
@@ -77,7 +77,11 @@ public final class RecipientChunks implements ChunkGroup {
     *  as in recipientNameChunk
     */
    public StringChunk recipientDisplayNameChunk;
-   
+   /**
+    * Holds the fixed sized properties, and the
+    *  pointers to the data of variable sized ones
+    */
+   private PropertiesChunk recipientProperties;
    
    public RecipientChunks(String name) {
       recipientNumber = -1;
@@ -191,11 +195,18 @@ public final class RecipientChunks implements ChunkGroup {
       else if(chunk.getChunkId() == DELIVERY_TYPE.id) {
          deliveryTypeChunk = (StringChunk)chunk;
       }
+      else if(chunk instanceof PropertiesChunk) {
+         recipientProperties = (PropertiesChunk) chunk;
+      }
 
       // And add to the main list
       allChunks.add(chunk);
    }
    
+   public void chunksComplete() {
+      // TODO Match variable sized properties to their chunks + index
+   }
+
    /**
     * Orders by the recipient number.
     */
index 166d38ba9cfad477cd75f3afcea9a361674a1f87..5cb0d4bc7c77c3b58125eb6bace51b302880d252 100644 (file)
@@ -29,8 +29,8 @@ import org.apache.poi.util.LittleEndian;
  * This only has a 8 byte header
  */
 public class StoragePropertiesChunk extends PropertiesChunk {
-   public StoragePropertiesChunk() {
-      super();
+   public StoragePropertiesChunk(ChunkGroup parentGroup) {
+      super(parentGroup);
    }
    
    @Override
index 434d0cbd6b34e8fa981ed6aed2d097e9eb56d05f..5709643cec4ff8f43ca8f6c8aba0302c0ebc89d9 100644 (file)
@@ -92,6 +92,12 @@ public final class POIFSChunkParser {
       // Now do the top level chunks
       processChunks(node, mainChunks);
       
+      // All chunks are now processed, have the ChunkGroup
+      // match up variable-length properties and their chunks
+      for (ChunkGroup group : groups) {
+         // TODO
+      }
+      
       // Finish
       return groups.toArray(new ChunkGroup[groups.size()]);
    }
@@ -123,10 +129,10 @@ public final class POIFSChunkParser {
       if (entryName.equals(PropertiesChunk.NAME)) {
          if (grouping instanceof Chunks) {
             // These should be the properties for the message itself
-            chunk = new MessagePropertiesChunk();
+            chunk = new MessagePropertiesChunk(grouping);
          } else {
             // Will be properties on an attachment or recipient
-            chunk = new StoragePropertiesChunk();
+            chunk = new StoragePropertiesChunk(grouping);
          }
       } else {
          // Check it's a regular chunk