package libcar import ( "crypto/sha256" "encoding/binary" "io" "github.com/hyphacoop/go-dasl/cid" "github.com/hyphacoop/go-dasl/drisl" ) type Writer struct { out io.Writer err error } func NewWriter(out io.Writer, roots []cid.Cid) (*Writer, error) { hdr := Header{ Version: CAR_HEADER_VERSION, Roots: roots, } b, err := drisl.Marshal(&hdr) if err != nil { return nil, err } if err := writeUvarint(out, uint64(len(b))); err != nil { return nil, err } if _, err = out.Write(b); err != nil { return nil, err } return &Writer{ out: out, }, nil } // Writes data block of any type (pre-computed CID). // // This can be used to write blocks with "raw" CID codec type (eg, not CBOR). // // It is the caller's responsibility to ensure the CID hash matches the block data. func (w *Writer) WriteBlockParts(bcid cid.Cid, bdata []byte) error { if w.err != nil { return w.err } hashb := bcid.Bytes() l := len(hashb) + len(bdata) // length varint if err := writeUvarint(w.out, uint64(l)); err != nil { w.err = err return w.err } // CID hash if _, err := w.out.Write(hashb); err != nil { w.err = err return w.err } // block data if _, err := w.out.Write(bdata); err != nil { w.err = err return w.err } return nil } // Writes block of already-marshalled CBOR data, computing CID with DASL-CBOR/DAG-CBOR codec type func (w *Writer) WriteBlock(bdata []byte) error { hash := sha256.Sum256(bdata) bcid, err := cid.NewCidFromInfo(cid.CodecDrisl, cid.HashTypeSha256, hash) if err != nil { return err } return w.WriteBlockParts(bcid, bdata) } // Marshals data to CBOR and writes block func (w *Writer) WriteData(data any) error { bdata, err := drisl.Marshal(data) if err != nil { return err } return w.WriteBlock(bdata) } func writeUvarint(w io.Writer, val uint64) error { lenBuf := []byte{} lenBuf = binary.AppendUvarint(lenBuf, val) if _, err := w.Write(lenBuf); err != nil { return err } return nil }