blob: 1819a6e61173aaa3f6ac29df996607d33aa8f433 [file] [log] [blame]
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// A utility class for safe and easy parsing of binary buffers.
#ifndef SYZYGY_COMMON_BUFFER_PARSER_H_
#define SYZYGY_COMMON_BUFFER_PARSER_H_
#include <stdint.h>
namespace common {
// A binary buffer parser
class BinaryBufferParser {
public:
// This object is allowed to have copy constructors.
BinaryBufferParser();
BinaryBufferParser(const void* data, size_t data_len);
// Sets the data associated to be parsed. Allows initializing this object
// after construction.
//
// @param data the data to be parsed.
// @param data_len the length of the data.
void SetData(const void* data, size_t data_len);
// Accessors.
const void* data() const { return data_; }
size_t data_len() const { return data_len_; }
// Check whether the buffer contains the range of data from @p pos to
// @p pos + @p data_len.
// @param pos the byte position of the start of the data range.
// @param data_len the byte length of the data range.
// @returns true iff the range of bytes from @p pos to @p pos + @p data_len.
bool Contains(size_t pos, size_t data_len) const;
// Retrieve a pointer into the buffer if the requested data is contained
// in our buffer.
// @param pos the position to get a pointer to.
// @param data_len the amount of data expected behind @p pos.
// @param data_ptr on success will contain a pointer to @p pos in data.
// @returns true iff Contains(pos, data_len).
// @note No alignment constraints are checked.
bool GetAt(size_t pos, size_t data_len, const void** data_ptr) const;
// Retrieve a typed pointer into the buffer if the requested data
// is contained in our buffer.
// @param pos the position to get a pointer to.
// @param data_len the amount of data expected behind @p pos.
// @param data_ptr on success will contain a pointer to @p pos in data.
// @returns true on success, false otherwise.
// @note The basic version of the function checks @p pos for alignment,
// whereas the IgnoreAlignment version ignores it.
template <class DataType>
bool GetAt(size_t pos, size_t data_len, const DataType** data_ptr) const {
return GetAtImplicitAlignment(pos, data_len, data_ptr);
}
template <class DataType>
bool GetAtIgnoreAlignment(
size_t pos, size_t data_len, const DataType** data_ptr) const {
return GetAtExplicitAlignment(pos, data_len, 1, data_ptr);
}
// Retrieve a typed pointer into the buffer if the requested structure
// fits into our buffer at position @pos.
// @param pos the position to get a pointer to.
// @param data_ptr on success will contain a pointer to @p pos in data.
// @returns true on success, false otherwise.
// @note The basic version of the function checks @p pos for alignment,
// whereas the IgnoreAlignment version ignores it.
template <class DataType>
bool GetAt(size_t pos, const DataType** data_ptr) const {
return GetAtImplicitAlignment(pos, sizeof(DataType), data_ptr);
}
template <class DataType>
bool GetAtIgnoreAlignment(size_t pos, const DataType** data_ptr) const {
return GetAtExplicitAlignment(pos, sizeof(DataType), 1, data_ptr);
}
// Retrieve a typed pointer to an array if the requested array fits into
// the buffer at the given position.
// @param pos the position to get a pointer to.
// @param count the number of elements to retrieve.
// @param data_ptr on success will contain a pointer to @p pos in data.
// @returns true on success, false otherwise.
// @note The basic version of the function checks @p pos for alignment,
// whereas the IgnoreAlignment version ignores it.
template <class DataType>
bool GetCountAt(size_t pos, size_t count, const DataType** data_ptr) const {
return GetAtImplicitAlignment(pos, sizeof(DataType) * count, data_ptr);
}
template <class DataType>
bool GetCountAtIgnoreAlignment(
size_t pos, size_t count, const DataType** data_ptr) const {
return GetAtExplicitAlignment(pos, sizeof(DataType) * count, 1, data_ptr);
}
// Get a zero terminated string starting at the byte offset @p pos.
// @param pos the byte offset where the string starts.
// @param ptr on success returns the string pointer.
// @param len on success returns the string character length.
// @returns true on success, e.g. there's a zero termiator in the buffer
// after @p pos, or false on failure, when @p pos is outside the buffer
// or there is no zero terminator in the buffer after @p pos.
// @note this function does not check @pos for appropriate alignment.
// @note The basic version of the function checks @p pos for alignment,
// whereas the IgnoreAlignment version ignores it.
bool GetStringAt(size_t pos, const char** ptr, size_t* len) const;
bool GetStringAt(size_t pos, const wchar_t** ptr, size_t* len) const;
bool GetStringAtIgnoreAlignment(
size_t pos, const wchar_t** ptr, size_t* len) const;
protected:
template <class DataType>
bool GetAtImplicitAlignment(
size_t pos, size_t size, const DataType** data_ptr) const;
template <class DataType>
bool GetAtExplicitAlignment(
size_t pos, size_t size, size_t align, const DataType** data_ptr) const;
const int8_t* data_;
size_t data_len_;
};
// A binary buffer reader allows reading sequentially from a binary buffer,
// as well as peeking at the current position without moving it.
class BinaryBufferReader {
public:
BinaryBufferReader(const void* data, size_t data_len);
// Accessors.
size_t pos() const { return pos_; }
void set_pos(size_t pos) { pos_ = pos; }
// Calculate the number of bytes remaining in the buffer.
// @returns the number of bytes remaining in the buffer.
size_t RemainingBytes() const;
// Advance the read position by @p bytes.
// @param bytes the number of bytes to advance the read position.
// @returns true iff the new position is in our buffer.
bool Consume(size_t bytes);
// Align the read position to the next even multiple of @p bytes.
// @param bytes the byte alignment, must be a power of two.
// @returns true iff the new position is in our buffer.
bool Align(size_t bytes);
// Check whether the read position is aligned to bytes.
// @param bytes the byte alignment to check, must be a power of two.
// @returns true iff the current position is an integer multiple of @p bytes.
bool IsAligned(size_t bytes);
// Retrieve a pointer into our buffer, without moving the read position.
bool Peek(size_t data_len, const void** data);
template <class DataType>
bool Peek(size_t data_len, const DataType** data_ptr) {
return Peek(data_len, reinterpret_cast<const void**>(data_ptr));
}
template <class DataType>
bool Peek(const DataType** data_ptr) {
return Peek(sizeof(**data_ptr), data_ptr);
}
// Retrieve a pointer into our buffer and advance the read position.
bool Read(size_t data_len, const void** data);
template <class DataType>
bool Read(size_t data_len, const DataType** data_ptr) {
return Read(data_len, reinterpret_cast<const void**>(data_ptr));
}
template <class DataType>
bool Read(const DataType** data_ptr) {
return Read(sizeof(**data_ptr), data_ptr);
}
// Retrieve a zero-terminated string from our buffer without
// advancing the read position.
bool PeekString(const char** str, size_t* str_len);
bool PeekString(const wchar_t** str, size_t* str_len);
// Retrieve a zero-terminated string from our buffer and
// advance the read position.
bool ReadString(const char** str, size_t* str_len);
bool ReadString(const wchar_t** str, size_t* str_len);
private:
// The buffer we read from.
BinaryBufferParser parser_;
// Current position.
size_t pos_;
};
} // namespace common
#include "syzygy/common/buffer_parser_impl.h"
#endif // SYZYGY_COMMON_BUFFER_PARSER_H_