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
|
#include <assert.h>
#include <math.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
/*
struct __IO_FILE {
size_t (*write)(FILE *, const unsigned char *, size_t);
size_t (*read)(FILE *, unsigned char *, size_t);
int (*seek)(FILE *, long, int);
long offset_in_file;
int buffered_char;
int has_buffered_char;
int fd;
uint8_t is_eof;
uint8_t has_error;
uint64_t file_size;
void *cookie;
};
*/
struct Memstream {
size_t buffer_usage;
char *buffer;
};
#define MEMSTREAM_DEF_SIZE 4096
size_t memstream_write(FILE *fp, const unsigned char *buf, size_t n) {
struct Memstream *c = fp->cookie;
// FIXME: Do a reallocation
if (c->buffer_usage + n >= fp->file_size) {
n = fp->file_size - c->buffer_usage;
}
memcpy(c->buffer + fp->offset_in_file, buf, n);
fp->offset_in_file += n;
if (fp->offset_in_file > (long)c->buffer_usage)
c->buffer_usage = fp->offset_in_file;
return n;
}
size_t memstream_read(FILE *fp, unsigned char *buf, size_t n) {
struct Memstream *c = fp->cookie;
size_t length_left = c->buffer_usage - fp->offset_in_file;
n = min(length_left, n);
memcpy(buf, c->buffer + fp->offset_in_file, n);
fp->offset_in_file += n;
if (0 == n)
fp->is_eof = 1;
return n;
}
int memstream_seek(FILE *stream, long offset, int whence) {
switch (whence) {
case SEEK_SET:
stream->offset_in_file = offset;
break;
case SEEK_CUR:
stream->offset_in_file += offset;
break;
case SEEK_END:
stream->offset_in_file = stream->file_size + offset;
break;
default:
assert(0);
break;
}
// FIXME: Error checking
return 0;
}
FILE *open_memstream(char **bufp, size_t *sizep) {
struct Memstream *c = NULL;
FILE *fp = malloc(sizeof(FILE));
if (!fp)
return NULL;
fp->offset_in_file = 0;
fp->buffered_char = 0;
fp->has_buffered_char = 0;
fp->seek = memstream_seek;
fp->fd = -1;
fp->is_eof = 0;
fp->has_error = 0;
fp->file_size = MEMSTREAM_DEF_SIZE;
fp->fflush = NULL;
fp->can_write = 1;
fp->can_read = 1;
fp->write = memstream_write;
fp->read = memstream_read;
c = malloc(sizeof(struct Memstream));
if (!c) {
goto _exit_memstream_fail;
}
fp->cookie = (void *)c;
c->buffer = *bufp = malloc(MEMSTREAM_DEF_SIZE);
if (!bufp) {
goto _exit_memstream_fail;
}
c->buffer_usage = 0;
return fp;
_exit_memstream_fail:
free(c);
free(fp);
return NULL;
}
|