furi_hal_compress.c 8.7 KB

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