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