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/BinaryStreamError.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
BinaryStreamWriter(WritableBinaryStreamRef Ref)18 BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStreamRef Ref)
19 : Stream(Ref) {}
20
BinaryStreamWriter(WritableBinaryStream & Stream)21 BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStream &Stream)
22 : Stream(Stream) {}
23
BinaryStreamWriter(MutableArrayRef<uint8_t> Data,llvm::support::endianness Endian)24 BinaryStreamWriter::BinaryStreamWriter(MutableArrayRef<uint8_t> Data,
25 llvm::support::endianness Endian)
26 : Stream(Data, Endian) {}
27
writeBytes(ArrayRef<uint8_t> Buffer)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
writeULEB128(uint64_t Value)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
writeSLEB128(int64_t Value)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
writeCString(StringRef Str)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
writeFixedString(StringRef Str)56 Error BinaryStreamWriter::writeFixedString(StringRef Str) {
57
58 return writeBytes(arrayRefFromStringRef(Str));
59 }
60
writeStreamRef(BinaryStreamRef Ref)61 Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref) {
62 return writeStreamRef(Ref, Ref.getLength());
63 }
64
writeStreamRef(BinaryStreamRef Ref,uint32_t Length)65 Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref, uint32_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>
split(uint32_t Off) const83 BinaryStreamWriter::split(uint32_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
padToAlignment(uint32_t Align)95 Error BinaryStreamWriter::padToAlignment(uint32_t Align) {
96 uint32_t NewOffset = alignTo(Offset, Align);
97 if (NewOffset > getLength())
98 return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
99 while (Offset < NewOffset)
100 if (auto EC = writeInteger('\0'))
101 return EC;
102 return Error::success();
103 }
104