heatshrink_encoder.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <stdbool.h>
  4. #include "heatshrink_encoder.h"
  5. typedef enum {
  6. HSES_NOT_FULL, /* input buffer not full enough */
  7. HSES_FILLED, /* buffer is full */
  8. HSES_SEARCH, /* searching for patterns */
  9. HSES_YIELD_TAG_BIT, /* yield tag bit */
  10. HSES_YIELD_LITERAL, /* emit literal byte */
  11. HSES_YIELD_BR_INDEX, /* yielding backref index */
  12. HSES_YIELD_BR_LENGTH, /* yielding backref length */
  13. HSES_SAVE_BACKLOG, /* copying buffer to backlog */
  14. HSES_FLUSH_BITS, /* flush bit buffer */
  15. HSES_DONE, /* done */
  16. } HSE_state;
  17. #if HEATSHRINK_DEBUGGING_LOGS
  18. #include <stdio.h>
  19. #include <ctype.h>
  20. #include <assert.h>
  21. #define LOG(...) fprintf(stderr, __VA_ARGS__)
  22. #define ASSERT(X) assert(X)
  23. static const char *state_names[] = {
  24. "not_full",
  25. "filled",
  26. "search",
  27. "yield_tag_bit",
  28. "yield_literal",
  29. "yield_br_index",
  30. "yield_br_length",
  31. "save_backlog",
  32. "flush_bits",
  33. "done",
  34. };
  35. #else
  36. #define LOG(...) /* no-op */
  37. #define ASSERT(X) /* no-op */
  38. #endif
  39. // Encoder flags
  40. enum {
  41. FLAG_IS_FINISHING = 0x01,
  42. };
  43. typedef struct {
  44. uint8_t *buf; /* output buffer */
  45. size_t buf_size; /* buffer size */
  46. size_t *output_size; /* bytes pushed to buffer, so far */
  47. } output_info;
  48. #define MATCH_NOT_FOUND ((uint16_t)-1)
  49. static uint16_t get_input_offset(heatshrink_encoder *hse);
  50. static uint16_t get_input_buffer_size(heatshrink_encoder *hse);
  51. static uint16_t get_lookahead_size(heatshrink_encoder *hse);
  52. static void add_tag_bit(heatshrink_encoder *hse, output_info *oi, uint8_t tag);
  53. static int can_take_byte(output_info *oi);
  54. static int is_finishing(heatshrink_encoder *hse);
  55. static void save_backlog(heatshrink_encoder *hse);
  56. /* Push COUNT (max 8) bits to the output buffer, which has room. */
  57. static void push_bits(heatshrink_encoder *hse, uint8_t count, uint8_t bits,
  58. output_info *oi);
  59. static uint8_t push_outgoing_bits(heatshrink_encoder *hse, output_info *oi);
  60. static void push_literal_byte(heatshrink_encoder *hse, output_info *oi);
  61. #if HEATSHRINK_DYNAMIC_ALLOC
  62. heatshrink_encoder *heatshrink_encoder_alloc(uint8_t* buffer, uint8_t window_sz2,
  63. uint8_t lookahead_sz2) {
  64. if ((window_sz2 < HEATSHRINK_MIN_WINDOW_BITS) ||
  65. (window_sz2 > HEATSHRINK_MAX_WINDOW_BITS) ||
  66. (lookahead_sz2 < HEATSHRINK_MIN_LOOKAHEAD_BITS) ||
  67. (lookahead_sz2 >= window_sz2)) {
  68. return NULL;
  69. }
  70. /* Note: 2 * the window size is used because the buffer needs to fit
  71. * (1 << window_sz2) bytes for the current input, and an additional
  72. * (1 << window_sz2) bytes for the previous buffer of input, which
  73. * will be scanned for useful backreferences. */
  74. size_t buf_sz = (2 << window_sz2);
  75. heatshrink_encoder *hse = HEATSHRINK_MALLOC(sizeof(*hse));
  76. if (hse == NULL) { return NULL; }
  77. hse->window_sz2 = window_sz2;
  78. hse->lookahead_sz2 = lookahead_sz2;
  79. hse->buffer = buffer;
  80. heatshrink_encoder_reset(hse);
  81. #if HEATSHRINK_USE_INDEX
  82. size_t index_sz = buf_sz*sizeof(uint16_t);
  83. hse->search_index = HEATSHRINK_MALLOC(index_sz + sizeof(struct hs_index));
  84. if (hse->search_index == NULL) {
  85. HEATSHRINK_FREE(hse, sizeof(*hse) + buf_sz);
  86. return NULL;
  87. }
  88. hse->search_index->size = index_sz;
  89. #endif
  90. LOG("-- allocated encoder with buffer size of %zu (%u byte input size)\n",
  91. buf_sz, get_input_buffer_size(hse));
  92. return hse;
  93. }
  94. void heatshrink_encoder_free(heatshrink_encoder *hse) {
  95. #if HEATSHRINK_USE_INDEX
  96. size_t index_sz = sizeof(struct hs_index) + hse->search_index->size;
  97. HEATSHRINK_FREE(hse->search_index, index_sz);
  98. (void)index_sz;
  99. #endif
  100. HEATSHRINK_FREE(hse, sizeof(heatshrink_encoder));
  101. }
  102. #endif
  103. void heatshrink_encoder_reset(heatshrink_encoder *hse) {
  104. hse->input_size = 0;
  105. hse->state = HSES_NOT_FULL;
  106. hse->match_scan_index = 0;
  107. hse->flags = 0;
  108. hse->bit_index = 0x80;
  109. hse->current_byte = 0x00;
  110. hse->match_length = 0;
  111. hse->outgoing_bits = 0x0000;
  112. hse->outgoing_bits_count = 0;
  113. #ifdef LOOP_DETECT
  114. hse->loop_detect = (uint32_t)-1;
  115. #endif
  116. }
  117. HSE_sink_res heatshrink_encoder_sink(heatshrink_encoder *hse,
  118. uint8_t *in_buf, size_t size, size_t *input_size) {
  119. if ((hse == NULL) || (in_buf == NULL) || (input_size == NULL)) {
  120. return HSER_SINK_ERROR_NULL;
  121. }
  122. /* Sinking more content after saying the content is done, tsk tsk */
  123. if (is_finishing(hse)) { return HSER_SINK_ERROR_MISUSE; }
  124. /* Sinking more content before processing is done */
  125. if (hse->state != HSES_NOT_FULL) { return HSER_SINK_ERROR_MISUSE; }
  126. uint16_t write_offset = get_input_offset(hse) + hse->input_size;
  127. uint16_t ibs = get_input_buffer_size(hse);
  128. uint16_t rem = ibs - hse->input_size;
  129. uint16_t cp_sz = rem < size ? rem : size;
  130. memcpy(&hse->buffer[write_offset], in_buf, cp_sz);
  131. *input_size = cp_sz;
  132. hse->input_size += cp_sz;
  133. LOG("-- sunk %u bytes (of %zu) into encoder at %d, input buffer now has %u\n",
  134. cp_sz, size, write_offset, hse->input_size);
  135. if (cp_sz == rem) {
  136. LOG("-- internal buffer is now full\n");
  137. hse->state = HSES_FILLED;
  138. }
  139. return HSER_SINK_OK;
  140. }
  141. /***************
  142. * Compression *
  143. ***************/
  144. static uint16_t find_longest_match(heatshrink_encoder *hse, uint16_t start,
  145. uint16_t end, const uint16_t maxlen, uint16_t *match_length);
  146. static void do_indexing(heatshrink_encoder *hse);
  147. static HSE_state st_step_search(heatshrink_encoder *hse);
  148. static HSE_state st_yield_tag_bit(heatshrink_encoder *hse,
  149. output_info *oi);
  150. static HSE_state st_yield_literal(heatshrink_encoder *hse,
  151. output_info *oi);
  152. static HSE_state st_yield_br_index(heatshrink_encoder *hse,
  153. output_info *oi);
  154. static HSE_state st_yield_br_length(heatshrink_encoder *hse,
  155. output_info *oi);
  156. static HSE_state st_save_backlog(heatshrink_encoder *hse);
  157. static HSE_state st_flush_bit_buffer(heatshrink_encoder *hse,
  158. output_info *oi);
  159. HSE_poll_res heatshrink_encoder_poll(heatshrink_encoder *hse,
  160. uint8_t *out_buf, size_t out_buf_size, size_t *output_size) {
  161. if ((hse == NULL) || (out_buf == NULL) || (output_size == NULL)) {
  162. return HSER_POLL_ERROR_NULL;
  163. }
  164. if (out_buf_size == 0) {
  165. LOG("-- MISUSE: output buffer size is 0\n");
  166. return HSER_POLL_ERROR_MISUSE;
  167. }
  168. *output_size = 0;
  169. output_info oi;
  170. oi.buf = out_buf;
  171. oi.buf_size = out_buf_size;
  172. oi.output_size = output_size;
  173. while (1) {
  174. LOG("-- polling, state %u (%s), flags 0x%02x\n",
  175. hse->state, state_names[hse->state], hse->flags);
  176. uint8_t in_state = hse->state;
  177. switch (in_state) {
  178. case HSES_NOT_FULL:
  179. return HSER_POLL_EMPTY;
  180. case HSES_FILLED:
  181. do_indexing(hse);
  182. hse->state = HSES_SEARCH;
  183. break;
  184. case HSES_SEARCH:
  185. hse->state = st_step_search(hse);
  186. break;
  187. case HSES_YIELD_TAG_BIT:
  188. hse->state = st_yield_tag_bit(hse, &oi);
  189. break;
  190. case HSES_YIELD_LITERAL:
  191. hse->state = st_yield_literal(hse, &oi);
  192. break;
  193. case HSES_YIELD_BR_INDEX:
  194. hse->state = st_yield_br_index(hse, &oi);
  195. break;
  196. case HSES_YIELD_BR_LENGTH:
  197. hse->state = st_yield_br_length(hse, &oi);
  198. break;
  199. case HSES_SAVE_BACKLOG:
  200. hse->state = st_save_backlog(hse);
  201. break;
  202. case HSES_FLUSH_BITS:
  203. hse->state = st_flush_bit_buffer(hse, &oi);
  204. /* fall through */
  205. case HSES_DONE:
  206. return HSER_POLL_EMPTY;
  207. default:
  208. LOG("-- bad state %s\n", state_names[hse->state]);
  209. return HSER_POLL_ERROR_MISUSE;
  210. }
  211. if (hse->state == in_state) {
  212. /* Check if output buffer is exhausted. */
  213. if (*output_size == out_buf_size) return HSER_POLL_MORE;
  214. }
  215. }
  216. }
  217. HSE_finish_res heatshrink_encoder_finish(heatshrink_encoder *hse) {
  218. if (hse == NULL) { return HSER_FINISH_ERROR_NULL; }
  219. LOG("-- setting is_finishing flag\n");
  220. hse->flags |= FLAG_IS_FINISHING;
  221. if (hse->state == HSES_NOT_FULL) { hse->state = HSES_FILLED; }
  222. return hse->state == HSES_DONE ? HSER_FINISH_DONE : HSER_FINISH_MORE;
  223. }
  224. static HSE_state st_step_search(heatshrink_encoder *hse) {
  225. uint16_t window_length = get_input_buffer_size(hse);
  226. uint16_t lookahead_sz = get_lookahead_size(hse);
  227. uint16_t msi = hse->match_scan_index;
  228. LOG("## step_search, scan @ +%d (%d/%d), input size %d\n",
  229. msi, hse->input_size + msi, 2*window_length, hse->input_size);
  230. bool fin = is_finishing(hse);
  231. if (msi > hse->input_size - (fin ? 1 : lookahead_sz)) {
  232. /* Current search buffer is exhausted, copy it into the
  233. * backlog and await more input. */
  234. LOG("-- end of search @ %d\n", msi);
  235. return fin ? HSES_FLUSH_BITS : HSES_SAVE_BACKLOG;
  236. }
  237. uint16_t input_offset = get_input_offset(hse);
  238. uint16_t end = input_offset + msi;
  239. uint16_t start = end - window_length;
  240. uint16_t max_possible = lookahead_sz;
  241. if (hse->input_size - msi < lookahead_sz) {
  242. max_possible = hse->input_size - msi;
  243. }
  244. uint16_t match_length = 0;
  245. uint16_t match_pos = find_longest_match(hse,
  246. start, end, max_possible, &match_length);
  247. if (match_pos == MATCH_NOT_FOUND) {
  248. LOG("ss Match not found\n");
  249. hse->match_scan_index++;
  250. hse->match_length = 0;
  251. return HSES_YIELD_TAG_BIT;
  252. } else {
  253. LOG("ss Found match of %d bytes at %d\n", match_length, match_pos);
  254. hse->match_pos = match_pos;
  255. hse->match_length = match_length;
  256. ASSERT(match_pos <= 1 << HEATSHRINK_ENCODER_WINDOW_BITS(hse) /*window_length*/);
  257. return HSES_YIELD_TAG_BIT;
  258. }
  259. }
  260. static HSE_state st_yield_tag_bit(heatshrink_encoder *hse,
  261. output_info *oi) {
  262. if (can_take_byte(oi)) {
  263. if (hse->match_length == 0) {
  264. add_tag_bit(hse, oi, HEATSHRINK_LITERAL_MARKER);
  265. return HSES_YIELD_LITERAL;
  266. } else {
  267. add_tag_bit(hse, oi, HEATSHRINK_BACKREF_MARKER);
  268. hse->outgoing_bits = hse->match_pos - 1;
  269. hse->outgoing_bits_count = HEATSHRINK_ENCODER_WINDOW_BITS(hse);
  270. return HSES_YIELD_BR_INDEX;
  271. }
  272. } else {
  273. return HSES_YIELD_TAG_BIT; /* output is full, continue */
  274. }
  275. }
  276. static HSE_state st_yield_literal(heatshrink_encoder *hse,
  277. output_info *oi) {
  278. if (can_take_byte(oi)) {
  279. push_literal_byte(hse, oi);
  280. return HSES_SEARCH;
  281. } else {
  282. return HSES_YIELD_LITERAL;
  283. }
  284. }
  285. static HSE_state st_yield_br_index(heatshrink_encoder *hse,
  286. output_info *oi) {
  287. if (can_take_byte(oi)) {
  288. LOG("-- yielding backref index %u\n", hse->match_pos);
  289. if (push_outgoing_bits(hse, oi) > 0) {
  290. return HSES_YIELD_BR_INDEX; /* continue */
  291. } else {
  292. hse->outgoing_bits = hse->match_length - 1;
  293. hse->outgoing_bits_count = HEATSHRINK_ENCODER_LOOKAHEAD_BITS(hse);
  294. return HSES_YIELD_BR_LENGTH; /* done */
  295. }
  296. } else {
  297. return HSES_YIELD_BR_INDEX; /* continue */
  298. }
  299. }
  300. static HSE_state st_yield_br_length(heatshrink_encoder *hse,
  301. output_info *oi) {
  302. if (can_take_byte(oi)) {
  303. LOG("-- yielding backref length %u\n", hse->match_length);
  304. if (push_outgoing_bits(hse, oi) > 0) {
  305. return HSES_YIELD_BR_LENGTH;
  306. } else {
  307. hse->match_scan_index += hse->match_length;
  308. hse->match_length = 0;
  309. return HSES_SEARCH;
  310. }
  311. } else {
  312. return HSES_YIELD_BR_LENGTH;
  313. }
  314. }
  315. static HSE_state st_save_backlog(heatshrink_encoder *hse) {
  316. LOG("-- saving backlog\n");
  317. save_backlog(hse);
  318. return HSES_NOT_FULL;
  319. }
  320. static HSE_state st_flush_bit_buffer(heatshrink_encoder *hse,
  321. output_info *oi) {
  322. if (hse->bit_index == 0x80) {
  323. LOG("-- done!\n");
  324. return HSES_DONE;
  325. } else if (can_take_byte(oi)) {
  326. LOG("-- flushing remaining byte (bit_index == 0x%02x)\n", hse->bit_index);
  327. oi->buf[(*oi->output_size)++] = hse->current_byte;
  328. LOG("-- done!\n");
  329. return HSES_DONE;
  330. } else {
  331. return HSES_FLUSH_BITS;
  332. }
  333. }
  334. static void add_tag_bit(heatshrink_encoder *hse, output_info *oi, uint8_t tag) {
  335. LOG("-- adding tag bit: %d\n", tag);
  336. push_bits(hse, 1, tag, oi);
  337. }
  338. static uint16_t get_input_offset(heatshrink_encoder *hse) {
  339. return get_input_buffer_size(hse);
  340. }
  341. static uint16_t get_input_buffer_size(heatshrink_encoder *hse) {
  342. return (1 << HEATSHRINK_ENCODER_WINDOW_BITS(hse));
  343. (void)hse;
  344. }
  345. static uint16_t get_lookahead_size(heatshrink_encoder *hse) {
  346. return (1 << HEATSHRINK_ENCODER_LOOKAHEAD_BITS(hse));
  347. (void)hse;
  348. }
  349. static void do_indexing(heatshrink_encoder *hse) {
  350. #if HEATSHRINK_USE_INDEX
  351. /* Build an index array I that contains flattened linked lists
  352. * for the previous instances of every byte in the buffer.
  353. *
  354. * For example, if buf[200] == 'x', then index[200] will either
  355. * be an offset i such that buf[i] == 'x', or a negative offset
  356. * to indicate end-of-list. This significantly speeds up matching,
  357. * while only using sizeof(uint16_t)*sizeof(buffer) bytes of RAM.
  358. *
  359. * Future optimization options:
  360. * 1. Since any negative value represents end-of-list, the other
  361. * 15 bits could be used to improve the index dynamically.
  362. *
  363. * 2. Likewise, the last lookahead_sz bytes of the index will
  364. * not be usable, so temporary data could be stored there to
  365. * dynamically improve the index.
  366. * */
  367. struct hs_index *hsi = HEATSHRINK_ENCODER_INDEX(hse);
  368. int16_t last[256];
  369. memset(last, 0xFF, sizeof(last));
  370. uint8_t * const data = hse->buffer;
  371. int16_t * const index = hsi->index;
  372. const uint16_t input_offset = get_input_offset(hse);
  373. const uint16_t end = input_offset + hse->input_size;
  374. for (uint16_t i=0; i<end; i++) {
  375. uint8_t v = data[i];
  376. int16_t lv = last[v];
  377. index[i] = lv;
  378. last[v] = i;
  379. }
  380. #else
  381. (void)hse;
  382. #endif
  383. }
  384. static int is_finishing(heatshrink_encoder *hse) {
  385. return hse->flags & FLAG_IS_FINISHING;
  386. }
  387. static int can_take_byte(output_info *oi) {
  388. return *oi->output_size < oi->buf_size;
  389. }
  390. /* Return the longest match for the bytes at buf[end:end+maxlen] between
  391. * buf[start] and buf[end-1]. If no match is found, return -1. */
  392. static uint16_t find_longest_match(heatshrink_encoder *hse, uint16_t start,
  393. uint16_t end, const uint16_t maxlen, uint16_t *match_length) {
  394. LOG("-- scanning for match of buf[%u:%u] between buf[%u:%u] (max %u bytes)\n",
  395. end, end + maxlen, start, end + maxlen - 1, maxlen);
  396. uint8_t *buf = hse->buffer;
  397. uint16_t match_maxlen = 0;
  398. uint16_t match_index = MATCH_NOT_FOUND;
  399. uint16_t len = 0;
  400. uint8_t * const needlepoint = &buf[end];
  401. #if HEATSHRINK_USE_INDEX
  402. struct hs_index *hsi = HEATSHRINK_ENCODER_INDEX(hse);
  403. int16_t pos = hsi->index[end];
  404. while (pos - (int16_t)start >= 0) {
  405. uint8_t * const pospoint = &buf[pos];
  406. len = 0;
  407. /* Only check matches that will potentially beat the current maxlen.
  408. * This is redundant with the index if match_maxlen is 0, but the
  409. * added branch overhead to check if it == 0 seems to be worse. */
  410. if (pospoint[match_maxlen] != needlepoint[match_maxlen]) {
  411. pos = hsi->index[pos];
  412. continue;
  413. }
  414. for (len = 1; len < maxlen; len++) {
  415. if (pospoint[len] != needlepoint[len]) break;
  416. }
  417. if (len > match_maxlen) {
  418. match_maxlen = len;
  419. match_index = pos;
  420. if (len == maxlen) { break; } /* won't find better */
  421. }
  422. pos = hsi->index[pos];
  423. }
  424. #else
  425. for (int16_t pos=end - 1; pos - (int16_t)start >= 0; pos--) {
  426. uint8_t * const pospoint = &buf[pos];
  427. if ((pospoint[match_maxlen] == needlepoint[match_maxlen])
  428. && (*pospoint == *needlepoint)) {
  429. for (len=1; len<maxlen; len++) {
  430. if (0) {
  431. LOG(" --> cmp buf[%d] == 0x%02x against %02x (start %u)\n",
  432. pos + len, pospoint[len], needlepoint[len], start);
  433. }
  434. if (pospoint[len] != needlepoint[len]) { break; }
  435. }
  436. if (len > match_maxlen) {
  437. match_maxlen = len;
  438. match_index = pos;
  439. if (len == maxlen) { break; } /* don't keep searching */
  440. }
  441. }
  442. }
  443. #endif
  444. const size_t break_even_point =
  445. (1 + HEATSHRINK_ENCODER_WINDOW_BITS(hse) +
  446. HEATSHRINK_ENCODER_LOOKAHEAD_BITS(hse));
  447. /* Instead of comparing break_even_point against 8*match_maxlen,
  448. * compare match_maxlen against break_even_point/8 to avoid
  449. * overflow. Since MIN_WINDOW_BITS and MIN_LOOKAHEAD_BITS are 4 and
  450. * 3, respectively, break_even_point/8 will always be at least 1. */
  451. if (match_maxlen > (break_even_point / 8)) {
  452. LOG("-- best match: %u bytes at -%u\n",
  453. match_maxlen, end - match_index);
  454. *match_length = match_maxlen;
  455. return end - match_index;
  456. }
  457. LOG("-- none found\n");
  458. return MATCH_NOT_FOUND;
  459. }
  460. static uint8_t push_outgoing_bits(heatshrink_encoder *hse, output_info *oi) {
  461. uint8_t count = 0;
  462. uint8_t bits = 0;
  463. if (hse->outgoing_bits_count > 8) {
  464. count = 8;
  465. bits = hse->outgoing_bits >> (hse->outgoing_bits_count - 8);
  466. } else {
  467. count = hse->outgoing_bits_count;
  468. bits = hse->outgoing_bits;
  469. }
  470. if (count > 0) {
  471. LOG("-- pushing %d outgoing bits: 0x%02x\n", count, bits);
  472. push_bits(hse, count, bits, oi);
  473. hse->outgoing_bits_count -= count;
  474. }
  475. return count;
  476. }
  477. /* Push COUNT (max 8) bits to the output buffer, which has room.
  478. * Bytes are set from the lowest bits, up. */
  479. static void push_bits(heatshrink_encoder *hse, uint8_t count, uint8_t bits,
  480. output_info *oi) {
  481. ASSERT(count <= 8);
  482. LOG("++ push_bits: %d bits, input of 0x%02x\n", count, bits);
  483. /* If adding a whole byte and at the start of a new output byte,
  484. * just push it through whole and skip the bit IO loop. */
  485. if (count == 8 && hse->bit_index == 0x80) {
  486. oi->buf[(*oi->output_size)++] = bits;
  487. } else {
  488. for (int i=count - 1; i>=0; i--) {
  489. bool bit = bits & (1 << i);
  490. if (bit) { hse->current_byte |= hse->bit_index; }
  491. if (0) {
  492. LOG(" -- setting bit %d at bit index 0x%02x, byte => 0x%02x\n",
  493. bit ? 1 : 0, hse->bit_index, hse->current_byte);
  494. }
  495. hse->bit_index >>= 1;
  496. if (hse->bit_index == 0x00) {
  497. hse->bit_index = 0x80;
  498. LOG(" > pushing byte 0x%02x\n", hse->current_byte);
  499. oi->buf[(*oi->output_size)++] = hse->current_byte;
  500. hse->current_byte = 0x00;
  501. }
  502. }
  503. }
  504. }
  505. static void push_literal_byte(heatshrink_encoder *hse, output_info *oi) {
  506. uint16_t processed_offset = hse->match_scan_index - 1;
  507. uint16_t input_offset = get_input_offset(hse) + processed_offset;
  508. uint8_t c = hse->buffer[input_offset];
  509. LOG("-- yielded literal byte 0x%02x ('%c') from +%d\n",
  510. c, isprint(c) ? c : '.', input_offset);
  511. push_bits(hse, 8, c, oi);
  512. }
  513. static void save_backlog(heatshrink_encoder *hse) {
  514. size_t input_buf_sz = get_input_buffer_size(hse);
  515. uint16_t msi = hse->match_scan_index;
  516. /* Copy processed data to beginning of buffer, so it can be
  517. * used for future matches. Don't bother checking whether the
  518. * input is less than the maximum size, because if it isn't,
  519. * we're done anyway. */
  520. uint16_t rem = input_buf_sz - msi; // unprocessed bytes
  521. uint16_t shift_sz = input_buf_sz + rem;
  522. memmove(&hse->buffer[0],
  523. &hse->buffer[input_buf_sz - rem],
  524. shift_sz);
  525. hse->match_scan_index = 0;
  526. hse->input_size -= input_buf_sz - rem;
  527. }