1 // Copyright 2015 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef NET_DER_INPUT_H_ 6 #define NET_DER_INPUT_H_ 7 8 #include <stddef.h> 9 #include <stdint.h> 10 11 #include <string> 12 13 #include "base/containers/span.h" 14 #include "net/base/net_export.h" 15 16 namespace net::der { 17 18 // An opaque class that represents a fixed buffer of data of a fixed length, 19 // to be used as an input to other operations. An Input object does not own 20 // the data it references, so callers are responsible for making sure that 21 // the data outlives the Input object and any other associated objects. 22 // 23 // All data access for an Input should be done through the ByteReader class. 24 // This class and associated classes are designed with safety in mind to make it 25 // difficult to read memory outside of an Input. ByteReader provides a simple 26 // API for reading through the Input sequentially. For more complicated uses, 27 // multiple instances of a ByteReader for a particular Input can be created. 28 class NET_EXPORT_PRIVATE Input { 29 public: 30 // Creates an empty Input, one from which no data can be read. 31 constexpr Input() = default; 32 33 // Creates an Input from a constant array |data|. 34 template <size_t N> Input(const uint8_t (& data)[N])35 constexpr explicit Input(const uint8_t (&data)[N]) : data_(data), len_(N) {} 36 37 // Creates an Input from the given |data| and |len|. Input(const uint8_t * data,size_t len)38 constexpr explicit Input(const uint8_t* data, size_t len) 39 : data_(data), len_(len) {} 40 41 // Creates an Input from a std::string_view 42 explicit Input(std::string_view sp); 43 44 // Creates an Input from a std::string. The lifetimes are a bit subtle when 45 // using this function: The constructed Input is only valid so long as |s| is 46 // still alive and not mutated. 47 explicit Input(const std::string* s); 48 49 // Returns the length in bytes of an Input's data. Length()50 constexpr size_t Length() const { return len_; } 51 52 // Returns a pointer to the Input's data. This method is marked as "unsafe" 53 // because access to the Input's data should be done through ByteReader 54 // instead. This method should only be used where using a ByteReader truly 55 // is not an option. UnsafeData()56 constexpr const uint8_t* UnsafeData() const { return data_; } 57 58 // Returns a copy of the data represented by this object as a std::string. 59 std::string AsString() const; 60 61 // Returns a std::string_view pointing to the same data as the Input. The 62 // resulting string_view must not outlive the data that was used to construct 63 // this Input. 64 std::string_view AsStringView() const; 65 66 // Returns a base::span pointing to the same data as the Input. The resulting 67 // base::span must not outlive the data that was used to construct this 68 // Input. 69 base::span<const uint8_t> AsSpan() const; 70 71 private: 72 // This constructor is deleted to prevent constructing an Input from a 73 // std::string r-value. Since the Input points to memory owned by another 74 // object, such an Input would point to invalid memory. Without this deleted 75 // constructor, a std::string could be passed in to the base::StringPiece 76 // constructor because of StringPiece's implicit constructor. 77 Input(std::string) = delete; 78 79 const uint8_t* data_ = nullptr; 80 size_t len_ = 0; 81 }; 82 83 // Return true if |lhs|'s data and |rhs|'s data are byte-wise equal. 84 NET_EXPORT_PRIVATE bool operator==(const Input& lhs, const Input& rhs); 85 86 // Return true if |lhs|'s data and |rhs|'s data are not byte-wise equal. 87 NET_EXPORT_PRIVATE bool operator!=(const Input& lhs, const Input& rhs); 88 89 // Returns true if |lhs|'s data is lexicographically less than |rhs|'s data. 90 NET_EXPORT_PRIVATE constexpr bool operator<(const Input& lhs, 91 const Input& rhs) { 92 // This is `std::lexicographical_compare`, but that's not `constexpr` until 93 // C++-20. 94 auto* it1 = lhs.UnsafeData(); 95 auto* it2 = rhs.UnsafeData(); 96 const auto* end1 = lhs.UnsafeData() + lhs.Length(); 97 const auto* end2 = rhs.UnsafeData() + rhs.Length(); 98 for (; it1 != end1 && it2 != end2; ++it1, ++it2) { 99 if (*it1 < *it2) { 100 return true; 101 } else if (*it2 < *it1) { 102 return false; 103 } 104 } 105 106 return it2 != end2; 107 } 108 109 // This class provides ways to read data from an Input in a bounds-checked way. 110 // The ByteReader is designed to read through the input sequentially. Once a 111 // byte has been read with a ByteReader, the caller can't go back and re-read 112 // that byte with the same reader. Of course, the caller can create multiple 113 // ByteReaders for the same input (or copy an existing ByteReader). 114 // 115 // For something simple like a single byte lookahead, the easiest way to do 116 // that is to copy the ByteReader and call ReadByte() on the copy - the original 117 // ByteReader will be unaffected and the peeked byte will be read through 118 // ReadByte(). For other read patterns, it can be useful to mark where one is 119 // in a ByteReader to be able to return to that spot. 120 // 121 // Some operations using Mark can also be done by creating a copy of the 122 // ByteReader. By using a Mark instead, you use less memory, but more 123 // importantly, you end up with an immutable object that matches the semantics 124 // of what is intended. 125 class NET_EXPORT_PRIVATE ByteReader { 126 public: 127 // Creates a ByteReader to read the data represented by an Input. 128 explicit ByteReader(const Input& in); 129 130 // Reads a single byte from the input source, putting the byte read in 131 // |*byte_p|. If a byte cannot be read from the input (because there is 132 // no input left), then this method returns false. 133 [[nodiscard]] bool ReadByte(uint8_t* out); 134 135 // Reads |len| bytes from the input source, and initializes an Input to 136 // point to that data. If there aren't enough bytes left in the input source, 137 // then this method returns false. 138 [[nodiscard]] bool ReadBytes(size_t len, Input* out); 139 140 // Returns how many bytes are left to read. BytesLeft()141 size_t BytesLeft() const { return len_; } 142 143 // Returns whether there is any more data to be read. 144 bool HasMore(); 145 146 private: 147 void Advance(size_t len); 148 149 const uint8_t* data_; 150 size_t len_; 151 }; 152 153 } // namespace net::der 154 155 #endif // NET_DER_INPUT_H_ 156