#define AL_LOG_SECTION "cache_handle" //#define AL_LOG_ENABLE_TRACE #include #include "../codec/codec.h" #include "handle.h" #include "entry.h" #include "threaded_waits.h" static off_t wait_for_size(struct cch_handle *handle, struct cch_handler *handler) { handle->wait.end = -1; if (!handler->wait_for_range(handler, &handle->wait)) { log_trace("Wait for size failed."); return -1; } struct cch_backing *backing = handle->entry->backing; return backing->get_size_if_known(backing); } s32 cch_handle_read(struct cch_handle *handle, u8 *buf, s32 count) { struct cch_handler *handler = handle->entry->handler; struct cch_backing *backing = handle->entry->backing; // filesize < 0: Size is yet to be evaluated and we can wait on it. // filesize = 0: Size is explicitly unknown. off_t filesize = backing->get_size_if_known(backing); if (filesize < 0) filesize = wait_for_size(handle, handler); if (filesize > 0) { if (handle->pointer >= filesize) { return CAMU_ERR_EOF; } else if (handle->pointer + count >= filesize) { count = filesize - handle->pointer; } } al_assert(count >= 0); handle->wait.start = handle->pointer; handle->wait.end = handle->pointer + count; if (!handler->wait_for_range(handler, &handle->wait)) { log_trace("Wait for range (%zd-%zd) failed.", handle->wait.start, handle->wait.end); return CAMU_ERR_EOF; } size_t available = (size_t)count; if (backing->mode == CACHE_BACKING_MAPPED) { u8 *ptr = backing->get_ptr(backing, handle->pointer, &available); if (ptr && available > 0) { al_memcpy(buf, ptr, available); } backing->unlock(backing); } else if (backing->mode == CACHE_BACKING_READ) { backing->read(backing, buf, handle->pointer, &available); } handle->pointer += available; log_trace("read(%u), pointer: %zd.", count, handle->pointer); return (available > 0) ? (s32)available : CAMU_ERR_EOF; } s32 cch_handle_write(struct cch_handle *handle, const u8 *buf, s32 count) { (void)handle; (void)buf; (void)count; return -1; } off_t cch_handle_seek(struct cch_handle *handle, off_t offset, s32 whence) { struct cch_handler *handler = handle->entry->handler; struct cch_backing *backing = handle->entry->backing; off_t filesize = backing->get_size_if_known(backing); if (filesize < 0) filesize = wait_for_size(handle, handler); if (filesize <= 0) return -1; if (whence == CAMU_SEEK_SIZE) { log_trace("SEEK_SIZE(), pointer: %zd, filesize: %zd.", handle->pointer, filesize); return filesize; } switch (whence) { case SEEK_SET: log_trace("SEEK_SET(%zd, %d), pointer: %zd.", offset, whence, handle->pointer); if (offset > filesize || offset < 0) { return -1; } handle->pointer = offset; break; case SEEK_CUR: log_trace("SEEK_CUR(%zd, %d), pointer: %zd.", offset, whence, handle->pointer); if (handle->pointer + offset > filesize || handle->pointer + offset < 0) { return -1; } handle->pointer += offset; break; case SEEK_END: log_trace("SEEK_END(%zd, %d), pointer: %zd.", offset, whence, handle->pointer); handle->pointer = filesize + offset; break; default: return -1; } return handle->pointer; } bool cch_handle_can_seek(struct cch_handle *handle) { struct cch_handler *handler = handle->entry->handler; return handler->can_seek(handler); } void cch_handle_disable(struct cch_handle *handle) { cch_threaded_wait_disable(&handle->wait); } void cch_handle_enable(struct cch_handle *handle) { cch_threaded_wait_enable(&handle->wait); }