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