80 lines
1.9 KiB
Go
80 lines
1.9 KiB
Go
// Package car implements the CARv1 file format.
|
|
package car
|
|
|
|
import (
|
|
"bytes"
|
|
|
|
"github.com/ipfs/go-cid"
|
|
"github.com/ipld/go-ipld-prime/codec/dagcbor"
|
|
"github.com/ipld/go-ipld-prime/datamodel"
|
|
"github.com/multiformats/go-multicodec"
|
|
)
|
|
|
|
// IdentityCID is the "zero-length "identity" multihash with "raw" codec".
|
|
//
|
|
// This is the best-practices placeholder value to refer to a non-existent or unknown object.
|
|
var IdentityCID cid.Cid
|
|
|
|
func init() {
|
|
id, err := cid.Cast([]byte{0x01, 0x55, 0x00, 0x00})
|
|
if err != nil {
|
|
panic("failed to create zero-length identity multihash with raw codec lmfao")
|
|
}
|
|
IdentityCID = id
|
|
}
|
|
|
|
// Block is a length-cid-data tuple.
|
|
// These make up most of CARv1.
|
|
//
|
|
// See https://ipld.io/specs/transport/car/carv1/#data
|
|
type Block struct {
|
|
Length int
|
|
Cid cid.Cid
|
|
Data []byte
|
|
}
|
|
|
|
// NewBlockFromRaw creates a new CIDv1 with the given multicodec contentType on the fly.
|
|
func NewBlockFromRaw(data []byte, contentType uint64) Block {
|
|
cidBuilder := cid.V1Builder{
|
|
Codec: contentType,
|
|
MhType: uint64(multicodec.Sha2_256),
|
|
}
|
|
id, err := cidBuilder.Sum(data)
|
|
if err != nil {
|
|
// Something is wrong with go-cid if this fails.
|
|
panic("failed to construct CID: " + err.Error())
|
|
}
|
|
return Block{
|
|
Length: id.ByteLen() + len(data),
|
|
Cid: id,
|
|
Data: data,
|
|
}
|
|
}
|
|
|
|
func NewBlockFromCBOR(node datamodel.Node, contentType uint64) (Block, error) {
|
|
// TODO: This could be rewritten as zero-copy
|
|
var buf bytes.Buffer
|
|
if err := dagcbor.Encode(node, &buf); err != nil {
|
|
return Block{}, err
|
|
}
|
|
return NewBlockFromRaw(buf.Bytes(), contentType), nil
|
|
}
|
|
|
|
// TotalLen returns the total length of the block, including the length prefix.
|
|
func (b Block) TotalLen() int {
|
|
return leb128Len(uint64(b.Length)) + b.Length
|
|
}
|
|
|
|
// leb128Len is like len(leb128.FromUInt64(x)).
|
|
// But without an allocation, therefore should be preferred.
|
|
func leb128Len(x uint64) (n int) {
|
|
n = 1
|
|
for {
|
|
x >>= 7
|
|
if x == 0 {
|
|
return
|
|
}
|
|
n++
|
|
}
|
|
}
|