Esempio n. 1
0
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;
}
Esempio n. 2
0
static void
S_fill(InStream *self, int64_t amount) {
    InStreamIVARS *const ivars     = InStream_IVARS(self);
    FileWindow *const window       = ivars->window;
    const int64_t virtual_file_pos = SI_tell(self);
    const int64_t real_file_pos    = virtual_file_pos + ivars->offset;
    const int64_t remaining        = ivars->len - virtual_file_pos;

    // Throw an error if the requested amount would take us beyond EOF.
    if (amount > remaining) {
        THROW(ERR,  "Read past EOF of %o (pos: %u64 len: %u64 request: %u64)",
              ivars->filename, virtual_file_pos, ivars->len, amount);
    }

    // Make the request.
    if (FH_Window(ivars->file_handle, window, real_file_pos, amount)) {
        char    *fw_buf    = FileWindow_Get_Buf(window);
        int64_t  fw_offset = FileWindow_Get_Offset(window);
        int64_t  fw_len    = FileWindow_Get_Len(window);
        char *const window_limit = fw_buf + fw_len;
        ivars->buf = fw_buf
                     - fw_offset          // theoretical start of real file
                     + ivars->offset      // top of virtual file
                     + virtual_file_pos;  // position within virtual file
        ivars->limit = window_limit - ivars->buf > remaining
                       ? ivars->buf + remaining
                       : window_limit;
    }
    else {
        Err *error = Err_get_error();
        CB_catf(Err_Get_Mess(error), " (%o)", ivars->filename);
        RETHROW(INCREF(error));
    }
}
Esempio n. 3
0
static void
S_fill(InStream *self, int64_t amount) {
    FileWindow *const window     = self->window;
    const int64_t virtual_file_pos = SI_tell(self);
    const int64_t real_file_pos    = virtual_file_pos + self->offset;
    const int64_t remaining        = self->len - virtual_file_pos;

    // Throw an error if the requested amount would take us beyond EOF.
    if (amount > remaining) {
        THROW(ERR,  "Read past EOF of %o (pos: %u64 len: %u64 request: %u64)",
              self->filename, virtual_file_pos, self->len, amount);
    }

    // Make the request.
    if (FH_Window(self->file_handle, window, real_file_pos, amount)) {
        char *const window_limit = window->buf + window->len;
        self->buf = window->buf
                    - window->offset    // theoretical start of real file
                    + self->offset      // top of virtual file
                    + virtual_file_pos; // position within virtual file
        self->limit = window_limit - self->buf > remaining
                      ? self->buf + remaining
                      : window_limit;
    }
    else {
        Err *error = Err_get_error();
        CB_catf(Err_Get_Mess(error), " (%o)", self->filename);
        RETHROW(INCREF(error));
    }
}
Esempio n. 4
0
InStream*
InStream_clone(InStream *self) {
    InStream *twin = (InStream*)VTable_Make_Obj(self->vtable);
    InStream_do_open(twin, (Obj*)self->file_handle);
    InStream_Seek(twin, SI_tell(self));
    return twin;
}
Esempio n. 5
0
static CFISH_INLINE void
SI_read_bytes(InStream *self, char* buf, size_t len) {
    InStreamIVARS *const ivars = InStream_IVARS(self);
    const int64_t available
        = CHY_PTR_TO_I64(ivars->limit) - CHY_PTR_TO_I64(ivars->buf);
    if (available >= (int64_t)len) {
        // Request is entirely within buffer, so copy.
        memcpy(buf, ivars->buf, len);
        ivars->buf += len;
    }
    else {
        // Pass along whatever we've got in the buffer.
        if (available > 0) {
            memcpy(buf, ivars->buf, (size_t)available);
            buf += available;
            len -= (size_t)available;
            ivars->buf += available;
        }

        if (len < IO_STREAM_BUF_SIZE) {
            // Ensure that we have enough mapped, then copy the rest.
            int64_t got = S_refill(self);
            if (got < (int64_t)len) {
                int64_t orig_pos = SI_tell(self) - available;
                int64_t orig_len = len + available;
                THROW(ERR,  "Read past EOF of %o (pos: %i64 len: %i64 "
                      "request: %i64)", ivars->filename, orig_pos,
                      ivars->len, orig_len);
            }
            memcpy(buf, ivars->buf, len);
            ivars->buf += len;
        }
        else {
            // Too big to handle via the buffer, so resort to a brute-force
            // read.
            const int64_t sub_file_pos  = SI_tell(self);
            const int64_t real_file_pos = sub_file_pos + ivars->offset;
            bool success
                = FH_Read(ivars->file_handle, buf, real_file_pos, len);
            if (!success) {
                RETHROW(INCREF(Err_get_error()));
            }
            InStream_Seek_IMP(self, sub_file_pos + len);
        }
    }
}
Esempio n. 6
0
InStream*
InStream_clone(InStream *self) {
    InStreamIVARS *const ivars = InStream_IVARS(self);
    VTable *vtable = InStream_Get_VTable(self);
    InStream *twin = (InStream*)VTable_Make_Obj(vtable);
    InStream_do_open(twin, (Obj*)ivars->file_handle);
    InStream_Seek(twin, SI_tell(self));
    return twin;
}
Esempio n. 7
0
InStream*
InStream_Clone_IMP(InStream *self) {
    InStreamIVARS *const ivars = InStream_IVARS(self);
    Class *klass = InStream_get_class(self);
    InStream *twin = (InStream*)Class_Make_Obj(klass);
    InStream_do_open(twin, (Obj*)ivars->file_handle);
    InStream_Seek(twin, SI_tell(self));
    return twin;
}
Esempio n. 8
0
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;
}
Esempio n. 9
0
int64_t
InStream_tell(InStream *self) {
    return SI_tell(self);
}
Esempio n. 10
0
int64_t
InStream_Tell_IMP(InStream *self) {
    return SI_tell(self);
}