来自PDF文档:“在流字典后面的关键字流后面应跟一个行尾标记,该标记由CARRIAGE RETURN和LINE FEED组成,或者只是一个LINE FEED,而不是单独的CARRIAGE RETURN。组成流的字节序列位于stream关键字后面的行尾标记和endstream关键字之间; 流字典指定确切的字节数。 < / EM>“
由于内容可能是二进制,因此 endstream 的出现不一定表示流的结束。现在考虑这个流:
[B, None, None, 3]
长度是跟随流的间接对象。显然,只有在解析了流之后才能读取。
我认为允许Length是一个间接对象,只能在流之后解析是一个设计缺陷。虽然它可以帮助PDF编写者按顺序输出PDF,但它使得PDF阅读器的解析非常困难。考虑到PDF文件的阅读频率高于写入,我不明白这一点。
那么如何才能正确解析这样的流?
答案 0 :(得分:2)
长度是跟随流的间接对象。 显然,只有在解析了流之后才能读取长度。
你叫什么&#34;显而易见&#34;是完全错的。
因为从前面解析PDF并在运行中确定PDF对象不是解析PDF的推荐方法。
虽然ISO 32000-1在这里有点模糊,但只是说
合规读者应从其末尾阅读PDF文件。
(ISO 32000-1,第7.5.5节文件预告片)
ISO 32000-2明确规定:
除线性化PDF文件外,应使用预告片和交叉引用表读取所有PDF文件,如以下子条款所述。以串行方式读取非线性化文件是不可靠的,因为在增量更新之后处理对象的方式。 (参见6.3.2,&#34; PDF处理器的符合性和#34;。)
(ISO 32000-2,第7.5节文件结构)
因此,如果您的PDF摘录,PDF处理器试图读取对象5 0
5 0
并在文件中获取其偏移量stream
关键字处识别出该对象是一个流并检索其长度值,该值恰好是对6 0
的间接引用,
6 0
并在文件中获取其偏移量30
,5 0
的流内容,知道其长度为30。您的方法被明确考虑并且#34;不可靠&#34;。
我认为允许Length是一个间接对象,只能在流是设计缺陷后解析。
如果没有交叉引用,那么您是对的。这也是FDF格式(没有强制交叉引用)指定的原因:
FDF基于PDF;它使用相同的语法,并且具有基本相同的文件结构(7.5,&#34;文件结构&#34;)。但是,它在以下方面与PDF不同:
[...]
- 流的长度不应由间接对象指定。
(ISO 32000-2,第12.7.8节表格数据格式)
关于评论:
所以我确定无法按顺序解析PDF,
尽管PDF的原始设计可能是用于顺序解析,但它已经进一步开发,只考虑通过交叉引用访问。 PDF根本不打算再顺序解析。当我在90年代后期开始处理PDF时就已经是这种情况。
唯一的原因是可以在流之后定义所需的二进制流长度。
到目前为止,这不是唯一的原因,还有更多情况需要交叉引用查找才能正确解析。
正如@mkl指出的那样,解析器必须在PDF文件结束之前的某处读取以获取startxref,希望它不会在二进制流的中间开始解析。
这不正确。 PDF必须以&#34; %% EOF&#34;结尾?加上可选的行尾。在此之前,必须有一个行尾,在该行之前是一个数字,在该行结束之前,在startxref之前。
这已在ISO 32000-1中明确表达:
文件的最后一行应仅包含文件结束标记 %% EOF 。前两行应包含,每行一个顺序,关键字 startxref 和解码流中从文件开头到外部参照最后一个交叉引用部分中的>关键字。
(ISO 32000-1,第7.5.5节文件预告片)
因此,没有在二进制流中间存在的危险&#34;如果PDF有效。
我不喜欢PDF格式的另一个原因是:在开发解析器时,通常会创建包含您正在处理的元素的测试文件。这种方法似乎适用于除流之外的所有方法。语法元素的绝对文件位置和多个随机访问的要求使这项任务更加困难。
您似乎误以为PDF格式是HTML格式的标记文本格式。不是这种情况。尽管使用某些ASCII关键字定义了许多语法元素并且有&#34;行&#34;,PDF是二进制格式,交叉引用表不是噱头,而是对象的中央访问中心,以及随机优化访问是通过设计完成的。