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