compress.c 8.1 KB

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