decode_other.go 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  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 && di+18 < len(dst) && 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. copy(dst[di:], dst[i:i+18])
  34. si += 2
  35. di += mLen
  36. continue
  37. }
  38. }
  39. case lLen == 0xF:
  40. for src[si] == 0xFF {
  41. lLen += 0xFF
  42. si++
  43. }
  44. lLen += int(src[si])
  45. si++
  46. fallthrough
  47. default:
  48. copy(dst[di:di+lLen], src[si:si+lLen])
  49. si += lLen
  50. di += lLen
  51. }
  52. }
  53. if si >= len(src) {
  54. return di
  55. }
  56. offset := int(src[si]) | int(src[si+1])<<8
  57. if offset == 0 {
  58. return hasError
  59. }
  60. si += 2
  61. // Match.
  62. mLen := b & 0xF
  63. if mLen == 0xF {
  64. for src[si] == 0xFF {
  65. mLen += 0xFF
  66. si++
  67. }
  68. mLen += int(src[si])
  69. si++
  70. }
  71. mLen += minMatch
  72. // Copy the match.
  73. expanded := dst[di-offset:]
  74. if mLen > offset {
  75. // Efficiently copy the match dst[di-offset:di] into the dst slice.
  76. bytesToCopy := offset * (mLen / offset)
  77. for n := offset; n <= bytesToCopy+offset; n *= 2 {
  78. copy(expanded[n:], expanded[:n])
  79. }
  80. di += bytesToCopy
  81. mLen -= bytesToCopy
  82. }
  83. di += copy(dst[di:di+mLen], expanded[:mLen])
  84. }
  85. }