xref: /src/contrib/llvm-project/llvm/lib/Support/BinaryStreamWriter.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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