Index: include/llvm/Support/BinaryStreamReader.h =================================================================== --- include/llvm/Support/BinaryStreamReader.h +++ include/llvm/Support/BinaryStreamReader.h @@ -96,6 +96,18 @@ return Error::success(); } + /// Read an unsigned LEB128 encoded value. + /// + /// \returns a success error code if the data was successfully read, otherwise + /// returns an appropriate error code. + Error readULEB128(uint64_t &Dest); + + /// Read a signed LEB128 encoded value. + /// + /// \returns a success error code if the data was successfully read, otherwise + /// returns an appropriate error code. + Error readSLEB128(int64_t &Dest); + /// Read a null terminated string from \p Dest. Whether a copy occurs depends /// on the implementation of the underlying stream. Updates the stream's /// offset to point after the newly read data. Index: include/llvm/Support/BinaryStreamWriter.h =================================================================== --- include/llvm/Support/BinaryStreamWriter.h +++ include/llvm/Support/BinaryStreamWriter.h @@ -79,6 +79,20 @@ return writeInteger(static_cast(Num)); } + /// Write the unsigned integer Value to the underlying stream using ULEB128 + /// encoding. + /// + /// \returns a success error code if the data was successfully written, + /// otherwise returns an appropriate error code. + Error writeULEB128(uint64_t Value); + + /// Write the unsigned integer Value to the underlying stream using ULEB128 + /// encoding. + /// + /// \returns a success error code if the data was successfully written, + /// otherwise returns an appropriate error code. + Error writeSLEB128(int64_t Value); + /// Write the string \p Str to the underlying stream followed by a null /// terminator. On success, updates the offset so that subsequent writes /// occur at the next unwritten position. \p Str need not be null terminated Index: lib/Support/BinaryStreamReader.cpp =================================================================== --- lib/Support/BinaryStreamReader.cpp +++ lib/Support/BinaryStreamReader.cpp @@ -10,6 +10,7 @@ #include "llvm/Support/BinaryStreamError.h" #include "llvm/Support/BinaryStreamRef.h" +#include "llvm/Support/LEB128.h" using namespace llvm; using endianness = llvm::support::endianness; @@ -40,6 +41,36 @@ return Error::success(); } +Error BinaryStreamReader::readULEB128(uint64_t &Dest) { + SmallVector EncodedBytes; + ArrayRef NextByte; + + // Copy the encoded ULEB into the buffer. + do { + if (auto Err = readBytes(NextByte, 1)) + return Err; + EncodedBytes.push_back(NextByte[0]); + } while (NextByte[0] & 0x80); + + Dest = decodeULEB128(EncodedBytes.begin(), nullptr, EncodedBytes.end()); + return Error::success(); +} + +Error BinaryStreamReader::readSLEB128(int64_t &Dest) { + SmallVector EncodedBytes; + ArrayRef NextByte; + + // Copy the encoded ULEB into the buffer. + do { + if (auto Err = readBytes(NextByte, 1)) + return Err; + EncodedBytes.push_back(NextByte[0]); + } while (NextByte[0] & 0x80); + + Dest = decodeSLEB128(EncodedBytes.begin(), nullptr, EncodedBytes.end()); + return Error::success(); +} + Error BinaryStreamReader::readCString(StringRef &Dest) { uint32_t OriginalOffset = getOffset(); uint32_t FoundOffset = 0; @@ -145,4 +176,4 @@ BinaryStreamReader W1{First}; BinaryStreamReader W2{Second}; return std::make_pair(W1, W2); -} \ No newline at end of file +} Index: lib/Support/BinaryStreamWriter.cpp =================================================================== --- lib/Support/BinaryStreamWriter.cpp +++ lib/Support/BinaryStreamWriter.cpp @@ -11,6 +11,7 @@ #include "llvm/Support/BinaryStreamError.h" #include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/BinaryStreamRef.h" +#include "llvm/Support/LEB128.h" using namespace llvm; @@ -31,6 +32,18 @@ return Error::success(); } +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}); +} + Error BinaryStreamWriter::writeCString(StringRef Str) { if (auto EC = writeFixedString(Str)) return EC; Index: unittests/Support/BinaryStreamTest.cpp =================================================================== --- unittests/Support/BinaryStreamTest.cpp +++ unittests/Support/BinaryStreamTest.cpp @@ -610,6 +610,77 @@ } } +TEST_F(BinaryStreamTest, StreamReaderULEB128) { + std::vector TestValues = { + 0, // Zero + 0x7F, // One byte + 0xFF, // One byte, all-ones + 0xAAAA, // Two bytes + 0xAAAAAAAA, // Four bytes + 0xAAAAAAAAAAAAAAAA, // Eight bytes + 0xffffffffffffffff // Eight bytess, all-ones + }; + + // Conservatively assume a 10-byte encoding for each of our LEB128s, with no + // alignment requirement. + initializeOutput(10 * TestValues.size(), 1); + initializeInputFromOutput(1); + + for (auto &Stream : Streams) { + // Write fields. + BinaryStreamWriter Writer(*Stream.Output); + for (const auto &Value : TestValues) + ASSERT_THAT_ERROR(Writer.writeULEB128(Value), Succeeded()); + + // Read fields. + BinaryStreamReader Reader(*Stream.Input); + std::vector Results; + Results.resize(TestValues.size()); + for (unsigned I = 0; I != TestValues.size(); ++I) + ASSERT_THAT_ERROR(Reader.readULEB128(Results[I]), Succeeded()); + + for (unsigned I = 0; I != TestValues.size(); ++I) + EXPECT_EQ(TestValues[I], Results[I]); + } +} + +TEST_F(BinaryStreamTest, StreamReaderSLEB128) { + std::vector TestValues = { + 0, // Zero + 0x7F, // One byte + -0x7F, // One byte, negative + 0xFF, // One byte, all-ones + 0xAAAA, // Two bytes + -0xAAAA, // Two bytes, negative + 0xAAAAAAAA, // Four bytes + -0xAAAAAAAA, // Four bytes, negative + 0x2AAAAAAAAAAAAAAA, // Eight bytes + -0x7ffffffffffffff // Eight bytess, negative + }; + + // Conservatively assume a 10-byte encoding for each of our LEB128s, with no + // alignment requirement. + initializeOutput(10 * TestValues.size(), 1); + initializeInputFromOutput(1); + + for (auto &Stream : Streams) { + // Write fields. + BinaryStreamWriter Writer(*Stream.Output); + for (const auto &Value : TestValues) + ASSERT_THAT_ERROR(Writer.writeSLEB128(Value), Succeeded()); + + // Read fields. + BinaryStreamReader Reader(*Stream.Input); + std::vector Results; + Results.resize(TestValues.size()); + for (unsigned I = 0; I != TestValues.size(); ++I) + ASSERT_THAT_ERROR(Reader.readSLEB128(Results[I]), Succeeded()); + + for (unsigned I = 0; I != TestValues.size(); ++I) + EXPECT_EQ(TestValues[I], Results[I]); + } +} + TEST_F(BinaryStreamTest, StreamReaderObject) { struct Foo { int X;