string_stream.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. #include "stream.h"
  2. #include "stream_i.h"
  3. #include "string_stream.h"
  4. #include <core/common_defines.h>
  5. typedef struct {
  6. Stream stream_base;
  7. FuriString* string;
  8. size_t index;
  9. } StringStream;
  10. static size_t string_stream_write_char(StringStream* stream, char c);
  11. static void string_stream_free(StringStream* stream);
  12. static bool string_stream_eof(StringStream* stream);
  13. static void string_stream_clean(StringStream* stream);
  14. static bool string_stream_seek(StringStream* stream, int32_t offset, StreamOffset offset_type);
  15. static size_t string_stream_tell(StringStream* stream);
  16. static size_t string_stream_size(StringStream* stream);
  17. static size_t string_stream_write(StringStream* stream, const char* data, size_t size);
  18. static size_t string_stream_read(StringStream* stream, char* data, size_t size);
  19. static bool string_stream_delete_and_insert(
  20. StringStream* stream,
  21. size_t delete_size,
  22. StreamWriteCB write_callback,
  23. const void* ctx);
  24. const StreamVTable string_stream_vtable = {
  25. .free = (StreamFreeFn)string_stream_free,
  26. .eof = (StreamEOFFn)string_stream_eof,
  27. .clean = (StreamCleanFn)string_stream_clean,
  28. .seek = (StreamSeekFn)string_stream_seek,
  29. .tell = (StreamTellFn)string_stream_tell,
  30. .size = (StreamSizeFn)string_stream_size,
  31. .write = (StreamWriteFn)string_stream_write,
  32. .read = (StreamReadFn)string_stream_read,
  33. .delete_and_insert = (StreamDeleteAndInsertFn)string_stream_delete_and_insert,
  34. };
  35. Stream* string_stream_alloc() {
  36. StringStream* stream = malloc(sizeof(StringStream));
  37. stream->string = furi_string_alloc();
  38. stream->index = 0;
  39. stream->stream_base.vtable = &string_stream_vtable;
  40. return (Stream*)stream;
  41. }
  42. static void string_stream_free(StringStream* stream) {
  43. furi_string_free(stream->string);
  44. free(stream);
  45. }
  46. static bool string_stream_eof(StringStream* stream) {
  47. return (string_stream_tell(stream) >= string_stream_size(stream));
  48. }
  49. static void string_stream_clean(StringStream* stream) {
  50. stream->index = 0;
  51. furi_string_reset(stream->string);
  52. }
  53. static bool string_stream_seek(StringStream* stream, int32_t offset, StreamOffset offset_type) {
  54. bool result = true;
  55. switch(offset_type) {
  56. case StreamOffsetFromStart:
  57. if(offset >= 0) {
  58. stream->index = offset;
  59. } else {
  60. result = false;
  61. stream->index = 0;
  62. }
  63. break;
  64. case StreamOffsetFromCurrent:
  65. if(((int32_t)stream->index + offset) >= 0) {
  66. stream->index += offset;
  67. } else {
  68. result = false;
  69. stream->index = 0;
  70. }
  71. break;
  72. case StreamOffsetFromEnd:
  73. if(((int32_t)furi_string_size(stream->string) + offset) >= 0) {
  74. stream->index = furi_string_size(stream->string) + offset;
  75. } else {
  76. result = false;
  77. stream->index = 0;
  78. }
  79. break;
  80. }
  81. int32_t diff = (stream->index - furi_string_size(stream->string));
  82. if(diff > 0) {
  83. stream->index -= diff;
  84. result = false;
  85. }
  86. return result;
  87. }
  88. static size_t string_stream_tell(StringStream* stream) {
  89. return stream->index;
  90. }
  91. static size_t string_stream_size(StringStream* stream) {
  92. return furi_string_size(stream->string);
  93. }
  94. static size_t string_stream_write(StringStream* stream, const char* data, size_t size) {
  95. // TODO: can be optimized for edge cases
  96. size_t i;
  97. for(i = 0; i < size; i++) {
  98. string_stream_write_char(stream, data[i]);
  99. }
  100. return i;
  101. }
  102. static size_t string_stream_read(StringStream* stream, char* data, size_t size) {
  103. size_t write_index = 0;
  104. const char* cstr = furi_string_get_cstr(stream->string);
  105. if(!string_stream_eof(stream)) {
  106. while(true) {
  107. if(write_index >= size) break;
  108. data[write_index] = cstr[stream->index];
  109. write_index++;
  110. string_stream_seek(stream, 1, StreamOffsetFromCurrent);
  111. if(string_stream_eof(stream)) break;
  112. }
  113. }
  114. return write_index;
  115. }
  116. static bool string_stream_delete_and_insert(
  117. StringStream* stream,
  118. size_t delete_size,
  119. StreamWriteCB write_callback,
  120. const void* ctx) {
  121. bool result = true;
  122. if(delete_size) {
  123. size_t remain_size = string_stream_size(stream) - string_stream_tell(stream);
  124. remain_size = MIN(delete_size, remain_size);
  125. if(remain_size != 0) {
  126. furi_string_replace_at(stream->string, stream->index, remain_size, "");
  127. }
  128. }
  129. if(write_callback) {
  130. FuriString* right;
  131. right = furi_string_alloc_set(&furi_string_get_cstr(stream->string)[stream->index]);
  132. furi_string_left(stream->string, string_stream_tell(stream));
  133. result &= write_callback((Stream*)stream, ctx);
  134. furi_string_cat(stream->string, right);
  135. furi_string_free(right);
  136. }
  137. return result;
  138. }
  139. /**
  140. * Write to string stream helper
  141. * @param stream
  142. * @param c
  143. * @return size_t
  144. */
  145. static size_t string_stream_write_char(StringStream* stream, char c) {
  146. if(string_stream_eof(stream)) {
  147. furi_string_push_back(stream->string, c);
  148. } else {
  149. furi_string_set_char(stream->string, stream->index, c);
  150. }
  151. stream->index++;
  152. return 1;
  153. }