Parsing 如何解析长度未知的二进制PDF流?

Parsing 如何解析长度未知的二进制PDF流?,parsing,pdf,stream,Parsing,Pdf,Stream,从PDF文档中:“流字典后面的关键字流后面应跟随由回车符和换行符或换行符组成的行尾标记,而不仅仅是回车符。组成流的字节序列位于stream关键字后面的行尾标记和endstream关键字之间流字典指定确切的字节数。“ 由于内容可能是二进制的,endstream的出现不一定表示流的结束。现在考虑此流时: %PDF-1.4 %307쏢 5 0 obj <</Length 6 0 R/Filter /FlateDecode>> stream x234+T03203T0^@A(23

从PDF文档中:“流字典后面的关键字流后面应跟随由回车符和换行符或换行符组成的行尾标记,而不仅仅是回车符。组成流的字节序列位于stream关键字后面的行尾标记和endstream关键字之间流字典指定确切的字节数。

由于内容可能是二进制的,endstream的出现不一定表示流的结束。现在考虑此流时:

%PDF-1.4
%307쏢
5 0 obj
<</Length 6 0 R/Filter /FlateDecode>>
stream
x234+T03203T0^@A(235234˥^_d256220^314^U310^E^@[364^F!endstream
endobj
6 0 obj
30
endobj
%PDF-1.4
%307쏢
50 obj
流动
x234+T03203T0^@A(235234^^^ uD256220^ 314^ U310^ E^-[364^ F!endstream
endobj
60 obj
30
endobj
Length是流后面的间接对象。显然,只有在解析流之后才能读取该长度

我认为,允许长度作为一个间接对象,只有在流之后才能解决,这是一个设计缺陷。虽然它可以帮助PDF编写器按顺序输出PDF,但它使PDF阅读器的解析变得相当困难。考虑到PDF文件的读取频率比写入频率更高,我不理解这一点

那么如何正确解析这样的流呢

Length是流后面的间接对象。显然,只有在解析流之后才能读取该长度

这是一个可以理解的结论,如果我们假设文件从开始到结束都是按顺序读取的

但是,这种假设是不正确的,因为从前端解析PDF并确定运行中的PDF对象不是解析PDF的推荐方法

虽然ISO 32000-1在这里有点含糊,只是说

合格的读者应该从末尾阅读PDF文件

(ISO 32000-1,第7.5.5节)

ISO 32000-2明确规定:

除线性化PDF文件外,所有PDF文件都应使用以下子条款中所述的拖车和交叉参考表读取。以串行方式读取非线性化文件不可靠,因为增量更新后处理对象的方式。(见6.3.2,“PDF处理器的一致性…)

(ISO 32000-2,第7.5节文件结构)

因此,对于您的PDF摘录,PDF处理器试图读取对象
50

  • 在交叉引用中查找对象
    5 0
    ,并在文件中获取其偏移量
  • 转到该偏移量并开始读取对象,首先解析流字典
  • 处,关键字识别对象是流,并检索其长度值,该值恰好是对
    6 0
    的间接引用
  • 在交叉引用中查找对象
    6 0
    ,并在文件中获取其偏移量
  • 转到该偏移量并读取对象,即数字
    30
  • 读取流对象的流内容
    5 0
    ,知道其长度为30
像您这样的方法被明确认为是“不可靠的”


我认为允许长度作为一个间接对象,只有在流之后才能解决,这是一个设计缺陷

如果没有交叉引用,则是正确的。这也是为什么FDF格式(没有强制交叉引用)指定:

FDF基于PDF;它使用相同的语法,基本上具有相同的文件结构(7.5,“文件结构”)。但是,它在以下方面与PDF不同:

[……]

  • 水流长度不得由间接物体规定
(ISO 32000-2第12.7.8节表格数据格式)


关于评论:


我是正确的PDF不能按顺序解析

虽然PDF的最初设计可能是用于顺序解析,但它已经得到了进一步的发展,只考虑了通过交叉引用进行访问。PDF不再是用于顺序解析。当我在90年代末开始处理PDF时,情况已经是这样了

唯一的原因是二进制流的所需长度可以在流之后定义

这不是唯一的原因,还有更多的情况需要交叉引用查找才能正确解析

AS @ MKL指出,解析器必须在PDF文件的末尾读取某处以获得StasxReF,希望它不会在二进制流中间开始解析。

这是不正确的。PDF必须以“%%EOF”结尾,并可选地加上一个行尾。在此之前,必须有一个行尾,在该数字之前,在该行尾之前,在该开始外部参照之前

这已在ISO 32000-1中明确表示:

文件的最后一行应仅包含文件结束标记,%%EOF。前面两行应按顺序每行包含一个关键字startxref,以及解码流中从文件开头到最后交叉引用中xref关键字开头的字节偏移量参考部分

(ISO 32000-1,第7.5.5节)

因此,如果PDF是有效的,就不会有“处于二进制流中间”的危险


PDF格式的另一个我不喜欢的地方是:在开发解析器时,您通常使用正在处理的某些元素创建测试文件。这种方法似乎可以处理除流以外的所有内容。语法元素的绝对文件位置以及对多个随机访问的要求使得这项任务更加困难

您似乎有一种误解,认为PDF格式是一种像HTML一样的带标签的文本格式。事实并非如此。尽管许多语法元素都是使用一些ASCII关键字定义的,并且存在“li”