Start on decoding fixed sized HSMF properties, and linking the variable sized ones with their matching chunks
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1441398 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
90d7b88fa3
commit
8edde11bbc
@ -418,14 +418,14 @@ public class MAPIMessage extends POIDocument {
|
|||||||
* @see #guess7BitEncoding()
|
* @see #guess7BitEncoding()
|
||||||
*/
|
*/
|
||||||
public void set7BitEncoding(String charset) {
|
public void set7BitEncoding(String charset) {
|
||||||
for(Chunk c : mainChunks.getAll()) {
|
for(Chunk c : mainChunks.getChunks()) {
|
||||||
if(c instanceof StringChunk) {
|
if(c instanceof StringChunk) {
|
||||||
((StringChunk)c).set7BitEncoding(charset);
|
((StringChunk)c).set7BitEncoding(charset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nameIdChunks!=null) {
|
if (nameIdChunks!=null) {
|
||||||
for(Chunk c : nameIdChunks.getAll()) {
|
for(Chunk c : nameIdChunks.getChunks()) {
|
||||||
if(c instanceof StringChunk) {
|
if(c instanceof StringChunk) {
|
||||||
((StringChunk)c).set7BitEncoding(charset);
|
((StringChunk)c).set7BitEncoding(charset);
|
||||||
}
|
}
|
||||||
@ -446,7 +446,7 @@ public class MAPIMessage extends POIDocument {
|
|||||||
* are stored as 7 bit rather than unicode?
|
* are stored as 7 bit rather than unicode?
|
||||||
*/
|
*/
|
||||||
public boolean has7BitEncodingStrings() {
|
public boolean has7BitEncodingStrings() {
|
||||||
for(Chunk c : mainChunks.getAll()) {
|
for(Chunk c : mainChunks.getChunks()) {
|
||||||
if(c instanceof StringChunk) {
|
if(c instanceof StringChunk) {
|
||||||
if( ((StringChunk)c).getType() == Types.ASCII_STRING ) {
|
if( ((StringChunk)c).getType() == Types.ASCII_STRING ) {
|
||||||
return true;
|
return true;
|
||||||
@ -455,7 +455,7 @@ public class MAPIMessage extends POIDocument {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (nameIdChunks!=null) {
|
if (nameIdChunks!=null) {
|
||||||
for(Chunk c : nameIdChunks.getAll()) {
|
for(Chunk c : nameIdChunks.getChunks()) {
|
||||||
if(c instanceof StringChunk) {
|
if(c instanceof StringChunk) {
|
||||||
if( ((StringChunk)c).getType() == Types.ASCII_STRING ) {
|
if( ((StringChunk)c).getType() == Types.ASCII_STRING ) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -172,6 +172,16 @@ public class AttachmentChunks implements ChunkGroup {
|
|||||||
allChunks.add(chunk);
|
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.
|
* Orders by the attachment number.
|
||||||
*/
|
*/
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
@ -33,4 +33,9 @@ public interface ChunkGroup {
|
|||||||
* Called by the parser whenever a chunk is found.
|
* Called by the parser whenever a chunk is found.
|
||||||
*/
|
*/
|
||||||
public void record(Chunk chunk);
|
public void record(Chunk chunk);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the parser when all chunks have been found.
|
||||||
|
*/
|
||||||
|
public void chunksComplete();
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,9 @@
|
|||||||
package org.apache.poi.hsmf.datatypes;
|
package org.apache.poi.hsmf.datatypes;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
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
|
* http://msdn.microsoft.com/en-us/library/ms526356%28v=exchg.10%29.aspx
|
||||||
*/
|
*/
|
||||||
public final class Chunks implements ChunkGroup {
|
public final class Chunks implements ChunkGroup {
|
||||||
/** Holds all the chunks that were found. */
|
/** Holds all the chunks that were found, indexed by their MAPIProperty */
|
||||||
private List<Chunk> allChunks = new ArrayList<Chunk>();
|
private Map<MAPIProperty,List<Chunk>> allChunks = new HashMap<MAPIProperty,List<Chunk>>();
|
||||||
|
|
||||||
/** Type of message that the MSG represents (ie. IPM.Note) */
|
/** Type of message that the MSG represents (ie. IPM.Note) */
|
||||||
public StringChunk messageClass;
|
public StringChunk messageClass;
|
||||||
@ -70,65 +72,72 @@ public final class Chunks implements ChunkGroup {
|
|||||||
/** The message properties */
|
/** The message properties */
|
||||||
public MessagePropertiesChunk messageProperties;
|
public MessagePropertiesChunk messageProperties;
|
||||||
|
|
||||||
|
public Map<MAPIProperty,List<Chunk>> getAll() {
|
||||||
public Chunk[] getAll() {
|
return allChunks;
|
||||||
return allChunks.toArray(new Chunk[allChunks.size()]);
|
|
||||||
}
|
}
|
||||||
public Chunk[] getChunks() {
|
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.
|
* Called by the parser whenever a chunk is found.
|
||||||
*/
|
*/
|
||||||
public void record(Chunk chunk) {
|
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;
|
messageClass = (StringChunk)chunk;
|
||||||
}
|
}
|
||||||
else if(chunk.getChunkId() == MAPIProperty.INTERNET_MESSAGE_ID.id) {
|
else if(prop == MAPIProperty.INTERNET_MESSAGE_ID) {
|
||||||
messageId = (StringChunk)chunk;
|
messageId = (StringChunk)chunk;
|
||||||
}
|
}
|
||||||
else if(chunk.getChunkId() == MAPIProperty.MESSAGE_SUBMISSION_ID.id) {
|
else if(prop == MAPIProperty.MESSAGE_SUBMISSION_ID) {
|
||||||
// TODO - parse
|
// TODO - parse
|
||||||
submissionChunk = (MessageSubmissionChunk)chunk;
|
submissionChunk = (MessageSubmissionChunk)chunk;
|
||||||
}
|
}
|
||||||
else if(chunk.getChunkId() == MAPIProperty.RECEIVED_BY_ADDRTYPE.id) {
|
else if(prop == MAPIProperty.RECEIVED_BY_ADDRTYPE) {
|
||||||
sentByServerType = (StringChunk)chunk;
|
sentByServerType = (StringChunk)chunk;
|
||||||
}
|
}
|
||||||
else if(chunk.getChunkId() == MAPIProperty.TRANSPORT_MESSAGE_HEADERS.id) {
|
else if(prop == MAPIProperty.TRANSPORT_MESSAGE_HEADERS) {
|
||||||
messageHeaders = (StringChunk)chunk;
|
messageHeaders = (StringChunk)chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(chunk.getChunkId() == MAPIProperty.CONVERSATION_TOPIC.id) {
|
else if(prop == MAPIProperty.CONVERSATION_TOPIC) {
|
||||||
conversationTopic = (StringChunk)chunk;
|
conversationTopic = (StringChunk)chunk;
|
||||||
}
|
}
|
||||||
else if(chunk.getChunkId() == MAPIProperty.SUBJECT.id) {
|
else if(prop == MAPIProperty.SUBJECT) {
|
||||||
subjectChunk = (StringChunk)chunk;
|
subjectChunk = (StringChunk)chunk;
|
||||||
}
|
}
|
||||||
else if(chunk.getChunkId() == MAPIProperty.ORIGINAL_SUBJECT.id) {
|
else if(prop == MAPIProperty.ORIGINAL_SUBJECT) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(chunk.getChunkId() == MAPIProperty.DISPLAY_TO.id) {
|
else if(prop == MAPIProperty.DISPLAY_TO) {
|
||||||
displayToChunk = (StringChunk)chunk;
|
displayToChunk = (StringChunk)chunk;
|
||||||
}
|
}
|
||||||
else if(chunk.getChunkId() == MAPIProperty.DISPLAY_CC.id) {
|
else if(prop == MAPIProperty.DISPLAY_CC) {
|
||||||
displayCCChunk = (StringChunk)chunk;
|
displayCCChunk = (StringChunk)chunk;
|
||||||
}
|
}
|
||||||
else if(chunk.getChunkId() == MAPIProperty.DISPLAY_BCC.id) {
|
else if(prop == MAPIProperty.DISPLAY_BCC) {
|
||||||
displayBCCChunk = (StringChunk)chunk;
|
displayBCCChunk = (StringChunk)chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(chunk.getChunkId() == MAPIProperty.SENDER_EMAIL_ADDRESS.id) {
|
else if(prop == MAPIProperty.SENDER_EMAIL_ADDRESS) {
|
||||||
emailFromChunk = (StringChunk)chunk;
|
emailFromChunk = (StringChunk)chunk;
|
||||||
}
|
}
|
||||||
else if(chunk.getChunkId() == MAPIProperty.SENDER_NAME.id) {
|
else if(prop == MAPIProperty.SENDER_NAME) {
|
||||||
displayFromChunk = (StringChunk)chunk;
|
displayFromChunk = (StringChunk)chunk;
|
||||||
}
|
}
|
||||||
else if(chunk.getChunkId() == MAPIProperty.BODY.id) {
|
else if(prop == MAPIProperty.BODY) {
|
||||||
textBodyChunk = (StringChunk)chunk;
|
textBodyChunk = (StringChunk)chunk;
|
||||||
}
|
}
|
||||||
else if(chunk.getChunkId() == MAPIProperty.BODY_HTML.id) {
|
else if(prop == MAPIProperty.BODY_HTML) {
|
||||||
if(chunk instanceof StringChunk) {
|
if(chunk instanceof StringChunk) {
|
||||||
htmlBodyChunkString = (StringChunk)chunk;
|
htmlBodyChunkString = (StringChunk)chunk;
|
||||||
}
|
}
|
||||||
@ -136,16 +145,21 @@ public final class Chunks implements ChunkGroup {
|
|||||||
htmlBodyChunkBinary = (ByteChunk)chunk;
|
htmlBodyChunkBinary = (ByteChunk)chunk;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(chunk.getChunkId() == MAPIProperty.RTF_COMPRESSED.id) {
|
else if(prop == MAPIProperty.RTF_COMPRESSED) {
|
||||||
rtfBodyChunk = (ByteChunk)chunk;
|
rtfBodyChunk = (ByteChunk)chunk;
|
||||||
}
|
}
|
||||||
else if(chunk.getChunkId() == MAPIProperty.UNKNOWN.id &&
|
else if(chunk instanceof MessagePropertiesChunk) {
|
||||||
chunk instanceof MessagePropertiesChunk) {
|
|
||||||
// TODO Should we maybe collect the contents of this?
|
|
||||||
messageProperties = (MessagePropertiesChunk) chunk;
|
messageProperties = (MessagePropertiesChunk) chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// And add to the main list
|
// 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,8 +33,8 @@ public class MessagePropertiesChunk extends PropertiesChunk {
|
|||||||
private long recipientCount;
|
private long recipientCount;
|
||||||
private long attachmentCount;
|
private long attachmentCount;
|
||||||
|
|
||||||
public MessagePropertiesChunk() {
|
public MessagePropertiesChunk(ChunkGroup parentGroup) {
|
||||||
super();
|
super(parentGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getNextRecipientId() {
|
public long getNextRecipientId() {
|
||||||
|
@ -44,4 +44,13 @@ public final class NameIdChunks implements ChunkGroup {
|
|||||||
public void record(Chunk chunk) {
|
public void record(Chunk chunk) {
|
||||||
allChunks.add(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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,9 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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.Types.MAPIType;
|
||||||
import org.apache.poi.hsmf.datatypes.PropertyValue.*;
|
|
||||||
import org.apache.poi.util.IOUtils;
|
import org.apache.poi.util.IOUtils;
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
import org.apache.poi.util.LittleEndian.BufferUnderrunException;
|
import org.apache.poi.util.LittleEndian.BufferUnderrunException;
|
||||||
@ -52,11 +53,19 @@ public abstract class PropertiesChunk extends Chunk {
|
|||||||
private Map<MAPIProperty, List<PropertyValue>> properties =
|
private Map<MAPIProperty, List<PropertyValue>> properties =
|
||||||
new HashMap<MAPIProperty, List<PropertyValue>>();
|
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.
|
* Creates a Properties Chunk.
|
||||||
*/
|
*/
|
||||||
protected PropertiesChunk() {
|
protected PropertiesChunk(ChunkGroup parentGroup) {
|
||||||
super(NAME, -1, Types.UNKNOWN);
|
super(NAME, -1, Types.UNKNOWN);
|
||||||
|
this.parentGroup = parentGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -132,7 +141,7 @@ public abstract class PropertiesChunk extends Chunk {
|
|||||||
// Wrap and store
|
// Wrap and store
|
||||||
PropertyValue propVal = null;
|
PropertyValue propVal = null;
|
||||||
if (isPointer) {
|
if (isPointer) {
|
||||||
// TODO Pointer type which can do lookup
|
propVal = new ChunkBasedPropertyValue(prop, flags, data);
|
||||||
}
|
}
|
||||||
else if (type == Types.LONG_LONG) {
|
else if (type == Types.LONG_LONG) {
|
||||||
propVal = new LongLongPropertyValue(prop, flags, data);
|
propVal = new LongLongPropertyValue(prop, flags, data);
|
||||||
|
@ -77,7 +77,11 @@ public final class RecipientChunks implements ChunkGroup {
|
|||||||
* as in recipientNameChunk
|
* as in recipientNameChunk
|
||||||
*/
|
*/
|
||||||
public StringChunk recipientDisplayNameChunk;
|
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) {
|
public RecipientChunks(String name) {
|
||||||
recipientNumber = -1;
|
recipientNumber = -1;
|
||||||
@ -191,11 +195,18 @@ public final class RecipientChunks implements ChunkGroup {
|
|||||||
else if(chunk.getChunkId() == DELIVERY_TYPE.id) {
|
else if(chunk.getChunkId() == DELIVERY_TYPE.id) {
|
||||||
deliveryTypeChunk = (StringChunk)chunk;
|
deliveryTypeChunk = (StringChunk)chunk;
|
||||||
}
|
}
|
||||||
|
else if(chunk instanceof PropertiesChunk) {
|
||||||
|
recipientProperties = (PropertiesChunk) chunk;
|
||||||
|
}
|
||||||
|
|
||||||
// And add to the main list
|
// And add to the main list
|
||||||
allChunks.add(chunk);
|
allChunks.add(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void chunksComplete() {
|
||||||
|
// TODO Match variable sized properties to their chunks + index
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Orders by the recipient number.
|
* Orders by the recipient number.
|
||||||
*/
|
*/
|
||||||
|
@ -29,8 +29,8 @@ import org.apache.poi.util.LittleEndian;
|
|||||||
* This only has a 8 byte header
|
* This only has a 8 byte header
|
||||||
*/
|
*/
|
||||||
public class StoragePropertiesChunk extends PropertiesChunk {
|
public class StoragePropertiesChunk extends PropertiesChunk {
|
||||||
public StoragePropertiesChunk() {
|
public StoragePropertiesChunk(ChunkGroup parentGroup) {
|
||||||
super();
|
super(parentGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -92,6 +92,12 @@ public final class POIFSChunkParser {
|
|||||||
// Now do the top level chunks
|
// Now do the top level chunks
|
||||||
processChunks(node, mainChunks);
|
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
|
// Finish
|
||||||
return groups.toArray(new ChunkGroup[groups.size()]);
|
return groups.toArray(new ChunkGroup[groups.size()]);
|
||||||
}
|
}
|
||||||
@ -123,10 +129,10 @@ public final class POIFSChunkParser {
|
|||||||
if (entryName.equals(PropertiesChunk.NAME)) {
|
if (entryName.equals(PropertiesChunk.NAME)) {
|
||||||
if (grouping instanceof Chunks) {
|
if (grouping instanceof Chunks) {
|
||||||
// These should be the properties for the message itself
|
// These should be the properties for the message itself
|
||||||
chunk = new MessagePropertiesChunk();
|
chunk = new MessagePropertiesChunk(grouping);
|
||||||
} else {
|
} else {
|
||||||
// Will be properties on an attachment or recipient
|
// Will be properties on an attachment or recipient
|
||||||
chunk = new StoragePropertiesChunk();
|
chunk = new StoragePropertiesChunk(grouping);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Check it's a regular chunk
|
// Check it's a regular chunk
|
||||||
|
Loading…
Reference in New Issue
Block a user