decode_other.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  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,!arm64 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.
  82. // If no overlap, use the built-in copy:
  83. if offset >= length {
  84. copy(dst[d:d+length], dst[d-offset:])
  85. d += length
  86. continue
  87. }
  88. // Unlike the built-in copy function, this byte-by-byte copy always runs
  89. // forwards, even if the slices overlap. Conceptually, this is:
  90. //
  91. // d += forwardCopy(dst[d:d+length], dst[d-offset:])
  92. //
  93. // We align the slices into a and b and show the compiler they are the same size.
  94. // This allows the loop to run without bounds checks.
  95. a := dst[d : d+length]
  96. b := dst[d-offset:]
  97. b = b[:len(a)]
  98. for i := range a {
  99. a[i] = b[i]
  100. }
  101. d += length
  102. }
  103. if d != len(dst) {
  104. return decodeErrCodeCorrupt
  105. }
  106. return 0
  107. }