Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. //===- BinaryStreamReader.h - Reads objects from a binary stream *- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8.  
  9. #ifndef LLVM_SUPPORT_BINARYSTREAMREADER_H
  10. #define LLVM_SUPPORT_BINARYSTREAMREADER_H
  11.  
  12. #include "llvm/ADT/ArrayRef.h"
  13. #include "llvm/ADT/StringRef.h"
  14. #include "llvm/Support/Alignment.h"
  15. #include "llvm/Support/BinaryStreamArray.h"
  16. #include "llvm/Support/BinaryStreamRef.h"
  17. #include "llvm/Support/ConvertUTF.h"
  18. #include "llvm/Support/Endian.h"
  19. #include "llvm/Support/Error.h"
  20. #include <type_traits>
  21.  
  22. namespace llvm {
  23.  
  24. /// Provides read only access to a subclass of `BinaryStream`.  Provides
  25. /// bounds checking and helpers for writing certain common data types such as
  26. /// null-terminated strings, integers in various flavors of endianness, etc.
  27. /// Can be subclassed to provide reading of custom datatypes, although no
  28. /// are overridable.
  29. class BinaryStreamReader {
  30. public:
  31.   BinaryStreamReader() = default;
  32.   explicit BinaryStreamReader(BinaryStreamRef Ref);
  33.   explicit BinaryStreamReader(BinaryStream &Stream);
  34.   explicit BinaryStreamReader(ArrayRef<uint8_t> Data,
  35.                               llvm::support::endianness Endian);
  36.   explicit BinaryStreamReader(StringRef Data, llvm::support::endianness Endian);
  37.  
  38.   BinaryStreamReader(const BinaryStreamReader &Other) = default;
  39.  
  40.   BinaryStreamReader &operator=(const BinaryStreamReader &Other) = default;
  41.  
  42.   virtual ~BinaryStreamReader() = default;
  43.  
  44.   /// Read as much as possible from the underlying string at the current offset
  45.   /// without invoking a copy, and set \p Buffer to the resulting data slice.
  46.   /// Updates the stream's offset to point after the newly read data.
  47.   ///
  48.   /// \returns a success error code if the data was successfully read, otherwise
  49.   /// returns an appropriate error code.
  50.   Error readLongestContiguousChunk(ArrayRef<uint8_t> &Buffer);
  51.  
  52.   /// Read \p Size bytes from the underlying stream at the current offset and
  53.   /// and set \p Buffer to the resulting data slice.  Whether a copy occurs
  54.   /// depends on the implementation of the underlying stream.  Updates the
  55.   /// stream's offset to point after the newly read data.
  56.   ///
  57.   /// \returns a success error code if the data was successfully read, otherwise
  58.   /// returns an appropriate error code.
  59.   Error readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size);
  60.  
  61.   /// Read an integer of the specified endianness into \p Dest and update the
  62.   /// stream's offset.  The data is always copied from the stream's underlying
  63.   /// buffer into \p Dest. Updates the stream's offset to point after the newly
  64.   /// read data.
  65.   ///
  66.   /// \returns a success error code if the data was successfully read, otherwise
  67.   /// returns an appropriate error code.
  68.   template <typename T> Error readInteger(T &Dest) {
  69.     static_assert(std::is_integral_v<T>,
  70.                   "Cannot call readInteger with non-integral value!");
  71.  
  72.     ArrayRef<uint8_t> Bytes;
  73.     if (auto EC = readBytes(Bytes, sizeof(T)))
  74.       return EC;
  75.  
  76.     Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
  77.         Bytes.data(), Stream.getEndian());
  78.     return Error::success();
  79.   }
  80.  
  81.   /// Similar to readInteger.
  82.   template <typename T> Error readEnum(T &Dest) {
  83.     static_assert(std::is_enum<T>::value,
  84.                   "Cannot call readEnum with non-enum value!");
  85.     std::underlying_type_t<T> N;
  86.     if (auto EC = readInteger(N))
  87.       return EC;
  88.     Dest = static_cast<T>(N);
  89.     return Error::success();
  90.   }
  91.  
  92.   /// Read an unsigned LEB128 encoded value.
  93.   ///
  94.   /// \returns a success error code if the data was successfully read, otherwise
  95.   /// returns an appropriate error code.
  96.   Error readULEB128(uint64_t &Dest);
  97.  
  98.   /// Read a signed LEB128 encoded value.
  99.   ///
  100.   /// \returns a success error code if the data was successfully read, otherwise
  101.   /// returns an appropriate error code.
  102.   Error readSLEB128(int64_t &Dest);
  103.  
  104.   /// Read a null terminated string from \p Dest.  Whether a copy occurs depends
  105.   /// on the implementation of the underlying stream.  Updates the stream's
  106.   /// offset to point after the newly read data.
  107.   ///
  108.   /// \returns a success error code if the data was successfully read, otherwise
  109.   /// returns an appropriate error code.
  110.   Error readCString(StringRef &Dest);
  111.  
  112.   /// Similar to readCString, however read a null-terminated UTF16 string
  113.   /// instead.
  114.   ///
  115.   /// \returns a success error code if the data was successfully read, otherwise
  116.   /// returns an appropriate error code.
  117.   Error readWideString(ArrayRef<UTF16> &Dest);
  118.  
  119.   /// Read a \p Length byte string into \p Dest.  Whether a copy occurs depends
  120.   /// on the implementation of the underlying stream.  Updates the stream's
  121.   /// offset to point after the newly read data.
  122.   ///
  123.   /// \returns a success error code if the data was successfully read, otherwise
  124.   /// returns an appropriate error code.
  125.   Error readFixedString(StringRef &Dest, uint32_t Length);
  126.  
  127.   /// Read the entire remainder of the underlying stream into \p Ref.  This is
  128.   /// equivalent to calling getUnderlyingStream().slice(Offset).  Updates the
  129.   /// stream's offset to point to the end of the stream.  Never causes a copy.
  130.   ///
  131.   /// \returns a success error code if the data was successfully read, otherwise
  132.   /// returns an appropriate error code.
  133.   Error readStreamRef(BinaryStreamRef &Ref);
  134.  
  135.   /// Read \p Length bytes from the underlying stream into \p Ref.  This is
  136.   /// equivalent to calling getUnderlyingStream().slice(Offset, Length).
  137.   /// Updates the stream's offset to point after the newly read object.  Never
  138.   /// causes a copy.
  139.   ///
  140.   /// \returns a success error code if the data was successfully read, otherwise
  141.   /// returns an appropriate error code.
  142.   Error readStreamRef(BinaryStreamRef &Ref, uint32_t Length);
  143.  
  144.   /// Read \p Length bytes from the underlying stream into \p Ref.  This is
  145.   /// equivalent to calling getUnderlyingStream().slice(Offset, Length).
  146.   /// Updates the stream's offset to point after the newly read object.  Never
  147.   /// causes a copy.
  148.   ///
  149.   /// \returns a success error code if the data was successfully read, otherwise
  150.   /// returns an appropriate error code.
  151.   Error readSubstream(BinarySubstreamRef &Ref, uint32_t Length);
  152.  
  153.   /// Get a pointer to an object of type T from the underlying stream, as if by
  154.   /// memcpy, and store the result into \p Dest.  It is up to the caller to
  155.   /// ensure that objects of type T can be safely treated in this manner.
  156.   /// Updates the stream's offset to point after the newly read object.  Whether
  157.   /// a copy occurs depends upon the implementation of the underlying
  158.   /// stream.
  159.   ///
  160.   /// \returns a success error code if the data was successfully read, otherwise
  161.   /// returns an appropriate error code.
  162.   template <typename T> Error readObject(const T *&Dest) {
  163.     ArrayRef<uint8_t> Buffer;
  164.     if (auto EC = readBytes(Buffer, sizeof(T)))
  165.       return EC;
  166.     Dest = reinterpret_cast<const T *>(Buffer.data());
  167.     return Error::success();
  168.   }
  169.  
  170.   /// Get a reference to a \p NumElements element array of objects of type T
  171.   /// from the underlying stream as if by memcpy, and store the resulting array
  172.   /// slice into \p array.  It is up to the caller to ensure that objects of
  173.   /// type T can be safely treated in this manner.  Updates the stream's offset
  174.   /// to point after the newly read object.  Whether a copy occurs depends upon
  175.   /// the implementation of the underlying stream.
  176.   ///
  177.   /// \returns a success error code if the data was successfully read, otherwise
  178.   /// returns an appropriate error code.
  179.   template <typename T>
  180.   Error readArray(ArrayRef<T> &Array, uint32_t NumElements) {
  181.     ArrayRef<uint8_t> Bytes;
  182.     if (NumElements == 0) {
  183.       Array = ArrayRef<T>();
  184.       return Error::success();
  185.     }
  186.  
  187.     if (NumElements > UINT32_MAX / sizeof(T))
  188.       return make_error<BinaryStreamError>(
  189.           stream_error_code::invalid_array_size);
  190.  
  191.     if (auto EC = readBytes(Bytes, NumElements * sizeof(T)))
  192.       return EC;
  193.  
  194.     assert(isAddrAligned(Align::Of<T>(), Bytes.data()) &&
  195.            "Reading at invalid alignment!");
  196.  
  197.     Array = ArrayRef<T>(reinterpret_cast<const T *>(Bytes.data()), NumElements);
  198.     return Error::success();
  199.   }
  200.  
  201.   /// Read a VarStreamArray of size \p Size bytes and store the result into
  202.   /// \p Array.  Updates the stream's offset to point after the newly read
  203.   /// array.  Never causes a copy (although iterating the elements of the
  204.   /// VarStreamArray may, depending upon the implementation of the underlying
  205.   /// stream).
  206.   ///
  207.   /// \returns a success error code if the data was successfully read, otherwise
  208.   /// returns an appropriate error code.
  209.   template <typename T, typename U>
  210.   Error readArray(VarStreamArray<T, U> &Array, uint32_t Size,
  211.                   uint32_t Skew = 0) {
  212.     BinaryStreamRef S;
  213.     if (auto EC = readStreamRef(S, Size))
  214.       return EC;
  215.     Array.setUnderlyingStream(S, Skew);
  216.     return Error::success();
  217.   }
  218.  
  219.   /// Read a FixedStreamArray of \p NumItems elements and store the result into
  220.   /// \p Array.  Updates the stream's offset to point after the newly read
  221.   /// array.  Never causes a copy (although iterating the elements of the
  222.   /// FixedStreamArray may, depending upon the implementation of the underlying
  223.   /// stream).
  224.   ///
  225.   /// \returns a success error code if the data was successfully read, otherwise
  226.   /// returns an appropriate error code.
  227.   template <typename T>
  228.   Error readArray(FixedStreamArray<T> &Array, uint32_t NumItems) {
  229.     if (NumItems == 0) {
  230.       Array = FixedStreamArray<T>();
  231.       return Error::success();
  232.     }
  233.  
  234.     if (NumItems > UINT32_MAX / sizeof(T))
  235.       return make_error<BinaryStreamError>(
  236.           stream_error_code::invalid_array_size);
  237.  
  238.     BinaryStreamRef View;
  239.     if (auto EC = readStreamRef(View, NumItems * sizeof(T)))
  240.       return EC;
  241.  
  242.     Array = FixedStreamArray<T>(View);
  243.     return Error::success();
  244.   }
  245.  
  246.   bool empty() const { return bytesRemaining() == 0; }
  247.   void setOffset(uint64_t Off) { Offset = Off; }
  248.   uint64_t getOffset() const { return Offset; }
  249.   uint64_t getLength() const { return Stream.getLength(); }
  250.   uint64_t bytesRemaining() const { return getLength() - getOffset(); }
  251.  
  252.   /// Advance the stream's offset by \p Amount bytes.
  253.   ///
  254.   /// \returns a success error code if at least \p Amount bytes remain in the
  255.   /// stream, otherwise returns an appropriate error code.
  256.   Error skip(uint64_t Amount);
  257.  
  258.   /// Examine the next byte of the underlying stream without advancing the
  259.   /// stream's offset.  If the stream is empty the behavior is undefined.
  260.   ///
  261.   /// \returns the next byte in the stream.
  262.   uint8_t peek() const;
  263.  
  264.   Error padToAlignment(uint32_t Align);
  265.  
  266.   std::pair<BinaryStreamReader, BinaryStreamReader>
  267.   split(uint64_t Offset) const;
  268.  
  269. private:
  270.   BinaryStreamRef Stream;
  271.   uint64_t Offset = 0;
  272. };
  273. } // namespace llvm
  274.  
  275. #endif // LLVM_SUPPORT_BINARYSTREAMREADER_H
  276.