1d9dc2829SZachary Turner //===- BinaryStreamWriter.cpp - Writes objects to a BinaryStream ----------===//
2d9dc2829SZachary Turner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d9dc2829SZachary Turner //
7d9dc2829SZachary Turner //===----------------------------------------------------------------------===//
8d9dc2829SZachary Turner 
9d9dc2829SZachary Turner #include "llvm/Support/BinaryStreamWriter.h"
10d9dc2829SZachary Turner 
11d9dc2829SZachary Turner #include "llvm/Support/BinaryStreamReader.h"
12d9dc2829SZachary Turner #include "llvm/Support/BinaryStreamRef.h"
13c1106c9bSLang Hames #include "llvm/Support/LEB128.h"
14d9dc2829SZachary Turner 
15d9dc2829SZachary Turner using namespace llvm;
16d9dc2829SZachary Turner 
BinaryStreamWriter(WritableBinaryStreamRef Ref)17d9a62633SZachary Turner BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStreamRef Ref)
18d9a62633SZachary Turner     : Stream(Ref) {}
19d9a62633SZachary Turner 
BinaryStreamWriter(WritableBinaryStream & Stream)20d9a62633SZachary Turner BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStream &Stream)
21d9a62633SZachary Turner     : Stream(Stream) {}
22d9a62633SZachary Turner 
BinaryStreamWriter(MutableArrayRef<uint8_t> Data,llvm::support::endianness Endian)23d9a62633SZachary Turner BinaryStreamWriter::BinaryStreamWriter(MutableArrayRef<uint8_t> Data,
24d9a62633SZachary Turner                                        llvm::support::endianness Endian)
25d9a62633SZachary Turner     : Stream(Data, Endian) {}
26d9dc2829SZachary Turner 
writeBytes(ArrayRef<uint8_t> Buffer)27d9dc2829SZachary Turner Error BinaryStreamWriter::writeBytes(ArrayRef<uint8_t> Buffer) {
28d9dc2829SZachary Turner   if (auto EC = Stream.writeBytes(Offset, Buffer))
29d9dc2829SZachary Turner     return EC;
30d9dc2829SZachary Turner   Offset += Buffer.size();
31d9dc2829SZachary Turner   return Error::success();
32d9dc2829SZachary Turner }
33d9dc2829SZachary Turner 
writeULEB128(uint64_t Value)34c1106c9bSLang Hames Error BinaryStreamWriter::writeULEB128(uint64_t Value) {
35c1106c9bSLang Hames   uint8_t EncodedBytes[10] = {0};
36c1106c9bSLang Hames   unsigned Size = encodeULEB128(Value, &EncodedBytes[0]);
37c1106c9bSLang Hames   return writeBytes({EncodedBytes, Size});
38c1106c9bSLang Hames }
39c1106c9bSLang Hames 
writeSLEB128(int64_t Value)40c1106c9bSLang Hames Error BinaryStreamWriter::writeSLEB128(int64_t Value) {
41c1106c9bSLang Hames   uint8_t EncodedBytes[10] = {0};
42c1106c9bSLang Hames   unsigned Size = encodeSLEB128(Value, &EncodedBytes[0]);
43c1106c9bSLang Hames   return writeBytes({EncodedBytes, Size});
44c1106c9bSLang Hames }
45c1106c9bSLang Hames 
writeCString(StringRef Str)46d9dc2829SZachary Turner Error BinaryStreamWriter::writeCString(StringRef Str) {
47d9dc2829SZachary Turner   if (auto EC = writeFixedString(Str))
48d9dc2829SZachary Turner     return EC;
49d9dc2829SZachary Turner   if (auto EC = writeObject('\0'))
50d9dc2829SZachary Turner     return EC;
51d9dc2829SZachary Turner 
52d9dc2829SZachary Turner   return Error::success();
53d9dc2829SZachary Turner }
54d9dc2829SZachary Turner 
writeFixedString(StringRef Str)55d9dc2829SZachary Turner Error BinaryStreamWriter::writeFixedString(StringRef Str) {
5696c6985bSZachary Turner 
5796c6985bSZachary Turner   return writeBytes(arrayRefFromStringRef(Str));
58d9dc2829SZachary Turner }
59d9dc2829SZachary Turner 
writeStreamRef(BinaryStreamRef Ref)60d9dc2829SZachary Turner Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref) {
61d9dc2829SZachary Turner   return writeStreamRef(Ref, Ref.getLength());
62d9dc2829SZachary Turner }
63d9dc2829SZachary Turner 
writeStreamRef(BinaryStreamRef Ref,uint64_t Length)64646299d1SNico Weber Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref, uint64_t Length) {
65d9dc2829SZachary Turner   BinaryStreamReader SrcReader(Ref.slice(0, Length));
66d9dc2829SZachary Turner   // This is a bit tricky.  If we just call readBytes, we are requiring that it
67d9dc2829SZachary Turner   // return us the entire stream as a contiguous buffer.  There is no guarantee
68d9dc2829SZachary Turner   // this can be satisfied by returning a reference straight from the buffer, as
69d9dc2829SZachary Turner   // an implementation may not store all data in a single contiguous buffer.  So
70d9dc2829SZachary Turner   // we iterate over each contiguous chunk, writing each one in succession.
71d9dc2829SZachary Turner   while (SrcReader.bytesRemaining() > 0) {
72d9dc2829SZachary Turner     ArrayRef<uint8_t> Chunk;
73d9dc2829SZachary Turner     if (auto EC = SrcReader.readLongestContiguousChunk(Chunk))
74d9dc2829SZachary Turner       return EC;
75d9dc2829SZachary Turner     if (auto EC = writeBytes(Chunk))
76d9dc2829SZachary Turner       return EC;
77d9dc2829SZachary Turner   }
78d9dc2829SZachary Turner   return Error::success();
79d9dc2829SZachary Turner }
80ea4e6075SZachary Turner 
81c504ae3cSZachary Turner std::pair<BinaryStreamWriter, BinaryStreamWriter>
split(uint64_t Off) const82646299d1SNico Weber BinaryStreamWriter::split(uint64_t Off) const {
83c504ae3cSZachary Turner   assert(getLength() >= Off);
84c504ae3cSZachary Turner 
85c504ae3cSZachary Turner   WritableBinaryStreamRef First = Stream.drop_front(Offset);
86c504ae3cSZachary Turner 
87c504ae3cSZachary Turner   WritableBinaryStreamRef Second = First.drop_front(Off);
88c504ae3cSZachary Turner   First = First.keep_front(Off);
89c504ae3cSZachary Turner   BinaryStreamWriter W1{First};
90c504ae3cSZachary Turner   BinaryStreamWriter W2{Second};
91c504ae3cSZachary Turner   return std::make_pair(W1, W2);
92c504ae3cSZachary Turner }
93c504ae3cSZachary Turner 
padToAlignment(uint32_t Align)94ea4e6075SZachary Turner Error BinaryStreamWriter::padToAlignment(uint32_t Align) {
95646299d1SNico Weber   uint64_t NewOffset = alignTo(Offset, Align);
96*6dedbcd5SStella Laurenzo   const uint64_t ZerosSize = 64;
97*6dedbcd5SStella Laurenzo   static constexpr char Zeros[ZerosSize] = {};
98881819ebSRui Ueyama   while (Offset < NewOffset)
99*6dedbcd5SStella Laurenzo     if (auto E = writeArray(
100*6dedbcd5SStella Laurenzo             ArrayRef<char>(Zeros, std::min(ZerosSize, NewOffset - Offset))))
101*6dedbcd5SStella Laurenzo       return E;
102ea4e6075SZachary Turner   return Error::success();
103ea4e6075SZachary Turner }
104