xref: /freebsd/contrib/llvm-project/llvm/lib/Support/BinaryStreamWriter.cpp (revision a03411e84728e9b267056fd31c7d1d9d1dc1b01e)
1 //===- BinaryStreamWriter.cpp - Writes objects to a BinaryStream ----------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/Support/BinaryStreamWriter.h"
10 
11 #include "llvm/ADT/StringExtras.h"
12 #include "llvm/Support/BinaryStreamReader.h"
13 #include "llvm/Support/BinaryStreamRef.h"
14 #include "llvm/Support/LEB128.h"
15 
16 using namespace llvm;
17 
18 BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStreamRef Ref)
19     : Stream(Ref) {}
20 
21 BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStream &Stream)
22     : Stream(Stream) {}
23 
24 BinaryStreamWriter::BinaryStreamWriter(MutableArrayRef<uint8_t> Data,
25                                        llvm::support::endianness Endian)
26     : Stream(Data, Endian) {}
27 
28 Error BinaryStreamWriter::writeBytes(ArrayRef<uint8_t> Buffer) {
29   if (auto EC = Stream.writeBytes(Offset, Buffer))
30     return EC;
31   Offset += Buffer.size();
32   return Error::success();
33 }
34 
35 Error BinaryStreamWriter::writeULEB128(uint64_t Value) {
36   uint8_t EncodedBytes[10] = {0};
37   unsigned Size = encodeULEB128(Value, &EncodedBytes[0]);
38   return writeBytes({EncodedBytes, Size});
39 }
40 
41 Error BinaryStreamWriter::writeSLEB128(int64_t Value) {
42   uint8_t EncodedBytes[10] = {0};
43   unsigned Size = encodeSLEB128(Value, &EncodedBytes[0]);
44   return writeBytes({EncodedBytes, Size});
45 }
46 
47 Error BinaryStreamWriter::writeCString(StringRef Str) {
48   if (auto EC = writeFixedString(Str))
49     return EC;
50   if (auto EC = writeObject('\0'))
51     return EC;
52 
53   return Error::success();
54 }
55 
56 Error BinaryStreamWriter::writeFixedString(StringRef Str) {
57 
58   return writeBytes(arrayRefFromStringRef(Str));
59 }
60 
61 Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref) {
62   return writeStreamRef(Ref, Ref.getLength());
63 }
64 
65 Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref, uint64_t Length) {
66   BinaryStreamReader SrcReader(Ref.slice(0, Length));
67   // This is a bit tricky.  If we just call readBytes, we are requiring that it
68   // return us the entire stream as a contiguous buffer.  There is no guarantee
69   // this can be satisfied by returning a reference straight from the buffer, as
70   // an implementation may not store all data in a single contiguous buffer.  So
71   // we iterate over each contiguous chunk, writing each one in succession.
72   while (SrcReader.bytesRemaining() > 0) {
73     ArrayRef<uint8_t> Chunk;
74     if (auto EC = SrcReader.readLongestContiguousChunk(Chunk))
75       return EC;
76     if (auto EC = writeBytes(Chunk))
77       return EC;
78   }
79   return Error::success();
80 }
81 
82 std::pair<BinaryStreamWriter, BinaryStreamWriter>
83 BinaryStreamWriter::split(uint64_t Off) const {
84   assert(getLength() >= Off);
85 
86   WritableBinaryStreamRef First = Stream.drop_front(Offset);
87 
88   WritableBinaryStreamRef Second = First.drop_front(Off);
89   First = First.keep_front(Off);
90   BinaryStreamWriter W1{First};
91   BinaryStreamWriter W2{Second};
92   return std::make_pair(W1, W2);
93 }
94 
95 Error BinaryStreamWriter::padToAlignment(uint32_t Align) {
96   uint64_t NewOffset = alignTo(Offset, Align);
97   const uint64_t ZerosSize = 64;
98   static constexpr char Zeros[ZerosSize] = {};
99   while (Offset < NewOffset)
100     if (auto E = writeArray(
101             ArrayRef<char>(Zeros, std::min(ZerosSize, NewOffset - Offset))))
102       return E;
103   return Error::success();
104 }
105