rangecoder.h 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /*
  2. * Small range coder implementation for lzma.
  3. * Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
  4. *
  5. * Based on LzmaDecode.c from the LZMA SDK 4.22 (http://www.7-zip.org/)
  6. * Copyright (c) 1999-2005 Igor Pavlov
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation; either
  11. * version 2.1 of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  21. */
  22. #include <stdint.h>
  23. #include "libbb.h"
  24. #ifndef always_inline
  25. # if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >0)
  26. # define always_inline __attribute__((always_inline)) inline
  27. # else
  28. # define always_inline inline
  29. # endif
  30. #endif
  31. #ifdef CONFIG_FEATURE_LZMA_FAST
  32. # define speed_inline always_inline
  33. #else
  34. # define speed_inline
  35. #endif
  36. typedef struct {
  37. int fd;
  38. uint8_t *ptr;
  39. uint8_t *buffer;
  40. uint8_t *buffer_end;
  41. int buffer_size;
  42. uint32_t code;
  43. uint32_t range;
  44. uint32_t bound;
  45. } rc_t;
  46. #define RC_TOP_BITS 24
  47. #define RC_MOVE_BITS 5
  48. #define RC_MODEL_TOTAL_BITS 11
  49. /* Called twice: once at startup and once in rc_normalize() */
  50. static void rc_read(rc_t * rc)
  51. {
  52. rc->buffer_size = read(rc->fd, rc->buffer, rc->buffer_size);
  53. if (rc->buffer_size <= 0)
  54. bb_error_msg_and_die("unexpected EOF");
  55. rc->ptr = rc->buffer;
  56. rc->buffer_end = rc->buffer + rc->buffer_size;
  57. }
  58. /* Called once */
  59. static always_inline void rc_init(rc_t * rc, int fd, int buffer_size)
  60. {
  61. int i;
  62. rc->fd = fd;
  63. rc->buffer = malloc(buffer_size);
  64. rc->buffer_size = buffer_size;
  65. rc->buffer_end = rc->buffer + rc->buffer_size;
  66. rc->ptr = rc->buffer_end;
  67. rc->code = 0;
  68. rc->range = 0xFFFFFFFF;
  69. for (i = 0; i < 5; i++) {
  70. if (rc->ptr >= rc->buffer_end)
  71. rc_read(rc);
  72. rc->code = (rc->code << 8) | *rc->ptr++;
  73. }
  74. }
  75. /* Called once. TODO: bb_maybe_free() */
  76. static always_inline void rc_free(rc_t * rc)
  77. {
  78. if (ENABLE_FEATURE_CLEAN_UP)
  79. free(rc->buffer);
  80. }
  81. /* Called twice, but one callsite is in speed_inline'd rc_is_bit_0_helper() */
  82. static void rc_do_normalize(rc_t * rc)
  83. {
  84. if (rc->ptr >= rc->buffer_end)
  85. rc_read(rc);
  86. rc->range <<= 8;
  87. rc->code = (rc->code << 8) | *rc->ptr++;
  88. }
  89. static always_inline void rc_normalize(rc_t * rc)
  90. {
  91. if (rc->range < (1 << RC_TOP_BITS)) {
  92. rc_do_normalize(rc);
  93. }
  94. }
  95. /* Called 9 times */
  96. /* Why rc_is_bit_0_helper exists?
  97. * Because we want to always expose (rc->code < rc->bound) to optimizer
  98. */
  99. static speed_inline uint32_t rc_is_bit_0_helper(rc_t * rc, uint16_t * p)
  100. {
  101. rc_normalize(rc);
  102. rc->bound = *p * (rc->range >> RC_MODEL_TOTAL_BITS);
  103. return rc->bound;
  104. }
  105. static always_inline int rc_is_bit_0(rc_t * rc, uint16_t * p)
  106. {
  107. uint32_t t = rc_is_bit_0_helper(rc, p);
  108. return rc->code < t;
  109. }
  110. /* Called ~10 times, but very small, thus inlined */
  111. static speed_inline void rc_update_bit_0(rc_t * rc, uint16_t * p)
  112. {
  113. rc->range = rc->bound;
  114. *p += ((1 << RC_MODEL_TOTAL_BITS) - *p) >> RC_MOVE_BITS;
  115. }
  116. static speed_inline void rc_update_bit_1(rc_t * rc, uint16_t * p)
  117. {
  118. rc->range -= rc->bound;
  119. rc->code -= rc->bound;
  120. *p -= *p >> RC_MOVE_BITS;
  121. }
  122. /* Called 4 times in unlzma loop */
  123. static int rc_get_bit(rc_t * rc, uint16_t * p, int *symbol)
  124. {
  125. if (rc_is_bit_0(rc, p)) {
  126. rc_update_bit_0(rc, p);
  127. *symbol *= 2;
  128. return 0;
  129. } else {
  130. rc_update_bit_1(rc, p);
  131. *symbol = *symbol * 2 + 1;
  132. return 1;
  133. }
  134. }
  135. /* Called once */
  136. static always_inline int rc_direct_bit(rc_t * rc)
  137. {
  138. rc_normalize(rc);
  139. rc->range >>= 1;
  140. if (rc->code >= rc->range) {
  141. rc->code -= rc->range;
  142. return 1;
  143. }
  144. return 0;
  145. }
  146. /* Called twice */
  147. static speed_inline void
  148. rc_bit_tree_decode(rc_t * rc, uint16_t * p, int num_levels, int *symbol)
  149. {
  150. int i = num_levels;
  151. *symbol = 1;
  152. while (i--)
  153. rc_get_bit(rc, p + *symbol, symbol);
  154. *symbol -= 1 << num_levels;
  155. }
  156. /* vi:set ts=4: */