1 // Copyright 2017 The Chromium Authors. All rights reserved. 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 COMPONENTS_ZUCCHINI_BUFFER_SOURCE_H_ 6 #define COMPONENTS_ZUCCHINI_BUFFER_SOURCE_H_ 7 8 #include <stddef.h> 9 #include <stdint.h> 10 11 #include <initializer_list> 12 #include <type_traits> 13 14 #include "base/check_op.h" 15 #include "components/zucchini/buffer_view.h" 16 17 namespace zucchini { 18 19 // BufferSource acts like an input stream with convenience methods to parse data 20 // from a contiguous sequence of raw data. The underlying ConstBufferView 21 // emulates a cursor to track current read position, and guards against buffer 22 // overrun. Where applicable, BufferSource should be passed by pointer to 23 // maintain cursor progress across reads. 24 class BufferSource : public ConstBufferView { 25 public: 26 // LEB128 info: http://dwarfstd.org/doc/dwarf-2.0.0.pdf , Section 7.6. 27 enum : size_t { kMaxLeb128Size = 5 }; 28 FromRange(const_iterator first,const_iterator last)29 static BufferSource FromRange(const_iterator first, const_iterator last) { 30 return BufferSource(ConstBufferView::FromRange(first, last)); 31 } 32 33 using ConstBufferView::ConstBufferView; 34 BufferSource() = default; 35 explicit BufferSource(ConstBufferView buffer); 36 BufferSource(const BufferSource&) = default; 37 BufferSource& operator=(BufferSource&&) = default; 38 39 // Moves the cursor forward by |n| bytes, or to the end if data is exhausted. 40 // Returns a reference to *this, to allow chaining, e.g.: 41 // if (!buffer_source.Skip(1024).GetValue<uint32_t>(&value)) { 42 // ... // Handle error. 43 // } 44 // Notice that Skip() defers error handling to GetValue(). 45 BufferSource& Skip(size_type n); 46 47 // Returns true if |value| matches data starting at the cursor when 48 // reinterpreted as the integral type |T|. 49 template <class T> CheckNextValue(const T & value)50 bool CheckNextValue(const T& value) const { 51 static_assert(std::is_integral<T>::value, 52 "Value type must be an integral type"); 53 DCHECK_NE(begin(), nullptr); 54 if (Remaining() < sizeof(T)) 55 return false; 56 return value == *reinterpret_cast<const T*>(begin()); 57 } 58 59 // Returns true if the next bytes.size() bytes at the cursor match those in 60 // |bytes|. 61 bool CheckNextBytes(std::initializer_list<uint8_t> bytes) const; 62 63 // Same as CheckNextBytes(), but moves the cursor by bytes.size() if read is 64 // successfull. 65 bool ConsumeBytes(std::initializer_list<uint8_t> bytes); 66 67 // Tries to reinterpret data as type |T|, starting at the cursor and to write 68 // the result into |value|, while moving the cursor forward by sizeof(T). 69 // Returns true if sufficient data is available, and false otherwise. 70 template <class T> GetValue(T * value)71 bool GetValue(T* value) { 72 static_assert(std::is_standard_layout<T>::value, 73 "Value type must be a standard layout type"); 74 75 DCHECK_NE(begin(), nullptr); 76 if (Remaining() < sizeof(T)) 77 return false; 78 *value = *reinterpret_cast<const T*>(begin()); 79 remove_prefix(sizeof(T)); 80 return true; 81 } 82 83 // Tries to reinterpret data as type |T| at the cursor and to return a 84 // reinterpreted pointer of type |T| pointing into the underlying data, while 85 // moving the cursor forward by sizeof(T). Returns nullptr if insufficient 86 // data is available. 87 template <class T> GetPointer()88 const T* GetPointer() { 89 static_assert(std::is_standard_layout<T>::value, 90 "Value type must be a standard layout type"); 91 92 DCHECK_NE(begin(), nullptr); 93 if (Remaining() < sizeof(T)) 94 return nullptr; 95 const T* ptr = reinterpret_cast<const T*>(begin()); 96 remove_prefix(sizeof(T)); 97 return ptr; 98 } 99 100 // Tries to reinterpret data as an array of type |T| with |count| elements, 101 // starting at the cursor, and to return a reinterpreted pointer of type |T| 102 // pointing into the underlying data, while advancing the cursor beyond the 103 // array. Returns nullptr if insufficient data is available. 104 template <class T> GetArray(size_t count)105 const T* GetArray(size_t count) { 106 static_assert(std::is_standard_layout<T>::value, 107 "Value type must be a standard layout type"); 108 109 if (Remaining() / sizeof(T) < count) 110 return nullptr; 111 const T* array = reinterpret_cast<const T*>(begin()); 112 remove_prefix(count * sizeof(T)); 113 return array; 114 } 115 116 // If sufficient data is available, assigns |buffer| to point to a region of 117 // |size| bytes starting at the cursor, while advancing the cursor beyond the 118 // region, and returns true. Otherwise returns false. 119 bool GetRegion(size_type size, ConstBufferView* buffer); 120 121 // Reads an Unsigned Little Endian Base 128 (uleb128) int at |first_|. If 122 // successful, writes the result to |value|, advances |first_|, and returns 123 // true. Otherwise returns false. 124 bool GetUleb128(uint32_t* value); 125 126 // Reads a Signed Little Endian Base 128 (sleb128) int at |first_|. If 127 // successful, writes the result to |value|, advances |first_|, and returns 128 // true. Otherwise returns false. 129 bool GetSleb128(int32_t* value); 130 131 // Reads uleb128 / sleb128 at |first_| but discards the result. If successful, 132 // advances |first_| and returns true. Otherwise returns false. 133 bool SkipLeb128(); 134 135 // Returns the number of bytes remaining from cursor until end. Remaining()136 size_type Remaining() const { return size(); } 137 }; 138 139 } // namespace zucchini 140 141 #endif // COMPONENTS_ZUCCHINI_BUFFER_SOURCE_H_ 142