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.

174 lines
4.0KB

  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. int ff_snappy_uncompress(GetByteContext *gb, uint8_t **buf, int64_t *size)
  107. {
  108. int64_t len = decode_len(gb);
  109. int ret = 0;
  110. uint8_t *p;
  111. if (len < 0)
  112. return len;
  113. if ((ret = av_reallocp(buf, len)) < 0)
  114. return AVERROR(ENOMEM);
  115. *size = len;
  116. p = *buf;
  117. while (bytestream2_get_bytes_left(gb) > 0) {
  118. uint8_t s = bytestream2_get_byte(gb);
  119. int val = s >> 2;
  120. switch (s & 0x03) {
  121. case SNAPPY_LITERAL:
  122. ret = snappy_literal(gb, p, len, val);
  123. break;
  124. case SNAPPY_COPY_1:
  125. ret = snappy_copy1(gb, *buf, p, len, val);
  126. break;
  127. case SNAPPY_COPY_2:
  128. ret = snappy_copy2(gb, *buf, p, len, val);
  129. break;
  130. case SNAPPY_COPY_4:
  131. ret = snappy_copy4(gb, *buf, p, len, val);
  132. break;
  133. }
  134. if (ret < 0)
  135. return ret;
  136. p += ret;
  137. len -= ret;
  138. }
  139. return 0;
  140. }