123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- BinaryStreamReader.h - Reads objects from a binary stream *- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_SUPPORT_BINARYSTREAMREADER_H
- #define LLVM_SUPPORT_BINARYSTREAMREADER_H
- #include "llvm/ADT/ArrayRef.h"
- #include "llvm/ADT/StringRef.h"
- #include "llvm/Support/Alignment.h"
- #include "llvm/Support/BinaryStreamArray.h"
- #include "llvm/Support/BinaryStreamRef.h"
- #include "llvm/Support/ConvertUTF.h"
- #include "llvm/Support/Endian.h"
- #include "llvm/Support/Error.h"
- #include <type_traits>
- namespace llvm {
- /// Provides read only access to a subclass of `BinaryStream`. Provides
- /// bounds checking and helpers for writing certain common data types such as
- /// null-terminated strings, integers in various flavors of endianness, etc.
- /// Can be subclassed to provide reading of custom datatypes, although no
- /// are overridable.
- class BinaryStreamReader {
- public:
- BinaryStreamReader() = default;
- explicit BinaryStreamReader(BinaryStreamRef Ref);
- explicit BinaryStreamReader(BinaryStream &Stream);
- explicit BinaryStreamReader(ArrayRef<uint8_t> Data,
- llvm::support::endianness Endian);
- explicit BinaryStreamReader(StringRef Data, llvm::support::endianness Endian);
- BinaryStreamReader(const BinaryStreamReader &Other) = default;
- BinaryStreamReader &operator=(const BinaryStreamReader &Other) = default;
- virtual ~BinaryStreamReader() = default;
- /// Read as much as possible from the underlying string at the current offset
- /// without invoking a copy, and set \p Buffer to the resulting data slice.
- /// Updates the stream's offset to point after the newly read data.
- ///
- /// \returns a success error code if the data was successfully read, otherwise
- /// returns an appropriate error code.
- Error readLongestContiguousChunk(ArrayRef<uint8_t> &Buffer);
- /// Read \p Size bytes from the underlying stream at the current offset and
- /// and set \p Buffer to the resulting data slice. Whether a copy occurs
- /// depends on the implementation of the underlying stream. Updates the
- /// stream's offset to point after the newly read data.
- ///
- /// \returns a success error code if the data was successfully read, otherwise
- /// returns an appropriate error code.
- Error readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size);
- /// Read an integer of the specified endianness into \p Dest and update the
- /// stream's offset. The data is always copied from the stream's underlying
- /// buffer into \p Dest. Updates the stream's offset to point after the newly
- /// read data.
- ///
- /// \returns a success error code if the data was successfully read, otherwise
- /// returns an appropriate error code.
- template <typename T> Error readInteger(T &Dest) {
- static_assert(std::is_integral_v<T>,
- "Cannot call readInteger with non-integral value!");
- ArrayRef<uint8_t> Bytes;
- if (auto EC = readBytes(Bytes, sizeof(T)))
- return EC;
- Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
- Bytes.data(), Stream.getEndian());
- return Error::success();
- }
- /// Similar to readInteger.
- template <typename T> Error readEnum(T &Dest) {
- static_assert(std::is_enum<T>::value,
- "Cannot call readEnum with non-enum value!");
- std::underlying_type_t<T> N;
- if (auto EC = readInteger(N))
- return EC;
- Dest = static_cast<T>(N);
- return Error::success();
- }
- /// Read an unsigned LEB128 encoded value.
- ///
- /// \returns a success error code if the data was successfully read, otherwise
- /// returns an appropriate error code.
- Error readULEB128(uint64_t &Dest);
- /// Read a signed LEB128 encoded value.
- ///
- /// \returns a success error code if the data was successfully read, otherwise
- /// returns an appropriate error code.
- Error readSLEB128(int64_t &Dest);
- /// Read a null terminated string from \p Dest. Whether a copy occurs depends
- /// on the implementation of the underlying stream. Updates the stream's
- /// offset to point after the newly read data.
- ///
- /// \returns a success error code if the data was successfully read, otherwise
- /// returns an appropriate error code.
- Error readCString(StringRef &Dest);
- /// Similar to readCString, however read a null-terminated UTF16 string
- /// instead.
- ///
- /// \returns a success error code if the data was successfully read, otherwise
- /// returns an appropriate error code.
- Error readWideString(ArrayRef<UTF16> &Dest);
- /// Read a \p Length byte string into \p Dest. Whether a copy occurs depends
- /// on the implementation of the underlying stream. Updates the stream's
- /// offset to point after the newly read data.
- ///
- /// \returns a success error code if the data was successfully read, otherwise
- /// returns an appropriate error code.
- Error readFixedString(StringRef &Dest, uint32_t Length);
- /// Read the entire remainder of the underlying stream into \p Ref. This is
- /// equivalent to calling getUnderlyingStream().slice(Offset). Updates the
- /// stream's offset to point to the end of the stream. Never causes a copy.
- ///
- /// \returns a success error code if the data was successfully read, otherwise
- /// returns an appropriate error code.
- Error readStreamRef(BinaryStreamRef &Ref);
- /// Read \p Length bytes from the underlying stream into \p Ref. This is
- /// equivalent to calling getUnderlyingStream().slice(Offset, Length).
- /// Updates the stream's offset to point after the newly read object. Never
- /// causes a copy.
- ///
- /// \returns a success error code if the data was successfully read, otherwise
- /// returns an appropriate error code.
- Error readStreamRef(BinaryStreamRef &Ref, uint32_t Length);
- /// Read \p Length bytes from the underlying stream into \p Ref. This is
- /// equivalent to calling getUnderlyingStream().slice(Offset, Length).
- /// Updates the stream's offset to point after the newly read object. Never
- /// causes a copy.
- ///
- /// \returns a success error code if the data was successfully read, otherwise
- /// returns an appropriate error code.
- Error readSubstream(BinarySubstreamRef &Ref, uint32_t Length);
- /// Get a pointer to an object of type T from the underlying stream, as if by
- /// memcpy, and store the result into \p Dest. It is up to the caller to
- /// ensure that objects of type T can be safely treated in this manner.
- /// Updates the stream's offset to point after the newly read object. Whether
- /// a copy occurs depends upon the implementation of the underlying
- /// stream.
- ///
- /// \returns a success error code if the data was successfully read, otherwise
- /// returns an appropriate error code.
- template <typename T> Error readObject(const T *&Dest) {
- ArrayRef<uint8_t> Buffer;
- if (auto EC = readBytes(Buffer, sizeof(T)))
- return EC;
- Dest = reinterpret_cast<const T *>(Buffer.data());
- return Error::success();
- }
- /// Get a reference to a \p NumElements element array of objects of type T
- /// from the underlying stream as if by memcpy, and store the resulting array
- /// slice into \p array. It is up to the caller to ensure that objects of
- /// type T can be safely treated in this manner. Updates the stream's offset
- /// to point after the newly read object. Whether a copy occurs depends upon
- /// the implementation of the underlying stream.
- ///
- /// \returns a success error code if the data was successfully read, otherwise
- /// returns an appropriate error code.
- template <typename T>
- Error readArray(ArrayRef<T> &Array, uint32_t NumElements) {
- ArrayRef<uint8_t> Bytes;
- if (NumElements == 0) {
- Array = ArrayRef<T>();
- return Error::success();
- }
- if (NumElements > UINT32_MAX / sizeof(T))
- return make_error<BinaryStreamError>(
- stream_error_code::invalid_array_size);
- if (auto EC = readBytes(Bytes, NumElements * sizeof(T)))
- return EC;
- assert(isAddrAligned(Align::Of<T>(), Bytes.data()) &&
- "Reading at invalid alignment!");
- Array = ArrayRef<T>(reinterpret_cast<const T *>(Bytes.data()), NumElements);
- return Error::success();
- }
- /// Read a VarStreamArray of size \p Size bytes and store the result into
- /// \p Array. Updates the stream's offset to point after the newly read
- /// array. Never causes a copy (although iterating the elements of the
- /// VarStreamArray may, depending upon the implementation of the underlying
- /// stream).
- ///
- /// \returns a success error code if the data was successfully read, otherwise
- /// returns an appropriate error code.
- template <typename T, typename U>
- Error readArray(VarStreamArray<T, U> &Array, uint32_t Size,
- uint32_t Skew = 0) {
- BinaryStreamRef S;
- if (auto EC = readStreamRef(S, Size))
- return EC;
- Array.setUnderlyingStream(S, Skew);
- return Error::success();
- }
- /// Read a FixedStreamArray of \p NumItems elements and store the result into
- /// \p Array. Updates the stream's offset to point after the newly read
- /// array. Never causes a copy (although iterating the elements of the
- /// FixedStreamArray may, depending upon the implementation of the underlying
- /// stream).
- ///
- /// \returns a success error code if the data was successfully read, otherwise
- /// returns an appropriate error code.
- template <typename T>
- Error readArray(FixedStreamArray<T> &Array, uint32_t NumItems) {
- if (NumItems == 0) {
- Array = FixedStreamArray<T>();
- return Error::success();
- }
- if (NumItems > UINT32_MAX / sizeof(T))
- return make_error<BinaryStreamError>(
- stream_error_code::invalid_array_size);
- BinaryStreamRef View;
- if (auto EC = readStreamRef(View, NumItems * sizeof(T)))
- return EC;
- Array = FixedStreamArray<T>(View);
- return Error::success();
- }
- bool empty() const { return bytesRemaining() == 0; }
- void setOffset(uint64_t Off) { Offset = Off; }
- uint64_t getOffset() const { return Offset; }
- uint64_t getLength() const { return Stream.getLength(); }
- uint64_t bytesRemaining() const { return getLength() - getOffset(); }
- /// Advance the stream's offset by \p Amount bytes.
- ///
- /// \returns a success error code if at least \p Amount bytes remain in the
- /// stream, otherwise returns an appropriate error code.
- Error skip(uint64_t Amount);
- /// Examine the next byte of the underlying stream without advancing the
- /// stream's offset. If the stream is empty the behavior is undefined.
- ///
- /// \returns the next byte in the stream.
- uint8_t peek() const;
- Error padToAlignment(uint32_t Align);
- std::pair<BinaryStreamReader, BinaryStreamReader>
- split(uint64_t Offset) const;
- private:
- BinaryStreamRef Stream;
- uint64_t Offset = 0;
- };
- } // namespace llvm
- #endif // LLVM_SUPPORT_BINARYSTREAMREADER_H
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|