lzo1x_decompress_safe.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*
  2. * LZO1X Decompressor from LZO
  3. *
  4. * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer <markus@oberhumer.com>
  5. *
  6. * The full LZO package can be found at:
  7. * http://www.oberhumer.com/opensource/lzo/
  8. *
  9. * Changed for Linux kernel use by:
  10. * Nitin Gupta <nitingupta910@gmail.com>
  11. * Richard Purdie <rpurdie@openedhand.com>
  12. */
  13. #ifndef STATIC
  14. #include <linux/module.h>
  15. #include <linux/kernel.h>
  16. #endif
  17. #include <asm/unaligned.h>
  18. #include <linux/lzo.h>
  19. #include "lzodefs.h"
  20. #define HAVE_IP(x) ((size_t)(ip_end - ip) >= (size_t)(x))
  21. #define HAVE_OP(x) ((size_t)(op_end - op) >= (size_t)(x))
  22. #define NEED_IP(x) if (!HAVE_IP(x)) goto input_overrun
  23. #define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun
  24. #define TEST_LB(m_pos) if ((m_pos) < out) goto lookbehind_overrun
  25. int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
  26. unsigned char *out, size_t *out_len)
  27. {
  28. unsigned char *op;
  29. const unsigned char *ip;
  30. size_t t, next;
  31. size_t state = 0;
  32. const unsigned char *m_pos;
  33. const unsigned char * const ip_end = in + in_len;
  34. unsigned char * const op_end = out + *out_len;
  35. op = out;
  36. ip = in;
  37. if (unlikely(in_len < 3))
  38. goto input_overrun;
  39. if (*ip > 17) {
  40. t = *ip++ - 17;
  41. if (t < 4) {
  42. next = t;
  43. goto match_next;
  44. }
  45. goto copy_literal_run;
  46. }
  47. for (;;) {
  48. t = *ip++;
  49. if (t < 16) {
  50. if (likely(state == 0)) {
  51. if (unlikely(t == 0)) {
  52. while (unlikely(*ip == 0)) {
  53. t += 255;
  54. ip++;
  55. NEED_IP(1);
  56. }
  57. t += 15 + *ip++;
  58. }
  59. t += 3;
  60. copy_literal_run:
  61. #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
  62. if (likely(HAVE_IP(t + 15) && HAVE_OP(t + 15))) {
  63. const unsigned char *ie = ip + t;
  64. unsigned char *oe = op + t;
  65. do {
  66. COPY8(op, ip);
  67. op += 8;
  68. ip += 8;
  69. COPY8(op, ip);
  70. op += 8;
  71. ip += 8;
  72. } while (ip < ie);
  73. ip = ie;
  74. op = oe;
  75. } else
  76. #endif
  77. {
  78. NEED_OP(t);
  79. NEED_IP(t + 3);
  80. do {
  81. *op++ = *ip++;
  82. } while (--t > 0);
  83. }
  84. state = 4;
  85. continue;
  86. } else if (state != 4) {
  87. next = t & 3;
  88. m_pos = op - 1;
  89. m_pos -= t >> 2;
  90. m_pos -= *ip++ << 2;
  91. TEST_LB(m_pos);
  92. NEED_OP(2);
  93. op[0] = m_pos[0];
  94. op[1] = m_pos[1];
  95. op += 2;
  96. goto match_next;
  97. } else {
  98. next = t & 3;
  99. m_pos = op - (1 + M2_MAX_OFFSET);
  100. m_pos -= t >> 2;
  101. m_pos -= *ip++ << 2;
  102. t = 3;
  103. }
  104. } else if (t >= 64) {
  105. next = t & 3;
  106. m_pos = op - 1;
  107. m_pos -= (t >> 2) & 7;
  108. m_pos -= *ip++ << 3;
  109. t = (t >> 5) - 1 + (3 - 1);
  110. } else if (t >= 32) {
  111. t = (t & 31) + (3 - 1);
  112. if (unlikely(t == 2)) {
  113. while (unlikely(*ip == 0)) {
  114. t += 255;
  115. ip++;
  116. NEED_IP(1);
  117. }
  118. t += 31 + *ip++;
  119. NEED_IP(2);
  120. }
  121. m_pos = op - 1;
  122. next = get_unaligned_le16(ip);
  123. ip += 2;
  124. m_pos -= next >> 2;
  125. next &= 3;
  126. } else {
  127. m_pos = op;
  128. m_pos -= (t & 8) << 11;
  129. t = (t & 7) + (3 - 1);
  130. if (unlikely(t == 2)) {
  131. while (unlikely(*ip == 0)) {
  132. t += 255;
  133. ip++;
  134. NEED_IP(1);
  135. }
  136. t += 7 + *ip++;
  137. NEED_IP(2);
  138. }
  139. next = get_unaligned_le16(ip);
  140. ip += 2;
  141. m_pos -= next >> 2;
  142. next &= 3;
  143. if (m_pos == op)
  144. goto eof_found;
  145. m_pos -= 0x4000;
  146. }
  147. TEST_LB(m_pos);
  148. #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
  149. if (op - m_pos >= 8) {
  150. unsigned char *oe = op + t;
  151. if (likely(HAVE_OP(t + 15))) {
  152. do {
  153. COPY8(op, m_pos);
  154. op += 8;
  155. m_pos += 8;
  156. COPY8(op, m_pos);
  157. op += 8;
  158. m_pos += 8;
  159. } while (op < oe);
  160. op = oe;
  161. if (HAVE_IP(6)) {
  162. state = next;
  163. COPY4(op, ip);
  164. op += next;
  165. ip += next;
  166. continue;
  167. }
  168. } else {
  169. NEED_OP(t);
  170. do {
  171. *op++ = *m_pos++;
  172. } while (op < oe);
  173. }
  174. } else
  175. #endif
  176. {
  177. unsigned char *oe = op + t;
  178. NEED_OP(t);
  179. op[0] = m_pos[0];
  180. op[1] = m_pos[1];
  181. op += 2;
  182. m_pos += 2;
  183. do {
  184. *op++ = *m_pos++;
  185. } while (op < oe);
  186. }
  187. match_next:
  188. state = next;
  189. t = next;
  190. #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
  191. if (likely(HAVE_IP(6) && HAVE_OP(4))) {
  192. COPY4(op, ip);
  193. op += t;
  194. ip += t;
  195. } else
  196. #endif
  197. {
  198. NEED_IP(t + 3);
  199. NEED_OP(t);
  200. while (t > 0) {
  201. *op++ = *ip++;
  202. t--;
  203. }
  204. }
  205. }
  206. eof_found:
  207. *out_len = op - out;
  208. return (t != 3 ? LZO_E_ERROR :
  209. ip == ip_end ? LZO_E_OK :
  210. ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN);
  211. input_overrun:
  212. *out_len = op - out;
  213. return LZO_E_INPUT_OVERRUN;
  214. output_overrun:
  215. *out_len = op - out;
  216. return LZO_E_OUTPUT_OVERRUN;
  217. lookbehind_overrun:
  218. *out_len = op - out;
  219. return LZO_E_LOOKBEHIND_OVERRUN;
  220. }
  221. #ifndef STATIC
  222. EXPORT_SYMBOL_GPL(lzo1x_decompress_safe);
  223. MODULE_LICENSE("GPL");
  224. MODULE_DESCRIPTION("LZO1X Decompressor");
  225. #endif