@@ -465,20 +465,27 @@ def _peek(self, num=1, full=True):
465465 # off by 4 bytes to try to point the user at the right spot.
466466 self ._error ("Invalid length field %d" % num , - 4 )
467467
468- got = self ._stream .peek (num )
469- if full and len (got ) < num :
470- # Going right to this error is a little iffy:
471- # BufferedReader.peek() does not promise to return the requested
472- # length, but does not clarify the conditions under which it
473- # returns fewer bytes. If this is an actual problem, we could loop
474- # until we have the requested length or EOF -- but the loop must
475- # explicitly seek() past already-peeked data, then reset after.
476- # https://docs.python.org/3/library/io.html#io.BufferedReader.peek
477- self ._error ("Trying to peek past end of stream" )
478-
479- # Interestingly, peek() can also return MORE than requested -- but for
480- # our purposes (e.g. ord(peek(1))) it's important to constrain it.
481- return got [:num ]
468+ # Instead of using self._stream.peek() at all, use read(num) and reset
469+ # the read pointer. BufferedReader.peek() does not promise to return
470+ # the requested length, but does not clarify the conditions under
471+ # which it returns fewer bytes.
472+ # https://docs.python.org/3/library/io.html#io.BufferedReader.peek
473+ # In practice, we've seen it fail with an input file up over 100Kb:
474+ # peek() returns only part of what we requested, but because we also
475+ # passed full=False (see LLSDNotationParser._get_re()), we didn't
476+ # notice and the parse failed looking for a map delimiter halfway
477+ # through a large decimal integer. read(num), on the other hand,
478+ # promises to return num bytes until actual EOF.
479+ oldpos = self ._stream .tell ()
480+ try :
481+ got = self ._stream .read (num )
482+ if full and len (got ) < num :
483+ self ._error ("Trying to peek past end of stream" )
484+
485+ return got
486+
487+ finally :
488+ self ._stream .seek (oldpos )
482489
483490 def _error (self , message , offset = 0 ):
484491 oldpos = self ._stream .tell ()
0 commit comments