1 |
|
|
/* $OpenBSD: open_wmemstream.c,v 1.8 2015/09/12 16:23:14 guenther Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org> |
5 |
|
|
* |
6 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
7 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
8 |
|
|
* copyright notice and this permission notice appear in all copies. |
9 |
|
|
* |
10 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 |
|
|
*/ |
18 |
|
|
|
19 |
|
|
#include <errno.h> |
20 |
|
|
#include <fcntl.h> |
21 |
|
|
#include <stdio.h> |
22 |
|
|
#include <stdint.h> |
23 |
|
|
#include <stdlib.h> |
24 |
|
|
#include <string.h> |
25 |
|
|
#include <wchar.h> |
26 |
|
|
#include "local.h" |
27 |
|
|
|
28 |
|
|
#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) |
29 |
|
|
|
30 |
|
|
struct state { |
31 |
|
|
wchar_t *string; /* actual stream */ |
32 |
|
|
wchar_t **pbuf; /* point to the stream */ |
33 |
|
|
size_t *psize; /* point to min(pos, len) */ |
34 |
|
|
size_t pos; /* current position */ |
35 |
|
|
size_t size; /* number of allocated wchar_t */ |
36 |
|
|
size_t len; /* length of the data */ |
37 |
|
|
mbstate_t mbs; /* conversion state of the stream */ |
38 |
|
|
}; |
39 |
|
|
|
40 |
|
|
static int |
41 |
|
|
wmemstream_write(void *v, const char *b, int l) |
42 |
|
|
{ |
43 |
|
|
struct state *st = v; |
44 |
|
|
wchar_t *p; |
45 |
|
|
size_t nmc, len, end; |
46 |
|
|
|
47 |
|
|
end = (st->pos + l); |
48 |
|
|
|
49 |
|
|
if (end >= st->size) { |
50 |
|
|
/* 1.6 is (very) close to the golden ratio. */ |
51 |
|
|
size_t sz = st->size * 8 / 5; |
52 |
|
|
|
53 |
|
|
if (sz < end + 1) |
54 |
|
|
sz = end + 1; |
55 |
|
|
p = reallocarray(st->string, sz, sizeof(wchar_t)); |
56 |
|
|
if (!p) |
57 |
|
|
return (-1); |
58 |
|
|
bzero(p + st->size, (sz - st->size) * sizeof(wchar_t)); |
59 |
|
|
*st->pbuf = st->string = p; |
60 |
|
|
st->size = sz; |
61 |
|
|
} |
62 |
|
|
|
63 |
|
|
nmc = (st->size - st->pos) * sizeof(wchar_t); |
64 |
|
|
len = mbsnrtowcs(st->string + st->pos, &b, nmc, l, &st->mbs); |
65 |
|
|
if (len == (size_t)-1) |
66 |
|
|
return (-1); |
67 |
|
|
st->pos += len; |
68 |
|
|
|
69 |
|
|
if (st->pos > st->len) { |
70 |
|
|
st->len = st->pos; |
71 |
|
|
st->string[st->len] = L'\0'; |
72 |
|
|
} |
73 |
|
|
|
74 |
|
|
*st->psize = st->pos; |
75 |
|
|
|
76 |
|
|
return (len); |
77 |
|
|
} |
78 |
|
|
|
79 |
|
|
static fpos_t |
80 |
|
|
wmemstream_seek(void *v, fpos_t off, int whence) |
81 |
|
|
{ |
82 |
|
|
struct state *st = v; |
83 |
|
|
ssize_t base = 0; |
84 |
|
|
|
85 |
|
|
switch (whence) { |
86 |
|
|
case SEEK_SET: |
87 |
|
|
break; |
88 |
|
|
case SEEK_CUR: |
89 |
|
|
base = st->pos; |
90 |
|
|
break; |
91 |
|
|
case SEEK_END: |
92 |
|
|
base = st->len; |
93 |
|
|
break; |
94 |
|
|
} |
95 |
|
|
|
96 |
|
|
if (off > (SIZE_MAX / sizeof(wchar_t)) - base || off < -base) { |
97 |
|
|
errno = EOVERFLOW; |
98 |
|
|
return (-1); |
99 |
|
|
} |
100 |
|
|
|
101 |
|
|
/* |
102 |
|
|
* XXX Clearing mbs here invalidates shift state for state- |
103 |
|
|
* dependent encodings, but they are not (yet) supported. |
104 |
|
|
*/ |
105 |
|
|
bzero(&st->mbs, sizeof(st->mbs)); |
106 |
|
|
|
107 |
|
|
st->pos = base + off; |
108 |
|
|
*st->psize = MINIMUM(st->pos, st->len); |
109 |
|
|
|
110 |
|
|
return (st->pos); |
111 |
|
|
} |
112 |
|
|
|
113 |
|
|
static int |
114 |
|
|
wmemstream_close(void *v) |
115 |
|
|
{ |
116 |
|
|
struct state *st = v; |
117 |
|
|
|
118 |
|
|
free(st); |
119 |
|
|
|
120 |
|
|
return (0); |
121 |
|
|
} |
122 |
|
|
|
123 |
|
|
FILE * |
124 |
|
|
open_wmemstream(wchar_t **pbuf, size_t *psize) |
125 |
|
|
{ |
126 |
|
|
struct state *st; |
127 |
|
|
FILE *fp; |
128 |
|
|
|
129 |
|
|
if (pbuf == NULL || psize == NULL) { |
130 |
|
|
errno = EINVAL; |
131 |
|
|
return (NULL); |
132 |
|
|
} |
133 |
|
|
|
134 |
|
|
if ((st = malloc(sizeof(*st))) == NULL) |
135 |
|
|
return (NULL); |
136 |
|
|
|
137 |
|
|
if ((fp = __sfp()) == NULL) { |
138 |
|
|
free(st); |
139 |
|
|
return (NULL); |
140 |
|
|
} |
141 |
|
|
|
142 |
|
|
st->size = BUFSIZ * sizeof(wchar_t); |
143 |
|
|
if ((st->string = calloc(1, st->size)) == NULL) { |
144 |
|
|
free(st); |
145 |
|
|
fp->_flags = 0; |
146 |
|
|
return (NULL); |
147 |
|
|
} |
148 |
|
|
|
149 |
|
|
*st->string = L'\0'; |
150 |
|
|
st->pos = 0; |
151 |
|
|
st->len = 0; |
152 |
|
|
st->pbuf = pbuf; |
153 |
|
|
st->psize = psize; |
154 |
|
|
bzero(&st->mbs, sizeof(st->mbs)); |
155 |
|
|
|
156 |
|
|
*pbuf = st->string; |
157 |
|
|
*psize = st->len; |
158 |
|
|
|
159 |
|
|
fp->_flags = __SWR; |
160 |
|
|
fp->_file = -1; |
161 |
|
|
fp->_cookie = st; |
162 |
|
|
fp->_read = NULL; |
163 |
|
|
fp->_write = wmemstream_write; |
164 |
|
|
fp->_seek = wmemstream_seek; |
165 |
|
|
fp->_close = wmemstream_close; |
166 |
|
|
_SET_ORIENTATION(fp, 1); |
167 |
|
|
|
168 |
|
|
return (fp); |
169 |
|
|
} |