furi-hal-compress.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  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 (2*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 (1) {
  51. HSD_poll_res res = heatshrink_decoder_poll(
  52. icon_decoder->decoder,
  53. icon_decoder->decoded_buff,
  54. sizeof(icon_decoder->decoded_buff),
  55. &data_processed);
  56. furi_assert((res == HSDR_POLL_EMPTY) || (res == HSDR_POLL_MORE));
  57. if (res != HSDR_POLL_MORE) {
  58. break;
  59. }
  60. }
  61. heatshrink_decoder_reset(icon_decoder->decoder);
  62. memset(icon_decoder->compress_buff, 0, sizeof(icon_decoder->compress_buff));
  63. *decoded_buff = icon_decoder->decoded_buff;
  64. } else {
  65. *decoded_buff = (uint8_t*)&icon_data[1];
  66. }
  67. }
  68. FuriHalCompress* furi_hal_compress_alloc(uint16_t compress_buff_size) {
  69. FuriHalCompress* compress = furi_alloc(sizeof(FuriHalCompress));
  70. compress->compress_buff = furi_alloc(compress_buff_size + FURI_HAL_COMPRESS_EXP_BUFF_SIZE);
  71. compress->encoder = heatshrink_encoder_alloc(compress->compress_buff, FURI_HAL_COMPRESS_EXP_BUFF_SIZE_LOG, FURI_HAL_COMPRESS_LOOKAHEAD_BUFF_SIZE_LOG);
  72. 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);
  73. return compress;
  74. }
  75. void furi_hal_compress_free(FuriHalCompress* compress) {
  76. furi_assert(compress);
  77. heatshrink_encoder_free(compress->encoder);
  78. heatshrink_decoder_free(compress->decoder);
  79. free(compress->compress_buff);
  80. free(compress);
  81. }
  82. 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) {
  83. furi_assert(compress);
  84. furi_assert(data_in);
  85. furi_assert(data_in_size);
  86. size_t sink_size = 0;
  87. size_t poll_size = 0;
  88. HSE_sink_res sink_res;
  89. HSE_poll_res poll_res;
  90. HSE_finish_res finish_res;
  91. bool encode_failed = false;
  92. size_t sunk = 0;
  93. size_t res_buff_size = sizeof(FuriHalCompressHeader);
  94. // Sink data to encoding buffer
  95. while((sunk < data_in_size) && !encode_failed) {
  96. sink_res = heatshrink_encoder_sink(compress->encoder, &data_in[sunk], data_in_size - sunk, &sink_size);
  97. if(sink_res != HSER_SINK_OK) {
  98. encode_failed = true;
  99. break;
  100. }
  101. sunk += sink_size;
  102. do {
  103. poll_res = heatshrink_encoder_poll(compress->encoder, &data_out[res_buff_size], data_out_size - res_buff_size, &poll_size);
  104. if(poll_res < 0) {
  105. encode_failed = true;
  106. break;
  107. }
  108. res_buff_size += poll_size;
  109. } while(poll_res == HSER_POLL_MORE);
  110. }
  111. // Notify sinking complete and poll encoded data
  112. finish_res = heatshrink_encoder_finish(compress->encoder);
  113. if(finish_res < 0) {
  114. encode_failed = true;
  115. } else {
  116. do {
  117. poll_res = heatshrink_encoder_poll(compress->encoder, &data_out[res_buff_size], data_out_size - 4 - res_buff_size, &poll_size);
  118. if(poll_res < 0) {
  119. encode_failed = true;
  120. break;
  121. }
  122. res_buff_size += poll_size;
  123. finish_res = heatshrink_encoder_finish(compress->encoder);
  124. } while(finish_res != HSER_FINISH_DONE);
  125. }
  126. bool result = true;
  127. // Write encoded data to output buffer if compression is efficient. Else - write header and original data
  128. if(!encode_failed && (res_buff_size < data_in_size + 1)) {
  129. FuriHalCompressHeader header = {.is_compressed = 0x01, .reserved = 0x00, .compressed_buff_size = res_buff_size};
  130. memcpy(data_out, &header, sizeof(header));
  131. *data_res_size = res_buff_size;
  132. } else if (data_out_size > data_in_size) {
  133. data_out[0] = 0x00;
  134. memcpy(&data_out[1], data_in, data_in_size);
  135. *data_res_size = data_in_size + 1;
  136. } else {
  137. *data_res_size = 0;
  138. result = false;
  139. }
  140. furi_hal_compress_reset(compress);
  141. return result;
  142. }
  143. 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) {
  144. furi_assert(compress);
  145. furi_assert(data_in);
  146. furi_assert(data_out);
  147. furi_assert(data_res_size);
  148. bool result = false;
  149. bool decode_failed = false;
  150. HSD_sink_res sink_res;
  151. HSD_poll_res poll_res;
  152. HSD_finish_res finish_res;
  153. size_t sink_size = 0;
  154. size_t res_buff_size = 0;
  155. size_t poll_size = 0;
  156. FuriHalCompressHeader* header = (FuriHalCompressHeader*) data_in;
  157. if(header->is_compressed) {
  158. // Sink data to decoding buffer
  159. size_t compressed_size = header->compressed_buff_size;
  160. size_t sunk = sizeof(FuriHalCompressHeader);
  161. while(sunk < compressed_size && !decode_failed) {
  162. sink_res = heatshrink_decoder_sink(compress->decoder, &data_in[sunk], compressed_size - sunk, &sink_size);
  163. if(sink_res < 0) {
  164. decode_failed = true;
  165. break;
  166. }
  167. sunk += sink_size;
  168. do {
  169. poll_res = heatshrink_decoder_poll(compress->decoder, &data_out[res_buff_size], data_out_size, &poll_size);
  170. if(poll_res < 0) {
  171. decode_failed = true;
  172. break;
  173. }
  174. res_buff_size += poll_size;
  175. } while(poll_res == HSDR_POLL_MORE);
  176. }
  177. // Notify sinking complete and poll decoded data
  178. if(!decode_failed) {
  179. finish_res = heatshrink_decoder_finish(compress->decoder);
  180. if(finish_res < 0) {
  181. decode_failed = true;
  182. } else {
  183. do {
  184. poll_res = heatshrink_decoder_poll(compress->decoder, &data_out[res_buff_size], data_out_size, &poll_size);
  185. res_buff_size += poll_size;
  186. finish_res = heatshrink_decoder_finish(compress->decoder);
  187. } while(finish_res != HSDR_FINISH_DONE);
  188. }
  189. }
  190. *data_res_size = res_buff_size;
  191. result = !decode_failed;
  192. } else if(data_out_size >= data_in_size - 1) {
  193. memcpy(data_out, &data_in[1], data_in_size);
  194. *data_res_size = data_in_size - 1;
  195. result = true;
  196. } else {
  197. result = false;
  198. }
  199. furi_hal_compress_reset(compress);
  200. return result;
  201. }