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