10b57cec5SDimitry Andric //===- BinaryStreamWriter.h - Writes objects to a BinaryStream ---*- C++-*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #ifndef LLVM_SUPPORT_BINARYSTREAMWRITER_H 100b57cec5SDimitry Andric #define LLVM_SUPPORT_BINARYSTREAMWRITER_H 110b57cec5SDimitry Andric 120b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h" 130b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 140b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamArray.h" 150b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamError.h" 160b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamRef.h" 170b57cec5SDimitry Andric #include "llvm/Support/Endian.h" 180b57cec5SDimitry Andric #include "llvm/Support/Error.h" 190b57cec5SDimitry Andric #include <cstdint> 200b57cec5SDimitry Andric #include <type_traits> 210b57cec5SDimitry Andric #include <utility> 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric namespace llvm { 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric /// Provides write only access to a subclass of `WritableBinaryStream`. 260b57cec5SDimitry Andric /// Provides bounds checking and helpers for writing certain common data types 270b57cec5SDimitry Andric /// such as null-terminated strings, integers in various flavors of endianness, 280b57cec5SDimitry Andric /// etc. Can be subclassed to provide reading and writing of custom datatypes, 290b57cec5SDimitry Andric /// although no methods are overridable. 300b57cec5SDimitry Andric class BinaryStreamWriter { 310b57cec5SDimitry Andric public: 320b57cec5SDimitry Andric BinaryStreamWriter() = default; 330b57cec5SDimitry Andric explicit BinaryStreamWriter(WritableBinaryStreamRef Ref); 340b57cec5SDimitry Andric explicit BinaryStreamWriter(WritableBinaryStream &Stream); 350b57cec5SDimitry Andric explicit BinaryStreamWriter(MutableArrayRef<uint8_t> Data, 36*5f757f3fSDimitry Andric llvm::endianness Endian); 370b57cec5SDimitry Andric 381fd87a68SDimitry Andric BinaryStreamWriter(const BinaryStreamWriter &Other) = default; 390b57cec5SDimitry Andric 401fd87a68SDimitry Andric BinaryStreamWriter &operator=(const BinaryStreamWriter &Other) = default; 410b57cec5SDimitry Andric 421fd87a68SDimitry Andric virtual ~BinaryStreamWriter() = default; 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric /// Write the bytes specified in \p Buffer to the underlying stream. 450b57cec5SDimitry Andric /// On success, updates the offset so that subsequent writes will occur 460b57cec5SDimitry Andric /// at the next unwritten position. 470b57cec5SDimitry Andric /// 480b57cec5SDimitry Andric /// \returns a success error code if the data was successfully written, 490b57cec5SDimitry Andric /// otherwise returns an appropriate error code. 500b57cec5SDimitry Andric Error writeBytes(ArrayRef<uint8_t> Buffer); 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric /// Write the integer \p Value to the underlying stream in the 530b57cec5SDimitry Andric /// specified endianness. On success, updates the offset so that 540b57cec5SDimitry Andric /// subsequent writes occur at the next unwritten position. 550b57cec5SDimitry Andric /// 560b57cec5SDimitry Andric /// \returns a success error code if the data was successfully written, 570b57cec5SDimitry Andric /// otherwise returns an appropriate error code. writeInteger(T Value)580b57cec5SDimitry Andric template <typename T> Error writeInteger(T Value) { 59bdd1243dSDimitry Andric static_assert(std::is_integral_v<T>, 600b57cec5SDimitry Andric "Cannot call writeInteger with non-integral value!"); 610b57cec5SDimitry Andric uint8_t Buffer[sizeof(T)]; 62*5f757f3fSDimitry Andric llvm::support::endian::write<T>(Buffer, Value, Stream.getEndian()); 630b57cec5SDimitry Andric return writeBytes(Buffer); 640b57cec5SDimitry Andric } 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric /// Similar to writeInteger writeEnum(T Num)670b57cec5SDimitry Andric template <typename T> Error writeEnum(T Num) { 680b57cec5SDimitry Andric static_assert(std::is_enum<T>::value, 690b57cec5SDimitry Andric "Cannot call writeEnum with non-Enum type"); 700b57cec5SDimitry Andric 715ffd83dbSDimitry Andric using U = std::underlying_type_t<T>; 720b57cec5SDimitry Andric return writeInteger<U>(static_cast<U>(Num)); 730b57cec5SDimitry Andric } 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric /// Write the unsigned integer Value to the underlying stream using ULEB128 760b57cec5SDimitry Andric /// encoding. 770b57cec5SDimitry Andric /// 780b57cec5SDimitry Andric /// \returns a success error code if the data was successfully written, 790b57cec5SDimitry Andric /// otherwise returns an appropriate error code. 800b57cec5SDimitry Andric Error writeULEB128(uint64_t Value); 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric /// Write the unsigned integer Value to the underlying stream using ULEB128 830b57cec5SDimitry Andric /// encoding. 840b57cec5SDimitry Andric /// 850b57cec5SDimitry Andric /// \returns a success error code if the data was successfully written, 860b57cec5SDimitry Andric /// otherwise returns an appropriate error code. 870b57cec5SDimitry Andric Error writeSLEB128(int64_t Value); 880b57cec5SDimitry Andric 890b57cec5SDimitry Andric /// Write the string \p Str to the underlying stream followed by a null 900b57cec5SDimitry Andric /// terminator. On success, updates the offset so that subsequent writes 910b57cec5SDimitry Andric /// occur at the next unwritten position. \p Str need not be null terminated 920b57cec5SDimitry Andric /// on input. 930b57cec5SDimitry Andric /// 940b57cec5SDimitry Andric /// \returns a success error code if the data was successfully written, 950b57cec5SDimitry Andric /// otherwise returns an appropriate error code. 960b57cec5SDimitry Andric Error writeCString(StringRef Str); 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric /// Write the string \p Str to the underlying stream without a null 990b57cec5SDimitry Andric /// terminator. On success, updates the offset so that subsequent writes 1000b57cec5SDimitry Andric /// occur at the next unwritten position. 1010b57cec5SDimitry Andric /// 1020b57cec5SDimitry Andric /// \returns a success error code if the data was successfully written, 1030b57cec5SDimitry Andric /// otherwise returns an appropriate error code. 1040b57cec5SDimitry Andric Error writeFixedString(StringRef Str); 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric /// Efficiently reads all data from \p Ref, and writes it to this stream. 1070b57cec5SDimitry Andric /// This operation will not invoke any copies of the source data, regardless 1080b57cec5SDimitry Andric /// of the source stream's implementation. 1090b57cec5SDimitry Andric /// 1100b57cec5SDimitry Andric /// \returns a success error code if the data was successfully written, 1110b57cec5SDimitry Andric /// otherwise returns an appropriate error code. 1120b57cec5SDimitry Andric Error writeStreamRef(BinaryStreamRef Ref); 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric /// Efficiently reads \p Size bytes from \p Ref, and writes it to this stream. 1150b57cec5SDimitry Andric /// This operation will not invoke any copies of the source data, regardless 1160b57cec5SDimitry Andric /// of the source stream's implementation. 1170b57cec5SDimitry Andric /// 1180b57cec5SDimitry Andric /// \returns a success error code if the data was successfully written, 1190b57cec5SDimitry Andric /// otherwise returns an appropriate error code. 120349cc55cSDimitry Andric Error writeStreamRef(BinaryStreamRef Ref, uint64_t Size); 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric /// Writes the object \p Obj to the underlying stream, as if by using memcpy. 1230b57cec5SDimitry Andric /// It is up to the caller to ensure that type of \p Obj can be safely copied 1240b57cec5SDimitry Andric /// in this fashion, as no checks are made to ensure that this is safe. 1250b57cec5SDimitry Andric /// 1260b57cec5SDimitry Andric /// \returns a success error code if the data was successfully written, 1270b57cec5SDimitry Andric /// otherwise returns an appropriate error code. writeObject(const T & Obj)1280b57cec5SDimitry Andric template <typename T> Error writeObject(const T &Obj) { 1290b57cec5SDimitry Andric static_assert(!std::is_pointer<T>::value, 1300b57cec5SDimitry Andric "writeObject should not be used with pointers, to write " 1310b57cec5SDimitry Andric "the pointed-to value dereference the pointer before calling " 1320b57cec5SDimitry Andric "writeObject"); 1330b57cec5SDimitry Andric return writeBytes( 1340b57cec5SDimitry Andric ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&Obj), sizeof(T))); 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric /// Writes an array of objects of type T to the underlying stream, as if by 1380b57cec5SDimitry Andric /// using memcpy. It is up to the caller to ensure that type of \p Obj can 1390b57cec5SDimitry Andric /// be safely copied in this fashion, as no checks are made to ensure that 1400b57cec5SDimitry Andric /// this is safe. 1410b57cec5SDimitry Andric /// 1420b57cec5SDimitry Andric /// \returns a success error code if the data was successfully written, 1430b57cec5SDimitry Andric /// otherwise returns an appropriate error code. writeArray(ArrayRef<T> Array)1440b57cec5SDimitry Andric template <typename T> Error writeArray(ArrayRef<T> Array) { 1450b57cec5SDimitry Andric if (Array.empty()) 1460b57cec5SDimitry Andric return Error::success(); 1470b57cec5SDimitry Andric if (Array.size() > UINT32_MAX / sizeof(T)) 1480b57cec5SDimitry Andric return make_error<BinaryStreamError>( 1490b57cec5SDimitry Andric stream_error_code::invalid_array_size); 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric return writeBytes( 1520b57cec5SDimitry Andric ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Array.data()), 1530b57cec5SDimitry Andric Array.size() * sizeof(T))); 1540b57cec5SDimitry Andric } 1550b57cec5SDimitry Andric 1560b57cec5SDimitry Andric /// Writes all data from the array \p Array to the underlying stream. 1570b57cec5SDimitry Andric /// 1580b57cec5SDimitry Andric /// \returns a success error code if the data was successfully written, 1590b57cec5SDimitry Andric /// otherwise returns an appropriate error code. 1600b57cec5SDimitry Andric template <typename T, typename U> writeArray(VarStreamArray<T,U> Array)1610b57cec5SDimitry Andric Error writeArray(VarStreamArray<T, U> Array) { 1620b57cec5SDimitry Andric return writeStreamRef(Array.getUnderlyingStream()); 1630b57cec5SDimitry Andric } 1640b57cec5SDimitry Andric 1650b57cec5SDimitry Andric /// Writes all elements from the array \p Array to the underlying stream. 1660b57cec5SDimitry Andric /// 1670b57cec5SDimitry Andric /// \returns a success error code if the data was successfully written, 1680b57cec5SDimitry Andric /// otherwise returns an appropriate error code. writeArray(FixedStreamArray<T> Array)1690b57cec5SDimitry Andric template <typename T> Error writeArray(FixedStreamArray<T> Array) { 1700b57cec5SDimitry Andric return writeStreamRef(Array.getUnderlyingStream()); 1710b57cec5SDimitry Andric } 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric /// Splits the Writer into two Writers at a given offset. 174349cc55cSDimitry Andric std::pair<BinaryStreamWriter, BinaryStreamWriter> split(uint64_t Off) const; 1750b57cec5SDimitry Andric setOffset(uint64_t Off)176349cc55cSDimitry Andric void setOffset(uint64_t Off) { Offset = Off; } getOffset()177349cc55cSDimitry Andric uint64_t getOffset() const { return Offset; } getLength()178349cc55cSDimitry Andric uint64_t getLength() const { return Stream.getLength(); } bytesRemaining()179349cc55cSDimitry Andric uint64_t bytesRemaining() const { return getLength() - getOffset(); } 1800b57cec5SDimitry Andric Error padToAlignment(uint32_t Align); 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric protected: 1830b57cec5SDimitry Andric WritableBinaryStreamRef Stream; 184349cc55cSDimitry Andric uint64_t Offset = 0; 1850b57cec5SDimitry Andric }; 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric } // end namespace llvm 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric #endif // LLVM_SUPPORT_BINARYSTREAMWRITER_H 190