1package multihash 2 3import ( 4 "errors" 5 "io" 6 "math" 7 8 "github.com/multiformats/go-varint" 9) 10 11// Reader is an io.Reader wrapper that exposes a function 12// to read a whole multihash, parse it, and return it. 13type Reader interface { 14 io.Reader 15 16 ReadMultihash() (Multihash, error) 17} 18 19// Writer is an io.Writer wrapper that exposes a function 20// to write a whole multihash. 21type Writer interface { 22 io.Writer 23 24 WriteMultihash(Multihash) error 25} 26 27// NewReader wraps an io.Reader with a multihash.Reader 28func NewReader(r io.Reader) Reader { 29 return &mhReader{r} 30} 31 32// NewWriter wraps an io.Writer with a multihash.Writer 33func NewWriter(w io.Writer) Writer { 34 return &mhWriter{w} 35} 36 37type mhReader struct { 38 r io.Reader 39} 40 41func (r *mhReader) Read(buf []byte) (n int, err error) { 42 return r.r.Read(buf) 43} 44 45func (r *mhReader) ReadByte() (byte, error) { 46 if br, ok := r.r.(io.ByteReader); ok { 47 return br.ReadByte() 48 } 49 var b [1]byte 50 n, err := r.r.Read(b[:]) 51 if n == 1 { 52 return b[0], nil 53 } 54 if err == nil { 55 if n != 0 { 56 panic("reader returned an invalid length") 57 } 58 err = io.ErrNoProgress 59 } 60 return 0, err 61} 62 63func (r *mhReader) ReadMultihash() (Multihash, error) { 64 code, err := varint.ReadUvarint(r) 65 if err != nil { 66 return nil, err 67 } 68 69 length, err := varint.ReadUvarint(r) 70 if err != nil { 71 return nil, err 72 } 73 if length > math.MaxInt32 { 74 return nil, errors.New("digest too long, supporting only <= 2^31-1") 75 } 76 77 buf := make([]byte, varint.UvarintSize(code)+varint.UvarintSize(length)+int(length)) 78 n := varint.PutUvarint(buf, code) 79 n += varint.PutUvarint(buf[n:], length) 80 if _, err := io.ReadFull(r.r, buf[n:]); err != nil { 81 return nil, err 82 } 83 84 return Cast(buf) 85} 86 87type mhWriter struct { 88 w io.Writer 89} 90 91func (w *mhWriter) Write(buf []byte) (n int, err error) { 92 return w.w.Write(buf) 93} 94 95func (w *mhWriter) WriteMultihash(m Multihash) error { 96 _, err := w.w.Write([]byte(m)) 97 return err 98} 99