decode_other.go 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. // +build !amd64 appengine !gc noasm
  2. package lz4
  3. func decodeBlock(dst, src []byte) (ret int) {
  4. const hasError = -2
  5. defer func() {
  6. if recover() != nil {
  7. ret = hasError
  8. }
  9. }()
  10. var si, di int
  11. for {
  12. // Literals and match lengths (token).
  13. b := int(src[si])
  14. si++
  15. // Literals.
  16. if lLen := b >> 4; lLen > 0 {
  17. switch {
  18. case lLen < 0xF && si+16 < len(src):
  19. // Shortcut 1
  20. // if we have enough room in src and dst, and the literals length
  21. // is small enough (0..14) then copy all 16 bytes, even if not all
  22. // are part of the literals.
  23. copy(dst[di:], src[si:si+16])
  24. si += lLen
  25. di += lLen
  26. if mLen := b & 0xF; mLen < 0xF {
  27. // Shortcut 2
  28. // if the match length (4..18) fits within the literals, then copy
  29. // all 18 bytes, even if not all are part of the literals.
  30. mLen += 4
  31. if offset := int(src[si]) | int(src[si+1])<<8; mLen <= offset {
  32. i := di - offset
  33. end := i + 18
  34. if end > len(dst) {
  35. // The remaining buffer may not hold 18 bytes.
  36. // See https://github.com/pierrec/lz4/issues/51.
  37. end = len(dst)
  38. }
  39. copy(dst[di:], dst[i:end])
  40. si += 2
  41. di += mLen
  42. continue
  43. }
  44. }
  45. case lLen == 0xF:
  46. for src[si] == 0xFF {
  47. lLen += 0xFF
  48. si++
  49. }
  50. lLen += int(src[si])
  51. si++
  52. fallthrough
  53. default:
  54. copy(dst[di:di+lLen], src[si:si+lLen])
  55. si += lLen
  56. di += lLen
  57. }
  58. }
  59. if si >= len(src) {
  60. return di
  61. }
  62. offset := int(src[si]) | int(src[si+1])<<8
  63. if offset == 0 {
  64. return hasError
  65. }
  66. si += 2
  67. // Match.
  68. mLen := b & 0xF
  69. if mLen == 0xF {
  70. for src[si] == 0xFF {
  71. mLen += 0xFF
  72. si++
  73. }
  74. mLen += int(src[si])
  75. si++
  76. }
  77. mLen += minMatch
  78. // Copy the match.
  79. expanded := dst[di-offset:]
  80. if mLen > offset {
  81. // Efficiently copy the match dst[di-offset:di] into the dst slice.
  82. bytesToCopy := offset * (mLen / offset)
  83. for n := offset; n <= bytesToCopy+offset; n *= 2 {
  84. copy(expanded[n:], expanded[:n])
  85. }
  86. di += bytesToCopy
  87. mLen -= bytesToCopy
  88. }
  89. di += copy(dst[di:di+mLen], expanded[:mLen])
  90. }
  91. }