| 2510 | return buffer |
| 2511 | |
| 2512 | def seek(self, cookie, whence=0): |
| 2513 | def _reset_encoder(position): |
| 2514 | """Reset the encoder (merely useful for proper BOM handling)""" |
| 2515 | try: |
| 2516 | encoder = self._encoder or self._get_encoder() |
| 2517 | except LookupError: |
| 2518 | # Sometimes the encoder doesn't exist |
| 2519 | pass |
| 2520 | else: |
| 2521 | if position != 0: |
| 2522 | encoder.setstate(0) |
| 2523 | else: |
| 2524 | encoder.reset() |
| 2525 | |
| 2526 | if self.closed: |
| 2527 | raise ValueError("tell on closed file") |
| 2528 | if not self._seekable: |
| 2529 | raise UnsupportedOperation("underlying stream is not seekable") |
| 2530 | if whence == SEEK_CUR: |
| 2531 | if cookie != 0: |
| 2532 | raise UnsupportedOperation("can't do nonzero cur-relative seeks") |
| 2533 | # Seeking to the current position should attempt to |
| 2534 | # sync the underlying buffer with the current position. |
| 2535 | whence = 0 |
| 2536 | cookie = self.tell() |
| 2537 | elif whence == SEEK_END: |
| 2538 | if cookie != 0: |
| 2539 | raise UnsupportedOperation("can't do nonzero end-relative seeks") |
| 2540 | self.flush() |
| 2541 | position = self.buffer.seek(0, whence) |
| 2542 | self._set_decoded_chars('') |
| 2543 | self._snapshot = None |
| 2544 | if self._decoder: |
| 2545 | self._decoder.reset() |
| 2546 | _reset_encoder(position) |
| 2547 | return position |
| 2548 | if whence != 0: |
| 2549 | raise ValueError("unsupported whence (%r)" % (whence,)) |
| 2550 | if cookie < 0: |
| 2551 | raise ValueError("negative seek position %r" % (cookie,)) |
| 2552 | self.flush() |
| 2553 | |
| 2554 | # The strategy of seek() is to go back to the safe start point |
| 2555 | # and replay the effect of read(chars_to_skip) from there. |
| 2556 | start_pos, dec_flags, bytes_to_feed, need_eof, chars_to_skip = \ |
| 2557 | self._unpack_cookie(cookie) |
| 2558 | |
| 2559 | # Seek back to the safe start point. |
| 2560 | self.buffer.seek(start_pos) |
| 2561 | self._set_decoded_chars('') |
| 2562 | self._snapshot = None |
| 2563 | |
| 2564 | # Restore the decoder to its state from the safe start point. |
| 2565 | if cookie == 0 and self._decoder: |
| 2566 | self._decoder.reset() |
| 2567 | elif self._decoder or dec_flags or chars_to_skip: |
| 2568 | self._decoder = self._decoder or self._get_decoder() |
| 2569 | self._decoder.setstate((b'', dec_flags)) |