3030__author_email__ = "biziqe@mathieu.fenniak.net"
3131
3232import logging
33+ import os
3334import re
3435import sys
3536from collections .abc import Iterable , Sequence
@@ -537,22 +538,34 @@ def _get_next_object_position(
537538 ) -> int :
538539 out = position_end
539540 for generation in generations :
540- location = pdf .xref [generation ]
541- values = [x for x in location .values () if position_before < x <= position_end ]
542- if values :
543- out = min (out , * values )
541+ for x in pdf .xref [generation ].values ():
542+ if position_before < x <= position_end :
543+ out = min (out , x )
544544 return out
545545
546546 @classmethod
547547 def _read_unsized_from_stream (
548- cls , stream : BinaryStreamType , pdf : PdfReaderProtocol
548+ cls , * , stream : BinaryStreamType , pdf : PdfReaderProtocol , length : int ,
549549 ) -> bytes :
550- object_position = cls ._get_next_object_position (
551- position_before = stream .tell (), position_end = 2 ** 32 , generations = list (pdf .xref ), pdf = pdf
552- ) - 1
553550 current_position = stream .tell ()
551+
552+ # Determine stream size.
553+ try :
554+ stream .seek (0 , os .SEEK_END )
555+ stream_length = stream .tell ()
556+ finally :
557+ stream .seek (current_position )
558+
559+ object_position = cls ._get_next_object_position (
560+ position_before = current_position , position_end = stream_length , generations = list (pdf .xref ), pdf = pdf
561+ )
562+
563+ bytes_to_read = object_position - current_position
564+ if bytes_to_read >= length :
565+ raise LimitReachedError (f"Requested length of { bytes_to_read } exceeds maximum allowed length." )
566+
554567 # Read until the next object position.
555- read_value = stream .read (object_position - stream . tell () )
568+ read_value = stream .read (bytes_to_read )
556569 endstream_position = read_value .find (b"endstream" )
557570 if endstream_position < 0 :
558571 raise PdfReadError (
@@ -661,15 +674,16 @@ def read_from_stream(
661674 if length is None : # if the PDF is damaged
662675 length = - 1
663676 pstart = stream .tell ()
677+
678+ from ..filters import MAX_DECLARED_STREAM_LENGTH # noqa: PLC0415
664679 if length >= 0 :
665- from ..filters import MAX_DECLARED_STREAM_LENGTH # noqa: PLC0415
666680 if length > MAX_DECLARED_STREAM_LENGTH :
667681 raise LimitReachedError (f"Declared stream length of { length } exceeds maximum allowed length." )
668682
669683 data ["__streamdata__" ] = stream .read (length )
670684 else :
671685 data ["__streamdata__" ] = read_until_regex (
672- stream , re .compile (b"endstream" )
686+ stream = stream , regex = re .compile (b"endstream" ), length = MAX_DECLARED_STREAM_LENGTH ,
673687 )
674688 e = read_non_whitespace (stream )
675689 ndstream = stream .read (8 )
@@ -688,7 +702,9 @@ def read_from_stream(
688702 data ["__streamdata__" ] = data ["__streamdata__" ][:- 1 ]
689703 elif pdf is not None and not pdf .strict :
690704 stream .seek (pstart , 0 )
691- data ["__streamdata__" ] = DictionaryObject ._read_unsized_from_stream (stream , pdf )
705+ data ["__streamdata__" ] = DictionaryObject ._read_unsized_from_stream (
706+ stream = stream , pdf = pdf , length = MAX_DECLARED_STREAM_LENGTH
707+ )
692708 pos = stream .tell ()
693709 else :
694710 stream .seek (pos , 0 )
@@ -1190,6 +1206,7 @@ class ContentStream(DecodedStreamObject):
11901206 * when .set_data() is called, ._operations is set to None.
11911207 * when .operations is set, ._data is set to None.
11921208 """
1209+ _OPERATOR_LENGTH_LIMIT = 128
11931210
11941211 def __init__ (
11951212 self ,
@@ -1349,7 +1366,9 @@ def _parse_content_stream(self, stream: StreamType) -> None:
13491366 break
13501367 stream .seek (- 1 , 1 )
13511368 if peek .isalpha () or peek in (b"'" , b'"' ):
1352- operator = read_until_regex (stream , NameObject .delimiter_pattern )
1369+ operator = read_until_regex (
1370+ stream = stream , regex = NameObject .delimiter_pattern , length = self ._OPERATOR_LENGTH_LIMIT
1371+ )
13531372 if operator == b"BI" :
13541373 # begin inline image - a completely different parsing
13551374 # mechanism is required, of course... thanks buddy...
0 commit comments