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  }