furi-hal-compress.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. #include <furi-hal-compress.h>
  2. #include <furi.h>
  3. #include <lib/heatshrink/heatshrink_encoder.h>
  4. #include <lib/heatshrink/heatshrink_decoder.h>
  5. #define TAG "FuriHalCompress"
  6. #define FURI_HAL_COMPRESS_ICON_ENCODED_BUFF_SIZE (512)
  7. #define FURI_HAL_COMPRESS_ICON_DECODED_BUFF_SIZE (1024)
  8. #define FURI_HAL_COMPRESS_EXP_BUFF_SIZE (1 << FURI_HAL_COMPRESS_EXP_BUFF_SIZE_LOG)
  9. typedef struct {
  10. uint8_t is_compressed;
  11. uint8_t reserved;
  12. uint16_t compressed_buff_size;
  13. } FuriHalCompressHeader;
  14. typedef struct {
  15. heatshrink_decoder* decoder;
  16. uint8_t compress_buff[FURI_HAL_COMPRESS_EXP_BUFF_SIZE + FURI_HAL_COMPRESS_ICON_ENCODED_BUFF_SIZE];
  17. uint8_t decoded_buff[FURI_HAL_COMPRESS_ICON_DECODED_BUFF_SIZE];
  18. } FuriHalCompressIcon;
  19. struct FuriHalCompress {
  20. heatshrink_encoder* encoder;
  21. heatshrink_decoder* decoder;
  22. uint8_t *compress_buff;
  23. uint16_t compress_buff_size;
  24. };
  25. static FuriHalCompressIcon* icon_decoder;
  26. static void furi_hal_compress_reset(FuriHalCompress* compress) {
  27. furi_assert(compress);
  28. heatshrink_encoder_reset(compress->encoder);
  29. heatshrink_decoder_reset(compress->decoder);
  30. memset(compress->compress_buff, 0, compress->compress_buff_size);
  31. }
  32. void furi_hal_compress_icon_init() {
  33. icon_decoder = furi_alloc(sizeof(FuriHalCompressIcon));
  34. icon_decoder->decoder = heatshrink_decoder_alloc(
  35. icon_decoder->compress_buff,
  36. FURI_HAL_COMPRESS_ICON_ENCODED_BUFF_SIZE,
  37. FURI_HAL_COMPRESS_EXP_BUFF_SIZE_LOG,
  38. FURI_HAL_COMPRESS_LOOKAHEAD_BUFF_SIZE_LOG);
  39. heatshrink_decoder_reset(icon_decoder->decoder);
  40. memset(icon_decoder->decoded_buff, 0, sizeof(icon_decoder->decoded_buff));
  41. FURI_LOG_I(TAG, "Init OK");
  42. }
  43. void furi_hal_compress_icon_decode(const uint8_t* icon_data, uint8_t** decoded_buff) {
  44. furi_assert(icon_data);
  45. furi_assert(decoded_buff);
  46. FuriHalCompressHeader* header = (FuriHalCompressHeader*) icon_data;
  47. if(header->is_compressed) {
  48. size_t data_processed = 0;
  49. heatshrink_decoder_sink(icon_decoder->decoder, (uint8_t*)&icon_data[4], header->compressed_buff_size, &data_processed);
  50. while(
  51. heatshrink_decoder_poll(
  52. icon_decoder->decoder,
  53. icon_decoder->decoded_buff,
  54. sizeof(icon_decoder->decoded_buff),
  55. &data_processed) == HSDR_POLL_MORE
  56. ) {};
  57. heatshrink_decoder_reset(icon_decoder->decoder);
  58. memset(icon_decoder->compress_buff, 0, sizeof(icon_decoder->compress_buff));
  59. *decoded_buff = icon_decoder->decoded_buff;
  60. } else {
  61. *decoded_buff = (uint8_t*)&icon_data[1];
  62. }
  63. }
  64. FuriHalCompress* furi_hal_compress_alloc(uint16_t compress_buff_size) {
  65. FuriHalCompress* compress = furi_alloc(sizeof(FuriHalCompress));
  66. compress->compress_buff = furi_alloc(compress_buff_size + FURI_HAL_COMPRESS_EXP_BUFF_SIZE);
  67. compress->encoder = heatshrink_encoder_alloc(compress->compress_buff, FURI_HAL_COMPRESS_EXP_BUFF_SIZE_LOG, FURI_HAL_COMPRESS_LOOKAHEAD_BUFF_SIZE_LOG);
  68. compress->decoder = heatshrink_decoder_alloc(compress->compress_buff, compress_buff_size, FURI_HAL_COMPRESS_EXP_BUFF_SIZE_LOG, FURI_HAL_COMPRESS_LOOKAHEAD_BUFF_SIZE_LOG);
  69. return compress;
  70. }
  71. void furi_hal_compress_free(FuriHalCompress* compress) {
  72. furi_assert(compress);
  73. heatshrink_encoder_free(compress->encoder);
  74. heatshrink_decoder_free(compress->decoder);
  75. free(compress->compress_buff);
  76. free(compress);
  77. }
  78. bool furi_hal_compress_encode(FuriHalCompress* compress, uint8_t* data_in, size_t data_in_size, uint8_t* data_out, size_t data_out_size, size_t* data_res_size) {
  79. furi_assert(compress);
  80. furi_assert(data_in);
  81. furi_assert(data_in_size);
  82. size_t sink_size = 0;
  83. size_t poll_size = 0;
  84. HSE_sink_res sink_res;
  85. HSE_poll_res poll_res;
  86. HSE_finish_res finish_res;
  87. bool encode_failed = false;
  88. size_t sunk = 0;
  89. size_t res_buff_size = sizeof(FuriHalCompressHeader);
  90. // Sink data to encoding buffer
  91. while((sunk < data_in_size) && !encode_failed) {
  92. sink_res = heatshrink_encoder_sink(compress->encoder, &data_in[sunk], data_in_size - sunk, &sink_size);
  93. if(sink_res != HSER_SINK_OK) {
  94. encode_failed = true;
  95. break;
  96. }
  97. sunk += sink_size;
  98. do {
  99. poll_res = heatshrink_encoder_poll(compress->encoder, &data_out[res_buff_size], data_out_size - res_buff_size, &poll_size);
  100. if(poll_res < 0) {
  101. encode_failed = true;
  102. break;
  103. }
  104. res_buff_size += poll_size;
  105. } while(poll_res == HSER_POLL_MORE);
  106. }
  107. // Notify sinking complete and poll encoded data
  108. finish_res = heatshrink_encoder_finish(compress->encoder);
  109. if(finish_res < 0) {
  110. encode_failed = true;
  111. } else {
  112. do {
  113. poll_res = heatshrink_encoder_poll(compress->encoder, &data_out[res_buff_size], data_out_size - 4 - res_buff_size, &poll_size);
  114. if(poll_res < 0) {
  115. encode_failed = true;
  116. break;
  117. }
  118. res_buff_size += poll_size;
  119. finish_res = heatshrink_encoder_finish(compress->encoder);
  120. } while(finish_res != HSER_FINISH_DONE);
  121. }
  122. bool result = true;
  123. // Write encoded data to output buffer if compression is efficient. Else - write header and original data
  124. if(!encode_failed && (res_buff_size < data_in_size + 1)) {
  125. FuriHalCompressHeader header = {.is_compressed = 0x01, .reserved = 0x00, .compressed_buff_size = res_buff_size};
  126. memcpy(data_out, &header, sizeof(header));
  127. *data_res_size = res_buff_size;
  128. } else if (data_out_size > data_in_size) {
  129. data_out[0] = 0x00;
  130. memcpy(&data_out[1], data_in, data_in_size);
  131. *data_res_size = data_in_size + 1;
  132. } else {
  133. *data_res_size = 0;
  134. result = false;
  135. }
  136. furi_hal_compress_reset(compress);
  137. return result;
  138. }
  139. bool furi_hal_compress_decode(FuriHalCompress* compress, uint8_t* data_in, size_t data_in_size, uint8_t* data_out, size_t data_out_size, size_t* data_res_size) {
  140. furi_assert(compress);
  141. furi_assert(data_in);
  142. furi_assert(data_out);
  143. furi_assert(data_res_size);
  144. bool result = false;
  145. bool decode_failed = false;
  146. HSD_sink_res sink_res;
  147. HSD_poll_res poll_res;
  148. HSD_finish_res finish_res;
  149. size_t sink_size = 0;
  150. size_t res_buff_size = 0;
  151. size_t poll_size = 0;
  152. FuriHalCompressHeader* header = (FuriHalCompressHeader*) data_in;
  153. if(header->is_compressed) {
  154. // Sink data to decoding buffer
  155. size_t compressed_size = header->compressed_buff_size;
  156. size_t sunk = sizeof(FuriHalCompressHeader);
  157. while(sunk < compressed_size && !decode_failed) {
  158. sink_res = heatshrink_decoder_sink(compress->decoder, &data_in[sunk], compressed_size - sunk, &sink_size);
  159. if(sink_res < 0) {
  160. decode_failed = true;
  161. break;
  162. }
  163. sunk += sink_size;
  164. do {
  165. poll_res = heatshrink_decoder_poll(compress->decoder, &data_out[res_buff_size], data_out_size, &poll_size);
  166. if(poll_res < 0) {
  167. decode_failed = true;
  168. break;
  169. }
  170. res_buff_size += poll_size;
  171. } while(poll_res == HSDR_POLL_MORE);
  172. }
  173. // Notify sinking complete and poll decoded data
  174. if(!decode_failed) {
  175. finish_res = heatshrink_decoder_finish(compress->decoder);
  176. if(finish_res < 0) {
  177. decode_failed = true;
  178. } else {
  179. do {
  180. poll_res = heatshrink_decoder_poll(compress->decoder, &data_out[res_buff_size], data_out_size, &poll_size);
  181. res_buff_size += poll_size;
  182. finish_res = heatshrink_decoder_finish(compress->decoder);
  183. } while(finish_res != HSDR_FINISH_DONE);
  184. }
  185. }
  186. *data_res_size = res_buff_size;
  187. result = !decode_failed;
  188. } else if(data_out_size >= data_in_size - 1) {
  189. memcpy(data_out, &data_in[1], data_in_size);
  190. *data_res_size = data_in_size - 1;
  191. result = true;
  192. } else {
  193. result = false;
  194. }
  195. furi_hal_compress_reset(compress);
  196. return result;
  197. }