| 1076 | return self._read_unlocked(size) |
| 1077 | |
| 1078 | def _read_unlocked(self, n=None): |
| 1079 | nodata_val = b"" |
| 1080 | empty_values = (b"", None) |
| 1081 | buf = self._read_buf |
| 1082 | pos = self._read_pos |
| 1083 | |
| 1084 | # Special case for when the number of bytes to read is unspecified. |
| 1085 | if n is None or n == -1: |
| 1086 | self._reset_read_buf() |
| 1087 | if hasattr(self.raw, 'readall'): |
| 1088 | chunk = self.raw.readall() |
| 1089 | if chunk is None: |
| 1090 | return buf[pos:] or None |
| 1091 | else: |
| 1092 | return buf[pos:] + chunk |
| 1093 | chunks = [buf[pos:]] # Strip the consumed bytes. |
| 1094 | current_size = 0 |
| 1095 | while True: |
| 1096 | # Read until EOF or until read() would block. |
| 1097 | chunk = self.raw.read() |
| 1098 | if chunk in empty_values: |
| 1099 | nodata_val = chunk |
| 1100 | break |
| 1101 | current_size += len(chunk) |
| 1102 | chunks.append(chunk) |
| 1103 | return b"".join(chunks) or nodata_val |
| 1104 | |
| 1105 | # The number of bytes to read is specified, return at most n bytes. |
| 1106 | avail = len(buf) - pos # Length of the available buffered data. |
| 1107 | if n <= avail: |
| 1108 | # Fast path: the data to read is fully buffered. |
| 1109 | self._read_pos += n |
| 1110 | return buf[pos:pos+n] |
| 1111 | # Slow path: read from the stream until enough bytes are read, |
| 1112 | # or until an EOF occurs or until read() would block. |
| 1113 | chunks = [buf[pos:]] |
| 1114 | wanted = max(self.buffer_size, n) |
| 1115 | while avail < n: |
| 1116 | chunk = self.raw.read(wanted) |
| 1117 | if chunk in empty_values: |
| 1118 | nodata_val = chunk |
| 1119 | break |
| 1120 | avail += len(chunk) |
| 1121 | chunks.append(chunk) |
| 1122 | # n is more than avail only when an EOF occurred or when |
| 1123 | # read() would have blocked. |
| 1124 | n = min(n, avail) |
| 1125 | out = b"".join(chunks) |
| 1126 | self._read_buf = out[n:] # Save the extra data in the buffer. |
| 1127 | self._read_pos = 0 |
| 1128 | return out[:n] if out else nodata_val |
| 1129 | |
| 1130 | def peek(self, size=0): |
| 1131 | """Returns buffered bytes without advancing the position. |