LCOV - code coverage report
Current view: top level - include/llvm/Support - BinaryStreamReader.h (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 47 54 87.0 %
Date: 2017-09-14 15:23:50 Functions: 73 77 94.8 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13