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.

101 lines
3.1 KiB

  1. // Copyright 2016 The Snappy-Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // +build !amd64 appengine !gc noasm
  5. package snappy
  6. // decode writes the decoding of src to dst. It assumes that the varint-encoded
  7. // length of the decompressed bytes has already been read, and that len(dst)
  8. // equals that length.
  9. //
  10. // It returns 0 on success or a decodeErrCodeXxx error code on failure.
  11. func decode(dst, src []byte) int {
  12. var d, s, offset, length int
  13. for s < len(src) {
  14. switch src[s] & 0x03 {
  15. case tagLiteral:
  16. x := uint32(src[s] >> 2)
  17. switch {
  18. case x < 60:
  19. s++
  20. case x == 60:
  21. s += 2
  22. if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
  23. return decodeErrCodeCorrupt
  24. }
  25. x = uint32(src[s-1])
  26. case x == 61:
  27. s += 3
  28. if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
  29. return decodeErrCodeCorrupt
  30. }
  31. x = uint32(src[s-2]) | uint32(src[s-1])<<8
  32. case x == 62:
  33. s += 4
  34. if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
  35. return decodeErrCodeCorrupt
  36. }
  37. x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16
  38. case x == 63:
  39. s += 5
  40. if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
  41. return decodeErrCodeCorrupt
  42. }
  43. x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24
  44. }
  45. length = int(x) + 1
  46. if length <= 0 {
  47. return decodeErrCodeUnsupportedLiteralLength
  48. }
  49. if length > len(dst)-d || length > len(src)-s {
  50. return decodeErrCodeCorrupt
  51. }
  52. copy(dst[d:], src[s:s+length])
  53. d += length
  54. s += length
  55. continue
  56. case tagCopy1:
  57. s += 2
  58. if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
  59. return decodeErrCodeCorrupt
  60. }
  61. length = 4 + int(src[s-2])>>2&0x7
  62. offset = int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1]))
  63. case tagCopy2:
  64. s += 3
  65. if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
  66. return decodeErrCodeCorrupt
  67. }
  68. length = 1 + int(src[s-3])>>2
  69. offset = int(uint32(src[s-2]) | uint32(src[s-1])<<8)
  70. case tagCopy4:
  71. s += 5
  72. if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
  73. return decodeErrCodeCorrupt
  74. }
  75. length = 1 + int(src[s-5])>>2
  76. offset = int(uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24)
  77. }
  78. if offset <= 0 || d < offset || length > len(dst)-d {
  79. return decodeErrCodeCorrupt
  80. }
  81. // Copy from an earlier sub-slice of dst to a later sub-slice. Unlike
  82. // the built-in copy function, this byte-by-byte copy always runs
  83. // forwards, even if the slices overlap. Conceptually, this is:
  84. //
  85. // d += forwardCopy(dst[d:d+length], dst[d-offset:])
  86. for end := d + length; d != end; d++ {
  87. dst[d] = dst[d-offset]
  88. }
  89. }
  90. if d != len(dst) {
  91. return decodeErrCodeCorrupt
  92. }
  93. return 0
  94. }