You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

184 lines
4.2KB

  1. /*
  2. * Snappy decompression algorithm
  3. * Copyright (c) 2015 Luca Barbato
  4. *
  5. * This file is part of Libav.
  6. *
  7. * Libav is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * Libav is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with Libav; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. #include "libavutil/mem.h"
  22. #include "bytestream.h"
  23. #include "snappy.h"
  24. enum {
  25. SNAPPY_LITERAL,
  26. SNAPPY_COPY_1,
  27. SNAPPY_COPY_2,
  28. SNAPPY_COPY_4,
  29. };
  30. static int64_t bytestream2_get_levarint(GetByteContext *gb)
  31. {
  32. uint64_t val = 0;
  33. int shift = 0;
  34. int tmp;
  35. do {
  36. tmp = bytestream2_get_byte(gb);
  37. val |= (tmp & 127) << shift;
  38. shift += 7;
  39. } while (tmp & 128);
  40. return val;
  41. }
  42. static int snappy_literal(GetByteContext *gb, uint8_t *p, int size, int val)
  43. {
  44. unsigned int len = 1;
  45. switch (val) {
  46. case 63:
  47. len += bytestream2_get_le32(gb);
  48. break;
  49. case 62:
  50. len += bytestream2_get_le24(gb);
  51. break;
  52. case 61:
  53. len += bytestream2_get_le16(gb);
  54. break;
  55. case 60:
  56. len += bytestream2_get_byte(gb);
  57. break;
  58. default: // val < 60
  59. len += val;
  60. }
  61. if (size < len)
  62. return AVERROR_INVALIDDATA;
  63. bytestream2_get_buffer(gb, p, len);
  64. return len;
  65. }
  66. static int snappy_copy(uint8_t *start, uint8_t *p, int size,
  67. unsigned int off, int len)
  68. {
  69. uint8_t *q;
  70. int i;
  71. if (off > p - start || size < len)
  72. return AVERROR_INVALIDDATA;
  73. q = p - off;
  74. for (i = 0; i < len; i++)
  75. p[i] = q[i];
  76. return len;
  77. }
  78. static int snappy_copy1(GetByteContext *gb, uint8_t *start, uint8_t *p,
  79. int size, int val)
  80. {
  81. int len = 4 + (val & 0x7);
  82. unsigned int off = bytestream2_get_byte(gb) | (val & 0x38) << 5;
  83. return snappy_copy(start, p, size, off, len);
  84. }
  85. static int snappy_copy2(GetByteContext *gb, uint8_t *start, uint8_t *p,
  86. int size, int val)
  87. {
  88. int len = 1 + val;
  89. unsigned int off = bytestream2_get_le16(gb);
  90. return snappy_copy(start, p, size, off, len);
  91. }
  92. static int snappy_copy4(GetByteContext *gb, uint8_t *start, uint8_t *p,
  93. int size, int val)
  94. {
  95. int len = 1 + val;
  96. unsigned int off = bytestream2_get_le32(gb);
  97. return snappy_copy(start, p, size, off, len);
  98. }
  99. static int64_t decode_len(GetByteContext *gb)
  100. {
  101. int64_t len = bytestream2_get_levarint(gb);
  102. if (len < 0 || len > UINT_MAX)
  103. return AVERROR_INVALIDDATA;
  104. return len;
  105. }
  106. int64_t ff_snappy_peek_uncompressed_length(GetByteContext *gb)
  107. {
  108. int pos = bytestream2_get_bytes_left(gb);
  109. int64_t len = decode_len(gb);
  110. bytestream2_seek(gb, -pos, SEEK_END);
  111. return len;
  112. }
  113. int ff_snappy_uncompress(GetByteContext *gb, uint8_t *buf, int64_t *size)
  114. {
  115. int64_t len = decode_len(gb);
  116. int ret = 0;
  117. uint8_t *p;
  118. if (len < 0)
  119. return len;
  120. if (len > *size)
  121. return AVERROR_BUG;
  122. *size = len;
  123. p = buf;
  124. while (bytestream2_get_bytes_left(gb) > 0) {
  125. uint8_t s = bytestream2_get_byte(gb);
  126. int val = s >> 2;
  127. switch (s & 0x03) {
  128. case SNAPPY_LITERAL:
  129. ret = snappy_literal(gb, p, len, val);
  130. break;
  131. case SNAPPY_COPY_1:
  132. ret = snappy_copy1(gb, buf, p, len, val);
  133. break;
  134. case SNAPPY_COPY_2:
  135. ret = snappy_copy2(gb, buf, p, len, val);
  136. break;
  137. case SNAPPY_COPY_4:
  138. ret = snappy_copy4(gb, buf, p, len, val);
  139. break;
  140. }
  141. if (ret < 0)
  142. return ret;
  143. p += ret;
  144. len -= ret;
  145. }
  146. return 0;
  147. }