1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
#define AL_LOG_SECTION "cache_handle"
//#define AL_LOG_ENABLE_TRACE
#include <al/log.h>
#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);
}
|