char* InStream_buf(InStream *self, size_t request) { InStreamIVARS *const ivars = InStream_IVARS(self); const int64_t bytes_in_buf = PTR_TO_I64(ivars->limit) - PTR_TO_I64(ivars->buf); /* It's common for client code to overestimate how much is needed, because * the request has to figure in worst-case for compressed data. However, * if we can still serve them everything they request (e.g. they ask for 5 * bytes, they really need 1 byte, and there's 1k in the buffer), we can * skip the following refill block. */ if ((int64_t)request > bytes_in_buf) { const int64_t remaining_in_file = ivars->len - SI_tell(self); int64_t amount = request; // Try to bump up small requests. if (amount < IO_STREAM_BUF_SIZE) { amount = IO_STREAM_BUF_SIZE; } // Don't read past EOF. if (remaining_in_file < amount) { amount = remaining_in_file; } // Only fill if the recalculated, possibly smaller request exceeds the // amount available in the buffer. if (amount > bytes_in_buf) { S_fill(self, amount); } } return ivars->buf; }
static int64_t S_refill(InStream *self) { // Determine the amount to request. const int64_t sub_file_pos = SI_tell(self); const int64_t remaining = self->len - sub_file_pos; const int64_t amount = remaining < IO_STREAM_BUF_SIZE ? remaining : IO_STREAM_BUF_SIZE; if (!remaining) { THROW(ERR, "Read past EOF of '%o' (offset: %i64 len: %i64)", self->filename, self->offset, self->len); } // Make the request. S_fill(self, amount); return amount; }
void InStream_fill(InStream *self, int64_t amount) { S_fill(self, amount); }