LCOV - code coverage report
Current view: top level - include/llvm/Support - BinaryStreamReader.h (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 162 187 86.6 %
Date: 2018-10-17 09:37:48 Functions: 80 86 93.0 %
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             : /// 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         422 :   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        3498 :   BinaryStreamReader(const BinaryStreamReader &Other)
      42        3498 :       : Stream(Other.Stream), Offset(Other.Offset) {}
      43             : 
      44             :   BinaryStreamReader &operator=(const BinaryStreamReader &Other) {
      45             :     Stream = Other.Stream;
      46         501 :     Offset = Other.Offset;
      47             :     return *this;
      48             :   }
      49             : 
      50       30957 :   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       92226 :   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       92226 :     ArrayRef<uint8_t> Bytes;
      81      184452 :     if (auto EC = readBytes(Bytes, sizeof(T)))
      82             :       return EC;
      83             : 
      84      179927 :     Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
      85       92226 :         Bytes.data(), Stream.getEndian());
      86             :     return Error::success();
      87             :   }
      88        4328 : 
      89             :   /// Similar to readInteger.
      90        9502 :   template <typename T> Error readEnum(T &Dest) {
      91             :     static_assert(std::is_enum<T>::value,
      92        4328 :                   "Cannot call readEnum with non-enum value!");
      93        8656 :     typename std::underlying_type<T>::type N;
      94       19004 :     if (auto EC = readInteger(N))
      95             :       return EC;
      96       14029 :     Dest = static_cast<T>(N);
      97        4328 :     return Error::success();
      98             :   }
      99             : 
     100        3652 :   /// 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        3652 :   /// \returns a success error code if the data was successfully read, otherwise
     105        7304 :   /// returns an appropriate error code.
     106             :   Error readCString(StringRef &Dest);
     107             : 
     108        6912 :   /// Similar to readCString, however read a null-terminated UTF16 string
     109        3652 :   /// instead.
     110             :   ///
     111             :   /// \returns a success error code if the data was successfully read, otherwise
     112        8356 :   /// returns an appropriate error code.
     113             :   Error readWideString(ArrayRef<UTF16> &Dest);
     114           1 : 
     115             :   /// Read a \p Length byte string into \p Dest.  Whether a copy occurs depends
     116        8356 :   /// on the implementation of the underlying stream.  Updates the stream's
     117       16712 :   /// offset to point after the newly read data.
     118           2 :   ///
     119             :   /// \returns a success error code if the data was successfully read, otherwise
     120       16713 :   /// returns an appropriate error code.
     121        8356 :   Error readFixedString(StringRef &Dest, uint32_t Length);
     122             : 
     123             :   /// Read the entire remainder of the underlying stream into \p Ref.  This is
     124       22528 :   /// 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       22528 :   /// returns an appropriate error code.
     129       45056 :   Error readStreamRef(BinaryStreamRef &Ref);
     130             : 
     131             :   /// Read \p Length bytes from the underlying stream into \p Ref.  This is
     132       45056 :   /// equivalent to calling getUnderlyingStream().slice(Offset, Length).
     133       22528 :   /// Updates the stream's offset to point after the newly read object.  Never
     134             :   /// causes a copy.
     135             :   ///
     136           2 :   /// \returns a success error code if the data was successfully read, otherwise
     137             :   /// returns an appropriate error code.
     138          18 :   Error readStreamRef(BinaryStreamRef &Ref, uint32_t Length);
     139             : 
     140           2 :   /// Read \p Length bytes from the underlying stream into \p Stream.  This is
     141           4 :   /// equivalent to calling getUnderlyingStream().slice(Offset, Length).
     142          36 :   /// Updates the stream's offset to point after the newly read object.  Never
     143             :   /// causes a copy.
     144          22 :   ///
     145           2 :   /// \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           4 : 
     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           4 :   /// Updates the stream's offset to point after the newly read object.  Whether
     153           8 :   /// a copy occurs depends upon the implementation of the underlying
     154             :   /// stream.
     155             :   ///
     156           4 :   /// \returns a success error code if the data was successfully read, otherwise
     157           4 :   /// returns an appropriate error code.
     158       20953 :   template <typename T> Error readObject(const T *&Dest) {
     159       20953 :     ArrayRef<uint8_t> Buffer;
     160       52847 :     if (auto EC = readBytes(Buffer, sizeof(T)))
     161             :       return EC;
     162       20950 :     Dest = reinterpret_cast<const T *>(Buffer.data());
     163             :     return Error::success();
     164       10941 :   }
     165       22744 : 
     166         862 :   /// Get a reference to a \p NumElements element array of objects of type T
     167        1724 :   /// from the underlying stream as if by memcpy, and store the resulting array
     168       21882 :   /// slice into \p array.  It is up to the caller to ensure that objects of
     169       11803 :   /// 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         878 :   ///
     173         878 :   /// \returns a success error code if the data was successfully read, otherwise
     174        1756 :   /// returns an appropriate error code.
     175             :   template <typename T>
     176        3439 :   Error readArray(ArrayRef<T> &Array, uint32_t NumElements) {
     177        2561 :     ArrayRef<uint8_t> Bytes;
     178        2561 :     if (NumElements == 0) {
     179         290 :       Array = ArrayRef<T>();
     180          33 :       return Error::success();
     181          66 :     }
     182             : 
     183        2337 :     if (NumElements > UINT32_MAX / sizeof(T))
     184             :       return make_error<BinaryStreamError>(
     185           0 :           stream_error_code::invalid_array_size);
     186         168 : 
     187        4776 :     if (auto EC = readBytes(Bytes, NumElements * sizeof(T)))
     188         336 :       return EC;
     189             : 
     190         483 :     assert(alignmentAdjustment(Bytes.data(), alignof(T)) == 0 &&
     191         315 :            "Reading at invalid alignment!");
     192         315 : 
     193        2305 :     Array = ArrayRef<T>(reinterpret_cast<const T *>(Bytes.data()), NumElements);
     194             :     return Error::success();
     195             :   }
     196             : 
     197          57 :   /// Read a VarStreamArray of size \p Size bytes and store the result into
     198          57 :   /// \p Array.  Updates the stream's offset to point after the newly read
     199          57 :   /// array.  Never causes a copy (although iterating the elements of the
     200           2 :   /// VarStreamArray may, depending upon the implementation of the underlying
     201         630 :   /// stream).
     202           2 :   ///
     203           0 :   /// \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        2198 :   Error readArray(VarStreamArray<T, U> &Array, uint32_t Size) {
     207         497 :     BinaryStreamRef S;
     208        4510 :     if (auto EC = readStreamRef(S, Size))
     209           0 :       return EC;
     210        2197 :     Array.setUnderlyingStream(S);
     211           4 :     return Error::success();
     212             :   }
     213         443 : 
     214          67 :   /// Read a FixedStreamArray of \p NumItems elements and store the result into
     215         886 :   /// \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         445 :   /// FixedStreamArray may, depending upon the implementation of the underlying
     218             :   /// stream).
     219             :   ///
     220        1077 :   /// \returns a success error code if the data was successfully read, otherwise
     221          31 :   /// returns an appropriate error code.
     222        2153 :   template <typename T>
     223        1210 :   Error readArray(FixedStreamArray<T> &Array, uint32_t NumItems) {
     224        2286 :     if (NumItems == 0) {
     225         142 :       Array = FixedStreamArray<T>();
     226             :       return Error::success();
     227         135 :     }
     228         134 : 
     229        1407 :     if (NumItems > UINT32_MAX / sizeof(T))
     230             :       return make_error<BinaryStreamError>(
     231         136 :           stream_error_code::invalid_array_size);
     232             : 
     233             :     BinaryStreamRef View;
     234        2451 :     if (auto EC = readStreamRef(View, NumItems * sizeof(T)))
     235           6 :       return EC;
     236         346 : 
     237        2497 :     Array = FixedStreamArray<T>(View);
     238        1031 :     return Error::success();
     239           0 :   }
     240         124 : 
     241         126 :   bool empty() const { return bytesRemaining() == 0; }
     242       85596 :   void setOffset(uint32_t Off) { Offset = Off; }
     243         893 :   uint32_t getOffset() const { return Offset; }
     244          62 :   uint32_t getLength() const { return Stream.getLength(); }
     245       29761 :   uint32_t bytesRemaining() const { return getLength() - getOffset(); }
     246         131 : 
     247             :   /// Advance the stream's offset by \p Amount bytes.
     248        1716 :   ///
     249             :   /// \returns a success error code if at least \p Amount bytes remain in the
     250             :   /// stream, otherwise returns an appropriate error code.
     251        1511 :   Error skip(uint32_t Amount);
     252         149 : 
     253           4 :   /// Examine the next byte of the underlying stream without advancing the
     254         199 :   /// stream's offset.  If the stream is empty the behavior is undefined.
     255          99 :   ///
     256         284 :   /// \returns the next byte in the stream.
     257         514 :   uint8_t peek() const;
     258         366 : 
     259        2259 :   Error padToAlignment(uint32_t Align);
     260         117 : 
     261          18 :   std::pair<BinaryStreamReader, BinaryStreamReader>
     262         294 :   split(uint32_t Offset) const;
     263         460 : 
     264             : private:
     265         345 :   BinaryStreamRef Stream;
     266          18 :   uint32_t Offset = 0;
     267           0 : };
     268        1039 : } // namespace llvm
     269         175 : 
     270          40 : #endif // LLVM_SUPPORT_BINARYSTREAMREADER_H

Generated by: LCOV version 1.13