string.mx raw

   1  // Copyright 2017 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  // Package cryptobyte contains types that help with parsing and constructing
   6  // length-prefixed, binary messages, including ASN.1 DER. (The asn1 subpackage
   7  // contains useful ASN.1 constants.)
   8  //
   9  // The String type is for parsing. It wraps a []byte slice and provides helper
  10  // functions for consuming structures, value by value.
  11  //
  12  // The Builder type is for constructing messages. It providers helper functions
  13  // for appending values and also for appending length-prefixed submessages –
  14  // without having to worry about calculating the length prefix ahead of time.
  15  //
  16  // See the documentation and examples for the Builder and String types to get
  17  // started.
  18  package cryptobyte
  19  
  20  // String represents a string of bytes. It provides methods for parsing
  21  // fixed-length and length-prefixed values from it.
  22  type String []byte
  23  
  24  // read advances a String by n bytes and returns them. If less than n bytes
  25  // remain, it returns nil.
  26  func (s *String) read(n int) []byte {
  27  	if len(*s) < n || n < 0 {
  28  		return nil
  29  	}
  30  	v := (*s)[:n]
  31  	*s = (*s)[n:]
  32  	return v
  33  }
  34  
  35  // readOK is like read but returns a bool to handle moxie's nil-empty-slice identity.
  36  func (s *String) readOK(n int) ([]byte, bool) {
  37  	if len(*s) < n || n < 0 {
  38  		return nil, false
  39  	}
  40  	v := (*s)[:n]
  41  	*s = (*s)[n:]
  42  	return v, true
  43  }
  44  
  45  // Skip advances the String by n byte and reports whether it was successful.
  46  func (s *String) Skip(n int) bool {
  47  	_, ok := s.readOK(n)
  48  	return ok
  49  }
  50  
  51  // ReadUint8 decodes an 8-bit value into out and advances over it.
  52  // It reports whether the read was successful.
  53  func (s *String) ReadUint8(out *uint8) bool {
  54  	v := s.read(1)
  55  	if v == nil {
  56  		return false
  57  	}
  58  	*out = uint8(v[0])
  59  	return true
  60  }
  61  
  62  // ReadUint16 decodes a big-endian, 16-bit value into out and advances over it.
  63  // It reports whether the read was successful.
  64  func (s *String) ReadUint16(out *uint16) bool {
  65  	v := s.read(2)
  66  	if v == nil {
  67  		return false
  68  	}
  69  	*out = uint16(v[0])<<8 | uint16(v[1])
  70  	return true
  71  }
  72  
  73  // ReadUint24 decodes a big-endian, 24-bit value into out and advances over it.
  74  // It reports whether the read was successful.
  75  func (s *String) ReadUint24(out *uint32) bool {
  76  	v := s.read(3)
  77  	if v == nil {
  78  		return false
  79  	}
  80  	*out = uint32(v[0])<<16 | uint32(v[1])<<8 | uint32(v[2])
  81  	return true
  82  }
  83  
  84  // ReadUint32 decodes a big-endian, 32-bit value into out and advances over it.
  85  // It reports whether the read was successful.
  86  func (s *String) ReadUint32(out *uint32) bool {
  87  	v := s.read(4)
  88  	if v == nil {
  89  		return false
  90  	}
  91  	*out = uint32(v[0])<<24 | uint32(v[1])<<16 | uint32(v[2])<<8 | uint32(v[3])
  92  	return true
  93  }
  94  
  95  // ReadUint48 decodes a big-endian, 48-bit value into out and advances over it.
  96  // It reports whether the read was successful.
  97  func (s *String) ReadUint48(out *uint64) bool {
  98  	v := s.read(6)
  99  	if v == nil {
 100  		return false
 101  	}
 102  	*out = uint64(v[0])<<40 | uint64(v[1])<<32 | uint64(v[2])<<24 | uint64(v[3])<<16 | uint64(v[4])<<8 | uint64(v[5])
 103  	return true
 104  }
 105  
 106  // ReadUint64 decodes a big-endian, 64-bit value into out and advances over it.
 107  // It reports whether the read was successful.
 108  func (s *String) ReadUint64(out *uint64) bool {
 109  	v := s.read(8)
 110  	if v == nil {
 111  		return false
 112  	}
 113  	*out = uint64(v[0])<<56 | uint64(v[1])<<48 | uint64(v[2])<<40 | uint64(v[3])<<32 | uint64(v[4])<<24 | uint64(v[5])<<16 | uint64(v[6])<<8 | uint64(v[7])
 114  	return true
 115  }
 116  
 117  func (s *String) readUnsigned(out *uint32, length int) bool {
 118  	v := s.read(length)
 119  	if v == nil {
 120  		return false
 121  	}
 122  	var result uint32
 123  	for i := 0; i < length; i++ {
 124  		result <<= 8
 125  		result |= uint32(v[i])
 126  	}
 127  	*out = result
 128  	return true
 129  }
 130  
 131  func (s *String) readLengthPrefixed(lenLen int, outChild *String) bool {
 132  	lenBytes, ok := s.readOK(lenLen)
 133  	if !ok {
 134  		return false
 135  	}
 136  	var length uint32
 137  	for _, b := range lenBytes {
 138  		length = length << 8
 139  		length = length | uint32(b)
 140  	}
 141  	v, ok := s.readOK(int(length))
 142  	if !ok {
 143  		return false
 144  	}
 145  	*outChild = v
 146  	return true
 147  }
 148  
 149  // ReadUint8LengthPrefixed reads the content of an 8-bit length-prefixed value
 150  // into out and advances over it. It reports whether the read was successful.
 151  func (s *String) ReadUint8LengthPrefixed(out *String) bool {
 152  	return s.readLengthPrefixed(1, out)
 153  }
 154  
 155  // ReadUint16LengthPrefixed reads the content of a big-endian, 16-bit
 156  // length-prefixed value into out and advances over it. It reports whether the
 157  // read was successful.
 158  func (s *String) ReadUint16LengthPrefixed(out *String) bool {
 159  	return s.readLengthPrefixed(2, out)
 160  }
 161  
 162  // ReadUint24LengthPrefixed reads the content of a big-endian, 24-bit
 163  // length-prefixed value into out and advances over it. It reports whether
 164  // the read was successful.
 165  func (s *String) ReadUint24LengthPrefixed(out *String) bool {
 166  	return s.readLengthPrefixed(3, out)
 167  }
 168  
 169  // ReadBytes reads n bytes into out and advances over them. It reports
 170  // whether the read was successful.
 171  func (s *String) ReadBytes(out *[]byte, n int) bool {
 172  	v, ok := s.readOK(n)
 173  	if !ok {
 174  		return false
 175  	}
 176  	*out = v
 177  	return true
 178  }
 179  
 180  // CopyBytes copies len(out) bytes into out and advances over them. It reports
 181  // whether the copy operation was successful
 182  func (s *String) CopyBytes(out []byte) bool {
 183  	n := len(out)
 184  	v, ok := s.readOK(n)
 185  	if !ok {
 186  		return false
 187  	}
 188  	return copy(out, v) == n
 189  }
 190  
 191  // Empty reports whether the string does not contain any bytes.
 192  func (s String) Empty() bool {
 193  	return len(s) == 0
 194  }
 195