171d5a254SDimitry Andric //===- BinaryStreamWriter.cpp - Writes objects to a BinaryStream ----------===//
271d5a254SDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
671d5a254SDimitry Andric //
771d5a254SDimitry Andric //===----------------------------------------------------------------------===//
871d5a254SDimitry Andric
971d5a254SDimitry Andric #include "llvm/Support/BinaryStreamWriter.h"
1071d5a254SDimitry Andric
117fa27ce4SDimitry Andric #include "llvm/ADT/StringExtras.h"
1271d5a254SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
1371d5a254SDimitry Andric #include "llvm/Support/BinaryStreamRef.h"
14e6d15924SDimitry Andric #include "llvm/Support/LEB128.h"
1571d5a254SDimitry Andric
1671d5a254SDimitry Andric using namespace llvm;
1771d5a254SDimitry Andric
BinaryStreamWriter(WritableBinaryStreamRef Ref)18b5630dbaSDimitry Andric BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStreamRef Ref)
19b5630dbaSDimitry Andric : Stream(Ref) {}
20b5630dbaSDimitry Andric
BinaryStreamWriter(WritableBinaryStream & Stream)21b5630dbaSDimitry Andric BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStream &Stream)
22b5630dbaSDimitry Andric : Stream(Stream) {}
23b5630dbaSDimitry Andric
BinaryStreamWriter(MutableArrayRef<uint8_t> Data,llvm::endianness Endian)24b5630dbaSDimitry Andric BinaryStreamWriter::BinaryStreamWriter(MutableArrayRef<uint8_t> Data,
25b1c73532SDimitry Andric llvm::endianness Endian)
26b5630dbaSDimitry Andric : Stream(Data, Endian) {}
2771d5a254SDimitry Andric
writeBytes(ArrayRef<uint8_t> Buffer)2871d5a254SDimitry Andric Error BinaryStreamWriter::writeBytes(ArrayRef<uint8_t> Buffer) {
2971d5a254SDimitry Andric if (auto EC = Stream.writeBytes(Offset, Buffer))
3071d5a254SDimitry Andric return EC;
3171d5a254SDimitry Andric Offset += Buffer.size();
3271d5a254SDimitry Andric return Error::success();
3371d5a254SDimitry Andric }
3471d5a254SDimitry Andric
writeULEB128(uint64_t Value)35e6d15924SDimitry Andric Error BinaryStreamWriter::writeULEB128(uint64_t Value) {
36e6d15924SDimitry Andric uint8_t EncodedBytes[10] = {0};
37e6d15924SDimitry Andric unsigned Size = encodeULEB128(Value, &EncodedBytes[0]);
38e6d15924SDimitry Andric return writeBytes({EncodedBytes, Size});
39e6d15924SDimitry Andric }
40e6d15924SDimitry Andric
writeSLEB128(int64_t Value)41e6d15924SDimitry Andric Error BinaryStreamWriter::writeSLEB128(int64_t Value) {
42e6d15924SDimitry Andric uint8_t EncodedBytes[10] = {0};
43e6d15924SDimitry Andric unsigned Size = encodeSLEB128(Value, &EncodedBytes[0]);
44e6d15924SDimitry Andric return writeBytes({EncodedBytes, Size});
45e6d15924SDimitry Andric }
46e6d15924SDimitry Andric
writeCString(StringRef Str)4771d5a254SDimitry Andric Error BinaryStreamWriter::writeCString(StringRef Str) {
4871d5a254SDimitry Andric if (auto EC = writeFixedString(Str))
4971d5a254SDimitry Andric return EC;
5071d5a254SDimitry Andric if (auto EC = writeObject('\0'))
5171d5a254SDimitry Andric return EC;
5271d5a254SDimitry Andric
5371d5a254SDimitry Andric return Error::success();
5471d5a254SDimitry Andric }
5571d5a254SDimitry Andric
writeFixedString(StringRef Str)5671d5a254SDimitry Andric Error BinaryStreamWriter::writeFixedString(StringRef Str) {
57044eb2f6SDimitry Andric
58044eb2f6SDimitry Andric return writeBytes(arrayRefFromStringRef(Str));
5971d5a254SDimitry Andric }
6071d5a254SDimitry Andric
writeStreamRef(BinaryStreamRef Ref)6171d5a254SDimitry Andric Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref) {
6271d5a254SDimitry Andric return writeStreamRef(Ref, Ref.getLength());
6371d5a254SDimitry Andric }
6471d5a254SDimitry Andric
writeStreamRef(BinaryStreamRef Ref,uint64_t Length)65c0981da4SDimitry Andric Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref, uint64_t Length) {
6671d5a254SDimitry Andric BinaryStreamReader SrcReader(Ref.slice(0, Length));
6771d5a254SDimitry Andric // This is a bit tricky. If we just call readBytes, we are requiring that it
6871d5a254SDimitry Andric // return us the entire stream as a contiguous buffer. There is no guarantee
6971d5a254SDimitry Andric // this can be satisfied by returning a reference straight from the buffer, as
7071d5a254SDimitry Andric // an implementation may not store all data in a single contiguous buffer. So
7171d5a254SDimitry Andric // we iterate over each contiguous chunk, writing each one in succession.
7271d5a254SDimitry Andric while (SrcReader.bytesRemaining() > 0) {
7371d5a254SDimitry Andric ArrayRef<uint8_t> Chunk;
7471d5a254SDimitry Andric if (auto EC = SrcReader.readLongestContiguousChunk(Chunk))
7571d5a254SDimitry Andric return EC;
7671d5a254SDimitry Andric if (auto EC = writeBytes(Chunk))
7771d5a254SDimitry Andric return EC;
7871d5a254SDimitry Andric }
7971d5a254SDimitry Andric return Error::success();
8071d5a254SDimitry Andric }
8171d5a254SDimitry Andric
82148779dfSDimitry Andric std::pair<BinaryStreamWriter, BinaryStreamWriter>
split(uint64_t Off) const83c0981da4SDimitry Andric BinaryStreamWriter::split(uint64_t Off) const {
84148779dfSDimitry Andric assert(getLength() >= Off);
85148779dfSDimitry Andric
86148779dfSDimitry Andric WritableBinaryStreamRef First = Stream.drop_front(Offset);
87148779dfSDimitry Andric
88148779dfSDimitry Andric WritableBinaryStreamRef Second = First.drop_front(Off);
89148779dfSDimitry Andric First = First.keep_front(Off);
90148779dfSDimitry Andric BinaryStreamWriter W1{First};
91148779dfSDimitry Andric BinaryStreamWriter W2{Second};
92148779dfSDimitry Andric return std::make_pair(W1, W2);
93148779dfSDimitry Andric }
94148779dfSDimitry Andric
padToAlignment(uint32_t Align)9571d5a254SDimitry Andric Error BinaryStreamWriter::padToAlignment(uint32_t Align) {
96c0981da4SDimitry Andric uint64_t NewOffset = alignTo(Offset, Align);
97145449b1SDimitry Andric const uint64_t ZerosSize = 64;
98145449b1SDimitry Andric static constexpr char Zeros[ZerosSize] = {};
997c7aba6eSDimitry Andric while (Offset < NewOffset)
100145449b1SDimitry Andric if (auto E = writeArray(
101145449b1SDimitry Andric ArrayRef<char>(Zeros, std::min(ZerosSize, NewOffset - Offset))))
102145449b1SDimitry Andric return E;
10371d5a254SDimitry Andric return Error::success();
10471d5a254SDimitry Andric }
105