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