furi-hal-compress.c 8.2 KB

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