decode_other.go 2.0 KB

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