浅析doc(word)格式文件内部结构

来源:互联网 发布:网络名誉侵权案例分析 编辑:程序博客网 时间:2024/06/06 01:56
以下是在处理 .doc 文件时必须了解的一些最重要的结构。
  • 2.1.1 WordDocument Stream

    Word 文档流是 .doc 文件中的主要流,其中包含文件中的所有数据(表格除外,表格存储在 1Table stream or 0Table stream中)。

    • File Information Block

      文件信息块从 Word 文档流的偏移 0x00 开始。它指定文件中所有其他数据的位置。位置由一对整数指定,第一个整数指定位置,第二个整数指定大小。这些整数出现在文件信息块的子结构中,如FibRgFcLcb97。位置名称带有前缀 fc。大小名称带有前缀 lcb。

    • Clx 结构

      Clx 结构是由零个或多个 Prc 结构组成的包含属性信息的数组,后跟一个 Pcdt 结构,该结构又包含一个 PlcPcd 结构。

  • Character

    字符可以是文本字符或非文本字符(如段落标记或对象锚点)。其大小可能因它是 ANSII、Unicode 还是控制字符而异。文档中的相邻字符在二进制文件中不一定相邻。

    • Character Position (CP)

      字符位置 (CP) 是一个无符号的 32 位整数,它给出字符在文档文本中的索引位置。

    • Pcd 结构

      Pcd 结构指定文本在 Word 文档流中的位置,同时指定文本的一些属性。

  • Plc

    PLC 结构是一个 CP 数组,后跟一个数据元素数组。不同的 Plc 结构具有不同的名称和功能,例如 Plcbkf 结构,它由书签和指向书签的指针组成。

  • PlcPcd 结构

    PlcPcd 结构是一个 PLC 结构,它将一个 CP 数组映射到 Pcd 结构。换言之,它将流中的字符位置映射到文档文本中的字符。

从 Word 文件提取文本

用于检索文本的正式算法在 MSDN 上开放规范文档中的 2.4.1 Retrieving Text下发布,并且在"示例"部分的 3.1 Example of a Clx下给出了一个介绍部分过程的示例。以下是该过程的简化版本。

从 Word 文档提取文本

  1. 将 .doc 文件读入数据流。

  2. 开始在 Word 文档流的偏移 0 处读取文件信息块 (FIB)。有关详细信息,请参阅 2.5.15 How to read the FIB

  3. 在文件信息块内,找到 FibRgFcLcb97 结构。此结构从 FIB 的第 154 个字节开始。它由一系列的 4 字节字段组成。

  4. 在第 268 个字节处读取 FibRgFcLcb97.fcClx 字段,在第 272 个字节处读取 FibRgFcLcb97.lcbClx 字段。这些字段指定 Clx 的偏移位置和大小。

  5. 在 FibRgFcLcb97.fcClx 字段指定的偏移处开始从表格流中读取 Clx 结构。

  6. 在 Clx 结构内,找到 Pcdt,其后紧跟可变长度的 Prc 结构的 .RgPrc 数组

    对于数组中的每个成员:

    1. 读取 .clxt 属性,该属性是 Prc 结构的 0 字节。如果 .clxt = 0x02,表明您已找到 Pcdt。

    2. 如果 .clxt = 0x01,读取后面 2 个字节作为有符号整数,然后跳过该数量的字节来到数组的下一成员。

  7. 在 Pcdt 结构内,找到 PlcPcd 结构,该结构从 Pcdt 的第 5 个字节开始。

  8. 加载 PlcPcd.aPcd 数组和 PlcPcd.aCp 数组。这些数组的成员通过索引值彼此对应。

  9. 对于 PlcPcd.aPcd 中的每个 Pcd 结构:

    1. 在当前 Pcd 结构的第 46 位处读取 Pcd.Fc.fCompressed 字段的值。如果为 0,则 Pcd 结构指代一个 16 位的 Unicode 字符。如果为 1,则指代一个 8 位的 ANSI 字符。

    2. 读取 Pcd.Fc 的值(当前 Pcd 的第 2-5 个字节)以及相应的 CP 值。

      • 如果是 Unicode,则位于当前 CP 值所指定的字符位置处的文本的起始偏移量等于在 Word 文档流中的 Pcd.Fc 值,且每个字符占两个字节。

      • 如果是 ANSI,则位于当前 CP 处的文本开始于 Pcd.Fc 值的一半的偏移量处,且每个字符占一个字节。

      在任一种情况下,当前 CP 指定的字符数都等于数组中下一个 CP 的值减去当前 CP 的值。

Word文件结构

1.1 Word文件结构  
  一个Word文件至少包括主流(Main   stream)和表流(Table   stream)两个流。其实这两个流就涵盖了Word中的大部分数据。主流中包括了所有文字,标格以及他们的属性。表流中含有样式,字体信息等。我们的工作主要关心Word文件中的文本内容,而文本的字体信息,样式等相对并不重要。因此,将主要关注主流(Main   stream)所包含的主要内容和存储格式。  
  以下是一些关于文件格式的一些术语:  
   页(Page):Word文件主流中开始于512字节边界的长度为512字节的文本段(字节0-511为0页,字节512-1023为1页,等)。在Word文件的数据结构中用两子介无符号整形PN(Page   Number)来表示页码。  
   字符位置CP   (Character   Position):四字节整数表示文件中字符在文本流中的逻辑坐标。  
   文件字符位置FC(   File   Character   position):四字节整数表示从文件开始处计算的字符位置。CP可以转化为FC,字符的FC=文本流开始处的FC+字符的CP。  
   文件头FIB   (File   Information   Block):位于Word文件的开始,记录了文本流的开始位置(FIB.fcMin),文本流的长度和文件状态等信息。  
   段(Paragraph):文本流中由段标记,标格标记,行标记分隔的连续的字符序列。  
   段属性PAP   (PAragraph   Properties):此数据结构描述了某一特定段的属性。  
   段属性偏移PAPX   (PAragraph   Property   EXception):此数据结构描述了某一特定段的属性与标准段属性相比的偏移。通过段属性偏移和标准段属性可以计算具体段的段属性。(本课题中主要关心段是否是表格和标题等属性)。  
   格式化磁盘存储页FKP   (Formatted   disK   Page):512字节的数据结构(占据一页),存储了Word文件中某部分段或字符的属性(本课题只关心段属性,以下只就段格式化磁盘存储页PFKP讨论),包含四部分:  
  1) 此页所描述的段的数量。  
  2) 存储FC的数组,按FC的升序排列,相邻的FC表示段的开始和结尾。  
  在PFKP中,   数据结构BX数组,BX[]中包含段的一般属性和对应段的PAPX位置---相应于该页起始位置的字偏移量(Word   Offset)。段属性偏移量。  
   
  Word文件整体结构复杂,有大量修饰性信息,下面主要列出了与读取文件中文本内容有关的数据存储格式(注:Word文件存储的前512字节不计算在内)。  
  主流;  
  开始FC=0,PN=0  
  内容 起始FC 长度  
  文件头FIB 0 <1024  
  文本(包括表格文字) FIB.fcMin FIB.ccpText  
  其余文本内容 FIB.fcMin+FIB.ccpText 结束于FIB.fcMac  
  格式化磁盘存储页 FIB.pnPapFirst 随文件长度变化  

  文件头FIB:  
  内容 起始FC 长度  
  文本流开始Fcmin 24 4  
  文本流结束Fcmac 28 4  
  主文本长度CcpText 76 4  
  脚注长度CcpFtn 80 4  
  子文档头长度CcpHdd 84 4  
  注释文本长度   CcpAtn 92 4  
  文本框文本长度CcpTxbx 100 4  
  第一个PAPX   FKP的页码数 124 4  
  所有PAPX   FKP的个数 128 4  

  文本流:  
  开始于FIB.fcMin,一般开始于FIB结束后的128的整数倍FC处。  
  1)   Word文件中的文本流采用ASCII和Unicode编码混合存储,其中纯英文文档采用ASCII编码存储,纯中文文档采用Unicode编码混合存储。而中英文混合文档中按照如下规则编码存储:  
  &#61548; 以页(512字节)为单位,即每一页的编码方式相同。  
  &#61548; 所有中文部分采用Unicode编码。  
  &#61548; 英文优先采用ASCII编码,当与中文在同一页时采用Unicode编码。  
  &#61548; 从页起始位置开始连续大于256字节英文序列采用ASCII编码,不足一页部分用0填补。  
  混合编码虽然给文本读取带来很大的麻烦,但既发挥了Unicode编码的好处,又节省了存储空间。  
  2)   以下是住文本流中的一些特殊符号:  
  符号 ASCII编码 Unicode编码  
  段结尾(Paragraph   End) 13 13   00  
  行分隔(Hard   Line   Break) 11 11   00  
  分隔连接符(Break   Hyphen) 45 45   00  
  空白符(Space) 32 32   00  
  制表符(Tab) 09 09   00  
  页分隔(Page   Break) 12 12   00  
  单元格标记(Cell   Mark) 07 07   00  
  表格行结束标记(Table   End   Mark) 07 07   00  

  3)文本流中存储了Word文件中所有的文本内容,包括主文本内容,脚注,尾注,文本框内文本等。下表是计算相应内容存储位置的算法:  
  内容 计算方法  
  主文本内容 Fib.fcMin  
  脚注(Footnote) Fib.fcMin+Fib.ccpText(注)  
  子文档头部  
  (Header   of   Subdocument) Fib.fcMin+Fib.ccpText+Fib.ccpFtn  
  注释子文档  
  (Annotation   Subdocument) Fib.fcMin+Fib.ccpText+Fib.ccpFtn+Fib.ccpHdr  
  尾注(Endnote) Fib.fcMin+Fib.ccpText  
  +Fib.ccpFtn+Fib.ccpHdr+Fib.ccpAtn  
  文本框文本(Textbox) Fib.fcMin+Fib.ccpText  
  +Fib.ccpFtn+Fib.ccpHdr+Fib.ccpAtn+Fib.ccpEdn  
  文本框头部(header   of   Textbox) Fib.fcMin+Fib.ccpText+Fib.ccpFtn+  
  Fib.ccpHdr+Fib.ccpAtn+Fib.ccpEdn+Fib.ccpTxbx  
  表4-4:Word文件格式中各个段落的起始位置  
  注:Fib.ccpText表示字的个数,实际应用时应该计算出字节数。  
  段格式化磁盘存储页(PAPX   FKP):  
  开始位置:Fib.pnPapFirst,与其他FKP交叉轮流存储。  
  PAPX   FKP的存储格式  
  位置 内容 说明  
  0 FC数组 段的起始和终结位置,共有crun+1个  
  4*(fkp.crun+1) BX数组 BX[0]为对应段的PAPX存储位置(偏移)  
  511-sizeof(grppapx) PAPX组 段的属性偏移  
  511 段个数(crun) 此FKP中所描述的段的个数 


结论

本文只是 MS-DOC 格式的一个样本。借助本文提供的工具,您可以进行简单的数据恢复。经过进一步研究后,您可以开始恢复格式信息和其他元数据,并最终执行"保存"操作。

参考链接:https://msdn.microsoft.com/zh-cn/library/office/gg615596%28v=office.14%29.aspx

http://wenku.baidu.com/link?url=P0-17H63-2qhLGcGAoMNVRRmOVNrqDPOktv3J18ZREzmuy1ITvoF_IL6yp29sfWeuqly48iVOSITJV0A4lnzvKvhxoUKY7nV24ZinbZs-Im

1 0