xref: /freebsd/contrib/llvm-project/llvm/lib/Support/BinaryStreamWriter.cpp (revision a2fda816eb054d5873be223ef2461741dfcc253c)
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::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