| 2486 | return buffer |
| 2487 | |
| 2488 | def seek(self, cookie, whence=0): |
| 2489 | def _reset_encoder(position): |
| 2490 | """Reset the encoder (merely useful for proper BOM handling)""" |
| 2491 | try: |
| 2492 | encoder = self._encoder or self._get_encoder() |
| 2493 | except LookupError: |
| 2494 | # Sometimes the encoder doesn't exist |
| 2495 | pass |
| 2496 | else: |
| 2497 | if position != 0: |
| 2498 | encoder.setstate(0) |
| 2499 | else: |
| 2500 | encoder.reset() |
| 2501 | |
| 2502 | if self.closed: |
| 2503 | raise ValueError("tell on closed file") |
| 2504 | if not self._seekable: |
| 2505 | raise UnsupportedOperation("underlying stream is not seekable") |
| 2506 | if whence == SEEK_CUR: |
| 2507 | if cookie != 0: |
| 2508 | raise UnsupportedOperation("can't do nonzero cur-relative seeks") |
| 2509 | # Seeking to the current position should attempt to |
| 2510 | # sync the underlying buffer with the current position. |
| 2511 | whence = 0 |
| 2512 | cookie = self.tell() |
| 2513 | elif whence == SEEK_END: |
| 2514 | if cookie != 0: |
| 2515 | raise UnsupportedOperation("can't do nonzero end-relative seeks") |
| 2516 | self.flush() |
| 2517 | position = self.buffer.seek(0, whence) |
| 2518 | self._set_decoded_chars('') |
| 2519 | self._snapshot = None |
| 2520 | if self._decoder: |
| 2521 | self._decoder.reset() |
| 2522 | _reset_encoder(position) |
| 2523 | return position |
| 2524 | if whence != 0: |
| 2525 | raise ValueError("unsupported whence (%r)" % (whence,)) |
| 2526 | if cookie < 0: |
| 2527 | raise ValueError("negative seek position %r" % (cookie,)) |
| 2528 | self.flush() |
| 2529 | |
| 2530 | # The strategy of seek() is to go back to the safe start point |
| 2531 | # and replay the effect of read(chars_to_skip) from there. |
| 2532 | start_pos, dec_flags, bytes_to_feed, need_eof, chars_to_skip = \ |
| 2533 | self._unpack_cookie(cookie) |
| 2534 | |
| 2535 | # Seek back to the safe start point. |
| 2536 | self.buffer.seek(start_pos) |
| 2537 | self._set_decoded_chars('') |
| 2538 | self._snapshot = None |
| 2539 | |
| 2540 | # Restore the decoder to its state from the safe start point. |
| 2541 | if cookie == 0 and self._decoder: |
| 2542 | self._decoder.reset() |
| 2543 | elif self._decoder or dec_flags or chars_to_skip: |
| 2544 | self._decoder = self._decoder or self._get_decoder() |
| 2545 | self._decoder.setstate((b'', dec_flags)) |