Commit | Line | Data |
---|---|---|
3719602c PC |
1 | /* Copyright (C) 2022 The RetroArch team |
2 | * | |
3 | * --------------------------------------------------------------------------------------- | |
4 | * The following license statement only applies to this file (network_stream.c). | |
5 | * --------------------------------------------------------------------------------------- | |
6 | * | |
7 | * Permission is hereby granted, free of charge, | |
8 | * to any person obtaining a copy of this software and associated documentation files (the "Software"), | |
9 | * to deal in the Software without restriction, including without limitation the rights to | |
10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, | |
11 | * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | |
12 | * | |
13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | |
14 | * | |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | |
16 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
19 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
21 | */ | |
22 | ||
23 | #include <stdlib.h> | |
24 | #include <string.h> | |
25 | ||
26 | #include <retro_endianness.h> | |
27 | ||
28 | #include <streams/network_stream.h> | |
29 | ||
30 | bool netstream_open(netstream_t *stream, void *buf, size_t size, size_t used) | |
31 | { | |
32 | if (buf) | |
33 | { | |
34 | /* Pre-allocated buffer must have a non-zero size. */ | |
35 | if (!size || used > size) | |
36 | return false; | |
37 | } | |
38 | else | |
39 | { | |
40 | if (size) | |
41 | { | |
42 | buf = malloc(size); | |
43 | if (!buf) | |
44 | return false; | |
45 | } | |
46 | ||
47 | used = 0; | |
48 | } | |
49 | ||
50 | stream->buf = buf; | |
51 | stream->size = size; | |
52 | stream->used = used; | |
53 | stream->pos = 0; | |
54 | ||
55 | return true; | |
56 | } | |
57 | ||
58 | void netstream_close(netstream_t *stream, bool dealloc) | |
59 | { | |
60 | if (dealloc) | |
61 | free(stream->buf); | |
62 | memset(stream, 0, sizeof(*stream)); | |
63 | } | |
64 | ||
65 | void netstream_reset(netstream_t *stream) | |
66 | { | |
67 | stream->pos = 0; | |
68 | stream->used = 0; | |
69 | } | |
70 | ||
71 | bool netstream_truncate(netstream_t *stream, size_t used) | |
72 | { | |
73 | if (used > stream->size) | |
74 | return false; | |
75 | ||
76 | stream->used = used; | |
77 | ||
78 | /* If the current stream position is past our new end of stream, | |
79 | set the current position to the end of the stream. */ | |
80 | if (stream->pos > used) | |
81 | stream->pos = used; | |
82 | ||
83 | return true; | |
84 | } | |
85 | ||
86 | void netstream_data(netstream_t *stream, void **data, size_t *len) | |
87 | { | |
88 | *data = stream->buf; | |
89 | *len = stream->used; | |
90 | } | |
91 | ||
92 | bool netstream_eof(netstream_t *stream) | |
93 | { | |
94 | return stream->pos >= stream->used; | |
95 | } | |
96 | ||
97 | size_t netstream_tell(netstream_t *stream) | |
98 | { | |
99 | return stream->pos; | |
100 | } | |
101 | ||
102 | bool netstream_seek(netstream_t *stream, long offset, int origin) | |
103 | { | |
104 | long pos = (long)stream->pos; | |
105 | long used = (long)stream->used; | |
106 | ||
107 | switch (origin) | |
108 | { | |
109 | case NETSTREAM_SEEK_SET: | |
110 | pos = offset; | |
111 | break; | |
112 | case NETSTREAM_SEEK_CUR: | |
113 | pos += offset; | |
114 | break; | |
115 | case NETSTREAM_SEEK_END: | |
116 | pos = used + offset; | |
117 | break; | |
118 | default: | |
119 | return false; | |
120 | } | |
121 | ||
122 | if (pos < 0 || pos > used) | |
123 | return false; | |
124 | ||
125 | stream->pos = (size_t)pos; | |
126 | ||
127 | return true; | |
128 | } | |
129 | ||
130 | bool netstream_read(netstream_t *stream, void *data, size_t len) | |
131 | { | |
132 | size_t remaining = stream->used - stream->pos; | |
133 | ||
134 | if (!data || !remaining || len > remaining) | |
135 | return false; | |
136 | ||
137 | /* If len is 0, read all remaining bytes. */ | |
138 | if (!len) | |
139 | len = remaining; | |
140 | ||
141 | memcpy(data, (uint8_t*)stream->buf + stream->pos, len); | |
142 | ||
143 | stream->pos += len; | |
144 | ||
145 | return true; | |
146 | } | |
147 | ||
148 | /* This one doesn't require any swapping. */ | |
149 | bool netstream_read_byte(netstream_t *stream, uint8_t *data) | |
150 | { | |
151 | return netstream_read(stream, data, sizeof(*data)); | |
152 | } | |
153 | ||
154 | #define NETSTREAM_READ_TYPE(name, type, swap) \ | |
155 | bool netstream_read_##name(netstream_t *stream, type *data) \ | |
156 | { \ | |
157 | if (!netstream_read(stream, data, sizeof(*data))) \ | |
158 | return false; \ | |
159 | *data = swap(*data); \ | |
160 | return true; \ | |
161 | } | |
162 | ||
163 | NETSTREAM_READ_TYPE(word, uint16_t, retro_be_to_cpu16) | |
164 | NETSTREAM_READ_TYPE(dword, uint32_t, retro_be_to_cpu32) | |
165 | NETSTREAM_READ_TYPE(qword, uint64_t, retro_be_to_cpu64) | |
166 | ||
167 | #undef NETSTREAM_READ_TYPE | |
168 | ||
169 | #ifdef __STDC_IEC_559__ | |
170 | #define NETSTREAM_READ_TYPE(name, type, type_alt, swap) \ | |
171 | bool netstream_read_##name(netstream_t *stream, type *data) \ | |
172 | { \ | |
173 | type_alt *data_alt = (type_alt*)data; \ | |
174 | if (!netstream_read(stream, data, sizeof(*data))) \ | |
175 | return false; \ | |
176 | *data_alt = swap(*data_alt); \ | |
177 | return true; \ | |
178 | } | |
179 | ||
180 | NETSTREAM_READ_TYPE(float, float, uint32_t, retro_be_to_cpu32) | |
181 | NETSTREAM_READ_TYPE(double, double, uint64_t, retro_be_to_cpu64) | |
182 | ||
183 | #undef NETSTREAM_READ_TYPE | |
184 | #endif | |
185 | ||
186 | int netstream_read_string(netstream_t *stream, char *s, size_t len) | |
187 | { | |
188 | char c; | |
189 | int ret = 0; | |
190 | ||
191 | if (!s || !len) | |
192 | return -1; | |
193 | ||
194 | for (; --len; ret++) | |
195 | { | |
196 | if (!netstream_read(stream, &c, sizeof(c))) | |
197 | return -1; | |
198 | ||
199 | *s++ = c; | |
200 | ||
201 | if (!c) | |
202 | break; | |
203 | } | |
204 | ||
205 | if (!len) | |
206 | { | |
207 | *s = '\0'; | |
208 | ||
209 | for (;; ret++) | |
210 | { | |
211 | if (!netstream_read(stream, &c, sizeof(c))) | |
212 | return -1; | |
213 | if (!c) | |
214 | break; | |
215 | } | |
216 | } | |
217 | ||
218 | return ret; | |
219 | } | |
220 | ||
221 | bool netstream_read_fixed_string(netstream_t *stream, char *s, size_t len) | |
222 | { | |
223 | if (!len) | |
224 | return false; | |
225 | ||
226 | if (!netstream_read(stream, s, len)) | |
227 | return false; | |
228 | ||
229 | /* Ensure the string is always null-terminated. */ | |
230 | s[len - 1] = '\0'; | |
231 | ||
232 | return true; | |
233 | } | |
234 | ||
235 | bool netstream_write(netstream_t *stream, const void *data, size_t len) | |
236 | { | |
237 | size_t remaining = stream->size - stream->pos; | |
238 | ||
239 | if (!data || !len) | |
240 | return false; | |
241 | ||
242 | if (len > remaining) | |
243 | { | |
244 | if (!stream->size) | |
245 | { | |
246 | stream->buf = malloc(len); | |
247 | if (!stream->buf) | |
248 | return false; | |
249 | stream->size = len; | |
250 | } | |
251 | else | |
252 | { | |
253 | size_t size = stream->size + (len - remaining); | |
254 | void *buf = realloc(stream->buf, size); | |
255 | ||
256 | if (!buf) | |
257 | return false; | |
258 | ||
259 | stream->buf = buf; | |
260 | stream->size = size; | |
261 | } | |
262 | } | |
263 | ||
264 | memcpy((uint8_t*)stream->buf + stream->pos, data, len); | |
265 | ||
266 | stream->pos += len; | |
267 | ||
268 | if (stream->pos > stream->used) | |
269 | stream->used = stream->pos; | |
270 | ||
271 | return true; | |
272 | } | |
273 | ||
274 | /* This one doesn't require any swapping. */ | |
275 | bool netstream_write_byte(netstream_t *stream, uint8_t data) | |
276 | { | |
277 | return netstream_write(stream, &data, sizeof(data)); | |
278 | } | |
279 | ||
280 | #define NETSTREAM_WRITE_TYPE(name, type, swap) \ | |
281 | bool netstream_write_##name(netstream_t *stream, type data) \ | |
282 | { \ | |
283 | data = swap(data); \ | |
284 | return netstream_write(stream, &data, sizeof(data)); \ | |
285 | } | |
286 | ||
287 | NETSTREAM_WRITE_TYPE(word, uint16_t, retro_cpu_to_be16) | |
288 | NETSTREAM_WRITE_TYPE(dword, uint32_t, retro_cpu_to_be32) | |
289 | NETSTREAM_WRITE_TYPE(qword, uint64_t, retro_cpu_to_be64) | |
290 | ||
291 | #undef NETSTREAM_WRITE_TYPE | |
292 | ||
293 | #ifdef __STDC_IEC_559__ | |
294 | #define NETSTREAM_WRITE_TYPE(name, type, type_alt, swap) \ | |
295 | bool netstream_write_##name(netstream_t *stream, type data) \ | |
296 | { \ | |
297 | type_alt *data_alt = (type_alt*)&data; \ | |
298 | *data_alt = swap(*data_alt); \ | |
299 | return netstream_write(stream, &data, sizeof(data)); \ | |
300 | } | |
301 | ||
302 | NETSTREAM_WRITE_TYPE(float, float, uint32_t, retro_cpu_to_be32) | |
303 | NETSTREAM_WRITE_TYPE(double, double, uint64_t, retro_cpu_to_be64) | |
304 | ||
305 | #undef NETSTREAM_WRITE_TYPE | |
306 | #endif | |
307 | ||
308 | bool netstream_write_string(netstream_t *stream, const char *s) | |
309 | { | |
310 | if (!s) | |
311 | return false; | |
312 | ||
313 | return netstream_write(stream, s, strlen(s) + 1); | |
314 | } | |
315 | ||
316 | bool netstream_write_fixed_string(netstream_t *stream, const char *s, | |
317 | size_t len) | |
318 | { | |
319 | char end = '\0'; | |
320 | ||
321 | if (!netstream_write(stream, s, len)) | |
322 | return false; | |
323 | ||
324 | /* Ensure the string is always null-terminated. */ | |
325 | netstream_seek(stream, -1, NETSTREAM_SEEK_CUR); | |
326 | netstream_write(stream, &end, sizeof(end)); | |
327 | ||
328 | return true; | |
329 | } |