summaryrefslogtreecommitdiff
path: root/quantum/painter/qp_stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'quantum/painter/qp_stream.c')
-rw-r--r--quantum/painter/qp_stream.c171
1 files changed, 171 insertions, 0 deletions
diff --git a/quantum/painter/qp_stream.c b/quantum/painter/qp_stream.c
new file mode 100644
index 0000000000..f00ae5ed38
--- /dev/null
+++ b/quantum/painter/qp_stream.c
@@ -0,0 +1,171 @@
+// Copyright 2021 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "qp_stream.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Stream API
+
+uint32_t qp_stream_read_impl(void *output_buf, uint32_t member_size, uint32_t num_members, qp_stream_t *stream) {
+ uint8_t *output_ptr = (uint8_t *)output_buf;
+
+ uint32_t i;
+ for (i = 0; i < (num_members * member_size); ++i) {
+ int16_t c = qp_stream_get(stream);
+ if (c < 0) {
+ break;
+ }
+
+ output_ptr[i] = (uint8_t)(c & 0xFF);
+ }
+
+ return i / member_size;
+}
+
+uint32_t qp_stream_write_impl(const void *input_buf, uint32_t member_size, uint32_t num_members, qp_stream_t *stream) {
+ uint8_t *input_ptr = (uint8_t *)input_buf;
+
+ uint32_t i;
+ for (i = 0; i < (num_members * member_size); ++i) {
+ if (!qp_stream_put(stream, input_ptr[i])) {
+ break;
+ }
+ }
+
+ return i / member_size;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Memory streams
+
+int16_t mem_get(qp_stream_t *stream) {
+ qp_memory_stream_t *s = (qp_memory_stream_t *)stream;
+ if (s->position >= s->length) {
+ s->is_eof = true;
+ return STREAM_EOF;
+ }
+ return s->buffer[s->position++];
+}
+
+bool mem_put(qp_stream_t *stream, uint8_t c) {
+ qp_memory_stream_t *s = (qp_memory_stream_t *)stream;
+ if (s->position >= s->length) {
+ s->is_eof = true;
+ return false;
+ }
+ s->buffer[s->position++] = c;
+ return true;
+}
+
+int mem_seek(qp_stream_t *stream, int32_t offset, int origin) {
+ qp_memory_stream_t *s = (qp_memory_stream_t *)stream;
+
+ // Handle as per fseek
+ int32_t position = s->position;
+ switch (origin) {
+ case SEEK_SET:
+ position = offset;
+ break;
+ case SEEK_CUR:
+ position += offset;
+ break;
+ case SEEK_END:
+ position = s->length + offset;
+ break;
+ default:
+ return -1;
+ }
+
+ // If we're before the start, ignore it.
+ if (position < 0) {
+ return -1;
+ }
+
+ // If we're at the end it's okay, we only care if we're after the end for failure purposes -- as per lseek()
+ if (position > s->length) {
+ return -1;
+ }
+
+ // Update the offset
+ s->position = position;
+
+ // Successful invocation of fseek() results in clearing of the EOF flag by default, mirror the same functionality
+ s->is_eof = false;
+
+ return 0;
+}
+
+int32_t mem_tell(qp_stream_t *stream) {
+ qp_memory_stream_t *s = (qp_memory_stream_t *)stream;
+ return s->position;
+}
+
+bool mem_is_eof(qp_stream_t *stream) {
+ qp_memory_stream_t *s = (qp_memory_stream_t *)stream;
+ return s->is_eof;
+}
+
+qp_memory_stream_t qp_make_memory_stream(void *buffer, int32_t length) {
+ qp_memory_stream_t stream = {
+ .base =
+ {
+ .get = mem_get,
+ .put = mem_put,
+ .seek = mem_seek,
+ .tell = mem_tell,
+ .is_eof = mem_is_eof,
+ },
+ .buffer = (uint8_t *)buffer,
+ .length = length,
+ .position = 0,
+ };
+ return stream;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// FILE streams
+
+#ifdef QP_STREAM_HAS_FILE_IO
+
+int16_t file_get(qp_stream_t *stream) {
+ qp_file_stream_t *s = (qp_file_stream_t *)stream;
+ int c = fgetc(s->file);
+ if (c < 0 || feof(s->file)) return STREAM_EOF;
+ return (uint16_t)c;
+}
+
+bool file_put(qp_stream_t *stream, uint8_t c) {
+ qp_file_stream_t *s = (qp_file_stream_t *)stream;
+ return fputc(c, s->file) == c;
+}
+
+int file_seek(qp_stream_t *stream, int32_t offset, int origin) {
+ qp_file_stream_t *s = (qp_file_stream_t *)stream;
+ return fseek(s->file, offset, origin);
+}
+
+int32_t file_tell(qp_stream_t *stream) {
+ qp_file_stream_t *s = (qp_file_stream_t *)stream;
+ return (int32_t)ftell(s->file);
+}
+
+bool file_is_eof(qp_stream_t *stream) {
+ qp_file_stream_t *s = (qp_file_stream_t *)stream;
+ return (bool)feof(s->file);
+}
+
+qp_file_stream_t qp_make_file_stream(FILE *f) {
+ qp_file_stream_t stream = {
+ .base =
+ {
+ .get = file_get,
+ .put = file_put,
+ .seek = file_seek,
+ .tell = file_tell,
+ .is_eof = file_is_eof,
+ },
+ .file = f,
+ };
+ return stream;
+}
+#endif // QP_STREAM_HAS_FILE_IO