diff options
Diffstat (limited to 'formats')
-rw-r--r-- | formats/idxfile/decoder.go | 23 | ||||
-rw-r--r-- | formats/idxfile/encoder.go | 24 | ||||
-rw-r--r-- | formats/index/decoder.go | 107 | ||||
-rw-r--r-- | formats/packfile/scanner.go | 126 |
4 files changed, 56 insertions, 224 deletions
diff --git a/formats/idxfile/decoder.go b/formats/idxfile/decoder.go index 57b508d..884d32b 100644 --- a/formats/idxfile/decoder.go +++ b/formats/idxfile/decoder.go @@ -2,11 +2,11 @@ package idxfile import ( "bytes" - "encoding/binary" "errors" "io" "gopkg.in/src-d/go-git.v4/core" + "gopkg.in/src-d/go-git.v4/utils/binary" ) var ( @@ -70,7 +70,7 @@ func validateHeader(r io.Reader) error { } func readVersion(idx *Idxfile, r io.Reader) error { - v, err := readInt32(r) + v, err := binary.ReadUint32(r) if err != nil { return err } @@ -80,21 +80,19 @@ func readVersion(idx *Idxfile, r io.Reader) error { } idx.Version = v - return nil } func readFanout(idx *Idxfile, r io.Reader) error { var err error - for i := 0; i < 255; i++ { - idx.Fanout[i], err = readInt32(r) + idx.Fanout[i], err = binary.ReadUint32(r) if err != nil { return err } } - idx.ObjectCount, err = readInt32(r) + idx.ObjectCount, err = binary.ReadUint32(r) return err } @@ -115,7 +113,7 @@ func readObjectNames(idx *Idxfile, r io.Reader) error { func readCRC32(idx *Idxfile, r io.Reader) error { c := int(idx.ObjectCount) for i := 0; i < c; i++ { - if err := binary.Read(r, binary.BigEndian, &idx.Entries[i].CRC32); err != nil { + if err := binary.Read(r, &idx.Entries[i].CRC32); err != nil { return err } } @@ -126,7 +124,7 @@ func readCRC32(idx *Idxfile, r io.Reader) error { func readOffsets(idx *Idxfile, r io.Reader) error { c := int(idx.ObjectCount) for i := 0; i < c; i++ { - o, err := readInt32(r) + o, err := binary.ReadUint32(r) if err != nil { return err } @@ -148,12 +146,3 @@ func readChecksums(idx *Idxfile, r io.Reader) error { return nil } - -func readInt32(r io.Reader) (uint32, error) { - var v uint32 - if err := binary.Read(r, binary.BigEndian, &v); err != nil { - return 0, err - } - - return v, nil -} diff --git a/formats/idxfile/encoder.go b/formats/idxfile/encoder.go index 0fe9ae6..164414a 100644 --- a/formats/idxfile/encoder.go +++ b/formats/idxfile/encoder.go @@ -2,13 +2,11 @@ package idxfile import ( "crypto/sha1" - "encoding/binary" - "fmt" "hash" "io" "sort" - "gopkg.in/src-d/go-git.v4/core" + "gopkg.in/src-d/go-git.v4/utils/binary" ) // An Encoder writes idx files to an output stream. @@ -56,13 +54,13 @@ func (e *Encoder) encodeHeader(idx *Idxfile) (int, error) { return c, err } - return c + 4, e.writeInt32(idx.Version) + return c + 4, binary.WriteUint32(e, idx.Version) } func (e *Encoder) encodeFanout(idx *Idxfile) (int, error) { fanout := idx.calculateFanout() for _, c := range fanout { - if err := e.writeInt32(c); err != nil { + if err := binary.WriteUint32(e, c); err != nil { return 0, err } } @@ -71,31 +69,23 @@ func (e *Encoder) encodeFanout(idx *Idxfile) (int, error) { } func (e *Encoder) encodeHashes(idx *Idxfile) (int, error) { - repet := make(map[core.Hash]int, 0) - sz := 0 for _, ent := range idx.Entries { i, err := e.Write(ent.Hash[:]) sz += i - repet[ent.Hash]++ if err != nil { return sz, err } } - for h, c := range repet { - if c > 1 { - fmt.Println(h, c) - } - } return sz, nil } func (e *Encoder) encodeCRC32(idx *Idxfile) (int, error) { sz := 0 for _, ent := range idx.Entries { - err := binary.Write(e, binary.BigEndian, ent.CRC32) + err := binary.Write(e, ent.CRC32) sz += 4 if err != nil { @@ -109,7 +99,7 @@ func (e *Encoder) encodeCRC32(idx *Idxfile) (int, error) { func (e *Encoder) encodeOffsets(idx *Idxfile) (int, error) { sz := 0 for _, ent := range idx.Entries { - if err := e.writeInt32(uint32(ent.Offset)); err != nil { + if err := binary.WriteUint32(e, uint32(ent.Offset)); err != nil { return sz, err } @@ -133,10 +123,6 @@ func (e *Encoder) encodeChecksums(idx *Idxfile) (int, error) { return 40, nil } -func (e *Encoder) writeInt32(value uint32) error { - return binary.Write(e, binary.BigEndian, value) -} - type EntryList []Entry func (p EntryList) Len() int { return len(p) } diff --git a/formats/index/decoder.go b/formats/index/decoder.go index 9bb25dd..8e37fd1 100644 --- a/formats/index/decoder.go +++ b/formats/index/decoder.go @@ -2,7 +2,6 @@ package index import ( "bytes" - "encoding/binary" "errors" "io" "io/ioutil" @@ -10,6 +9,7 @@ import ( "time" "gopkg.in/src-d/go-git.v4/core" + "gopkg.in/src-d/go-git.v4/utils/binary" ) var ( @@ -50,14 +50,14 @@ func NewDecoder(r io.Reader) *Decoder { // Decode reads the whole index object from its input and stores it in the // value pointed to by idx. func (d *Decoder) Decode(idx *Index) error { - version, err := validateHeader(d.r) + var err error + idx.Version, err = validateHeader(d.r) if err != nil { return err } - idx.Version = version - - if err := binary.Read(d.r, binary.BigEndian, &idx.EntryCount); err != nil { + idx.EntryCount, err = binary.ReadUint32(d.r) + if err != nil { return err } @@ -101,7 +101,7 @@ func (d *Decoder) readEntry(idx *Index) (*Entry, error) { &e.Flags, } - if err := readBinary(d.r, flow...); err != nil { + if err := binary.Read(d.r, flow...); err != nil { return nil, err } @@ -111,8 +111,8 @@ func (d *Decoder) readEntry(idx *Index) (*Entry, error) { e.Stage = Stage(e.Flags>>12) & 0x3 if e.Flags&EntryExtended != 0 { - var extended uint16 - if err := readBinary(d.r, &extended); err != nil { + extended, err := binary.ReadUint16(d.r) + if err != nil { return nil, err } @@ -150,7 +150,7 @@ func (d *Decoder) readEntryName(idx *Index, e *Entry) error { } func (d *Decoder) doReadEntryNameV4() (string, error) { - l, err := readVariableWidthInt(d.r) + l, err := binary.ReadVariableWidthInt(d.r) if err != nil { return "", err } @@ -160,7 +160,7 @@ func (d *Decoder) doReadEntryNameV4() (string, error) { base = d.lastEntry.Name[:len(d.lastEntry.Name)-int(l)] } - name, err := readUntil(d.r, '\x00') + name, err := binary.ReadUntil(d.r, '\x00') if err != nil { return "", err } @@ -172,7 +172,7 @@ func (d *Decoder) doReadEntryName(e *Entry) (string, error) { pLen := e.Flags & nameMask name := make([]byte, int64(pLen)) - if err := binary.Read(d.r, binary.BigEndian, &name); err != nil { + if err := binary.Read(d.r, &name); err != nil { return "", err } @@ -217,8 +217,8 @@ func (d *Decoder) readExtension(idx *Index) error { return err } - var len uint32 - if err := binary.Read(d.r, binary.BigEndian, &len); err != nil { + len, err := binary.ReadUint32(d.r) + if err != nil { return err } @@ -254,7 +254,8 @@ func validateHeader(r io.Reader) (version uint32, err error) { return 0, ErrMalformedSignature } - if err := binary.Read(r, binary.BigEndian, &version); err != nil { + version, err = binary.ReadUint32(r) + if err != nil { return 0, err } @@ -291,14 +292,14 @@ func (d *treeExtensionDecoder) Decode(t *Tree) error { func (d *treeExtensionDecoder) readEntry() (*TreeEntry, error) { e := &TreeEntry{} - path, err := readUntil(d.r, '\x00') + path, err := binary.ReadUntil(d.r, '\x00') if err != nil { return nil, err } e.Path = string(path) - count, err := readUntil(d.r, ' ') + count, err := binary.ReadUntil(d.r, ' ') if err != nil { return nil, err } @@ -315,7 +316,7 @@ func (d *treeExtensionDecoder) readEntry() (*TreeEntry, error) { } e.Entries = i - trees, err := readUntil(d.r, '\n') + trees, err := binary.ReadUntil(d.r, '\n') if err != nil { return nil, err } @@ -327,7 +328,7 @@ func (d *treeExtensionDecoder) readEntry() (*TreeEntry, error) { e.Trees = i - if err := binary.Read(d.r, binary.BigEndian, &e.Hash); err != nil { + if err := binary.Read(d.r, &e.Hash); err != nil { return nil, err } @@ -358,7 +359,7 @@ func (d *resolveUndoDecoder) readEntry() (*ResolveUndoEntry, error) { Stages: make(map[Stage]core.Hash, 0), } - path, err := readUntil(d.r, '\x00') + path, err := binary.ReadUntil(d.r, '\x00') if err != nil { return nil, err } @@ -373,7 +374,7 @@ func (d *resolveUndoDecoder) readEntry() (*ResolveUndoEntry, error) { for s := range e.Stages { var hash core.Hash - if err := binary.Read(d.r, binary.BigEndian, hash[:]); err != nil { + if err := binary.Read(d.r, hash[:]); err != nil { return nil, err } @@ -384,7 +385,7 @@ func (d *resolveUndoDecoder) readEntry() (*ResolveUndoEntry, error) { } func (d *resolveUndoDecoder) readStage(e *ResolveUndoEntry, s Stage) error { - ascii, err := readUntil(d.r, '\x00') + ascii, err := binary.ReadUntil(d.r, '\x00') if err != nil { return err } @@ -400,67 +401,3 @@ func (d *resolveUndoDecoder) readStage(e *ResolveUndoEntry, s Stage) error { return nil } - -func readBinary(r io.Reader, data ...interface{}) error { - for _, v := range data { - err := binary.Read(r, binary.BigEndian, v) - if err != nil { - return err - } - } - - return nil -} - -func readUntil(r io.Reader, delim byte) ([]byte, error) { - var buf [1]byte - value := make([]byte, 0, 16) - for { - if _, err := r.Read(buf[:]); err != nil { - if err == io.EOF { - return nil, err - } - - return nil, err - } - - if buf[0] == delim { - return value, nil - } - - value = append(value, buf[0]) - } -} - -// dheader[pos] = ofs & 127; -// while (ofs >>= 7) -// dheader[--pos] = 128 | (--ofs & 127); -// -func readVariableWidthInt(r io.Reader) (int64, error) { - var c byte - if err := readBinary(r, &c); err != nil { - return 0, err - } - - var v = int64(c & maskLength) - for moreBytesInLength(c) { - v++ - if err := readBinary(r, &c); err != nil { - return 0, err - } - - v = (v << lengthBits) + int64(c&maskLength) - } - - return v, nil -} - -const ( - maskContinue = uint8(128) // 1000 000 - maskLength = uint8(127) // 0111 1111 - lengthBits = uint8(7) // subsequent bytes has 7 bits to store the length -) - -func moreBytesInLength(c byte) bool { - return c&maskContinue > 0 -} diff --git a/formats/packfile/scanner.go b/formats/packfile/scanner.go index a5e4215..69cc7d0 100644 --- a/formats/packfile/scanner.go +++ b/formats/packfile/scanner.go @@ -4,7 +4,6 @@ import ( "bufio" "bytes" "compress/zlib" - "encoding/binary" "fmt" "hash" "hash/crc32" @@ -12,6 +11,7 @@ import ( "io/ioutil" "gopkg.in/src-d/go-git.v4/core" + "gopkg.in/src-d/go-git.v4/utils/binary" ) var ( @@ -129,7 +129,7 @@ func (s *Scanner) isValidSignature(sig []byte) bool { // readVersion reads and returns the version field of a packfile. func (s *Scanner) readVersion() (uint32, error) { - return s.readInt32() + return binary.ReadUint32(s.r) } // isSupportedVersion returns whether version v is supported by the parser. @@ -140,17 +140,7 @@ func (s *Scanner) isSupportedVersion(v uint32) bool { // readCount reads and returns the count of objects field of a packfile. func (s *Scanner) readCount() (uint32, error) { - return s.readInt32() -} - -// ReadInt32 reads 4 bytes and returns them as a Big Endian int32. -func (s *Scanner) readInt32() (uint32, error) { - var v uint32 - if err := binary.Read(s.r, binary.BigEndian, &v); err != nil { - return 0, err - } - - return v, nil + return binary.ReadUint32(s.r) } // NextObjectHeader returns the ObjectHeader for the next object in the reader @@ -177,15 +167,15 @@ func (s *Scanner) NextObjectHeader() (*ObjectHeader, error) { switch h.Type { case core.OFSDeltaObject: - no, err := s.readNegativeOffset() + no, err := binary.ReadVariableWidthInt(s.r) if err != nil { return nil, err } - h.OffsetReference = h.Offset + no + h.OffsetReference = h.Offset - no case core.REFDeltaObject: var err error - h.Reference, err = s.readHash() + h.Reference, err = binary.ReadHash(s.r) if err != nil { return nil, err } @@ -240,10 +230,19 @@ func (s *Scanner) readObjectTypeAndLength() (core.ObjectType, int64, error) { return t, l, err } +const ( + maskType = uint8(112) // 0111 0000 + maskFirstLength = uint8(15) // 0000 1111 + maskContinue = uint8(128) // 1000 000 + firstLengthBits = uint8(4) // the first byte has 4 bits to store the length + maskLength = uint8(127) // 0111 1111 + lengthBits = uint8(7) // subsequent bytes has 7 bits to store the length +) + func (s *Scanner) readType() (core.ObjectType, byte, error) { var c byte var err error - if c, err = s.readByte(); err != nil { + if c, err = s.r.ReadByte(); err != nil { return core.ObjectType(0), 0, err } @@ -252,6 +251,10 @@ func (s *Scanner) readType() (core.ObjectType, byte, error) { return typ, c, nil } +func parseType(b byte) core.ObjectType { + return core.ObjectType((b & maskType) >> firstLengthBits) +} + // the length is codified in the last 4 bits of the first byte and in // the last 7 bits of subsequent bytes. Last byte has a 0 MSB. func (s *Scanner) readLength(first byte) (int64, error) { @@ -260,8 +263,8 @@ func (s *Scanner) readLength(first byte) (int64, error) { c := first shift := firstLengthBits var err error - for moreBytesInLength(c) { - if c, err = s.readByte(); err != nil { + for c&maskContinue > 0 { + if c, err = s.r.ReadByte(); err != nil { return 0, err } @@ -324,73 +327,7 @@ func (s *Scanner) Checksum() (core.Hash, error) { return core.ZeroHash, err } - return s.readHash() -} - -// ReadHash reads a hash. -func (s *Scanner) readHash() (core.Hash, error) { - var h core.Hash - if _, err := io.ReadFull(s.r, h[:]); err != nil { - return core.ZeroHash, err - } - - return h, nil -} - -// ReadNegativeOffset reads and returns an offset from a OFS DELTA -// object entry in a packfile. OFS DELTA offsets are specified in Git -// VLQ special format: -// -// Ordinary VLQ has some redundancies, example: the number 358 can be -// encoded as the 2-octet VLQ 0x8166 or the 3-octet VLQ 0x808166 or the -// 4-octet VLQ 0x80808166 and so forth. -// -// To avoid these redundancies, the VLQ format used in Git removes this -// prepending redundancy and extends the representable range of shorter -// VLQs by adding an offset to VLQs of 2 or more octets in such a way -// that the lowest possible value for such an (N+1)-octet VLQ becomes -// exactly one more than the maximum possible value for an N-octet VLQ. -// In particular, since a 1-octet VLQ can store a maximum value of 127, -// the minimum 2-octet VLQ (0x8000) is assigned the value 128 instead of -// 0. Conversely, the maximum value of such a 2-octet VLQ (0xff7f) is -// 16511 instead of just 16383. Similarly, the minimum 3-octet VLQ -// (0x808000) has a value of 16512 instead of zero, which means -// that the maximum 3-octet VLQ (0xffff7f) is 2113663 instead of -// just 2097151. And so forth. -// -// This is how the offset is saved in C: -// -// dheader[pos] = ofs & 127; -// while (ofs >>= 7) -// dheader[--pos] = 128 | (--ofs & 127); -// -func (s *Scanner) readNegativeOffset() (int64, error) { - var c byte - var err error - - if c, err = s.readByte(); err != nil { - return 0, err - } - - var offset = int64(c & maskLength) - for moreBytesInLength(c) { - offset++ - if c, err = s.readByte(); err != nil { - return 0, err - } - offset = (offset << lengthBits) + int64(c&maskLength) - } - - return -offset, nil -} - -func (s *Scanner) readByte() (byte, error) { - b, err := s.r.ReadByte() - if err != nil { - return 0, err - } - - return b, err + return binary.ReadHash(s.r) } // Close reads the reader until io.EOF @@ -399,23 +336,6 @@ func (s *Scanner) Close() error { return err } -func moreBytesInLength(c byte) bool { - return c&maskContinue > 0 -} - -var ( - maskContinue = uint8(128) // 1000 0000 - maskType = uint8(112) // 0111 0000 - maskFirstLength = uint8(15) // 0000 1111 - firstLengthBits = uint8(4) // the first byte has 4 bits to store the length - maskLength = uint8(127) // 0111 1111 - lengthBits = uint8(7) // subsequent bytes has 7 bits to store the length -) - -func parseType(b byte) core.ObjectType { - return core.ObjectType((b & maskType) >> firstLengthBits) -} - type trackableReader struct { count int64 io.Reader |