1317017Sdim//===- BinaryStreamWriter.cpp - Writes objects to a BinaryStream ----------===//
2317017Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6317017Sdim//
7317017Sdim//===----------------------------------------------------------------------===//
8317017Sdim
9317017Sdim#include "llvm/Support/BinaryStreamWriter.h"
10317017Sdim
11317017Sdim#include "llvm/Support/BinaryStreamError.h"
12317017Sdim#include "llvm/Support/BinaryStreamReader.h"
13317017Sdim#include "llvm/Support/BinaryStreamRef.h"
14353358Sdim#include "llvm/Support/LEB128.h"
15317017Sdim
16317017Sdimusing namespace llvm;
17317017Sdim
18318681SdimBinaryStreamWriter::BinaryStreamWriter(WritableBinaryStreamRef Ref)
19318681Sdim    : Stream(Ref) {}
20317017Sdim
21318681SdimBinaryStreamWriter::BinaryStreamWriter(WritableBinaryStream &Stream)
22318681Sdim    : Stream(Stream) {}
23318681Sdim
24318681SdimBinaryStreamWriter::BinaryStreamWriter(MutableArrayRef<uint8_t> Data,
25318681Sdim                                       llvm::support::endianness Endian)
26318681Sdim    : Stream(Data, Endian) {}
27318681Sdim
28317017SdimError BinaryStreamWriter::writeBytes(ArrayRef<uint8_t> Buffer) {
29317017Sdim  if (auto EC = Stream.writeBytes(Offset, Buffer))
30317017Sdim    return EC;
31317017Sdim  Offset += Buffer.size();
32317017Sdim  return Error::success();
33317017Sdim}
34317017Sdim
35353358SdimError BinaryStreamWriter::writeULEB128(uint64_t Value) {
36353358Sdim  uint8_t EncodedBytes[10] = {0};
37353358Sdim  unsigned Size = encodeULEB128(Value, &EncodedBytes[0]);
38353358Sdim  return writeBytes({EncodedBytes, Size});
39353358Sdim}
40353358Sdim
41353358SdimError BinaryStreamWriter::writeSLEB128(int64_t Value) {
42353358Sdim  uint8_t EncodedBytes[10] = {0};
43353358Sdim  unsigned Size = encodeSLEB128(Value, &EncodedBytes[0]);
44353358Sdim  return writeBytes({EncodedBytes, Size});
45353358Sdim}
46353358Sdim
47317017SdimError BinaryStreamWriter::writeCString(StringRef Str) {
48317017Sdim  if (auto EC = writeFixedString(Str))
49317017Sdim    return EC;
50317017Sdim  if (auto EC = writeObject('\0'))
51317017Sdim    return EC;
52317017Sdim
53317017Sdim  return Error::success();
54317017Sdim}
55317017Sdim
56317017SdimError BinaryStreamWriter::writeFixedString(StringRef Str) {
57327952Sdim
58327952Sdim  return writeBytes(arrayRefFromStringRef(Str));
59317017Sdim}
60317017Sdim
61317017SdimError BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref) {
62317017Sdim  return writeStreamRef(Ref, Ref.getLength());
63317017Sdim}
64317017Sdim
65317017SdimError BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref, uint32_t Length) {
66317017Sdim  BinaryStreamReader SrcReader(Ref.slice(0, Length));
67317017Sdim  // This is a bit tricky.  If we just call readBytes, we are requiring that it
68317017Sdim  // return us the entire stream as a contiguous buffer.  There is no guarantee
69317017Sdim  // this can be satisfied by returning a reference straight from the buffer, as
70317017Sdim  // an implementation may not store all data in a single contiguous buffer.  So
71317017Sdim  // we iterate over each contiguous chunk, writing each one in succession.
72317017Sdim  while (SrcReader.bytesRemaining() > 0) {
73317017Sdim    ArrayRef<uint8_t> Chunk;
74317017Sdim    if (auto EC = SrcReader.readLongestContiguousChunk(Chunk))
75317017Sdim      return EC;
76317017Sdim    if (auto EC = writeBytes(Chunk))
77317017Sdim      return EC;
78317017Sdim  }
79317017Sdim  return Error::success();
80317017Sdim}
81317017Sdim
82317778Sdimstd::pair<BinaryStreamWriter, BinaryStreamWriter>
83317778SdimBinaryStreamWriter::split(uint32_t Off) const {
84317778Sdim  assert(getLength() >= Off);
85317778Sdim
86317778Sdim  WritableBinaryStreamRef First = Stream.drop_front(Offset);
87317778Sdim
88317778Sdim  WritableBinaryStreamRef Second = First.drop_front(Off);
89317778Sdim  First = First.keep_front(Off);
90317778Sdim  BinaryStreamWriter W1{First};
91317778Sdim  BinaryStreamWriter W2{Second};
92317778Sdim  return std::make_pair(W1, W2);
93317778Sdim}
94317778Sdim
95317017SdimError BinaryStreamWriter::padToAlignment(uint32_t Align) {
96317017Sdim  uint32_t NewOffset = alignTo(Offset, Align);
97317017Sdim  if (NewOffset > getLength())
98317017Sdim    return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
99320041Sdim  while (Offset < NewOffset)
100320041Sdim    if (auto EC = writeInteger('\0'))
101320041Sdim      return EC;
102317017Sdim  return Error::success();
103317017Sdim}
104