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