2017-02-27 23:11:43 +01:00
|
|
|
//===- BinaryStreamWriter.cpp - Writes objects to a BinaryStream ----------===//
|
2016-06-10 07:09:12 +02:00
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2016-06-10 07:09:12 +02:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-03-02 21:52:51 +01:00
|
|
|
#include "llvm/Support/BinaryStreamWriter.h"
|
2016-06-10 07:09:12 +02:00
|
|
|
|
2017-03-15 23:18:53 +01:00
|
|
|
#include "llvm/Support/BinaryStreamError.h"
|
2017-03-02 21:52:51 +01:00
|
|
|
#include "llvm/Support/BinaryStreamReader.h"
|
|
|
|
#include "llvm/Support/BinaryStreamRef.h"
|
2019-04-17 17:38:27 +02:00
|
|
|
#include "llvm/Support/LEB128.h"
|
2016-06-10 07:09:12 +02:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
[BinaryStream] Reduce the amount of boiler plate needed to use.
Often you have an array and you just want to use it. With the current
design, you have to first construct a `BinaryByteStream`, and then create
a `BinaryStreamRef` from it. Worse, the `BinaryStreamRef` holds a pointer
to the `BinaryByteStream`, so you can't just create a temporary one to
appease the compiler, you have to actually hold onto both the `ArrayRef`
as well as the `BinaryByteStream` *AND* the `BinaryStreamReader` on top of
that. This makes for very cumbersome code, often requiring one to store a
`BinaryByteStream` in a class just to circumvent this.
At the cost of some added complexity (not exposed to users, but internal
to the library), we can do better than this. This patch allows us to
construct `BinaryStreamReaders` and `BinaryStreamWriters` directly from
source data (e.g. `StringRef`, `MutableArrayRef<uint8_t>`, etc). Not only
does this reduce the amount of code you have to type and make it more
obvious how to use it, but it solves real lifetime issues when it's
inconvenient to hold onto a `BinaryByteStream` for a long time.
The additional complexity is in the form of an added layer of indirection.
Whereas before we simply stored a `BinaryStream*` in the ref, we now store
both a `BinaryStream*` **and** a `std::shared_ptr<BinaryStream>`. When
the user wants to construct a `BinaryStreamRef` directly from an
`ArrayRef` etc, we allocate an internal object that holds ownership over a
`BinaryByteStream` and forwards all calls, and store this in the
`shared_ptr<>`. This also maintains the ref semantics, as you can copy it
by value and references refer to the same underlying stream -- the one
being held in the object stored in the `shared_ptr`.
Differential Revision: https://reviews.llvm.org/D33293
llvm-svn: 303294
2017-05-17 22:23:31 +02:00
|
|
|
BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStreamRef Ref)
|
|
|
|
: Stream(Ref) {}
|
|
|
|
|
|
|
|
BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStream &Stream)
|
|
|
|
: Stream(Stream) {}
|
|
|
|
|
|
|
|
BinaryStreamWriter::BinaryStreamWriter(MutableArrayRef<uint8_t> Data,
|
|
|
|
llvm::support::endianness Endian)
|
|
|
|
: Stream(Data, Endian) {}
|
2016-06-10 07:09:12 +02:00
|
|
|
|
2017-02-27 23:11:43 +01:00
|
|
|
Error BinaryStreamWriter::writeBytes(ArrayRef<uint8_t> Buffer) {
|
2016-06-10 07:09:12 +02:00
|
|
|
if (auto EC = Stream.writeBytes(Offset, Buffer))
|
|
|
|
return EC;
|
|
|
|
Offset += Buffer.size();
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2019-04-17 17:38:27 +02:00
|
|
|
Error BinaryStreamWriter::writeULEB128(uint64_t Value) {
|
|
|
|
uint8_t EncodedBytes[10] = {0};
|
|
|
|
unsigned Size = encodeULEB128(Value, &EncodedBytes[0]);
|
|
|
|
return writeBytes({EncodedBytes, Size});
|
|
|
|
}
|
|
|
|
|
|
|
|
Error BinaryStreamWriter::writeSLEB128(int64_t Value) {
|
|
|
|
uint8_t EncodedBytes[10] = {0};
|
|
|
|
unsigned Size = encodeSLEB128(Value, &EncodedBytes[0]);
|
|
|
|
return writeBytes({EncodedBytes, Size});
|
|
|
|
}
|
|
|
|
|
2017-02-27 23:11:43 +01:00
|
|
|
Error BinaryStreamWriter::writeCString(StringRef Str) {
|
2016-06-10 07:09:12 +02:00
|
|
|
if (auto EC = writeFixedString(Str))
|
|
|
|
return EC;
|
|
|
|
if (auto EC = writeObject('\0'))
|
|
|
|
return EC;
|
|
|
|
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2017-02-27 23:11:43 +01:00
|
|
|
Error BinaryStreamWriter::writeFixedString(StringRef Str) {
|
2017-11-27 19:48:37 +01:00
|
|
|
|
|
|
|
return writeBytes(arrayRefFromStringRef(Str));
|
2016-06-10 07:09:12 +02:00
|
|
|
}
|
|
|
|
|
2017-02-27 23:11:43 +01:00
|
|
|
Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref) {
|
|
|
|
return writeStreamRef(Ref, Ref.getLength());
|
2016-06-10 07:09:12 +02:00
|
|
|
}
|
|
|
|
|
2017-02-27 23:11:43 +01:00
|
|
|
Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref, uint32_t Length) {
|
|
|
|
BinaryStreamReader SrcReader(Ref.slice(0, Length));
|
2016-06-10 07:09:12 +02:00
|
|
|
// This is a bit tricky. If we just call readBytes, we are requiring that it
|
2017-02-27 23:11:43 +01:00
|
|
|
// return us the entire stream as a contiguous buffer. There is no guarantee
|
|
|
|
// this can be satisfied by returning a reference straight from the buffer, as
|
|
|
|
// an implementation may not store all data in a single contiguous buffer. So
|
|
|
|
// we iterate over each contiguous chunk, writing each one in succession.
|
2016-06-10 07:09:12 +02:00
|
|
|
while (SrcReader.bytesRemaining() > 0) {
|
|
|
|
ArrayRef<uint8_t> Chunk;
|
|
|
|
if (auto EC = SrcReader.readLongestContiguousChunk(Chunk))
|
|
|
|
return EC;
|
|
|
|
if (auto EC = writeBytes(Chunk))
|
|
|
|
return EC;
|
|
|
|
}
|
|
|
|
return Error::success();
|
|
|
|
}
|
2017-03-15 23:18:53 +01:00
|
|
|
|
2017-05-03 17:58:37 +02:00
|
|
|
std::pair<BinaryStreamWriter, BinaryStreamWriter>
|
|
|
|
BinaryStreamWriter::split(uint32_t Off) const {
|
|
|
|
assert(getLength() >= Off);
|
|
|
|
|
|
|
|
WritableBinaryStreamRef First = Stream.drop_front(Offset);
|
|
|
|
|
|
|
|
WritableBinaryStreamRef Second = First.drop_front(Off);
|
|
|
|
First = First.keep_front(Off);
|
|
|
|
BinaryStreamWriter W1{First};
|
|
|
|
BinaryStreamWriter W2{Second};
|
|
|
|
return std::make_pair(W1, W2);
|
|
|
|
}
|
|
|
|
|
2017-03-15 23:18:53 +01:00
|
|
|
Error BinaryStreamWriter::padToAlignment(uint32_t Align) {
|
|
|
|
uint32_t NewOffset = alignTo(Offset, Align);
|
|
|
|
if (NewOffset > getLength())
|
|
|
|
return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
|
2017-06-16 04:17:35 +02:00
|
|
|
while (Offset < NewOffset)
|
2017-06-16 04:42:33 +02:00
|
|
|
if (auto EC = writeInteger('\0'))
|
|
|
|
return EC;
|
2017-03-15 23:18:53 +01:00
|
|
|
return Error::success();
|
|
|
|
}
|