nbplib

commit 1f6b5e0fb5e82fe675857c9c322d6cd0b76adc3b

Author: mesyeti <mesyeti@mesyeti.uk>

add stream library

 README.md | 11 ++
 nbplib/stream.c | 255 +++++++++++++++++++++++++++++++++++++++++++++++++++
 nbplib/stream.h | 86 +++++++++++++++++


diff --git a/README.md b/README.md
index b08f18ae34af6bead4aa4296174edb0f182b2710..98e8899d5446cd299419eef1324898a7a6670ef3 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,12 @@
 # plib
 
-A collection (soon) of libraries to help with portability
\ No newline at end of file
+A collection (soon) of libraries to help with portability
+
+## How to use
+Add the `.c` file for the library/s you want to use to your build system, or `#include` the
+`.c` file in your project's source file. Use the header files the same way you would
+typically use a library.
+
+## Libraries
+- stream
+  - An extendable stream implementation




diff --git a/nbplib/stream.c b/nbplib/stream.c
new file mode 100644
index 0000000000000000000000000000000000000000..01264065db5a2d71721b118a77cd818b676d4c2c
--- /dev/null
+++ b/nbplib/stream.c
@@ -0,0 +1,255 @@
+#ifndef NBP_NO_STDIO
+	#include <stdio.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include "stream.h"
+
+void NBP_Stream_Close(NBP_Stream* stream) {
+	if (stream->close) {
+		stream->close(stream);
+	}
+
+	if (stream->data) {
+		free(stream->data);
+	}
+}
+
+size_t NBP_Stream_Write(NBP_Stream* stream, size_t size, void* data) {
+	if (!stream->write) return 0;
+
+	return stream->write(stream, size, data);
+}
+
+size_t NBP_Stream_Read(NBP_Stream* stream, size_t size, void* dest) {
+	return stream->read(stream, size, dest);
+}
+
+size_t NBP_Stream_Peek(NBP_Stream* stream) {
+	return stream->peek(stream);
+}
+
+bool NBP_Stream_Seek(NBP_Stream* stream, size_t where) {
+	return stream->seek(stream, where);
+}
+
+size_t NBP_Stream_Size(NBP_Stream* stream) {
+	return stream->size(stream);
+}
+
+bool NBP_Stream_Advance(NBP_Stream* stream, size_t bytes) {
+	return NBP_Stream_Seek(stream, NBP_Stream_Peek(stream) + bytes);
+}
+
+#ifndef NBP_NO_STDIO
+	typedef struct {
+		FILE*  file;
+	} FileStream;
+
+	static void FileClose(NBP_Stream* stream) {
+		FileStream* data = (FileStream*) stream->data;
+		fclose(data->file);
+	}
+
+	static size_t FileWrite(NBP_Stream* p_stream, size_t size, void* data) {
+		FileStream* stream = (FileStream*) p_stream->data;
+
+		return fwrite(data, 1, size, stream->file);
+	}
+
+	static size_t FileRead(NBP_Stream* stream, size_t size, void* dest) {
+		FileStream* data = (FileStream*) stream->data;
+
+		return fread(dest, 1, size, data->file);
+	}
+
+	static size_t FilePeek(NBP_Stream* stream) {
+		FileStream* data = (FileStream*) stream->data;
+
+		return (size_t) ftell(data->file);
+	}
+
+	static bool FileSeek(NBP_Stream* stream, size_t where) {
+		FileStream* data = (FileStream*) stream->data;
+
+		return fseek(data->file, (long) where, SEEK_SET) == 0;
+	}
+
+	static size_t FileSize(NBP_Stream* stream) {
+		FileStream* data = (FileStream*) stream->data;
+
+		long oldPos = ftell(data->file);
+		fseek(data->file, 0, SEEK_END);
+
+		size_t ret = (size_t) ftell(data->file);
+		fseek(data->file, oldPos, SEEK_SET);
+
+		return ret;
+	}
+
+	bool NBP_Stream_File(NBP_Stream* dest, FILE* file, bool close) {
+		FileStream* data = malloc(sizeof(FileStream));
+
+		if (!data) return false;
+
+		data->file = file;
+
+		*dest = (NBP_Stream) {
+			.data = data,
+			.close = close? &FileClose : NULL,
+			.write = &FileWrite,
+			.read  = &FileRead,
+			.peek  = &FilePeek,
+			.seek  = &FileSeek,
+			.size  = &FileSize
+		};
+		return true;
+	}
+#endif
+
+typedef struct {
+	uint8_t* data;
+	size_t   offset;
+	size_t   size;
+} MemStream;
+
+static void MemClose(NBP_Stream* stream) {
+	MemStream* data = (MemStream*) stream->data;
+
+	free(data->data);
+}
+
+static size_t MemRead(NBP_Stream* stream, size_t size, void* dest) {
+	MemStream* data = (MemStream*) stream->data;
+
+	if (data->offset + size > data->size) {
+		size = data->size - data->offset;
+	}
+	if (data->offset >= data->size) {
+		return 0;
+	}
+
+	memcpy(dest, &data->data[data->offset], size);
+
+	data->offset += size;
+
+	return size;
+}
+
+static size_t MemPeek(NBP_Stream* stream) {
+	MemStream* data = (MemStream*) stream->data;
+
+	return data->offset;
+}
+
+static bool MemSeek(NBP_Stream* stream, size_t where) {
+	MemStream* data = (MemStream*) stream->data;
+
+	if (where > data->size) {
+		return false;
+	}
+
+	data->offset = where;
+	return true;
+}
+
+static size_t MemSize(NBP_Stream* stream) {
+	MemStream* data = (MemStream*) stream->data;
+
+	return data->size;
+}
+
+bool NBP_Stream_Memory(NBP_Stream* dest, void* addr, size_t size, bool free) {
+	MemStream* data = malloc(sizeof(MemStream));
+
+	if (!data) return false;
+
+	data->data   = addr;
+	data->offset = 0;
+	data->size   = size;
+
+	*dest = (NBP_Stream) {
+		.data = data,
+		.close = free? &MemClose : NULL,
+		.write = NULL,
+		.read  = &MemRead,
+		.peek  = &MemPeek,
+		.seek  = &MemSeek,
+		.size  = &MemSize
+	};
+}
+
+typedef struct {
+	NBP_Stream* stream;
+	size_t  offset;
+	size_t  start;
+	size_t  size;
+} SubStream;
+
+static size_t SubRead(NBP_Stream* stream, size_t size, void* dest) {
+	SubStream* data = (SubStream*) stream->data;
+
+	if (data->offset + size > data->size) {
+		size = data->size - data->offset;
+	}
+	if (data->offset >= data->size) {
+		return 0;
+	}
+
+	NBP_Stream_Seek(data->stream, data->start + data->offset);
+	size_t ret = NBP_Stream_Read(data->stream, size, dest);
+
+	data->offset += size;
+
+	return ret;
+}
+
+static size_t SubPeek(NBP_Stream* stream) {
+	SubStream* data = (SubStream*) stream->data;
+	return data->offset;
+}
+
+static bool SubSeek(NBP_Stream* stream, size_t where) {
+	SubStream* data = (SubStream*) stream->data;
+
+	if (where > data->size) {
+		return false;
+	}
+
+	data->offset = where;
+	return true;
+}
+
+static size_t SubSize(NBP_Stream* stream) {
+	SubStream* data = (SubStream*) stream->data;
+
+	return data->size;
+}
+
+bool NBP_Stream_SubStream(NBP_Stream* dest, NBP_Stream* stream, size_t start, size_t size) {
+	SubStream* data = malloc(sizeof(SubStream));
+
+	if (!data) return false;
+
+	data->stream = stream;
+	data->offset = 0;
+	data->start  = start;
+	data->size   = size;
+
+	*dest = (NBP_Stream) {
+		.data = data,
+		.close = NULL,
+		.write = NULL,
+		.read  = &SubRead,
+		.peek  = &SubPeek,
+		.seek  = &SubSeek,
+		.size  = &SubSize
+	};
+	return true;
+}
+
+bool NBP_Stream_Blank(NBP_Stream* dest) {
+	*dest = (NBP_Stream) {0};
+	return true;
+}




diff --git a/nbplib/stream.h b/nbplib/stream.h
new file mode 100644
index 0000000000000000000000000000000000000000..70abb7ae3c6155640215f5cfa697be991964975f
--- /dev/null
+++ b/nbplib/stream.h
@@ -0,0 +1,86 @@
+#ifndef NBP_STREAM_H
+#define NBP_STREAM_H
+
+#include <stdint.h>
+
+// Options
+// define `NBP_NO_STDIO` to remove operations requiring stdio
+
+// Template for creating Stream implementations:
+/*
+static void Close(Stream* stream) {
+	TYPE* data = (TYPE*) stream->data;
+}
+
+static size_t Read(Stream* stream, size_t size, void* dest) {
+	TYPE* data = (TYPE*) stream->data;
+}
+
+static size_t Peek(Stream* stream) {
+	TYPE* data = (TYPE*) stream->data;
+}
+
+static bool Seek(Stream* stream, size_t where) {
+	TYPE* data = (TYPE*) stream->data;
+}
+
+static size_t Size(Stream* stream) {
+	TYPE* data = (TYPE*) stream->data;
+}
+*/
+
+typedef struct NBP_Stream NBP_Stream;
+
+struct NBP_Stream {
+	void* data;
+
+	void   (*close)(NBP_Stream* stream);
+	size_t (*write)(NBP_Stream* stream, size_t size, void* data);
+	size_t (*read)(NBP_Stream* stream, size_t size, void* dest);
+	size_t (*peek)(NBP_Stream* stream);
+	bool   (*seek)(NBP_Stream* stream, size_t where);
+	size_t (*size)(NBP_Stream* stream);
+};
+
+// FUNCTIONS
+
+// Closes a stream
+void NBP_Stream_Close(NBP_Stream* stream);
+
+// Writes `size` bytes from `data` into `stream`
+size_t NBP_Stream_Write(NBP_Stream* stream, size_t size, void* data);
+
+// Reads `size` bytes from `stream` into `dest`
+size_t NBP_Stream_Read(NBP_Stream* stream, size_t size, void* dest);
+
+// Returns the offset where `stream` is seeked
+size_t NBP_Stream_Peek(NBP_Stream* stream);
+
+// Seeks `stream` to `where` bytes from the start of the stream
+bool NBP_Stream_Seek(NBP_Stream* stream, size_t where);
+
+// Returns the length of the stream
+size_t NBP_Stream_Size(NBP_Stream* stream);
+
+// Seeks `stream` forward by `bytes` bytes
+bool NBP_Stream_Advance(NBP_Stream* stream, size_t bytes);
+
+// Creates a file stream
+// - `close` - If true, closing the stream will close `file`
+// - Returns true on success
+bool NBP_Stream_File(NBP_Stream* dest, FILE* file, bool close);
+
+// Creates a memory stream
+// - `free` - If true, closing the stream will free `addr`
+// - Returns true on success
+bool NBP_Stream_Memory(NBP_Stream* dest, void* addr, size_t size, bool free);
+
+// Creates a sub-stream that reads data from a certain point in `stream`
+// - Returns true on success
+bool NBP_Stream_SubStream(NBP_Stream* dest, NBP_Stream* stream, size_t start, size_t size);
+
+// Blank stream that can't do anything
+// - Returns true on success
+bool NBP_Stream_Blank(NBP_Stream* dest);
+
+#endif