github.com/driusan/dgit@v0.0.0-20221118233547-f39f0c15edbb/git/delta/reader.go (about)

     1  package delta
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  
     7  	"compress/flate"
     8  )
     9  
    10  // Reader reads a Delta from Src and computes the
    11  // delta using Base to resolve inserts.
    12  type Reader struct {
    13  	src  flate.Reader
    14  	base io.ReadSeeker
    15  
    16  	sz uint64
    17  	// unread from the last read
    18  	cached []byte
    19  }
    20  
    21  // Creates a new Delta using src and base as the source and
    22  func NewReader(src flate.Reader, base io.ReadSeeker) Reader {
    23  	d := Reader{src: src, base: base}
    24  	// Read the source length. We don't care about the value,
    25  	// but need to advance the stream by an approprite amount
    26  	d.readVariable()
    27  
    28  	// Read the target length so we know when we've finished processing
    29  	// the delta stream.
    30  	d.sz = d.readVariable()
    31  	return d
    32  }
    33  
    34  // Reads the resolved delta from the underlying delta stream into buf
    35  func (d *Reader) Read(buf []byte) (int, error) {
    36  	// Read the cached data before we read more from
    37  	// the stream
    38  	if len(d.cached) > 0 {
    39  		return d.readCached(buf)
    40  	}
    41  	instruction, err := d.src.ReadByte()
    42  	if err != nil {
    43  		return 0, err
    44  	}
    45  	if instruction == 0 {
    46  		panic("Reserved/undocumented instruction found.")
    47  	}
    48  	if instruction >= 128 {
    49  		var offset, length uint64
    50  
    51  		if instruction&0x01 != 0 {
    52  			o, err := d.src.ReadByte()
    53  			if err != nil {
    54  				return 0, err
    55  			}
    56  			offset = uint64(o)
    57  		}
    58  		if instruction&0x02 != 0 {
    59  			o, err := d.src.ReadByte()
    60  			if err != nil {
    61  				return 0, err
    62  			}
    63  			offset |= uint64(o) << 8
    64  		}
    65  		if instruction&0x04 != 0 {
    66  			o, err := d.src.ReadByte()
    67  			if err != nil {
    68  				return 0, err
    69  			}
    70  			offset |= uint64(o) << 16
    71  		}
    72  		if instruction&0x08 != 0 {
    73  			o, err := d.src.ReadByte()
    74  			if err != nil {
    75  				return 0, err
    76  			}
    77  			offset |= uint64(o) << 24
    78  		}
    79  
    80  		if instruction&0x10 != 0 {
    81  			l, err := d.src.ReadByte()
    82  			if err != nil {
    83  				return 0, err
    84  			}
    85  			length = uint64(l)
    86  		}
    87  		if instruction&0x20 != 0 {
    88  			l, err := d.src.ReadByte()
    89  			if err != nil {
    90  				return 0, err
    91  			}
    92  			length |= uint64(l) << 8
    93  		}
    94  		if instruction&0x40 != 0 {
    95  			l, err := d.src.ReadByte()
    96  			if err != nil {
    97  				return 0, err
    98  			}
    99  			length |= uint64(l) << 16
   100  		}
   101  		if length == 0 {
   102  			length = 0x10000
   103  		}
   104  
   105  		if _, err := d.base.Seek(int64(offset), io.SeekStart); err != nil {
   106  			return 0, err
   107  		}
   108  		if uint64(len(buf)) >= length {
   109  			// It should all fit in the buffer
   110  			n, err := io.ReadFull(d.base, buf[:length])
   111  			if err != nil {
   112  				return n, err
   113  			}
   114  			if int(n) != int(length) {
   115  				return n, fmt.Errorf("Could not read %v bytes", length)
   116  			}
   117  			return n, err
   118  		}
   119  		// It's not going to all fit in the buffer, so cache it
   120  		// and then return from the cache
   121  		d.cached = make([]byte, length)
   122  		if _, err := io.ReadFull(d.base, d.cached); err != nil {
   123  			return 0, err
   124  		}
   125  		return d.readCached(buf)
   126  	} else {
   127  		// Read instruction bytes
   128  		length := int(instruction)
   129  		if len(buf) >= length {
   130  			// It fits into the buffer, so don't
   131  			// bother caching,
   132  			n, err := io.ReadFull(d.src, buf[:length])
   133  			if n != length {
   134  				return n, fmt.Errorf("Could not read %v bytes", n)
   135  			}
   136  			return n, err
   137  		}
   138  		d.cached = make([]byte, length)
   139  		n, err := io.ReadFull(d.src, d.cached)
   140  		if err != nil {
   141  			return n, err
   142  		}
   143  		if n != length {
   144  			return n, fmt.Errorf("Insert: Could not read %v bytes", length)
   145  		}
   146  		return d.readCached(buf)
   147  	}
   148  	panic("Unreachable code reached")
   149  }
   150  
   151  func (d *Reader) readCached(buf []byte) (n int, err error) {
   152  	n = copy(buf, d.cached)
   153  	if n == len(d.cached) {
   154  		d.cached = nil
   155  	} else {
   156  		d.cached = d.cached[n:]
   157  	}
   158  	return n, nil
   159  }
   160  
   161  // Reads a variable length integer from the underlying stream and
   162  // returns it as a uint64
   163  func (d *Reader) readVariable() uint64 {
   164  	var val uint64
   165  	var i uint = 0
   166  	for {
   167  		b, err := d.src.ReadByte()
   168  		if err != nil {
   169  			panic(err)
   170  		}
   171  		val |= uint64(b&127) << (i * 7)
   172  		if b < 128 {
   173  			break
   174  		}
   175  		i += 1
   176  	}
   177  	return val
   178  }
   179  
   180  func (d Reader) Len() int {
   181  	return int(d.sz)
   182  }