@@ -404,13 +404,12 @@ def _reset(self, something):
404404 # Wrap an incoming bytes string into a stream. If the passed bytes
405405 # string is so large that the overhead of copying it into a
406406 # BytesIO is significant, advise caller to pass a stream instead.
407- # BytesIO has no peek() method, so wrap it in BufferedReader.
408- self ._stream = io .BufferedReader (io .BytesIO (something ))
409- elif hasattr (something , 'peek' ):
410- # 'something' is already a buffered stream, use directly
407+ self ._stream = io .BytesIO (something )
408+ elif something .seekable ():
409+ # 'something' is already a seekable stream, use directly
411410 self ._stream = something
412411 else :
413- # 'something' isn't buffered , wrap in BufferedReader
412+ # 'something' isn't seekable , wrap in BufferedReader
414413 # (let BufferedReader handle the problem of passing an
415414 # inappropriate object)
416415 self ._stream = io .BufferedReader (something )
@@ -482,49 +481,23 @@ def _next_nonblank(self):
482481 c = self ._stream .read (1 )
483482 return c
484483
485- def _getc (self , num = 1 ):
484+ def _getc (self , num = 1 , full = True ):
486485 got = self ._stream .read (num )
487- if len (got ) < num :
486+ if full and len (got ) < num :
488487 self ._error ("Trying to read past end of stream" )
489488 return got
490489
491- def _peek (self , num = 1 , full = True ):
492- # full=True means error if we can't peek ahead num bytes
493- if num < 0 :
494- # There aren't many ways this can happen. The likeliest is that
495- # we've just read garbage length bytes from a binary input string.
496- # We happen to know that lengths are encoded as 4 bytes, so back
497- # off by 4 bytes to try to point the user at the right spot.
498- self ._error ("Invalid length field %d" % num , - 4 )
499-
500- # Instead of using self._stream.peek() at all, use read(num) and reset
501- # the read pointer. BufferedReader.peek() does not promise to return
502- # the requested length, but does not clarify the conditions under
503- # which it returns fewer bytes.
504- # https://docs.python.org/3/library/io.html#io.BufferedReader.peek
505- # In practice, we've seen it fail with an input file up over 100Kb:
506- # peek() returns only part of what we requested, but because we also
507- # passed full=False (see LLSDNotationParser._get_re()), we didn't
508- # notice and the parse failed looking for a map delimiter halfway
509- # through a large decimal integer. read(num), on the other hand,
510- # promises to return num bytes until actual EOF.
511- oldpos = self ._stream .tell ()
512- try :
513- got = self ._stream .read (num )
514- if full and len (got ) < num :
515- self ._error ("Trying to peek past end of stream" )
516-
517- return got
518-
519- finally :
520- self ._stream .seek (oldpos )
490+ def _putback (self , cc ):
491+ # if this test fails, it's not a user error, it's a coding error
492+ assert self ._stream .tell () >= len (cc )
493+ self ._stream .seek (- len (cc ), io .SEEK_CUR )
521494
522495 def _error (self , message , offset = 0 ):
523496 oldpos = self ._stream .tell ()
524497 # 'offset' is relative to current pos
525498 self ._stream .seek (offset , io .SEEK_CUR )
526499 raise LLSDParseError ("%s at byte %d: %r" %
527- (message , oldpos + offset , self ._peek (1 , full = False )))
500+ (message , oldpos + offset , self ._getc (1 , full = False )))
528501
529502 # map char following escape char to corresponding character
530503 _escaped = {
0 commit comments