package client import ( "fmt" "io" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" "github.com/ipld/go-car/util" "github.com/multiformats/go-varint" ) // ————————————————————————————————————————————————————————— // // This code is temporary, and should be deleted when // https://github.com/ipld/go-car/issues/196 is resolved. // // ————————————————————————————————————————————————————————— func init() { cbor.RegisterCborType(CarHeader{}) } type CarHeader struct { Roots []cid.Cid Version uint64 } func readHeader(r io.Reader) (*CarHeader, error) { hb, err := ldRead(r, false) if err != nil { return nil, err } var ch CarHeader if err := cbor.DecodeInto(hb, &ch); err != nil { return nil, fmt.Errorf("invalid header: %v", err) } return &ch, nil } func writeHeader(h *CarHeader, w io.Writer) error { hb, err := cbor.DumpObject(h) if err != nil { return err } return util.LdWrite(w, hb) } func ldRead(r io.Reader, zeroLenAsEOF bool) ([]byte, error) { l, err := varint.ReadUvarint(toByteReader(r)) if err != nil { // If the length of bytes read is non-zero when the error is EOF then signal an unclean EOF. if l > 0 && err == io.EOF { return nil, io.ErrUnexpectedEOF } return nil, err } else if l == 0 && zeroLenAsEOF { return nil, io.EOF } buf := make([]byte, l) if _, err := io.ReadFull(r, buf); err != nil { return nil, err } return buf, nil } type readerPlusByte struct { io.Reader } func (rb readerPlusByte) ReadByte() (byte, error) { return readByte(rb) } func readByte(r io.Reader) (byte, error) { var p [1]byte _, err := io.ReadFull(r, p[:]) return p[0], err } func toByteReader(r io.Reader) io.ByteReader { if br, ok := r.(io.ByteReader); ok { return br } return &readerPlusByte{r} }