decode_other.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  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. package snapref
  5. // decode writes the decoding of src to dst. It assumes that the varint-encoded
  6. // length of the decompressed bytes has already been read, and that len(dst)
  7. // equals that length.
  8. //
  9. // It returns 0 on success or a decodeErrCodeXxx error code on failure.
  10. func decode(dst, src []byte) int {
  11. var d, s, offset, length int
  12. for s < len(src) {
  13. switch src[s] & 0x03 {
  14. case tagLiteral:
  15. x := uint32(src[s] >> 2)
  16. switch {
  17. case x < 60:
  18. s++
  19. case x == 60:
  20. s += 2
  21. if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
  22. return decodeErrCodeCorrupt
  23. }
  24. x = uint32(src[s-1])
  25. case x == 61:
  26. s += 3
  27. if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
  28. return decodeErrCodeCorrupt
  29. }
  30. x = uint32(src[s-2]) | uint32(src[s-1])<<8
  31. case x == 62:
  32. s += 4
  33. if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
  34. return decodeErrCodeCorrupt
  35. }
  36. x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16
  37. case x == 63:
  38. s += 5
  39. if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
  40. return decodeErrCodeCorrupt
  41. }
  42. x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24
  43. }
  44. length = int(x) + 1
  45. if length <= 0 {
  46. return decodeErrCodeUnsupportedLiteralLength
  47. }
  48. if length > len(dst)-d || length > len(src)-s {
  49. return decodeErrCodeCorrupt
  50. }
  51. copy(dst[d:], src[s:s+length])
  52. d += length
  53. s += length
  54. continue
  55. case tagCopy1:
  56. s += 2
  57. if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
  58. return decodeErrCodeCorrupt
  59. }
  60. length = 4 + int(src[s-2])>>2&0x7
  61. offset = int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1]))
  62. case tagCopy2:
  63. s += 3
  64. if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
  65. return decodeErrCodeCorrupt
  66. }
  67. length = 1 + int(src[s-3])>>2
  68. offset = int(uint32(src[s-2]) | uint32(src[s-1])<<8)
  69. case tagCopy4:
  70. s += 5
  71. if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
  72. return decodeErrCodeCorrupt
  73. }
  74. length = 1 + int(src[s-5])>>2
  75. offset = int(uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24)
  76. }
  77. if offset <= 0 || d < offset || length > len(dst)-d {
  78. return decodeErrCodeCorrupt
  79. }
  80. // Copy from an earlier sub-slice of dst to a later sub-slice.
  81. // If no overlap, use the built-in copy:
  82. if offset >= length {
  83. copy(dst[d:d+length], dst[d-offset:])
  84. d += length
  85. continue
  86. }
  87. // Unlike the built-in copy function, this byte-by-byte copy always runs
  88. // forwards, even if the slices overlap. Conceptually, this is:
  89. //
  90. // d += forwardCopy(dst[d:d+length], dst[d-offset:])
  91. //
  92. // We align the slices into a and b and show the compiler they are the same size.
  93. // This allows the loop to run without bounds checks.
  94. a := dst[d : d+length]
  95. b := dst[d-offset:]
  96. b = b[:len(a)]
  97. for i := range a {
  98. a[i] = b[i]
  99. }
  100. d += length
  101. }
  102. if d != len(dst) {
  103. return decodeErrCodeCorrupt
  104. }
  105. return 0
  106. }