我为此添加了一些必要的功能到 POI 和一个单元测试,它提取可以在 Outlook 中打开的嵌入式 MSG。命名 id 属性的处理可能不完整(这与验证我的增强功能的单元测试无关)。
https://svn.apache.org/viewvc/poi/trunk/src/scratchpad/testcases/org/apache/poi/hsmf/TestExtractEmbeddedMSG.java?view=markup
单元测试示例:
获取附加的味精
MAPIMessage attachedMsg = attachments[0].getEmbeddedMessage();
重建附加味精的方法
private POIFSFileSystem rebuildFromAttached(MAPIMessage attachedMsg) throws IOException {
// Create new MSG and copy properties.
POIFSFileSystem newDoc = new POIFSFileSystem();
MessagePropertiesChunk topLevelChunk = new MessagePropertiesChunk(null);
// Copy attachments and recipients.
int recipientscount = 0;
int attachmentscount = 0;
for (Entry entry : attachedMsg.getDirectory()) {
if (entry.getName().startsWith(RecipientChunks.PREFIX)) {
recipientscount++;
DirectoryEntry newDir = newDoc.createDirectory(entry.getName());
for (Entry e : ((DirectoryEntry) entry)) {
EntryUtils.copyNodeRecursively(e, newDir);
}
} else if (entry.getName().startsWith(AttachmentChunks.PREFIX)) {
attachmentscount++;
DirectoryEntry newDir = newDoc.createDirectory(entry.getName());
for (Entry e : ((DirectoryEntry) entry)) {
EntryUtils.copyNodeRecursively(e, newDir);
}
}
}
// Copy properties from properties stream.
MessagePropertiesChunk mpc = attachedMsg.getMainChunks().getMessageProperties();
for (Map.Entry<MAPIProperty, PropertyValue> p : mpc.getRawProperties().entrySet()) {
PropertyValue val = p.getValue();
if (!(val instanceof ChunkBasedPropertyValue)) {
MAPIType type = val.getActualType();
if (type != null && type != Types.UNKNOWN) {
topLevelChunk.setProperty(val);
}
}
}
// Create nameid entries.
DirectoryEntry nameid = newDoc.getRoot().createDirectory(NameIdChunks.NAME);
// GUID stream
nameid.createDocument(PropertiesChunk.DEFAULT_NAME_PREFIX + "00020102", new ByteArrayInputStream(new byte[0]));
// Entry stream
nameid.createDocument(PropertiesChunk.DEFAULT_NAME_PREFIX + "00030102", new ByteArrayInputStream(new byte[0]));
// String stream
nameid.createDocument(PropertiesChunk.DEFAULT_NAME_PREFIX + "00040102", new ByteArrayInputStream(new byte[0]));
// Base properties.
// Attachment/Recipient counter.
topLevelChunk.setAttachmentCount(attachmentscount);
topLevelChunk.setRecipientCount(recipientscount);
topLevelChunk.setNextAttachmentId(attachmentscount);
topLevelChunk.setNextRecipientId(recipientscount);
// Unicode string format.
byte[] storeSupportMaskData = new byte[4];
PropertyValue.LongPropertyValue storeSupportPropertyValue = new PropertyValue.LongPropertyValue(MAPIProperty.STORE_SUPPORT_MASK,
MessagePropertiesChunk.PROPERTIES_FLAG_READABLE | MessagePropertiesChunk.PROPERTIES_FLAG_WRITEABLE,
storeSupportMaskData);
storeSupportPropertyValue.setValue(0x00040000);
topLevelChunk.setProperty(storeSupportPropertyValue);
topLevelChunk.setProperty(new PropertyValue(MAPIProperty.HASATTACH,
MessagePropertiesChunk.PROPERTIES_FLAG_READABLE | MessagePropertiesChunk.PROPERTIES_FLAG_WRITEABLE,
attachmentscount == 0 ? new byte[] { 0 } : new byte[] { 1 }));
// Copy properties from MSG file system.
for (Chunk chunk : attachedMsg.getMainChunks().getChunks()) {
if (!(chunk instanceof MessagePropertiesChunk)) {
String entryName = chunk.getEntryName();
String entryType = entryName.substring(entryName.length() - 4);
int iType = Integer.parseInt(entryType, 16);
MAPIType type = Types.getById(iType);
if (type != null && type != Types.UNKNOWN) {
MAPIProperty mprop = MAPIProperty.createCustom(chunk.getChunkId(), type, chunk.getEntryName());
ByteArrayOutputStream data = new ByteArrayOutputStream();
chunk.writeValue(data);
PropertyValue pval = new PropertyValue(mprop, MessagePropertiesChunk.PROPERTIES_FLAG_READABLE
| MessagePropertiesChunk.PROPERTIES_FLAG_WRITEABLE, data.toByteArray(), type);
topLevelChunk.setProperty(pval);
}
}
}
topLevelChunk.writeProperties(newDoc.getRoot());
return newDoc;
}
重建附加的味精
try (POIFSFileSystem extractedAttachedMsg = rebuildFromAttached(attachedMsg)) {
try (ByteArrayOutputStream extractedAttachedMsgOut = new ByteArrayOutputStream()) {
extractedAttachedMsg.writeFilesystem(extractedAttachedMsgOut);
byte[] extratedAttachedMsgRaw = extractedAttachedMsgOut.toByteArray();
// this byte array can be persisted to disk and opened in MS Outlook
}
}
问候, 多米尼克