You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

171 lines
4.5 KiB

  1. // Copyright 2021 Nick Brassel (@tzarc)
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "qp_stream.h"
  4. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  5. // Stream API
  6. uint32_t qp_stream_read_impl(void *output_buf, uint32_t member_size, uint32_t num_members, qp_stream_t *stream) {
  7. uint8_t *output_ptr = (uint8_t *)output_buf;
  8. uint32_t i;
  9. for (i = 0; i < (num_members * member_size); ++i) {
  10. int16_t c = qp_stream_get(stream);
  11. if (c < 0) {
  12. break;
  13. }
  14. output_ptr[i] = (uint8_t)(c & 0xFF);
  15. }
  16. return i / member_size;
  17. }
  18. uint32_t qp_stream_write_impl(const void *input_buf, uint32_t member_size, uint32_t num_members, qp_stream_t *stream) {
  19. uint8_t *input_ptr = (uint8_t *)input_buf;
  20. uint32_t i;
  21. for (i = 0; i < (num_members * member_size); ++i) {
  22. if (!qp_stream_put(stream, input_ptr[i])) {
  23. break;
  24. }
  25. }
  26. return i / member_size;
  27. }
  28. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  29. // Memory streams
  30. int16_t mem_get(qp_stream_t *stream) {
  31. qp_memory_stream_t *s = (qp_memory_stream_t *)stream;
  32. if (s->position >= s->length) {
  33. s->is_eof = true;
  34. return STREAM_EOF;
  35. }
  36. return s->buffer[s->position++];
  37. }
  38. bool mem_put(qp_stream_t *stream, uint8_t c) {
  39. qp_memory_stream_t *s = (qp_memory_stream_t *)stream;
  40. if (s->position >= s->length) {
  41. s->is_eof = true;
  42. return false;
  43. }
  44. s->buffer[s->position++] = c;
  45. return true;
  46. }
  47. int mem_seek(qp_stream_t *stream, int32_t offset, int origin) {
  48. qp_memory_stream_t *s = (qp_memory_stream_t *)stream;
  49. // Handle as per fseek
  50. int32_t position = s->position;
  51. switch (origin) {
  52. case SEEK_SET:
  53. position = offset;
  54. break;
  55. case SEEK_CUR:
  56. position += offset;
  57. break;
  58. case SEEK_END:
  59. position = s->length + offset;
  60. break;
  61. default:
  62. return -1;
  63. }
  64. // If we're before the start, ignore it.
  65. if (position < 0) {
  66. return -1;
  67. }
  68. // If we're at the end it's okay, we only care if we're after the end for failure purposes -- as per lseek()
  69. if (position > s->length) {
  70. return -1;
  71. }
  72. // Update the offset
  73. s->position = position;
  74. // Successful invocation of fseek() results in clearing of the EOF flag by default, mirror the same functionality
  75. s->is_eof = false;
  76. return 0;
  77. }
  78. int32_t mem_tell(qp_stream_t *stream) {
  79. qp_memory_stream_t *s = (qp_memory_stream_t *)stream;
  80. return s->position;
  81. }
  82. bool mem_is_eof(qp_stream_t *stream) {
  83. qp_memory_stream_t *s = (qp_memory_stream_t *)stream;
  84. return s->is_eof;
  85. }
  86. qp_memory_stream_t qp_make_memory_stream(void *buffer, int32_t length) {
  87. qp_memory_stream_t stream = {
  88. .base =
  89. {
  90. .get = mem_get,
  91. .put = mem_put,
  92. .seek = mem_seek,
  93. .tell = mem_tell,
  94. .is_eof = mem_is_eof,
  95. },
  96. .buffer = (uint8_t *)buffer,
  97. .length = length,
  98. .position = 0,
  99. };
  100. return stream;
  101. }
  102. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  103. // FILE streams
  104. #ifdef QP_STREAM_HAS_FILE_IO
  105. int16_t file_get(qp_stream_t *stream) {
  106. qp_file_stream_t *s = (qp_file_stream_t *)stream;
  107. int c = fgetc(s->file);
  108. if (c < 0 || feof(s->file)) return STREAM_EOF;
  109. return (uint16_t)c;
  110. }
  111. bool file_put(qp_stream_t *stream, uint8_t c) {
  112. qp_file_stream_t *s = (qp_file_stream_t *)stream;
  113. return fputc(c, s->file) == c;
  114. }
  115. int file_seek(qp_stream_t *stream, int32_t offset, int origin) {
  116. qp_file_stream_t *s = (qp_file_stream_t *)stream;
  117. return fseek(s->file, offset, origin);
  118. }
  119. int32_t file_tell(qp_stream_t *stream) {
  120. qp_file_stream_t *s = (qp_file_stream_t *)stream;
  121. return (int32_t)ftell(s->file);
  122. }
  123. bool file_is_eof(qp_stream_t *stream) {
  124. qp_file_stream_t *s = (qp_file_stream_t *)stream;
  125. return (bool)feof(s->file);
  126. }
  127. qp_file_stream_t qp_make_file_stream(FILE *f) {
  128. qp_file_stream_t stream = {
  129. .base =
  130. {
  131. .get = file_get,
  132. .put = file_put,
  133. .seek = file_seek,
  134. .tell = file_tell,
  135. .is_eof = file_is_eof,
  136. },
  137. .file = f,
  138. };
  139. return stream;
  140. }
  141. #endif // QP_STREAM_HAS_FILE_IO