| 261 | } |
| 262 | |
| 263 | Status ScannerContext::Stream::GetBytesInternal(int64_t requested_len, |
| 264 | uint8_t** out_buffer, bool peek, int64_t* out_len) { |
| 265 | DCHECK_GT(requested_len, boundary_buffer_bytes_left_); |
| 266 | DCHECK(output_buffer_bytes_left_ != &io_buffer_bytes_left_ |
| 267 | || requested_len > io_buffer_bytes_left_) << "All bytes in output buffer " |
| 268 | << requested_len << " " << io_buffer_bytes_left_; |
| 269 | *out_buffer = nullptr; |
| 270 | |
| 271 | if (boundary_buffer_bytes_left_ == 0) boundary_buffer_->Clear(); |
| 272 | DCHECK(ValidateBufferPointers()); |
| 273 | |
| 274 | // First this loop ensures, by reading I/O buffers one-by-one, that we've got all of |
| 275 | // the requested bytes in 'boundary_buffer_', 'io_buffer_', or split between the two. |
| 276 | // We may not be able to get all of the bytes if we hit eof. |
| 277 | while (boundary_buffer_bytes_left_ + io_buffer_bytes_left_ < requested_len) { |
| 278 | if (io_buffer_bytes_left_ > 0) { |
| 279 | // Copy the remainder of 'io_buffer_' to 'boundary_buffer_' before getting the next |
| 280 | // 'io_buffer_'. Preallocate 'boundary_buffer_' to avoid unnecessary resizes for |
| 281 | // large reads. |
| 282 | RETURN_IF_ERROR(boundary_buffer_->GrowBuffer(requested_len)); |
| 283 | RETURN_IF_ERROR(CopyIoToBoundary(io_buffer_bytes_left_)); |
| 284 | } |
| 285 | int64_t remaining_requested_len = requested_len - boundary_buffer_bytes_left_; |
| 286 | RETURN_IF_ERROR(GetNextBuffer(remaining_requested_len)); |
| 287 | if (UNLIKELY(parent_->cancelled())) return CONTEXT_CANCELLED; |
| 288 | // No more bytes (i.e. EOF). |
| 289 | if (io_buffer_bytes_left_ == 0) break; |
| 290 | } |
| 291 | |
| 292 | // We have read the full 'requested_len' bytes or hit eof. |
| 293 | // We can assemble the contiguous bytes in two ways: |
| 294 | // 1. if the the read range falls entirely with an I/O buffer, we return a pointer into |
| 295 | // that I/O buffer. |
| 296 | // 2. if the read straddles I/O buffers, we append the data to 'boundary_buffer_'. |
| 297 | // 'boundary_buffer_' may already contain some of the data that we need if we did a |
| 298 | // "peek" earlier. |
| 299 | int64_t requested_bytes_left = requested_len - boundary_buffer_bytes_left_; |
| 300 | DCHECK_GE(requested_bytes_left, 0); |
| 301 | int64_t num_bytes_left_to_copy = min(io_buffer_bytes_left_, requested_bytes_left); |
| 302 | *out_len = boundary_buffer_bytes_left_ + num_bytes_left_to_copy; |
| 303 | DCHECK_LE(*out_len, requested_len); |
| 304 | if (boundary_buffer_bytes_left_ == 0) { |
| 305 | // Case 1: return a pointer into the I/O buffer. |
| 306 | output_buffer_pos_ = &io_buffer_pos_; |
| 307 | output_buffer_bytes_left_ = &io_buffer_bytes_left_; |
| 308 | } else { |
| 309 | // Case 2: return a pointer into the boundary buffer, after copying any required |
| 310 | // data from the I/O buffer. |
| 311 | DCHECK_EQ(output_buffer_pos_, &boundary_buffer_pos_); |
| 312 | DCHECK_EQ(output_buffer_bytes_left_, &boundary_buffer_bytes_left_); |
| 313 | if (io_buffer_bytes_left_ > 0) { |
| 314 | RETURN_IF_ERROR(CopyIoToBoundary(num_bytes_left_to_copy)); |
| 315 | } |
| 316 | } |
| 317 | *out_buffer = *output_buffer_pos_; |
| 318 | if (!peek) { |
| 319 | total_bytes_returned_ += *out_len; |
| 320 | AdvanceBufferPos(*out_len, output_buffer_pos_, output_buffer_bytes_left_); |
nothing calls this directly
no test coverage detected