0

我正在尝试以编程方式替换 OFT 文件(Outlook 消息模板)中的嵌入图像,该文件采用复合文件二进制格式(因为使用任何人类可读的东西都会让我的生活变得太容易)。

为了处理这个文件,我使用了 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 当然对此一无所知。

为什么写入较小的流会损坏文件,而写入较大的流可以工作?

更新:

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

在此处输入图像描述

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

在此处输入图像描述

这两个附件之间只有一组 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:

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

4

2 回答 2

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(我们不能这样做)或免费的(我们对此的预算为零)。

于 2014-02-28T20:22:16.660 回答
0

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

于 2014-02-28T00:31:34.400 回答