xref: /freebsd-src/contrib/llvm-project/llvm/lib/Support/BinaryStreamWriter.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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 
BinaryStreamWriter(WritableBinaryStreamRef Ref)180b57cec5SDimitry Andric BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStreamRef Ref)
190b57cec5SDimitry Andric     : Stream(Ref) {}
200b57cec5SDimitry Andric 
BinaryStreamWriter(WritableBinaryStream & Stream)210b57cec5SDimitry Andric BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStream &Stream)
220b57cec5SDimitry Andric     : Stream(Stream) {}
230b57cec5SDimitry Andric 
BinaryStreamWriter(MutableArrayRef<uint8_t> Data,llvm::endianness Endian)240b57cec5SDimitry Andric BinaryStreamWriter::BinaryStreamWriter(MutableArrayRef<uint8_t> Data,
25*5f757f3fSDimitry Andric                                        llvm::endianness Endian)
260b57cec5SDimitry Andric     : Stream(Data, Endian) {}
270b57cec5SDimitry Andric 
writeBytes(ArrayRef<uint8_t> Buffer)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 
writeULEB128(uint64_t Value)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 
writeSLEB128(int64_t Value)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 
writeCString(StringRef Str)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 
writeFixedString(StringRef Str)560b57cec5SDimitry Andric Error BinaryStreamWriter::writeFixedString(StringRef Str) {
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric   return writeBytes(arrayRefFromStringRef(Str));
590b57cec5SDimitry Andric }
600b57cec5SDimitry Andric 
writeStreamRef(BinaryStreamRef Ref)610b57cec5SDimitry Andric Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref) {
620b57cec5SDimitry Andric   return writeStreamRef(Ref, Ref.getLength());
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric 
writeStreamRef(BinaryStreamRef Ref,uint64_t Length)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>
split(uint64_t Off) const83349cc55cSDimitry 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 
padToAlignment(uint32_t Align)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