示例#1
0
InStream*
InStream_Reopen_IMP(InStream *self, String *filename, int64_t offset,
                    int64_t len) {
    InStreamIVARS *const ivars = InStream_IVARS(self);
    if (!ivars->file_handle) {
        THROW(ERR, "Can't Reopen() closed InStream %o", ivars->filename);
    }
    if (offset + len > FH_Length(ivars->file_handle)) {
        THROW(ERR, "Offset + length too large (%i64 + %i64 > %i64)",
              offset, len, FH_Length(ivars->file_handle));
    }

    Class *klass = InStream_get_class(self);
    InStream *other = (InStream*)Class_Make_Obj(klass);
    InStreamIVARS *const ovars = InStream_IVARS(other);
    InStream_do_open(other, (Obj*)ivars->file_handle);
    if (filename != NULL) {
        String *temp = ovars->filename;
        ovars->filename = Str_Clone(filename);
        DECREF(temp);
    }
    ovars->offset = offset;
    ovars->len    = len;
    InStream_Seek(other, 0);

    return other;
}
示例#2
0
static void
test_refill(TestBatchRunner *runner) {
    RAMFile    *file      = RAMFile_new(NULL, false);
    OutStream  *outstream = OutStream_open((Obj*)file);
    InStream   *instream;
    char        scratch[5];
    InStreamIVARS *ivars;

    for (int32_t i = 0; i < 1023; i++) {
        OutStream_Write_U8(outstream, 'x');
    }
    OutStream_Write_U8(outstream, 'y');
    OutStream_Write_U8(outstream, 'z');
    OutStream_Close(outstream);

    instream = InStream_open((Obj*)file);
    ivars = InStream_IVARS(instream);
    InStream_Refill(instream);
    TEST_INT_EQ(runner, ivars->limit - ivars->buf, IO_STREAM_BUF_SIZE,
                "Refill");
    TEST_INT_EQ(runner, (long)InStream_Tell(instream), 0,
                "Correct file pos after standing-start Refill()");
    DECREF(instream);

    instream = InStream_open((Obj*)file);
    ivars = InStream_IVARS(instream);
    InStream_Fill(instream, 30);
    TEST_INT_EQ(runner, ivars->limit - ivars->buf, 30, "Fill()");
    TEST_INT_EQ(runner, (long)InStream_Tell(instream), 0,
                "Correct file pos after standing-start Fill()");
    DECREF(instream);

    instream = InStream_open((Obj*)file);
    ivars = InStream_IVARS(instream);
    InStream_Read_Bytes(instream, scratch, 5);
    TEST_INT_EQ(runner, ivars->limit - ivars->buf,
                IO_STREAM_BUF_SIZE - 5, "small read triggers refill");
    DECREF(instream);

    instream = InStream_open((Obj*)file);
    ivars = InStream_IVARS(instream);
    TEST_INT_EQ(runner, InStream_Read_U8(instream), 'x', "Read_U8");
    InStream_Seek(instream, 1023);
    TEST_INT_EQ(runner, (long)FileWindow_IVARS(ivars->window)->offset, 0,
                "no unnecessary refill on Seek");
    TEST_INT_EQ(runner, (long)InStream_Tell(instream), 1023, "Seek/Tell");
    TEST_INT_EQ(runner, InStream_Read_U8(instream), 'y',
                "correct data after in-buffer Seek()");
    TEST_INT_EQ(runner, InStream_Read_U8(instream), 'z', "automatic Refill");
    TEST_TRUE(runner, (FileWindow_IVARS(ivars->window)->offset != 0),
              "refilled");

    DECREF(instream);
    DECREF(outstream);
    DECREF(file);
}
示例#3
0
文件: InStream.c 项目: theory/lucy
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));
    }
}
示例#4
0
文件: InStream.c 项目: theory/lucy
void
InStream_seek(InStream *self, int64_t target) {
    InStreamIVARS *const ivars = InStream_IVARS(self);
    FileWindow *const window = ivars->window;
    char    *fw_buf    = FileWindow_Get_Buf(window);
    int64_t  fw_offset = FileWindow_Get_Offset(window);
    int64_t  fw_len    = FileWindow_Get_Len(window);
    int64_t  virtual_window_top = fw_offset - ivars->offset;
    int64_t  virtual_window_end = virtual_window_top + fw_len;

    if (target < 0) {
        THROW(ERR, "Can't Seek '%o' to negative target %i64", ivars->filename,
              target);
    }
    // Seek within window if possible.
    else if (target >= virtual_window_top
             && target <= virtual_window_end
            ) {
        ivars->buf = fw_buf - fw_offset + ivars->offset + target;
    }
    else if (target > ivars->len) {
        THROW(ERR, "Can't Seek '%o' past EOF (%i64 > %i64)", ivars->filename,
              target, ivars->len);
    }
    else {
        // Target is outside window.  Set all buffer and limit variables to
        // NULL to trigger refill on the next read.  Store the file position
        // in the FileWindow's offset.
        FH_Release_Window(ivars->file_handle, window);
        ivars->buf   = NULL;
        ivars->limit = NULL;
        FileWindow_Set_Offset(window, ivars->offset + target);
    }
}
示例#5
0
文件: InStream.c 项目: theory/lucy
static INLINE int64_t
SI_tell(InStream *self) {
    InStreamIVARS *const ivars = InStream_IVARS(self);
    char *fw_buf = FileWindow_Get_Buf(ivars->window);
    int64_t pos_in_buf = PTR_TO_I64(ivars->buf) - PTR_TO_I64(fw_buf);
    return pos_in_buf + FileWindow_Get_Offset(ivars->window) - ivars->offset;
}
示例#6
0
文件: InStream.c 项目: theory/lucy
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;
}
示例#7
0
static void
test_Seek_and_Tell(TestBatchRunner *runner) {
    int64_t     gb1      = INT64_C(0x40000000);
    int64_t     gb3      = gb1 * 3;
    int64_t     gb6      = gb1 * 6;
    int64_t     gb12     = gb1 * 12;
    FileHandle *fh       = (FileHandle*)MockFileHandle_new(NULL, gb12);
    InStream   *instream = InStream_open((Obj*)fh);
    InStreamIVARS *const ivars = InStream_IVARS(instream);

    InStream_Buf(instream, 10000);
    TEST_TRUE(runner, ivars->limit == ((char*)NULL) + 10000,
              "InStream_Buf sets limit");

    InStream_Seek(instream, gb6);
    TEST_TRUE(runner, InStream_Tell(instream) == gb6,
              "Tell after seek forwards outside buffer");
    TEST_TRUE(runner, ivars->buf == NULL,
              "Seek forwards outside buffer sets buf to NULL");
    TEST_TRUE(runner, ivars->limit == NULL,
              "Seek forwards outside buffer sets limit to NULL");
    TEST_TRUE(runner, FileWindow_IVARS(ivars->window)->offset == gb6,
              "Seek forwards outside buffer tracks pos in window offset");

    InStream_Buf(instream, (size_t)gb1);
    TEST_TRUE(runner, ivars->limit == ((char*)NULL) + gb1,
              "InStream_Buf sets limit");

    InStream_Seek(instream, gb6 + 10);
    TEST_TRUE(runner, InStream_Tell(instream) == gb6 + 10,
              "Tell after seek forwards within buffer");
    TEST_TRUE(runner, ivars->buf == ((char*)NULL) + 10,
              "Seek within buffer sets buf");
    TEST_TRUE(runner, ivars->limit == ((char*)NULL) + gb1,
              "Seek within buffer leaves limit alone");

    InStream_Seek(instream, gb6 + 1);
    TEST_TRUE(runner, InStream_Tell(instream) == gb6 + 1,
              "Tell after seek backwards within buffer");
    TEST_TRUE(runner, ivars->buf == ((char*)NULL) + 1,
              "Seek backwards within buffer sets buf");
    TEST_TRUE(runner, ivars->limit == ((char*)NULL) + gb1,
              "Seek backwards within buffer leaves limit alone");

    InStream_Seek(instream, gb3);
    TEST_TRUE(runner, InStream_Tell(instream) == gb3,
              "Tell after seek backwards outside buffer");
    TEST_TRUE(runner, ivars->buf == NULL,
              "Seek backwards outside buffer sets buf to NULL");
    TEST_TRUE(runner, ivars->limit == NULL,
              "Seek backwards outside buffer sets limit to NULL");
    TEST_TRUE(runner, FileWindow_IVARS(ivars->window)->offset == gb3,
              "Seek backwards outside buffer tracks pos in window offset");

    DECREF(instream);
    DECREF(fh);
}
示例#8
0
文件: InStream.c 项目: theory/lucy
int
InStream_read_raw_c64(InStream *self, char *buf) {
    InStreamIVARS *const ivars = InStream_IVARS(self);
    uint8_t *dest = (uint8_t*)buf;
    do {
        *dest = SI_read_u8(self, ivars);
    } while ((*dest++ & 0x80) != 0);
    return dest - (uint8_t*)buf;
}
示例#9
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;
}
示例#10
0
文件: InStream.c 项目: theory/lucy
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;
}
示例#11
0
文件: InStream.c 项目: theory/lucy
void
InStream_destroy(InStream *self) {
    InStreamIVARS *const ivars = InStream_IVARS(self);
    if (ivars->file_handle) {
        InStream_Close(self);
    }
    DECREF(ivars->filename);
    DECREF(ivars->window);
    SUPER_DESTROY(self, INSTREAM);
}
示例#12
0
static void
test_Close(TestBatchRunner *runner) {
    RAMFile  *file     = RAMFile_new(NULL, false);
    InStream *instream = InStream_open((Obj*)file);
    InStream_Close(instream);
    TEST_TRUE(runner, InStream_IVARS(instream)->file_handle == NULL,
              "Close decrements FileHandle's refcount");
    DECREF(instream);
    DECREF(file);
}
示例#13
0
文件: InStream.c 项目: theory/lucy
void
InStream_close(InStream *self) {
    InStreamIVARS *const ivars = InStream_IVARS(self);
    if (ivars->file_handle) {
        FH_Release_Window(ivars->file_handle, ivars->window);
        // Note that we don't close the FileHandle, because it's probably
        // shared.
        DECREF(ivars->file_handle);
        ivars->file_handle = NULL;
    }
}
示例#14
0
文件: InStream.c 项目: theory/lucy
uint64_t
InStream_read_c64(InStream *self) {
    InStreamIVARS *const ivars = InStream_IVARS(self);
    uint64_t retval = 0;
    while (1) {
        const uint8_t ubyte = SI_read_u8(self, ivars);
        retval = (retval << 7) | (ubyte & 0x7f);
        if ((ubyte & 0x80) == 0) {
            break;
        }
    }
    return retval;
}
示例#15
0
文件: InStream.c 项目: theory/lucy
InStream*
InStream_reopen(InStream *self, const CharBuf *filename, int64_t offset,
                int64_t len) {
    InStreamIVARS *const ivars = InStream_IVARS(self);
    if (!ivars->file_handle) {
        THROW(ERR, "Can't Reopen() closed InStream %o", ivars->filename);
    }
    if (offset + len > FH_Length(ivars->file_handle)) {
        THROW(ERR, "Offset + length too large (%i64 + %i64 > %i64)",
              offset, len, FH_Length(ivars->file_handle));
    }

    VTable *vtable = InStream_Get_VTable(self);
    InStream *other = (InStream*)VTable_Make_Obj(vtable);
    InStreamIVARS *const ovars = InStream_IVARS(other);
    InStream_do_open(other, (Obj*)ivars->file_handle);
    if (filename != NULL) { CB_Mimic(ovars->filename, (Obj*)filename); }
    ovars->offset = offset;
    ovars->len    = len;
    InStream_Seek(other, 0);

    return other;
}
示例#16
0
文件: InStream.c 项目: theory/lucy
void
InStream_advance_buf(InStream *self, char *buf) {
    InStreamIVARS *const ivars = InStream_IVARS(self);
    if (buf > ivars->limit) {
        int64_t overrun = PTR_TO_I64(buf) - PTR_TO_I64(ivars->limit);
        THROW(ERR, "Supplied value is %i64 bytes beyond end of buffer",
              overrun);
    }
    else if (buf < ivars->buf) {
        int64_t underrun = PTR_TO_I64(ivars->buf) - PTR_TO_I64(buf);
        THROW(ERR, "Can't Advance_Buf backwards: (underrun: %i64))", underrun);
    }
    else {
        ivars->buf = buf;
    }
}
示例#17
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);
        }
    }
}
示例#18
0
文件: InStream.c 项目: theory/lucy
InStream*
InStream_do_open(InStream *self, Obj *file) {
    InStreamIVARS *const ivars = InStream_IVARS(self);

    // Init.
    ivars->buf          = NULL;
    ivars->limit        = NULL;
    ivars->offset       = 0;
    ivars->window       = FileWindow_new();

    // Obtain a FileHandle.
    if (Obj_Is_A(file, FILEHANDLE)) {
        ivars->file_handle = (FileHandle*)INCREF(file);
    }
    else if (Obj_Is_A(file, RAMFILE)) {
        ivars->file_handle
            = (FileHandle*)RAMFH_open(NULL, FH_READ_ONLY, (RAMFile*)file);
    }
    else if (Obj_Is_A(file, CHARBUF)) {
        ivars->file_handle
            = (FileHandle*)FSFH_open((CharBuf*)file, FH_READ_ONLY);
    }
    else {
        Err_set_error(Err_new(CB_newf("Invalid type for param 'file': '%o'",
                                      Obj_Get_Class_Name(file))));
        DECREF(self);
        return NULL;
    }
    if (!ivars->file_handle) {
        ERR_ADD_FRAME(Err_get_error());
        DECREF(self);
        return NULL;
    }

    // Get length and filename from the FileHandle.
    ivars->filename     = CB_Clone(FH_Get_Path(ivars->file_handle));
    ivars->len          = FH_Length(ivars->file_handle);
    if (ivars->len == -1) {
        ERR_ADD_FRAME(Err_get_error());
        DECREF(self);
        return NULL;
    }

    return self;
}
示例#19
0
文件: InStream.c 项目: theory/lucy
static int64_t
S_refill(InStream *self) {
    InStreamIVARS *const ivars = InStream_IVARS(self);

    // Determine the amount to request.
    const int64_t sub_file_pos = SI_tell(self);
    const int64_t remaining    = ivars->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)",
              ivars->filename, ivars->offset, ivars->len);
    }

    // Make the request.
    S_fill(self, amount);

    return amount;
}
示例#20
0
static void
test_Buf(TestBatchRunner *runner) {
    RAMFile    *file      = RAMFile_new(NULL, false);
    OutStream  *outstream = OutStream_open((Obj*)file);
    size_t      size      = IO_STREAM_BUF_SIZE * 2 + 5;
    InStream   *instream;
    char       *buf;

    for (uint32_t i = 0; i < size; i++) {
        OutStream_Write_U8(outstream, 'a');
    }
    OutStream_Close(outstream);

    instream = InStream_open((Obj*)file);
    InStreamIVARS *const ivars = InStream_IVARS(instream);
    buf = InStream_Buf(instream, 5);
    TEST_INT_EQ(runner, ivars->limit - buf, IO_STREAM_BUF_SIZE,
                "Small request bumped up");

    buf += IO_STREAM_BUF_SIZE - 10; // 10 bytes left in buffer.
    InStream_Advance_Buf(instream, buf);

    buf = InStream_Buf(instream, 10);
    TEST_INT_EQ(runner, ivars->limit - buf, 10,
                "Exact request doesn't trigger refill");

    buf = InStream_Buf(instream, 11);
    TEST_INT_EQ(runner, ivars->limit - buf, IO_STREAM_BUF_SIZE,
                "Requesting over limit triggers refill");

    int64_t  expected = InStream_Length(instream) - InStream_Tell(instream);
    char    *buff     = InStream_Buf(instream, 100000);
    int64_t  got      = PTR_TO_I64(ivars->limit) - PTR_TO_I64(buff);
    TEST_TRUE(runner, got == expected,
              "Requests greater than file size get pared down");

    DECREF(instream);
    DECREF(outstream);
    DECREF(file);
}
示例#21
0
String*
InStream_Get_Filename_IMP(InStream *self) {
    return InStream_IVARS(self)->filename;
}
示例#22
0
文件: InStream.c 项目: theory/lucy
uint8_t
InStream_read_u8(InStream *self) {
    InStreamIVARS *const ivars = InStream_IVARS(self);
    return SI_read_u8(self, ivars);
}
示例#23
0
int64_t
InStream_Length_IMP(InStream *self) {
    return InStream_IVARS(self)->len;
}
示例#24
0
文件: InStream.c 项目: theory/lucy
int64_t
InStream_length(InStream *self) {
    return InStream_IVARS(self)->len;
}
示例#25
0
int8_t
InStream_Read_I8_IMP(InStream *self) {
    InStreamIVARS *const ivars = InStream_IVARS(self);
    return (int8_t)SI_read_u8(self, ivars);
}
示例#26
0
文件: InStream.c 项目: theory/lucy
CharBuf*
InStream_get_filename(InStream *self) {
    return InStream_IVARS(self)->filename;
}