使用Outlook .OFT文件修改文件附件流的问题

时间:2014-02-28 00:15:17

标签: c# outlook oft openmcdf

我正在尝试以编程方式替换OFT文件(一个Outlook消息模板)中的嵌入图像,该文件位于Compound File Binary Format中(因为使用任何人类可读的东西会让我的生活变得简单)。

要使用此文件,我正在使用OpenMCDF

由于嵌入的图像基本上是文件附件,我可以像这样得到图像的流:

static string FOOTER_IMG = "__substg1.0_37010102"; //Stream ID for embedded JPEG footer image
static string ATTACHMENT2 = "__attach_version1.0_#00000001"; //Storage ID for attached footer image
// ...
CFStream imgStream2 = file.RootStorage.GetStorage(ATTACHMENT2).GetStream(FOOTER_IMG);

然后,我可以使用所需图像中的字节更新该流,如下所示:

byte[] img2 = File.ReadAllBytes(footerimgFile); // New file
imgStream2.SetData(img2);

但是,当我在Outlook中加载.OFT文件时,图像不再加载,我得到一个红色X表示无法加载图像。我花了几个小时来分析那个OFT文件的每一个部分,而原始模板和新模板之间改变的是我替换的一个流。

以下事情变得奇怪:

我注意到我可以用之前相同的字节替换字节并保存它,所以我的保存机制正在运行。我想也许OFT模板存储了必须匹配的图像的某种散列。所以我修改了一些随机字节,图像仍然加载(有时带有一些时髦的颜色)。最终,我意识到如果新图像包含的字节少于原始图像,则会中断。我可以用更大的图像替换图像, 可以工作!我也可以在流的末尾填充一个尾随零的较小图像,它仍然可以工作。

这让我想出了一个真正的黑客杰作:

if (img2.Length < 5585) img2 = img2.Concat(new byte[5585 - img2.Length]).ToArray();

基本上,如果img2太小,我会填充足够的字节,使其与原始图像的大小相同(确切地说是5585字节)。这样可行。但是......是的。

我的问题:

Microsoft OFT文件格式是否存储某些其他流或其他CDF容器中附件的字节数?如果这是CDF的标准属性,您会认为OpenMCDF会更新此计数。这让我相信这是OFT文件格式的属性,OpenMCDF当然对此一无所知。

为什么写一个较小的流会破坏文件,写一个更大的流工作?

更新

从我read so far开始,__properties_version1.0流包含一个指针列表(偏移?),以标记各种其他流的位置。我猜这里的东西需要更新。目前,我在附件容器中有这些流:

enter image description here

据我所知__properties_version1.0在第一个附件(36,463字节文件)和第二个附件(5,585字节文件)之间几乎没有变化。第二个附件的__properties_version1.0是:

enter image description here

这两个附件之间只有一组8个字节可以更改。在附件1中,我们有:

  
    

6F 8E 00 00 03 00 2D 00

  

在附件2(如上图所示)中,我们有:

  
    

D1 15 00 00 03 00 6F 08

  

那些补偿吗?似乎不是一个范围,或者数字会上升。那些数字也方式太大而不适合文件大小。另外,无论如何,在这里存储文件大小似乎是多余的。所以,我再次不知道为什么更改0x37010102流的大小会导致图像不再加载。

另一件毫无意义的事情。我可以用更大或更小的文件更改第一个附件的大小,并且没有任何中断。但是,除了 0x37010102流中的数据之外,这两个容器中的任何流都没有区别。为什么这种方法适用于一种附件而不适用于另一种附件?

更新2:

我注意到两个附件之间的__properties_version1.0流中的两个差异确实对应于文件大小:

6F 8E 00 00 03 00 2D 00 // Attachment 1
D1 15 00 00 03 00 6F 08 // Attachment 2

6F 8E似乎是文件大小的小端表示,因为十进制中的8E6F将是36463,这是第一个附件中的字节数。十进制的15D1是5585,第二个附件的大小。所以,这个流肯定是存储文件大小。现在看看如果文件没有损坏,我修复那些字节。

更新3:

因此,更改这些字节修复以前损坏的文件,这就是关键!现在只是为了找到一种以编程方式执行此操作的方法。

2 个答案:

答案 0 :(得分:0)

您是使用嵌入式HTML图像(只是常规图像附件)还是嵌入式RTF图像(哪种OLE存储)? 您是否只是在不调整任何其他属性的情况下截断特定流?

答案 1 :(得分:0)

嗯,就像这样的时候我觉得自己像一个超级书呆子。这是解决问题的代码。请注意,如果附件中有其他属性,propBytes中的字节偏移可能会有所不同。

// Fix file size on prop stream
var propStream = file.RootStorage.GetStorage(ATTACHMENT2).GetStream("__properties_version1.0");
var propBytes = propStream.GetData();
propBytes[0xb0] = (byte)(img2.Length & 0xFF);
propBytes[0xb1] = (byte)(img2.Length >> 8);
propStream.SetData(propBytes);

但是,我喜欢这个解决方案比填充额外的零更好。

我认为真正的解决方案是使用处理.MSG格式的第三方库,但是我找不到任何不能让你安装Outlook或Exchange的服务器(我们不能做)或免费(我们没有预算)。