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
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::support::endianness Endian)
26    : Stream(Data, Endian) {}
27
28Error 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
35Error 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
41Error 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
47Error 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
56Error BinaryStreamWriter::writeFixedString(StringRef Str) {
57
58  return writeBytes(arrayRefFromStringRef(Str));
59}
60
61Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref) {
62  return writeStreamRef(Ref, Ref.getLength());
63}
64
65Error 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
82std::pair<BinaryStreamWriter, BinaryStreamWriter>
83BinaryStreamWriter::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
95Error 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