github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/p2p/p2putil/multicodec_old/header.go (about) 1 package multicodec 2 3 import ( 4 "bytes" 5 "errors" 6 "io" 7 ) 8 9 var ( 10 errType = errors.New("multicodec type error") 11 errHeaderInvalid = errors.New("multicodec header invalid") 12 errMismatch = errors.New("multicodec did not match") 13 errVarints = errors.New("multicodec varints not yet implemented") 14 ) 15 16 // Header returns a multicodec header with the given path. 17 func Header(path []byte) []byte { 18 b, err := HeaderSafe(path) 19 if err != nil { 20 panic(err.Error) 21 } 22 return b 23 } 24 25 // HeaderSafe works like Header but it returns error instead of calling panic 26 func HeaderSafe(path []byte) ([]byte, error) { 27 l := len(path) + 1 // + \n 28 if l >= 127 { 29 return nil, errVarints 30 } 31 32 buf := make([]byte, l+1) 33 buf[0] = byte(l) 34 copy(buf[1:], path) 35 buf[l] = '\n' 36 return buf, nil 37 } 38 39 // HeaderPath returns the multicodec path from header 40 func HeaderPath(hdr []byte) []byte { 41 hdr = hdr[1:] 42 if hdr[len(hdr)-1] == '\n' { 43 hdr = hdr[:len(hdr)-1] 44 } 45 return hdr 46 } 47 48 // WriteHeader writes a multicodec header to a writer. 49 // It uses the given path. 50 func WriteHeader(w io.Writer, path []byte) error { 51 hdr := Header(path) 52 _, err := w.Write(hdr) 53 return err 54 } 55 56 // ReadHeader reads a multicodec header from a reader. 57 // Returns the header found, or an error if the header 58 // mismatched. 59 func ReadHeader(r io.Reader) (path []byte, err error) { 60 lbuf := make([]byte, 1) 61 if _, err := r.Read(lbuf); err != nil { 62 return nil, err 63 } 64 65 l := int(lbuf[0]) 66 if l > 127 { 67 return nil, errVarints 68 } 69 70 buf := make([]byte, l+1) 71 buf[0] = lbuf[0] 72 if _, err := io.ReadFull(r, buf[1:]); err != nil { 73 return nil, err 74 } 75 if buf[l] != '\n' { 76 return nil, errHeaderInvalid 77 } 78 return buf, nil 79 } 80 81 // ReadPath reads a multicodec header from a reader. 82 // Returns the path found, or an error if the header 83 // mismatched. 84 func ReadPath(r io.Reader) (path []byte, err error) { 85 hdr, err := ReadHeader(r) 86 if err != nil { 87 return nil, err 88 } 89 return HeaderPath(hdr), nil 90 } 91 92 // ConsumePath reads a multicodec header from a reader, 93 // verifying it matches given path. If it does not, it returns 94 // ErrProtocolMismatch 95 func ConsumePath(r io.Reader, path []byte) (err error) { 96 actual, err := ReadPath(r) 97 if !bytes.Equal(path, actual) { 98 return errMismatch 99 } 100 return nil 101 } 102 103 // ConsumeHeader reads a multicodec header from a reader, 104 // verifying it matches given header. If it does not, it returns 105 // ErrProtocolMismatch 106 func ConsumeHeader(r io.Reader, header []byte) (err error) { 107 actual := make([]byte, len(header)) 108 if _, err := io.ReadFull(r, actual); err != nil { 109 return err 110 } 111 112 if !bytes.Equal(header, actual) { 113 return errMismatch 114 } 115 return nil 116 } 117 118 // WrapHeaderReader returns a reader that first reads the 119 // given header, and then the given reader, using io.MultiReader. 120 // It is useful if the header has been read through, but still 121 // needed to pass to a decoder. 122 func WrapHeaderReader(hdr []byte, r io.Reader) io.Reader { 123 return io.MultiReader(bytes.NewReader(hdr), r) 124 }