142 lines
5.2 KiB
C++
142 lines
5.2 KiB
C++
// Copyright 2017 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#ifndef COMPONENTS_ZUCCHINI_BUFFER_SOURCE_H_
|
|
#define COMPONENTS_ZUCCHINI_BUFFER_SOURCE_H_
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
#include <initializer_list>
|
|
#include <type_traits>
|
|
|
|
#include "base/check_op.h"
|
|
#include "components/zucchini/buffer_view.h"
|
|
|
|
namespace zucchini {
|
|
|
|
// BufferSource acts like an input stream with convenience methods to parse data
|
|
// from a contiguous sequence of raw data. The underlying ConstBufferView
|
|
// emulates a cursor to track current read position, and guards against buffer
|
|
// overrun. Where applicable, BufferSource should be passed by pointer to
|
|
// maintain cursor progress across reads.
|
|
class BufferSource : public ConstBufferView {
|
|
public:
|
|
// LEB128 info: http://dwarfstd.org/doc/dwarf-2.0.0.pdf , Section 7.6.
|
|
enum : size_t { kMaxLeb128Size = 5 };
|
|
|
|
static BufferSource FromRange(const_iterator first, const_iterator last) {
|
|
return BufferSource(ConstBufferView::FromRange(first, last));
|
|
}
|
|
|
|
using ConstBufferView::ConstBufferView;
|
|
BufferSource() = default;
|
|
explicit BufferSource(ConstBufferView buffer);
|
|
BufferSource(const BufferSource&) = default;
|
|
BufferSource& operator=(BufferSource&&) = default;
|
|
|
|
// Moves the cursor forward by |n| bytes, or to the end if data is exhausted.
|
|
// Returns a reference to *this, to allow chaining, e.g.:
|
|
// if (!buffer_source.Skip(1024).GetValue<uint32_t>(&value)) {
|
|
// ... // Handle error.
|
|
// }
|
|
// Notice that Skip() defers error handling to GetValue().
|
|
BufferSource& Skip(size_type n);
|
|
|
|
// Returns true if |value| matches data starting at the cursor when
|
|
// reinterpreted as the integral type |T|.
|
|
template <class T>
|
|
bool CheckNextValue(const T& value) const {
|
|
static_assert(std::is_integral<T>::value,
|
|
"Value type must be an integral type");
|
|
DCHECK_NE(begin(), nullptr);
|
|
if (Remaining() < sizeof(T))
|
|
return false;
|
|
return value == *reinterpret_cast<const T*>(begin());
|
|
}
|
|
|
|
// Returns true if the next bytes.size() bytes at the cursor match those in
|
|
// |bytes|.
|
|
bool CheckNextBytes(std::initializer_list<uint8_t> bytes) const;
|
|
|
|
// Same as CheckNextBytes(), but moves the cursor by bytes.size() if read is
|
|
// successfull.
|
|
bool ConsumeBytes(std::initializer_list<uint8_t> bytes);
|
|
|
|
// Tries to reinterpret data as type |T|, starting at the cursor and to write
|
|
// the result into |value|, while moving the cursor forward by sizeof(T).
|
|
// Returns true if sufficient data is available, and false otherwise.
|
|
template <class T>
|
|
bool GetValue(T* value) {
|
|
static_assert(std::is_standard_layout<T>::value,
|
|
"Value type must be a standard layout type");
|
|
|
|
DCHECK_NE(begin(), nullptr);
|
|
if (Remaining() < sizeof(T))
|
|
return false;
|
|
*value = *reinterpret_cast<const T*>(begin());
|
|
remove_prefix(sizeof(T));
|
|
return true;
|
|
}
|
|
|
|
// Tries to reinterpret data as type |T| at the cursor and to return a
|
|
// reinterpreted pointer of type |T| pointing into the underlying data, while
|
|
// moving the cursor forward by sizeof(T). Returns nullptr if insufficient
|
|
// data is available.
|
|
template <class T>
|
|
const T* GetPointer() {
|
|
static_assert(std::is_standard_layout<T>::value,
|
|
"Value type must be a standard layout type");
|
|
|
|
DCHECK_NE(begin(), nullptr);
|
|
if (Remaining() < sizeof(T))
|
|
return nullptr;
|
|
const T* ptr = reinterpret_cast<const T*>(begin());
|
|
remove_prefix(sizeof(T));
|
|
return ptr;
|
|
}
|
|
|
|
// Tries to reinterpret data as an array of type |T| with |count| elements,
|
|
// starting at the cursor, and to return a reinterpreted pointer of type |T|
|
|
// pointing into the underlying data, while advancing the cursor beyond the
|
|
// array. Returns nullptr if insufficient data is available.
|
|
template <class T>
|
|
const T* GetArray(size_t count) {
|
|
static_assert(std::is_standard_layout<T>::value,
|
|
"Value type must be a standard layout type");
|
|
|
|
if (Remaining() / sizeof(T) < count)
|
|
return nullptr;
|
|
const T* array = reinterpret_cast<const T*>(begin());
|
|
remove_prefix(count * sizeof(T));
|
|
return array;
|
|
}
|
|
|
|
// If sufficient data is available, assigns |buffer| to point to a region of
|
|
// |size| bytes starting at the cursor, while advancing the cursor beyond the
|
|
// region, and returns true. Otherwise returns false.
|
|
bool GetRegion(size_type size, ConstBufferView* buffer);
|
|
|
|
// Reads an Unsigned Little Endian Base 128 (uleb128) int at |first_|. If
|
|
// successful, writes the result to |value|, advances |first_|, and returns
|
|
// true. Otherwise returns false.
|
|
bool GetUleb128(uint32_t* value);
|
|
|
|
// Reads a Signed Little Endian Base 128 (sleb128) int at |first_|. If
|
|
// successful, writes the result to |value|, advances |first_|, and returns
|
|
// true. Otherwise returns false.
|
|
bool GetSleb128(int32_t* value);
|
|
|
|
// Reads uleb128 / sleb128 at |first_| but discards the result. If successful,
|
|
// advances |first_| and returns true. Otherwise returns false.
|
|
bool SkipLeb128();
|
|
|
|
// Returns the number of bytes remaining from cursor until end.
|
|
size_type Remaining() const { return size(); }
|
|
};
|
|
|
|
} // namespace zucchini
|
|
|
|
#endif // COMPONENTS_ZUCCHINI_BUFFER_SOURCE_H_
|