reader_legacy.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. package lz4
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. "io"
  6. )
  7. // ReaderLegacy implements the LZ4Demo frame decoder.
  8. // The Header is set after the first call to Read().
  9. type ReaderLegacy struct {
  10. Header
  11. // Handler called when a block has been successfully read.
  12. // It provides the number of bytes read.
  13. OnBlockDone func(size int)
  14. lastBlock bool
  15. buf [8]byte // Scrap buffer.
  16. pos int64 // Current position in src.
  17. src io.Reader // Source.
  18. zdata []byte // Compressed data.
  19. data []byte // Uncompressed data.
  20. idx int // Index of unread bytes into data.
  21. skip int64 // Bytes to skip before next read.
  22. dpos int64 // Position in dest
  23. }
  24. // NewReaderLegacy returns a new LZ4Demo frame decoder.
  25. // No access to the underlying io.Reader is performed.
  26. func NewReaderLegacy(src io.Reader) *ReaderLegacy {
  27. r := &ReaderLegacy{src: src}
  28. return r
  29. }
  30. // readHeader checks the frame magic number and parses the frame descriptoz.
  31. // Skippable frames are supported even as a first frame although the LZ4
  32. // specifications recommends skippable frames not to be used as first frames.
  33. func (z *ReaderLegacy) readLegacyHeader() error {
  34. z.lastBlock = false
  35. magic, err := z.readUint32()
  36. if err != nil {
  37. z.pos += 4
  38. if err == io.ErrUnexpectedEOF {
  39. return io.EOF
  40. }
  41. return err
  42. }
  43. if magic != frameMagicLegacy {
  44. return ErrInvalid
  45. }
  46. z.pos += 4
  47. // Legacy has fixed 8MB blocksizes
  48. // https://github.com/lz4/lz4/blob/dev/doc/lz4_Frame_format.md#legacy-frame
  49. bSize := blockSize4M * 2
  50. // Allocate the compressed/uncompressed buffers.
  51. // The compressed buffer cannot exceed the uncompressed one.
  52. if n := 2 * bSize; cap(z.zdata) < n {
  53. z.zdata = make([]byte, n, n)
  54. }
  55. if debugFlag {
  56. debug("header block max size size=%d", bSize)
  57. }
  58. z.zdata = z.zdata[:bSize]
  59. z.data = z.zdata[:cap(z.zdata)][bSize:]
  60. z.idx = len(z.data)
  61. z.Header.done = true
  62. if debugFlag {
  63. debug("header read: %v", z.Header)
  64. }
  65. return nil
  66. }
  67. // Read decompresses data from the underlying source into the supplied buffer.
  68. //
  69. // Since there can be multiple streams concatenated, Header values may
  70. // change between calls to Read(). If that is the case, no data is actually read from
  71. // the underlying io.Reader, to allow for potential input buffer resizing.
  72. func (z *ReaderLegacy) Read(buf []byte) (int, error) {
  73. if debugFlag {
  74. debug("Read buf len=%d", len(buf))
  75. }
  76. if !z.Header.done {
  77. if err := z.readLegacyHeader(); err != nil {
  78. return 0, err
  79. }
  80. if debugFlag {
  81. debug("header read OK compressed buffer %d / %d uncompressed buffer %d : %d index=%d",
  82. len(z.zdata), cap(z.zdata), len(z.data), cap(z.data), z.idx)
  83. }
  84. }
  85. if len(buf) == 0 {
  86. return 0, nil
  87. }
  88. if z.idx == len(z.data) {
  89. // No data ready for reading, process the next block.
  90. if debugFlag {
  91. debug(" reading block from writer %d %d", z.idx, blockSize4M*2)
  92. }
  93. // Reset uncompressed buffer
  94. z.data = z.zdata[:cap(z.zdata)][len(z.zdata):]
  95. bLen, err := z.readUint32()
  96. if err != nil {
  97. return 0, err
  98. }
  99. if debugFlag {
  100. debug(" bLen %d (0x%x) offset = %d (0x%x)", bLen, bLen, z.pos, z.pos)
  101. }
  102. z.pos += 4
  103. // Legacy blocks are always compressed, even when detrimental
  104. if debugFlag {
  105. debug(" compressed block size %d", bLen)
  106. }
  107. if int(bLen) > cap(z.data) {
  108. return 0, fmt.Errorf("lz4: invalid block size: %d", bLen)
  109. }
  110. zdata := z.zdata[:bLen]
  111. if _, err := io.ReadFull(z.src, zdata); err != nil {
  112. return 0, err
  113. }
  114. z.pos += int64(bLen)
  115. n, err := UncompressBlock(zdata, z.data)
  116. if err != nil {
  117. return 0, err
  118. }
  119. z.data = z.data[:n]
  120. if z.OnBlockDone != nil {
  121. z.OnBlockDone(n)
  122. }
  123. z.idx = 0
  124. // Legacy blocks are fixed to 8MB, if we read a decompressed block smaller than this
  125. // it means we've reached the end...
  126. if n < blockSize4M*2 {
  127. z.lastBlock = true
  128. }
  129. }
  130. if z.skip > int64(len(z.data[z.idx:])) {
  131. z.skip -= int64(len(z.data[z.idx:]))
  132. z.dpos += int64(len(z.data[z.idx:]))
  133. z.idx = len(z.data)
  134. return 0, nil
  135. }
  136. z.idx += int(z.skip)
  137. z.dpos += z.skip
  138. z.skip = 0
  139. n := copy(buf, z.data[z.idx:])
  140. z.idx += n
  141. z.dpos += int64(n)
  142. if debugFlag {
  143. debug("%v] copied %d bytes to input (%d:%d)", z.lastBlock, n, z.idx, len(z.data))
  144. }
  145. if z.lastBlock && len(z.data) == z.idx {
  146. return n, io.EOF
  147. }
  148. return n, nil
  149. }
  150. // Seek implements io.Seeker, but supports seeking forward from the current
  151. // position only. Any other seek will return an error. Allows skipping output
  152. // bytes which aren't needed, which in some scenarios is faster than reading
  153. // and discarding them.
  154. // Note this may cause future calls to Read() to read 0 bytes if all of the
  155. // data they would have returned is skipped.
  156. func (z *ReaderLegacy) Seek(offset int64, whence int) (int64, error) {
  157. if offset < 0 || whence != io.SeekCurrent {
  158. return z.dpos + z.skip, ErrUnsupportedSeek
  159. }
  160. z.skip += offset
  161. return z.dpos + z.skip, nil
  162. }
  163. // Reset discards the Reader's state and makes it equivalent to the
  164. // result of its original state from NewReader, but reading from r instead.
  165. // This permits reusing a Reader rather than allocating a new one.
  166. func (z *ReaderLegacy) Reset(r io.Reader) {
  167. z.Header = Header{}
  168. z.pos = 0
  169. z.src = r
  170. z.zdata = z.zdata[:0]
  171. z.data = z.data[:0]
  172. z.idx = 0
  173. }
  174. // readUint32 reads an uint32 into the supplied buffer.
  175. // The idea is to make use of the already allocated buffers avoiding additional allocations.
  176. func (z *ReaderLegacy) readUint32() (uint32, error) {
  177. buf := z.buf[:4]
  178. _, err := io.ReadFull(z.src, buf)
  179. x := binary.LittleEndian.Uint32(buf)
  180. return x, err
  181. }