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.

186 lines
4.3KB

  1. /*
  2. * Snappy decompression algorithm
  3. * Copyright (c) 2015 Luca Barbato
  4. *
  5. * This file is part of FFmpeg.
  6. *
  7. * FFmpeg 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. * FFmpeg 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 FFmpeg; 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. if (shift > 31 || ((tmp & 127LL) << shift) > INT_MAX)
  38. return AVERROR_INVALIDDATA;
  39. val |= (tmp & 127) << shift;
  40. shift += 7;
  41. } while (tmp & 128);
  42. return val;
  43. }
  44. static int snappy_literal(GetByteContext *gb, uint8_t *p, int size, int val)
  45. {
  46. unsigned int len = 1;
  47. switch (val) {
  48. case 63:
  49. len += bytestream2_get_le32(gb);
  50. break;
  51. case 62:
  52. len += bytestream2_get_le24(gb);
  53. break;
  54. case 61:
  55. len += bytestream2_get_le16(gb);
  56. break;
  57. case 60:
  58. len += bytestream2_get_byte(gb);
  59. break;
  60. default: // val < 60
  61. len += val;
  62. }
  63. if (size < len)
  64. return AVERROR_INVALIDDATA;
  65. bytestream2_get_buffer(gb, p, len);
  66. return len;
  67. }
  68. static int snappy_copy(uint8_t *start, uint8_t *p, int size,
  69. unsigned int off, int len)
  70. {
  71. uint8_t *q;
  72. int i;
  73. if (off > p - start || size < len)
  74. return AVERROR_INVALIDDATA;
  75. q = p - off;
  76. for (i = 0; i < len; i++)
  77. p[i] = q[i];
  78. return len;
  79. }
  80. static int snappy_copy1(GetByteContext *gb, uint8_t *start, uint8_t *p,
  81. int size, int val)
  82. {
  83. int len = 4 + (val & 0x7);
  84. unsigned int off = bytestream2_get_byte(gb) | (val & 0x38) << 5;
  85. return snappy_copy(start, p, size, off, len);
  86. }
  87. static int snappy_copy2(GetByteContext *gb, uint8_t *start, uint8_t *p,
  88. int size, int val)
  89. {
  90. int len = 1 + val;
  91. unsigned int off = bytestream2_get_le16(gb);
  92. return snappy_copy(start, p, size, off, len);
  93. }
  94. static int snappy_copy4(GetByteContext *gb, uint8_t *start, uint8_t *p,
  95. int size, int val)
  96. {
  97. int len = 1 + val;
  98. unsigned int off = bytestream2_get_le32(gb);
  99. return snappy_copy(start, p, size, off, len);
  100. }
  101. static int64_t decode_len(GetByteContext *gb)
  102. {
  103. int64_t len = bytestream2_get_levarint(gb);
  104. if (len < 0 || len > UINT_MAX)
  105. return AVERROR_INVALIDDATA;
  106. return len;
  107. }
  108. int64_t ff_snappy_peek_uncompressed_length(GetByteContext *gb)
  109. {
  110. int pos = bytestream2_get_bytes_left(gb);
  111. int64_t len = decode_len(gb);
  112. bytestream2_seek(gb, -pos, SEEK_END);
  113. return len;
  114. }
  115. int ff_snappy_uncompress(GetByteContext *gb, uint8_t *buf, int64_t *size)
  116. {
  117. int64_t len = decode_len(gb);
  118. int ret = 0;
  119. uint8_t *p;
  120. if (len < 0)
  121. return len;
  122. if (len > *size)
  123. return AVERROR_BUFFER_TOO_SMALL;
  124. *size = len;
  125. p = buf;
  126. while (bytestream2_get_bytes_left(gb) > 0) {
  127. uint8_t s = bytestream2_get_byte(gb);
  128. int val = s >> 2;
  129. switch (s & 0x03) {
  130. case SNAPPY_LITERAL:
  131. ret = snappy_literal(gb, p, len, val);
  132. break;
  133. case SNAPPY_COPY_1:
  134. ret = snappy_copy1(gb, buf, p, len, val);
  135. break;
  136. case SNAPPY_COPY_2:
  137. ret = snappy_copy2(gb, buf, p, len, val);
  138. break;
  139. case SNAPPY_COPY_4:
  140. ret = snappy_copy4(gb, buf, p, len, val);
  141. break;
  142. }
  143. if (ret < 0)
  144. return ret;
  145. p += ret;
  146. len -= ret;
  147. }
  148. return 0;
  149. }