#ifndef LLVM_SUPPORT_BINARYBYTESTREAM_H
#define LLVM_SUPPORT_BINARYBYTESTREAM_H
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/BinaryStream.h"
#include "llvm/Support/BinaryStreamError.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/MemoryBuffer.h"
#include <cstdint>
#include <cstring>
#include <memory>
namespace llvm {
class BinaryByteStream : public BinaryStream {
public:
BinaryByteStream() = default;
BinaryByteStream(ArrayRef<uint8_t> Data, llvm::support::endianness Endian)
: Endian(Endian), Data(Data) {}
BinaryByteStream(StringRef Data, llvm::support::endianness Endian)
: Endian(Endian), Data(Data.bytes_begin(), Data.bytes_end()) {}
llvm::support::endianness getEndian() const override { return Endian; }
Error readBytes(uint64_t Offset, uint64_t Size,
ArrayRef<uint8_t> &Buffer) override {
if (auto EC = checkOffsetForRead(Offset, Size))
return EC;
Buffer = Data.slice(Offset, Size);
return Error::success();
}
Error readLongestContiguousChunk(uint64_t Offset,
ArrayRef<uint8_t> &Buffer) override {
if (auto EC = checkOffsetForRead(Offset, 1))
return EC;
Buffer = Data.slice(Offset);
return Error::success();
}
uint64_t getLength() override { return Data.size(); }
ArrayRef<uint8_t> data() const { return Data; }
StringRef str() const {
const char *CharData = reinterpret_cast<const char *>(Data.data());
return StringRef(CharData, Data.size());
}
protected:
llvm::support::endianness Endian;
ArrayRef<uint8_t> Data;
};
class MemoryBufferByteStream : public BinaryByteStream {
public:
MemoryBufferByteStream(std::unique_ptr<MemoryBuffer> Buffer,
llvm::support::endianness Endian)
: BinaryByteStream(Buffer->getBuffer(), Endian),
MemBuffer(std::move(Buffer)) {}
std::unique_ptr<MemoryBuffer> MemBuffer;
};
class MutableBinaryByteStream : public WritableBinaryStream {
public:
MutableBinaryByteStream() = default;
MutableBinaryByteStream(MutableArrayRef<uint8_t> Data,
llvm::support::endianness Endian)
: Data(Data), ImmutableStream(Data, Endian) {}
llvm::support::endianness getEndian() const override {
return ImmutableStream.getEndian();
}
Error readBytes(uint64_t Offset, uint64_t Size,
ArrayRef<uint8_t> &Buffer) override {
return ImmutableStream.readBytes(Offset, Size, Buffer);
}
Error readLongestContiguousChunk(uint64_t Offset,
ArrayRef<uint8_t> &Buffer) override {
return ImmutableStream.readLongestContiguousChunk(Offset, Buffer);
}
uint64_t getLength() override { return ImmutableStream.getLength(); }
Error writeBytes(uint64_t Offset, ArrayRef<uint8_t> Buffer) override {
if (Buffer.empty())
return Error::success();
if (auto EC = checkOffsetForWrite(Offset, Buffer.size()))
return EC;
uint8_t *DataPtr = const_cast<uint8_t *>(Data.data());
::memcpy(DataPtr + Offset, Buffer.data(), Buffer.size());
return Error::success();
}
Error commit() override { return Error::success(); }
MutableArrayRef<uint8_t> data() const { return Data; }
private:
MutableArrayRef<uint8_t> Data;
BinaryByteStream ImmutableStream;
};
class AppendingBinaryByteStream : public WritableBinaryStream {
std::vector<uint8_t> Data;
llvm::support::endianness Endian = llvm::support::little;
public:
AppendingBinaryByteStream() = default;
AppendingBinaryByteStream(llvm::support::endianness Endian)
: Endian(Endian) {}
void clear() { Data.clear(); }
llvm::support::endianness getEndian() const override { return Endian; }
Error readBytes(uint64_t Offset, uint64_t Size,
ArrayRef<uint8_t> &Buffer) override {
if (auto EC = checkOffsetForWrite(Offset, Buffer.size()))
return EC;
Buffer = makeArrayRef(Data).slice(Offset, Size);
return Error::success();
}
void insert(uint64_t Offset, ArrayRef<uint8_t> Bytes) {
Data.insert(Data.begin() + Offset, Bytes.begin(), Bytes.end());
}
Error readLongestContiguousChunk(uint64_t Offset,
ArrayRef<uint8_t> &Buffer) override {
if (auto EC = checkOffsetForWrite(Offset, 1))
return EC;
Buffer = makeArrayRef(Data).slice(Offset);
return Error::success();
}
uint64_t getLength() override { return Data.size(); }
Error writeBytes(uint64_t Offset, ArrayRef<uint8_t> Buffer) override {
if (Buffer.empty())
return Error::success();
if (Offset > getLength())
return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
uint64_t RequiredSize = Offset + Buffer.size();
if (RequiredSize > Data.size())
Data.resize(RequiredSize);
::memcpy(Data.data() + Offset, Buffer.data(), Buffer.size());
return Error::success();
}
Error commit() override { return Error::success(); }
BinaryStreamFlags getFlags() const override { return BSF_Write | BSF_Append; }
MutableArrayRef<uint8_t> data() { return Data; }
};
class FileBufferByteStream : public WritableBinaryStream {
private:
class StreamImpl : public MutableBinaryByteStream {
public:
StreamImpl(std::unique_ptr<FileOutputBuffer> Buffer,
llvm::support::endianness Endian)
: MutableBinaryByteStream(
MutableArrayRef<uint8_t>(Buffer->getBufferStart(),
Buffer->getBufferEnd()),
Endian),
FileBuffer(std::move(Buffer)) {}
Error commit() override {
if (FileBuffer->commit())
return make_error<BinaryStreamError>(
stream_error_code::filesystem_error);
return Error::success();
}
uint8_t *getBufferStart() const { return FileBuffer->getBufferStart(); }
uint8_t *getBufferEnd() const { return FileBuffer->getBufferEnd(); }
private:
std::unique_ptr<FileOutputBuffer> FileBuffer;
};
public:
FileBufferByteStream(std::unique_ptr<FileOutputBuffer> Buffer,
llvm::support::endianness Endian)
: Impl(std::move(Buffer), Endian) {}
llvm::support::endianness getEndian() const override {
return Impl.getEndian();
}
Error readBytes(uint64_t Offset, uint64_t Size,
ArrayRef<uint8_t> &Buffer) override {
return Impl.readBytes(Offset, Size, Buffer);
}
Error readLongestContiguousChunk(uint64_t Offset,
ArrayRef<uint8_t> &Buffer) override {
return Impl.readLongestContiguousChunk(Offset, Buffer);
}
uint64_t getLength() override { return Impl.getLength(); }
Error writeBytes(uint64_t Offset, ArrayRef<uint8_t> Data) override {
return Impl.writeBytes(Offset, Data);
}
Error commit() override { return Impl.commit(); }
uint8_t *getBufferStart() const { return Impl.getBufferStart(); }
uint8_t *getBufferEnd() const { return Impl.getBufferEnd(); }
private:
StreamImpl Impl;
};
}
#endif