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
16using namespace llvm;
17
18BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStreamRef Ref)
19 : Stream(Ref) {}
20
21BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStream &Stream)
22 : Stream(Stream) {}
23
24BinaryStreamWriter::BinaryStreamWriter(MutableArrayRef<uint8_t> Data,
25 llvm::endianness Endian)
26 : Stream(Data, Endian) {}
27
28Error BinaryStreamWriter::writeBytes(ArrayRef<uint8_t> Buffer) {
29 if (auto EC = Stream.writeBytes(Offset, Data: Buffer))
30 return EC;
31 Offset += Buffer.size();
32 return Error::success();
33}
34
35Error BinaryStreamWriter::writeULEB128(uint64_t Value) {
36 uint8_t EncodedBytes[10] = {0};
37 unsigned Size = encodeULEB128(Value, p: &EncodedBytes[0]);
38 return writeBytes(Buffer: {EncodedBytes, Size});
39}
40
41Error BinaryStreamWriter::writeSLEB128(int64_t Value) {
42 uint8_t EncodedBytes[10] = {0};
43 unsigned Size = encodeSLEB128(Value, p: &EncodedBytes[0]);
44 return writeBytes(Buffer: {EncodedBytes, Size});
45}
46
47Error BinaryStreamWriter::writeCString(StringRef Str) {
48 if (auto EC = writeFixedString(Str))
49 return EC;
50 if (auto EC = writeObject(Obj: '\0'))
51 return EC;
52
53 return Error::success();
54}
55
56Error BinaryStreamWriter::writeFixedString(StringRef Str) {
57
58 return writeBytes(Buffer: arrayRefFromStringRef(Input: Str));
59}
60
61Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref) {
62 return writeStreamRef(Ref, Size: Ref.getLength());
63}
64
65Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref, uint64_t Length) {
66 BinaryStreamReader SrcReader(Ref.slice(Offset: 0, Len: 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(Buffer&: Chunk))
75 return EC;
76 if (auto EC = writeBytes(Buffer: Chunk))
77 return EC;
78 }
79 return Error::success();
80}
81
82std::pair<BinaryStreamWriter, BinaryStreamWriter>
83BinaryStreamWriter::split(uint64_t Off) const {
84 assert(getLength() >= Off);
85
86 WritableBinaryStreamRef First = Stream.drop_front(N: Offset);
87
88 WritableBinaryStreamRef Second = First.drop_front(N: Off);
89 First = First.keep_front(N: Off);
90 BinaryStreamWriter W1{First};
91 BinaryStreamWriter W2{Second};
92 return std::make_pair(x&: W1, y&: W2);
93}
94
95Error BinaryStreamWriter::padToAlignment(uint32_t Align) {
96 uint64_t NewOffset = alignTo(Value: Offset, Align);
97 const uint64_t ZerosSize = 64;
98 static constexpr char Zeros[ZerosSize] = {};
99 while (Offset < NewOffset)
100 if (auto E = writeArray(
101 Array: ArrayRef<char>(Zeros, std::min(a: ZerosSize, b: NewOffset - Offset))))
102 return E;
103 return Error::success();
104}
105