10b57cec5SDimitry Andric //===- BinaryStreamWriter.cpp - Writes objects to a BinaryStream ----------===// 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 #include "llvm/Support/BinaryStreamWriter.h" 100b57cec5SDimitry Andric 1106c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h" 120b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamReader.h" 130b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamRef.h" 140b57cec5SDimitry Andric #include "llvm/Support/LEB128.h" 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric using namespace llvm; 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStreamRef Ref) 190b57cec5SDimitry Andric : Stream(Ref) {} 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStream &Stream) 220b57cec5SDimitry Andric : Stream(Stream) {} 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric BinaryStreamWriter::BinaryStreamWriter(MutableArrayRef<uint8_t> Data, 25*5f757f3fSDimitry Andric llvm::endianness Endian) 260b57cec5SDimitry Andric : Stream(Data, Endian) {} 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric Error BinaryStreamWriter::writeBytes(ArrayRef<uint8_t> Buffer) { 290b57cec5SDimitry Andric if (auto EC = Stream.writeBytes(Offset, Buffer)) 300b57cec5SDimitry Andric return EC; 310b57cec5SDimitry Andric Offset += Buffer.size(); 320b57cec5SDimitry Andric return Error::success(); 330b57cec5SDimitry Andric } 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric Error BinaryStreamWriter::writeULEB128(uint64_t Value) { 360b57cec5SDimitry Andric uint8_t EncodedBytes[10] = {0}; 370b57cec5SDimitry Andric unsigned Size = encodeULEB128(Value, &EncodedBytes[0]); 380b57cec5SDimitry Andric return writeBytes({EncodedBytes, Size}); 390b57cec5SDimitry Andric } 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric Error BinaryStreamWriter::writeSLEB128(int64_t Value) { 420b57cec5SDimitry Andric uint8_t EncodedBytes[10] = {0}; 430b57cec5SDimitry Andric unsigned Size = encodeSLEB128(Value, &EncodedBytes[0]); 440b57cec5SDimitry Andric return writeBytes({EncodedBytes, Size}); 450b57cec5SDimitry Andric } 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric Error BinaryStreamWriter::writeCString(StringRef Str) { 480b57cec5SDimitry Andric if (auto EC = writeFixedString(Str)) 490b57cec5SDimitry Andric return EC; 500b57cec5SDimitry Andric if (auto EC = writeObject('\0')) 510b57cec5SDimitry Andric return EC; 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric return Error::success(); 540b57cec5SDimitry Andric } 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric Error BinaryStreamWriter::writeFixedString(StringRef Str) { 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric return writeBytes(arrayRefFromStringRef(Str)); 590b57cec5SDimitry Andric } 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref) { 620b57cec5SDimitry Andric return writeStreamRef(Ref, Ref.getLength()); 630b57cec5SDimitry Andric } 640b57cec5SDimitry Andric 65349cc55cSDimitry Andric Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref, uint64_t Length) { 660b57cec5SDimitry Andric BinaryStreamReader SrcReader(Ref.slice(0, Length)); 670b57cec5SDimitry Andric // This is a bit tricky. If we just call readBytes, we are requiring that it 680b57cec5SDimitry Andric // return us the entire stream as a contiguous buffer. There is no guarantee 690b57cec5SDimitry Andric // this can be satisfied by returning a reference straight from the buffer, as 700b57cec5SDimitry Andric // an implementation may not store all data in a single contiguous buffer. So 710b57cec5SDimitry Andric // we iterate over each contiguous chunk, writing each one in succession. 720b57cec5SDimitry Andric while (SrcReader.bytesRemaining() > 0) { 730b57cec5SDimitry Andric ArrayRef<uint8_t> Chunk; 740b57cec5SDimitry Andric if (auto EC = SrcReader.readLongestContiguousChunk(Chunk)) 750b57cec5SDimitry Andric return EC; 760b57cec5SDimitry Andric if (auto EC = writeBytes(Chunk)) 770b57cec5SDimitry Andric return EC; 780b57cec5SDimitry Andric } 790b57cec5SDimitry Andric return Error::success(); 800b57cec5SDimitry Andric } 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric std::pair<BinaryStreamWriter, BinaryStreamWriter> 83349cc55cSDimitry Andric BinaryStreamWriter::split(uint64_t Off) const { 840b57cec5SDimitry Andric assert(getLength() >= Off); 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric WritableBinaryStreamRef First = Stream.drop_front(Offset); 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric WritableBinaryStreamRef Second = First.drop_front(Off); 890b57cec5SDimitry Andric First = First.keep_front(Off); 900b57cec5SDimitry Andric BinaryStreamWriter W1{First}; 910b57cec5SDimitry Andric BinaryStreamWriter W2{Second}; 920b57cec5SDimitry Andric return std::make_pair(W1, W2); 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric Error BinaryStreamWriter::padToAlignment(uint32_t Align) { 96349cc55cSDimitry Andric uint64_t NewOffset = alignTo(Offset, Align); 9781ad6265SDimitry Andric const uint64_t ZerosSize = 64; 9881ad6265SDimitry Andric static constexpr char Zeros[ZerosSize] = {}; 990b57cec5SDimitry Andric while (Offset < NewOffset) 10081ad6265SDimitry Andric if (auto E = writeArray( 10181ad6265SDimitry Andric ArrayRef<char>(Zeros, std::min(ZerosSize, NewOffset - Offset)))) 10281ad6265SDimitry Andric return E; 1030b57cec5SDimitry Andric return Error::success(); 1040b57cec5SDimitry Andric } 105