diff --git a/Makefile.common b/Makefile.common index c0f8d82581..c9de56340c 100644 --- a/Makefile.common +++ b/Makefile.common @@ -281,6 +281,7 @@ OBJ += \ $(LIBRETRO_COMM_DIR)/streams/file_stream_transforms.o \ $(LIBRETRO_COMM_DIR)/streams/interface_stream.o \ $(LIBRETRO_COMM_DIR)/streams/memory_stream.o \ + $(LIBRETRO_COMM_DIR)/streams/network_stream.o \ $(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.o OBJ += \ diff --git a/griffin/griffin.c b/griffin/griffin.c index 4b73a41b2a..39c18ce3db 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -1113,6 +1113,7 @@ FILE #include "../libretro-common/streams/file_stream_transforms.c" #include "../libretro-common/streams/interface_stream.c" #include "../libretro-common/streams/memory_stream.c" +#include "../libretro-common/streams/network_stream.c" #ifndef __WINRT__ #include "../libretro-common/vfs/vfs_implementation.c" #endif diff --git a/libretro-common/include/streams/network_stream.h b/libretro-common/include/streams/network_stream.h new file mode 100644 index 0000000000..0a80232f23 --- /dev/null +++ b/libretro-common/include/streams/network_stream.h @@ -0,0 +1,203 @@ +/* Copyright (C) 2022 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (network_stream.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _LIBRETRO_SDK_NETWORK_STREAM_H +#define _LIBRETRO_SDK_NETWORK_STREAM_H + +#include +#include + +#include + +#include + +RETRO_BEGIN_DECLS + +enum +{ + NETSTREAM_SEEK_SET = 0, + NETSTREAM_SEEK_CUR, + NETSTREAM_SEEK_END +}; + +typedef struct netstream +{ + void *buf; + size_t size; + size_t used; + size_t pos; +} netstream_t; + +/** + * netstream_open: + * + * @stream : Pointer to a network stream object. + * @buf : Pre-allocated buffer. Pass NULL to dynamically allocate a buffer. + * @size : Buffer size. Pass 0 for no pre-allocated/initial buffer. + * @used : Buffer bytes in use. Ignored for non pre-allocated buffers. + * + * Opens a network stream. + * + * Returns: true on success, false otherwise. + */ +bool netstream_open(netstream_t *stream, void *buf, size_t size, size_t used); + +/** + * netstream_close: + * + * @stream : Pointer to a network stream object. + * @dealloc : Whether to deallocate/free the buffer or not. + * + * Closes a network stream. + * + */ +void netstream_close(netstream_t *stream, bool dealloc); + +/** + * netstream_reset: + * + * @stream : Pointer to a network stream object. + * + * Resets a network stream to its initial position, + * discarding any used bytes in the process. + * + */ +void netstream_reset(netstream_t *stream); + +/** + * netstream_truncate: + * + * @stream : Pointer to a network stream object. + * @used : Amount of bytes used. + * + * Truncates the network stream. + * Truncation can either extend or reduce the amount of bytes used. + * + * Returns: true on success, false otherwise. + */ +bool netstream_truncate(netstream_t *stream, size_t used); + +/** + * netstream_data: + * + * @stream : Pointer to a network stream object. + * @data : Pointer to an object to store a reference of the stream's data. + * @len : Pointer to an object to store the amount of bytes in use. + * + * Gets the network stream's data. + * + */ +void netstream_data(netstream_t *stream, void **data, size_t *len); + +/** + * netstream_tell: + * + * @stream : Pointer to a network stream object. + * + * Gets the network stream's current position. + * + * Returns: current value of the position indicator. + */ +size_t netstream_tell(netstream_t *stream); + +/** + * netstream_seek: + * + * @stream : Pointer to a network stream object. + * @offset : Position's offset. + * @origin : Position used as reference for the offset. + * + * Sets the network stream's current position. + * + * Returns: true on success, false otherwise. + */ +bool netstream_seek(netstream_t *stream, long offset, int origin); + +/** + * netstream_read: + * + * @stream : Pointer to a network stream object. + * @data : Pointer to a storage for data read from the network stream. + * @len : Amount of bytes to read. Pass 0 to read all remaining bytes. + * + * Reads raw data from the network stream. + * + * Returns: true on success, false otherwise. + */ +bool netstream_read(netstream_t *stream, void *data, size_t len); + +/** + * netstream_read_(type): + * + * @stream : Pointer to a network stream object. + * @data : Pointer to a storage for data read from the network stream. + * + * Reads data from the network stream. + * Network byte order is always big endian. + * + * Returns: true on success, false otherwise. + */ +bool netstream_read_byte(netstream_t *stream, uint8_t *data); +bool netstream_read_word(netstream_t *stream, uint16_t *data); +bool netstream_read_dword(netstream_t *stream, uint32_t *data); +bool netstream_read_qword(netstream_t *stream, uint64_t *data); +#ifdef __STDC_IEC_559__ +bool netstream_read_float(netstream_t *stream, float *data); +bool netstream_read_double(netstream_t *stream, double *data); +#endif + +/** + * netstream_write: + * + * @stream : Pointer to a network stream object. + * @data : Data to write into the network stream. + * @len : Amount of bytes to write. + * + * Writes raw data into the network stream. + * + * Returns: true on success, false otherwise. + */ +bool netstream_write(netstream_t *stream, const void *data, size_t len); + +/** + * netstream_write_(type): + * + * @stream : Pointer to a network stream object. + * @data : Data to write into the network stream. + * + * Writes data into the network stream. + * Network byte order is always big endian. + * + * Returns: true on success, false otherwise. + */ +bool netstream_write_byte(netstream_t *stream, uint8_t data); +bool netstream_write_word(netstream_t *stream, uint16_t data); +bool netstream_write_dword(netstream_t *stream, uint32_t data); +bool netstream_write_qword(netstream_t *stream, uint64_t data); +#ifdef __STDC_IEC_559__ +bool netstream_write_float(netstream_t *stream, float data); +bool netstream_write_double(netstream_t *stream, double data); +#endif + +RETRO_END_DECLS + +#endif diff --git a/libretro-common/streams/network_stream.c b/libretro-common/streams/network_stream.c new file mode 100644 index 0000000000..569e93659f --- /dev/null +++ b/libretro-common/streams/network_stream.c @@ -0,0 +1,252 @@ +/* Copyright (C) 2022 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (network_stream.c). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include + +#include + +bool netstream_open(netstream_t *stream, void *buf, size_t size, size_t used) +{ + if (buf) + { + /* Pre-allocated buffer must have a non-zero size. */ + if (!size || used > size) + return false; + } + else + { + if (size) + { + buf = malloc(size); + if (!buf) + return false; + } + + used = 0; + } + + stream->buf = buf; + stream->size = size; + stream->used = used; + stream->pos = 0; + + return true; +} + +void netstream_close(netstream_t *stream, bool dealloc) +{ + if (dealloc) + free(stream->buf); + memset(stream, 0, sizeof(*stream)); +} + +void netstream_reset(netstream_t *stream) +{ + stream->pos = 0; + stream->used = 0; +} + +bool netstream_truncate(netstream_t *stream, size_t used) +{ + if (used > stream->size) + return false; + + stream->used = used; + + /* If the current stream position is past our new end of stream, + set the current position to the end of the stream. */ + if (stream->pos > used) + stream->pos = used; + + return true; +} + +void netstream_data(netstream_t *stream, void **data, size_t *len) +{ + *data = stream->buf; + *len = stream->used; +} + +size_t netstream_tell(netstream_t *stream) +{ + return stream->pos; +} + +bool netstream_seek(netstream_t *stream, long offset, int origin) +{ + long pos = (long)stream->pos; + long used = (long)stream->used; + + switch (origin) + { + case NETSTREAM_SEEK_SET: + pos = offset; + break; + case NETSTREAM_SEEK_CUR: + pos += offset; + break; + case NETSTREAM_SEEK_END: + pos = used + offset; + break; + default: + return false; + } + + if (pos < 0 || pos > used) + return false; + + stream->pos = (size_t)pos; + + return true; +} + +bool netstream_read(netstream_t *stream, void *data, size_t len) +{ + size_t remaining = stream->used - stream->pos; + + if (!data || !remaining || len > remaining) + return false; + + /* If len is 0, read all remaining bytes. */ + if (!len) + len = remaining; + + memcpy(data, (uint8_t*)stream->buf + stream->pos, len); + + stream->pos += len; + + return true; +} + +/* This one doesn't require any swapping. */ +bool netstream_read_byte(netstream_t *stream, uint8_t *data) +{ + return netstream_read(stream, data, sizeof(*data)); +} + +#define NETSTREAM_READ_TYPE(name, type, swap) \ +bool netstream_read_##name(netstream_t *stream, type *data) \ +{ \ + if (!netstream_read(stream, data, sizeof(*data))) \ + return false; \ + *data = swap(*data); \ + return true; \ +} + +NETSTREAM_READ_TYPE(word, uint16_t, retro_be_to_cpu16) +NETSTREAM_READ_TYPE(dword, uint32_t, retro_be_to_cpu32) +NETSTREAM_READ_TYPE(qword, uint64_t, retro_be_to_cpu64) + +#undef NETSTREAM_READ_TYPE + +#ifdef __STDC_IEC_559__ +#define NETSTREAM_READ_TYPE(name, type, type_alt, swap) \ +bool netstream_read_##name(netstream_t *stream, type *data) \ +{ \ + type_alt *data_alt = (type_alt*)data; \ + if (!netstream_read(stream, data, sizeof(*data))) \ + return false; \ + *data_alt = swap(*data_alt); \ + return true; \ +} + +NETSTREAM_READ_TYPE(float, float, uint32_t, retro_be_to_cpu32) +NETSTREAM_READ_TYPE(double, double, uint64_t, retro_be_to_cpu64) + +#undef NETSTREAM_READ_TYPE +#endif + +bool netstream_write(netstream_t *stream, const void *data, size_t len) +{ + size_t remaining = stream->size - stream->pos; + + if (!data || !len) + return false; + + if (len > remaining) + { + if (!stream->size) + { + stream->buf = malloc(len); + if (!stream->buf) + return false; + stream->size = len; + } + else + { + size_t size = stream->size + (len - remaining); + void *buf = realloc(stream->buf, size); + + if (!buf) + return false; + + stream->buf = buf; + stream->size = size; + } + } + + memcpy((uint8_t*)stream->buf + stream->pos, data, len); + + stream->pos += len; + + if (stream->pos > stream->used) + stream->used = stream->pos; + + return true; +} + +/* This one doesn't require any swapping. */ +bool netstream_write_byte(netstream_t *stream, uint8_t data) +{ + return netstream_write(stream, &data, sizeof(data)); +} + +#define NETSTREAM_WRITE_TYPE(name, type, swap) \ +bool netstream_write_##name(netstream_t *stream, type data) \ +{ \ + data = swap(data); \ + return netstream_write(stream, &data, sizeof(data)); \ +} + +NETSTREAM_WRITE_TYPE(word, uint16_t, retro_cpu_to_be16) +NETSTREAM_WRITE_TYPE(dword, uint32_t, retro_cpu_to_be32) +NETSTREAM_WRITE_TYPE(qword, uint64_t, retro_cpu_to_be64) + +#undef NETSTREAM_WRITE_TYPE + +#ifdef __STDC_IEC_559__ +#define NETSTREAM_WRITE_TYPE(name, type, type_alt, swap) \ +bool netstream_write_##name(netstream_t *stream, type data) \ +{ \ + type_alt *data_alt = (type_alt*)&data; \ + *data_alt = swap(*data_alt); \ + return netstream_write(stream, &data, sizeof(data)); \ +} + +NETSTREAM_WRITE_TYPE(float, float, uint32_t, retro_cpu_to_be32) +NETSTREAM_WRITE_TYPE(double, double, uint64_t, retro_cpu_to_be64) + +#undef NETSTREAM_WRITE_TYPE +#endif