17a7e6055SDimitry Andric //===- BinaryStreamWriter.cpp - Writes objects to a BinaryStream ----------===//
27a7e6055SDimitry Andric //
37a7e6055SDimitry Andric // The LLVM Compiler Infrastructure
47a7e6055SDimitry Andric //
57a7e6055SDimitry Andric // This file is distributed under the University of Illinois Open Source
67a7e6055SDimitry Andric // License. See LICENSE.TXT for details.
77a7e6055SDimitry Andric //
87a7e6055SDimitry Andric //===----------------------------------------------------------------------===//
97a7e6055SDimitry Andric
107a7e6055SDimitry Andric #include "llvm/Support/BinaryStreamWriter.h"
117a7e6055SDimitry Andric
127a7e6055SDimitry Andric #include "llvm/Support/BinaryStreamError.h"
137a7e6055SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
147a7e6055SDimitry Andric #include "llvm/Support/BinaryStreamRef.h"
157a7e6055SDimitry Andric
167a7e6055SDimitry Andric using namespace llvm;
177a7e6055SDimitry Andric
BinaryStreamWriter(WritableBinaryStreamRef Ref)18d8866befSDimitry Andric BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStreamRef Ref)
19d8866befSDimitry Andric : Stream(Ref) {}
20d8866befSDimitry Andric
BinaryStreamWriter(WritableBinaryStream & Stream)21d8866befSDimitry Andric BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStream &Stream)
22d8866befSDimitry Andric : Stream(Stream) {}
23d8866befSDimitry Andric
BinaryStreamWriter(MutableArrayRef<uint8_t> Data,llvm::support::endianness Endian)24d8866befSDimitry Andric BinaryStreamWriter::BinaryStreamWriter(MutableArrayRef<uint8_t> Data,
25d8866befSDimitry Andric llvm::support::endianness Endian)
26d8866befSDimitry Andric : Stream(Data, Endian) {}
277a7e6055SDimitry Andric
writeBytes(ArrayRef<uint8_t> Buffer)287a7e6055SDimitry Andric Error BinaryStreamWriter::writeBytes(ArrayRef<uint8_t> Buffer) {
297a7e6055SDimitry Andric if (auto EC = Stream.writeBytes(Offset, Buffer))
307a7e6055SDimitry Andric return EC;
317a7e6055SDimitry Andric Offset += Buffer.size();
327a7e6055SDimitry Andric return Error::success();
337a7e6055SDimitry Andric }
347a7e6055SDimitry Andric
writeCString(StringRef Str)357a7e6055SDimitry Andric Error BinaryStreamWriter::writeCString(StringRef Str) {
367a7e6055SDimitry Andric if (auto EC = writeFixedString(Str))
377a7e6055SDimitry Andric return EC;
387a7e6055SDimitry Andric if (auto EC = writeObject('\0'))
397a7e6055SDimitry Andric return EC;
407a7e6055SDimitry Andric
417a7e6055SDimitry Andric return Error::success();
427a7e6055SDimitry Andric }
437a7e6055SDimitry Andric
writeFixedString(StringRef Str)447a7e6055SDimitry Andric Error BinaryStreamWriter::writeFixedString(StringRef Str) {
45*2cab237bSDimitry Andric
46*2cab237bSDimitry Andric return writeBytes(arrayRefFromStringRef(Str));
477a7e6055SDimitry Andric }
487a7e6055SDimitry Andric
writeStreamRef(BinaryStreamRef Ref)497a7e6055SDimitry Andric Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref) {
507a7e6055SDimitry Andric return writeStreamRef(Ref, Ref.getLength());
517a7e6055SDimitry Andric }
527a7e6055SDimitry Andric
writeStreamRef(BinaryStreamRef Ref,uint32_t Length)537a7e6055SDimitry Andric Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref, uint32_t Length) {
547a7e6055SDimitry Andric BinaryStreamReader SrcReader(Ref.slice(0, Length));
557a7e6055SDimitry Andric // This is a bit tricky. If we just call readBytes, we are requiring that it
567a7e6055SDimitry Andric // return us the entire stream as a contiguous buffer. There is no guarantee
577a7e6055SDimitry Andric // this can be satisfied by returning a reference straight from the buffer, as
587a7e6055SDimitry Andric // an implementation may not store all data in a single contiguous buffer. So
597a7e6055SDimitry Andric // we iterate over each contiguous chunk, writing each one in succession.
607a7e6055SDimitry Andric while (SrcReader.bytesRemaining() > 0) {
617a7e6055SDimitry Andric ArrayRef<uint8_t> Chunk;
627a7e6055SDimitry Andric if (auto EC = SrcReader.readLongestContiguousChunk(Chunk))
637a7e6055SDimitry Andric return EC;
647a7e6055SDimitry Andric if (auto EC = writeBytes(Chunk))
657a7e6055SDimitry Andric return EC;
667a7e6055SDimitry Andric }
677a7e6055SDimitry Andric return Error::success();
687a7e6055SDimitry Andric }
697a7e6055SDimitry Andric
70f37b6182SDimitry Andric std::pair<BinaryStreamWriter, BinaryStreamWriter>
split(uint32_t Off) const71f37b6182SDimitry Andric BinaryStreamWriter::split(uint32_t Off) const {
72f37b6182SDimitry Andric assert(getLength() >= Off);
73f37b6182SDimitry Andric
74f37b6182SDimitry Andric WritableBinaryStreamRef First = Stream.drop_front(Offset);
75f37b6182SDimitry Andric
76f37b6182SDimitry Andric WritableBinaryStreamRef Second = First.drop_front(Off);
77f37b6182SDimitry Andric First = First.keep_front(Off);
78f37b6182SDimitry Andric BinaryStreamWriter W1{First};
79f37b6182SDimitry Andric BinaryStreamWriter W2{Second};
80f37b6182SDimitry Andric return std::make_pair(W1, W2);
81f37b6182SDimitry Andric }
82f37b6182SDimitry Andric
padToAlignment(uint32_t Align)837a7e6055SDimitry Andric Error BinaryStreamWriter::padToAlignment(uint32_t Align) {
847a7e6055SDimitry Andric uint32_t NewOffset = alignTo(Offset, Align);
857a7e6055SDimitry Andric if (NewOffset > getLength())
867a7e6055SDimitry Andric return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
8724d58133SDimitry Andric while (Offset < NewOffset)
8824d58133SDimitry Andric if (auto EC = writeInteger('\0'))
8924d58133SDimitry Andric return EC;
907a7e6055SDimitry Andric return Error::success();
917a7e6055SDimitry Andric }
92