blob: d2a05b02167603d391a62462f7cab20bb75ce83b [file] [log] [blame]
// 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/logging.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_