libretro: adjust psxclock description
[pcsx_rearmed.git] / deps / libretro-common / streams / network_stream.c
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 }