Home | History | Annotate | Download | only in Support
      1 //===- BinaryStreamWriter.h - Writes objects to a BinaryStream ---*- 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_BINARYSTREAMWRITER_H
     11 #define LLVM_SUPPORT_BINARYSTREAMWRITER_H
     12 
     13 #include "llvm/ADT/ArrayRef.h"
     14 #include "llvm/ADT/STLExtras.h"
     15 #include "llvm/ADT/StringRef.h"
     16 #include "llvm/Support/BinaryStreamArray.h"
     17 #include "llvm/Support/BinaryStreamError.h"
     18 #include "llvm/Support/BinaryStreamRef.h"
     19 #include "llvm/Support/Endian.h"
     20 #include "llvm/Support/Error.h"
     21 #include <cstdint>
     22 #include <type_traits>
     23 #include <utility>
     24 
     25 namespace llvm {
     26 
     27 /// \brief Provides write only access to a subclass of `WritableBinaryStream`.
     28 /// Provides bounds checking and helpers for writing certain common data types
     29 /// such as null-terminated strings, integers in various flavors of endianness,
     30 /// etc.  Can be subclassed to provide reading and writing of custom datatypes,
     31 /// although no methods are overridable.
     32 class BinaryStreamWriter {
     33 public:
     34   BinaryStreamWriter() = default;
     35   explicit BinaryStreamWriter(WritableBinaryStreamRef Ref);
     36   explicit BinaryStreamWriter(WritableBinaryStream &Stream);
     37   explicit BinaryStreamWriter(MutableArrayRef<uint8_t> Data,
     38                               llvm::support::endianness Endian);
     39 
     40   BinaryStreamWriter(const BinaryStreamWriter &Other)
     41       : Stream(Other.Stream), Offset(Other.Offset) {}
     42 
     43   BinaryStreamWriter &operator=(const BinaryStreamWriter &Other) {
     44     Stream = Other.Stream;
     45     Offset = Other.Offset;
     46     return *this;
     47   }
     48 
     49   virtual ~BinaryStreamWriter() {}
     50 
     51   /// Write the bytes specified in \p Buffer to the underlying stream.
     52   /// On success, updates the offset so that subsequent writes will occur
     53   /// at the next unwritten position.
     54   ///
     55   /// \returns a success error code if the data was successfully written,
     56   /// otherwise returns an appropriate error code.
     57   Error writeBytes(ArrayRef<uint8_t> Buffer);
     58 
     59   /// Write the the integer \p Value to the underlying stream in the
     60   /// specified endianness.  On success, updates the offset so that
     61   /// subsequent writes occur at the next unwritten position.
     62   ///
     63   /// \returns a success error code if the data was successfully written,
     64   /// otherwise returns an appropriate error code.
     65   template <typename T> Error writeInteger(T Value) {
     66     static_assert(std::is_integral<T>::value,
     67                   "Cannot call writeInteger with non-integral value!");
     68     uint8_t Buffer[sizeof(T)];
     69     llvm::support::endian::write<T, llvm::support::unaligned>(
     70         Buffer, Value, Stream.getEndian());
     71     return writeBytes(Buffer);
     72   }
     73 
     74   /// Similar to writeInteger
     75   template <typename T> Error writeEnum(T Num) {
     76     static_assert(std::is_enum<T>::value,
     77                   "Cannot call writeEnum with non-Enum type");
     78 
     79     using U = typename std::underlying_type<T>::type;
     80     return writeInteger<U>(static_cast<U>(Num));
     81   }
     82 
     83   /// Write the the string \p Str to the underlying stream followed by a null
     84   /// terminator.  On success, updates the offset so that subsequent writes
     85   /// occur at the next unwritten position.  \p Str need not be null terminated
     86   /// on input.
     87   ///
     88   /// \returns a success error code if the data was successfully written,
     89   /// otherwise returns an appropriate error code.
     90   Error writeCString(StringRef Str);
     91 
     92   /// Write the the string \p Str to the underlying stream without a null
     93   /// terminator.  On success, updates the offset so that subsequent writes
     94   /// occur at the next unwritten position.
     95   ///
     96   /// \returns a success error code if the data was successfully written,
     97   /// otherwise returns an appropriate error code.
     98   Error writeFixedString(StringRef Str);
     99 
    100   /// Efficiently reads all data from \p Ref, and writes it to this stream.
    101   /// This operation will not invoke any copies of the source data, regardless
    102   /// of the source stream's implementation.
    103   ///
    104   /// \returns a success error code if the data was successfully written,
    105   /// otherwise returns an appropriate error code.
    106   Error writeStreamRef(BinaryStreamRef Ref);
    107 
    108   /// Efficiently reads \p Size bytes from \p Ref, and writes it to this stream.
    109   /// This operation will not invoke any copies of the source data, regardless
    110   /// of the source stream's implementation.
    111   ///
    112   /// \returns a success error code if the data was successfully written,
    113   /// otherwise returns an appropriate error code.
    114   Error writeStreamRef(BinaryStreamRef Ref, uint32_t Size);
    115 
    116   /// Writes the object \p Obj to the underlying stream, as if by using memcpy.
    117   /// It is up to the caller to ensure that type of \p Obj can be safely copied
    118   /// in this fashion, as no checks are made to ensure that this is safe.
    119   ///
    120   /// \returns a success error code if the data was successfully written,
    121   /// otherwise returns an appropriate error code.
    122   template <typename T> Error writeObject(const T &Obj) {
    123     static_assert(!std::is_pointer<T>::value,
    124                   "writeObject should not be used with pointers, to write "
    125                   "the pointed-to value dereference the pointer before calling "
    126                   "writeObject");
    127     return writeBytes(
    128         ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&Obj), sizeof(T)));
    129   }
    130 
    131   /// Writes an array of objects of type T to the underlying stream, as if by
    132   /// using memcpy.  It is up to the caller to ensure that type of \p Obj can
    133   /// be safely copied in this fashion, as no checks are made to ensure that
    134   /// this is safe.
    135   ///
    136   /// \returns a success error code if the data was successfully written,
    137   /// otherwise returns an appropriate error code.
    138   template <typename T> Error writeArray(ArrayRef<T> Array) {
    139     if (Array.empty())
    140       return Error::success();
    141     if (Array.size() > UINT32_MAX / sizeof(T))
    142       return make_error<BinaryStreamError>(
    143           stream_error_code::invalid_array_size);
    144 
    145     return writeBytes(
    146         ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Array.data()),
    147                           Array.size() * sizeof(T)));
    148   }
    149 
    150   /// Writes all data from the array \p Array to the underlying stream.
    151   ///
    152   /// \returns a success error code if the data was successfully written,
    153   /// otherwise returns an appropriate error code.
    154   template <typename T, typename U>
    155   Error writeArray(VarStreamArray<T, U> Array) {
    156     return writeStreamRef(Array.getUnderlyingStream());
    157   }
    158 
    159   /// Writes all elements from the array \p Array to the underlying stream.
    160   ///
    161   /// \returns a success error code if the data was successfully written,
    162   /// otherwise returns an appropriate error code.
    163   template <typename T> Error writeArray(FixedStreamArray<T> Array) {
    164     return writeStreamRef(Array.getUnderlyingStream());
    165   }
    166 
    167   /// Splits the Writer into two Writers at a given offset.
    168   std::pair<BinaryStreamWriter, BinaryStreamWriter> split(uint32_t Off) const;
    169 
    170   void setOffset(uint32_t Off) { Offset = Off; }
    171   uint32_t getOffset() const { return Offset; }
    172   uint32_t getLength() const { return Stream.getLength(); }
    173   uint32_t bytesRemaining() const { return getLength() - getOffset(); }
    174   Error padToAlignment(uint32_t Align);
    175 
    176 protected:
    177   WritableBinaryStreamRef Stream;
    178   uint32_t Offset = 0;
    179 };
    180 
    181 } // end namespace llvm
    182 
    183 #endif // LLVM_SUPPORT_BINARYSTREAMWRITER_H
    184