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