xref: /freebsd/contrib/llvm-project/llvm/lib/Support/BinaryStreamWriter.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
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