1 #include "stdio_impl.h"
2 #include <errno.h>
3 #include <limits.h>
4 #include <string.h>
5 #include <wchar.h>
6
7 struct cookie {
8 wchar_t** bufp;
9 size_t* sizep;
10 size_t pos;
11 wchar_t* buf;
12 size_t len;
13 size_t space;
14 mbstate_t mbs;
15 };
16
wms_seek(FILE * f,off_t off,int whence)17 static off_t wms_seek(FILE* f, off_t off, int whence) {
18 ssize_t base;
19 struct cookie* c = f->cookie;
20 if (whence > 2U) {
21 fail:
22 errno = EINVAL;
23 return -1;
24 }
25 base = (size_t[3]){0, c->pos, c->len}[whence];
26 if (off < -base || off > SSIZE_MAX / 4 - base)
27 goto fail;
28 memset(&c->mbs, 0, sizeof c->mbs);
29 return c->pos = base + off;
30 }
31
wms_write(FILE * f,const unsigned char * buf,size_t len)32 static size_t wms_write(FILE* f, const unsigned char* buf, size_t len) {
33 struct cookie* c = f->cookie;
34 size_t len2;
35 wchar_t* newbuf;
36 if (len + c->pos >= c->space) {
37 len2 = (2 * c->space + 1) | (c->pos + len + 1);
38 if (len2 > SSIZE_MAX / 4)
39 return 0;
40 newbuf = realloc(c->buf, len2 * 4);
41 if (!newbuf)
42 return 0;
43 *c->bufp = c->buf = newbuf;
44 memset(c->buf + c->space, 0, 4 * (len2 - c->space));
45 c->space = len2;
46 }
47
48 len2 = mbsnrtowcs(c->buf + c->pos, (void*)&buf, len, c->space - c->pos, &c->mbs);
49 if (len2 == -1)
50 return 0;
51 c->pos += len2;
52 if (c->pos >= c->len)
53 c->len = c->pos;
54 *c->sizep = c->pos;
55 return len;
56 }
57
wms_close(FILE * f)58 static int wms_close(FILE* f) {
59 return 0;
60 }
61
open_wmemstream(wchar_t ** bufp,size_t * sizep)62 FILE* open_wmemstream(wchar_t** bufp, size_t* sizep) {
63 FILE* f;
64 struct cookie* c;
65 wchar_t* buf;
66
67 if (!(f = malloc(sizeof *f + sizeof *c)))
68 return 0;
69 if (!(buf = malloc(sizeof *buf))) {
70 free(f);
71 return 0;
72 }
73 memset(f, 0, sizeof *f + sizeof *c);
74 f->cookie = c = (void*)(f + 1);
75
76 c->bufp = bufp;
77 c->sizep = sizep;
78 c->pos = c->len = c->space = *sizep = 0;
79 c->buf = *bufp = buf;
80 *buf = 0;
81
82 f->flags = F_NORD;
83 f->fd = -1;
84 f->buf = (void*)(c + 1);
85 f->buf_size = 0;
86 f->lbf = EOF;
87 f->write = wms_write;
88 f->seek = wms_seek;
89 f->close = wms_close;
90
91 return __ofl_add(f);
92 }
93