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()
|
||||
*/
|
||||
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;
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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.
|
||||
*/
|
||||
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;
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user