Index: llvm/trunk/include/llvm/BinaryFormat/MsgPack.h =================================================================== --- llvm/trunk/include/llvm/BinaryFormat/MsgPack.h +++ llvm/trunk/include/llvm/BinaryFormat/MsgPack.h @@ -0,0 +1,93 @@ +//===-- MsgPack.h - MessagePack Constants -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains constants used for implementing MessagePack support. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_BINARYFORMAT_MSGPACK_H +#define LLVM_BINARYFORMAT_MSGPACK_H + +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Endian.h" + +namespace llvm { +namespace msgpack { + +/// The endianness of all multi-byte encoded values in MessagePack. +constexpr support::endianness Endianness = support::big; + +/// The first byte identifiers of MessagePack object formats. +namespace FirstByte { +#define HANDLE_MP_FIRST_BYTE(ID, NAME) constexpr uint8_t NAME = ID; +#include "llvm/BinaryFormat/MsgPack.def" +} + +/// Most significant bits used to identify "Fix" variants in MessagePack. +/// +/// For example, FixStr objects encode their size in the five least significant +/// bits of their first byte, which is identified by the bit pattern "101" in +/// the three most significant bits. So FixBits::String contains 0b10100000. +/// +/// A corresponding mask of the bit pattern is found in \c FixBitsMask. +namespace FixBits { +#define HANDLE_MP_FIX_BITS(ID, NAME) constexpr uint8_t NAME = ID; +#include "llvm/BinaryFormat/MsgPack.def" +} + +/// Mask of bits used to identify "Fix" variants in MessagePack. +/// +/// For example, FixStr objects encode their size in the five least significant +/// bits of their first byte, which is identified by the bit pattern "101" in +/// the three most significant bits. So FixBitsMask::String contains +/// 0b11100000. +/// +/// The corresponding bit pattern to mask for is found in FixBits. +namespace FixBitsMask { +#define HANDLE_MP_FIX_BITS_MASK(ID, NAME) constexpr uint8_t NAME = ID; +#include "llvm/BinaryFormat/MsgPack.def" +} + +/// The maximum value or size encodable in "Fix" variants of formats. +/// +/// For example, FixStr objects encode their size in the five least significant +/// bits of their first byte, so the largest encodable size is 0b00011111. +namespace FixMax { +#define HANDLE_MP_FIX_MAX(ID, NAME) constexpr uint8_t NAME = ID; +#include "llvm/BinaryFormat/MsgPack.def" +} + +/// The exact size encodable in "Fix" variants of formats. +/// +/// The only objects for which an exact size makes sense are of Extension type. +/// +/// For example, FixExt4 stores an extension type containing exactly four bytes. +namespace FixLen { +#define HANDLE_MP_FIX_LEN(ID, NAME) constexpr uint8_t NAME = ID; +#include "llvm/BinaryFormat/MsgPack.def" +} + +/// The minimum value or size encodable in "Fix" variants of formats. +/// +/// The only object for which a minimum makes sense is a negative FixNum. +/// +/// Negative FixNum objects encode their signed integer value in one byte, but +/// they must have the pattern "111" as their three most significant bits. This +/// means all values are negative, and the smallest representable value is +/// 0b11100000. +namespace FixMin { +#define HANDLE_MP_FIX_MIN(ID, NAME) constexpr int8_t NAME = ID; +#include "llvm/BinaryFormat/MsgPack.def" +} + +} // end namespace msgpack +} // end namespace llvm + +#endif // LLVM_BINARYFORMAT_MSGPACK_H Index: llvm/trunk/include/llvm/BinaryFormat/MsgPack.def =================================================================== --- llvm/trunk/include/llvm/BinaryFormat/MsgPack.def +++ llvm/trunk/include/llvm/BinaryFormat/MsgPack.def @@ -0,0 +1,108 @@ +//===- MsgPack.def - MessagePack definitions --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Macros for running through MessagePack enumerators. +/// +//===----------------------------------------------------------------------===// + +#if !( \ + defined HANDLE_MP_FIRST_BYTE || defined HANDLE_MP_FIX_BITS || \ + defined HANDLE_MP_FIX_BITS_MASK || defined HANDLE_MP_FIX_MAX || \ + defined HANDLE_MP_FIX_LEN || defined HANDLE_MP_FIX_MIN) +#error "Missing macro definition of HANDLE_MP*" +#endif + +#ifndef HANDLE_MP_FIRST_BYTE +#define HANDLE_MP_FIRST_BYTE(ID, NAME) +#endif + +#ifndef HANDLE_MP_FIX_BITS +#define HANDLE_MP_FIX_BITS(ID, NAME) +#endif + +#ifndef HANDLE_MP_FIX_BITS_MASK +#define HANDLE_MP_FIX_BITS_MASK(ID, NAME) +#endif + +#ifndef HANDLE_MP_FIX_MAX +#define HANDLE_MP_FIX_MAX(ID, NAME) +#endif + +#ifndef HANDLE_MP_FIX_LEN +#define HANDLE_MP_FIX_LEN(ID, NAME) +#endif + +#ifndef HANDLE_MP_FIX_MIN +#define HANDLE_MP_FIX_MIN(ID, NAME) +#endif + +HANDLE_MP_FIRST_BYTE(0xc0, Nil) +HANDLE_MP_FIRST_BYTE(0xc2, False) +HANDLE_MP_FIRST_BYTE(0xc3, True) +HANDLE_MP_FIRST_BYTE(0xc4, Bin8) +HANDLE_MP_FIRST_BYTE(0xc5, Bin16) +HANDLE_MP_FIRST_BYTE(0xc6, Bin32) +HANDLE_MP_FIRST_BYTE(0xc7, Ext8) +HANDLE_MP_FIRST_BYTE(0xc8, Ext16) +HANDLE_MP_FIRST_BYTE(0xc9, Ext32) +HANDLE_MP_FIRST_BYTE(0xca, Float32) +HANDLE_MP_FIRST_BYTE(0xcb, Float64) +HANDLE_MP_FIRST_BYTE(0xcc, UInt8) +HANDLE_MP_FIRST_BYTE(0xcd, UInt16) +HANDLE_MP_FIRST_BYTE(0xce, UInt32) +HANDLE_MP_FIRST_BYTE(0xcf, UInt64) +HANDLE_MP_FIRST_BYTE(0xd0, Int8) +HANDLE_MP_FIRST_BYTE(0xd1, Int16) +HANDLE_MP_FIRST_BYTE(0xd2, Int32) +HANDLE_MP_FIRST_BYTE(0xd3, Int64) +HANDLE_MP_FIRST_BYTE(0xd4, FixExt1) +HANDLE_MP_FIRST_BYTE(0xd5, FixExt2) +HANDLE_MP_FIRST_BYTE(0xd6, FixExt4) +HANDLE_MP_FIRST_BYTE(0xd7, FixExt8) +HANDLE_MP_FIRST_BYTE(0xd8, FixExt16) +HANDLE_MP_FIRST_BYTE(0xd9, Str8) +HANDLE_MP_FIRST_BYTE(0xda, Str16) +HANDLE_MP_FIRST_BYTE(0xdb, Str32) +HANDLE_MP_FIRST_BYTE(0xdc, Array16) +HANDLE_MP_FIRST_BYTE(0xdd, Array32) +HANDLE_MP_FIRST_BYTE(0xde, Map16) +HANDLE_MP_FIRST_BYTE(0xdf, Map32) + +HANDLE_MP_FIX_BITS(0x00, PositiveInt) +HANDLE_MP_FIX_BITS(0x80, Map) +HANDLE_MP_FIX_BITS(0x90, Array) +HANDLE_MP_FIX_BITS(0xa0, String) +HANDLE_MP_FIX_BITS(0xe0, NegativeInt) + +HANDLE_MP_FIX_BITS_MASK(0x80, PositiveInt) +HANDLE_MP_FIX_BITS_MASK(0xf0, Map) +HANDLE_MP_FIX_BITS_MASK(0xf0, Array) +HANDLE_MP_FIX_BITS_MASK(0xe0, String) +HANDLE_MP_FIX_BITS_MASK(0xe0, NegativeInt) + +HANDLE_MP_FIX_MAX(0x7f, PositiveInt) +HANDLE_MP_FIX_MAX(0x0f, Map) +HANDLE_MP_FIX_MAX(0x0f, Array) +HANDLE_MP_FIX_MAX(0x1f, String) + +HANDLE_MP_FIX_LEN(0x01, Ext1) +HANDLE_MP_FIX_LEN(0x02, Ext2) +HANDLE_MP_FIX_LEN(0x04, Ext4) +HANDLE_MP_FIX_LEN(0x08, Ext8) +HANDLE_MP_FIX_LEN(0x10, Ext16) + +HANDLE_MP_FIX_MIN(-0x20, NegativeInt) + +#undef HANDLE_MP_FIRST_BYTE +#undef HANDLE_MP_FIX_BITS +#undef HANDLE_MP_FIX_BITS_MASK +#undef HANDLE_MP_FIX_MAX +#undef HANDLE_MP_FIX_LEN +#undef HANDLE_MP_FIX_MIN Index: llvm/trunk/include/llvm/BinaryFormat/MsgPackReader.h =================================================================== --- llvm/trunk/include/llvm/BinaryFormat/MsgPackReader.h +++ llvm/trunk/include/llvm/BinaryFormat/MsgPackReader.h @@ -0,0 +1,148 @@ +//===- MsgPackReader.h - Simple MsgPack reader ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This is a MessagePack reader. +/// +/// See https://github.com/msgpack/msgpack/blob/master/spec.md for the full +/// standard. +/// +/// Typical usage: +/// \code +/// StringRef input = GetInput(); +/// msgpack::Reader MPReader(input); +/// msgpack::Object Obj; +/// +/// while (MPReader.read(Obj)) { +/// switch (Obj.Kind) { +/// case msgpack::Type::Int: +// // Use Obj.Int +/// break; +/// // ... +/// } +/// } +/// \endcode +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_MSGPACKREADER_H +#define LLVM_SUPPORT_MSGPACKREADER_H + +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include + +namespace llvm { +namespace msgpack { + +/// MessagePack types as defined in the standard, with the exception of Integer +/// being divided into a signed Int and unsigned UInt variant in order to map +/// directly to C++ types. +/// +/// The types map onto corresponding union members of the \c Object struct. +enum class Type : uint8_t { + Int, + UInt, + Nil, + Boolean, + Float, + String, + Binary, + Array, + Map, + Extension, +}; + +/// Extension types are composed of a user-defined type ID and an uninterpreted +/// sequence of bytes. +struct ExtensionType { + /// User-defined extension type. + int8_t Type; + /// Raw bytes of the extension object. + StringRef Bytes; +}; + +/// MessagePack object, represented as a tagged union of C++ types. +/// +/// All types except \c Type::Nil (which has only one value, and so is +/// completely represented by the \c Kind itself) map to a exactly one union +/// member. +struct Object { + Type Kind; + union { + /// Value for \c Type::Int. + int64_t Int; + /// Value for \c Type::Uint. + uint64_t UInt; + /// Value for \c Type::Boolean. + bool Bool; + /// Value for \c Type::Float. + double Float; + /// Value for \c Type::String and \c Type::Binary. + StringRef Raw; + /// Value for \c Type::Array and \c Type::Map. + size_t Length; + /// Value for \c Type::Extension. + ExtensionType Extension; + }; + + Object() : Kind(Type::Int), Int(0) {} +}; + +/// Reads MessagePack objects from memory, one at a time. +class Reader { +public: + /// Construct a reader, keeping a reference to the \p InputBuffer. + Reader(MemoryBufferRef InputBuffer); + /// Construct a reader, keeping a reference to the \p Input. + Reader(StringRef Input); + + Reader(const Reader &) = delete; + Reader &operator=(const Reader &) = delete; + + /// Read one object from the input buffer, advancing past it. + /// + /// The \p Obj is updated with the kind of the object read, and the + /// corresponding union member is updated. + /// + /// For the collection objects (Array and Map), only the length is read, and + /// the caller must make and additional \c N calls (in the case of Array) or + /// \c N*2 calls (in the case of Map) to \c Read to retrieve the collection + /// elements. + /// + /// \param [out] Obj filled with next object on success. + /// + /// \returns true when object successfully read, false when at end of + /// input (and so \p Obj was not updated), otherwise an error. + Expected read(Object &Obj); + +private: + MemoryBufferRef InputBuffer; + StringRef::iterator Current; + StringRef::iterator End; + + size_t remainingSpace() { + // The rest of the code maintains the invariant that End >= Current, so + // that this cast is always defined behavior. + return static_cast(End - Current); + } + + template Expected readRaw(Object &Obj); + template Expected readInt(Object &Obj); + template Expected readUInt(Object &Obj); + template Expected readLength(Object &Obj); + template Expected readExt(Object &Obj); + Expected createRaw(Object &Obj, uint32_t Size); + Expected createExt(Object &Obj, uint32_t Size); +}; + +} // end namespace msgpack +} // end namespace llvm + +#endif // LLVM_SUPPORT_MSGPACKREADER_H Index: llvm/trunk/include/llvm/BinaryFormat/MsgPackWriter.h =================================================================== --- llvm/trunk/include/llvm/BinaryFormat/MsgPackWriter.h +++ llvm/trunk/include/llvm/BinaryFormat/MsgPackWriter.h @@ -0,0 +1,131 @@ +//===- MsgPackWriter.h - Simple MsgPack writer ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains a MessagePack writer. +/// +/// See https://github.com/msgpack/msgpack/blob/master/spec.md for the full +/// specification. +/// +/// Typical usage: +/// \code +/// raw_ostream output = GetOutputStream(); +/// msgpack::Writer MPWriter(output); +/// MPWriter.writeNil(); +/// MPWriter.write(false); +/// MPWriter.write("string"); +/// // ... +/// \endcode +/// +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_MSGPACKPARSER_H +#define LLVM_SUPPORT_MSGPACKPARSER_H + +#include "llvm/BinaryFormat/MsgPack.h" +#include "llvm/Support/EndianStream.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { +namespace msgpack { + +/// Writes MessagePack objects to an output stream, one at a time. +class Writer { +public: + /// Construct a writer, optionally enabling "Compatibility Mode" as defined + /// in the MessagePack specification. + /// + /// When in \p Compatible mode, the writer will write \c Str16 formats + /// instead of \c Str8 formats, and will refuse to write any \c Bin formats. + /// + /// \param OS stream to output MessagePack objects to. + /// \param Compatible when set, write in "Compatibility Mode". + Writer(raw_ostream &OS, bool Compatible = false); + + Writer(const Writer &) = delete; + Writer &operator=(const Writer &) = delete; + + /// Write a \em Nil to the output stream. + /// + /// The output will be the \em nil format. + void writeNil(); + + /// Write a \em Boolean to the output stream. + /// + /// The output will be a \em bool format. + void write(bool b); + + /// Write a signed integer to the output stream. + /// + /// The output will be in the smallest possible \em int format. + /// + /// The format chosen may be for an unsigned integer. + void write(int64_t i); + + /// Write an unsigned integer to the output stream. + /// + /// The output will be in the smallest possible \em int format. + void write(uint64_t u); + + /// Write a floating point number to the output stream. + /// + /// The output will be in the smallest possible \em float format. + void write(double d); + + /// Write a string to the output stream. + /// + /// The output will be in the smallest possible \em str format. + void write(StringRef s); + + /// Write a memory buffer to the output stream. + /// + /// The output will be in the smallest possible \em bin format. + /// + /// \warning Do not use this overload if in \c Compatible mode. + void write(MemoryBufferRef Buffer); + + /// Write the header for an \em Array of the given size. + /// + /// The output will be in the smallest possible \em array format. + // + /// The header contains an identifier for the \em array format used, as well + /// as an encoding of the size of the array. + /// + /// N.B. The caller must subsequently call \c Write an additional \p Size + /// times to complete the array. + void writeArraySize(uint32_t Size); + + /// Write the header for a \em Map of the given size. + /// + /// The output will be in the smallest possible \em map format. + // + /// The header contains an identifier for the \em map format used, as well + /// as an encoding of the size of the map. + /// + /// N.B. The caller must subsequently call \c Write and additional \c Size*2 + /// times to complete the map. Each even numbered call to \c Write defines a + /// new key, and each odd numbered call defines the previous key's value. + void writeMapSize(uint32_t Size); + + /// Write a typed memory buffer (an extension type) to the output stream. + /// + /// The output will be in the smallest possible \em ext format. + void writeExt(int8_t Type, MemoryBufferRef Buffer); + +private: + support::endian::Writer EW; + bool Compatible; +}; + +} // end namespace msgpack +} // end namespace llvm + +#endif // LLVM_SUPPORT_MSGPACKPARSER_H Index: llvm/trunk/lib/BinaryFormat/CMakeLists.txt =================================================================== --- llvm/trunk/lib/BinaryFormat/CMakeLists.txt +++ llvm/trunk/lib/BinaryFormat/CMakeLists.txt @@ -1,6 +1,8 @@ add_llvm_library(LLVMBinaryFormat Dwarf.cpp Magic.cpp + MsgPackReader.cpp + MsgPackWriter.cpp Wasm.cpp ADDITIONAL_HEADER_DIRS Index: llvm/trunk/lib/BinaryFormat/MsgPackReader.cpp =================================================================== --- llvm/trunk/lib/BinaryFormat/MsgPackReader.cpp +++ llvm/trunk/lib/BinaryFormat/MsgPackReader.cpp @@ -0,0 +1,255 @@ +//===- MsgPackReader.cpp - Simple MsgPack reader ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements a MessagePack reader. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/BinaryFormat/MsgPackReader.h" +#include "llvm/BinaryFormat/MsgPack.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::support; +using namespace msgpack; + +Reader::Reader(MemoryBufferRef InputBuffer) + : InputBuffer(InputBuffer), Current(InputBuffer.getBufferStart()), + End(InputBuffer.getBufferEnd()) {} + +Reader::Reader(StringRef Input) : Reader({Input, "MsgPack"}) {} + +Expected Reader::read(Object &Obj) { + if (Current == End) + return false; + + uint8_t FB = static_cast(*Current++); + + switch (FB) { + case FirstByte::Nil: + Obj.Kind = Type::Nil; + return true; + case FirstByte::True: + Obj.Kind = Type::Boolean; + Obj.Bool = true; + return true; + case FirstByte::False: + Obj.Kind = Type::Boolean; + Obj.Bool = false; + return true; + case FirstByte::Int8: + Obj.Kind = Type::Int; + return readInt(Obj); + case FirstByte::Int16: + Obj.Kind = Type::Int; + return readInt(Obj); + case FirstByte::Int32: + Obj.Kind = Type::Int; + return readInt(Obj); + case FirstByte::Int64: + Obj.Kind = Type::Int; + return readInt(Obj); + case FirstByte::UInt8: + Obj.Kind = Type::UInt; + return readUInt(Obj); + case FirstByte::UInt16: + Obj.Kind = Type::UInt; + return readUInt(Obj); + case FirstByte::UInt32: + Obj.Kind = Type::UInt; + return readUInt(Obj); + case FirstByte::UInt64: + Obj.Kind = Type::UInt; + return readUInt(Obj); + case FirstByte::Float32: + Obj.Kind = Type::Float; + if (sizeof(float) > remainingSpace()) + return make_error( + "Invalid Float32 with insufficient payload", + std::make_error_code(std::errc::invalid_argument)); + Obj.Float = BitsToFloat(endian::read(Current)); + Current += sizeof(float); + return true; + case FirstByte::Float64: + Obj.Kind = Type::Float; + if (sizeof(double) > remainingSpace()) + return make_error( + "Invalid Float64 with insufficient payload", + std::make_error_code(std::errc::invalid_argument)); + Obj.Float = BitsToDouble(endian::read(Current)); + Current += sizeof(double); + return true; + case FirstByte::Str8: + Obj.Kind = Type::String; + return readRaw(Obj); + case FirstByte::Str16: + Obj.Kind = Type::String; + return readRaw(Obj); + case FirstByte::Str32: + Obj.Kind = Type::String; + return readRaw(Obj); + case FirstByte::Bin8: + Obj.Kind = Type::Binary; + return readRaw(Obj); + case FirstByte::Bin16: + Obj.Kind = Type::Binary; + return readRaw(Obj); + case FirstByte::Bin32: + Obj.Kind = Type::Binary; + return readRaw(Obj); + case FirstByte::Array16: + Obj.Kind = Type::Array; + return readLength(Obj); + case FirstByte::Array32: + Obj.Kind = Type::Array; + return readLength(Obj); + case FirstByte::Map16: + Obj.Kind = Type::Map; + return readLength(Obj); + case FirstByte::Map32: + Obj.Kind = Type::Map; + return readLength(Obj); + case FirstByte::FixExt1: + Obj.Kind = Type::Extension; + return createExt(Obj, FixLen::Ext1); + case FirstByte::FixExt2: + Obj.Kind = Type::Extension; + return createExt(Obj, FixLen::Ext2); + case FirstByte::FixExt4: + Obj.Kind = Type::Extension; + return createExt(Obj, FixLen::Ext4); + case FirstByte::FixExt8: + Obj.Kind = Type::Extension; + return createExt(Obj, FixLen::Ext8); + case FirstByte::FixExt16: + Obj.Kind = Type::Extension; + return createExt(Obj, FixLen::Ext16); + case FirstByte::Ext8: + Obj.Kind = Type::Extension; + return readExt(Obj); + case FirstByte::Ext16: + Obj.Kind = Type::Extension; + return readExt(Obj); + case FirstByte::Ext32: + Obj.Kind = Type::Extension; + return readExt(Obj); + } + + if ((FB & FixBitsMask::NegativeInt) == FixBits::NegativeInt) { + Obj.Kind = Type::Int; + int8_t I; + static_assert(sizeof(I) == sizeof(FB), "Unexpected type sizes"); + memcpy(&I, &FB, sizeof(FB)); + Obj.Int = I; + return true; + } + + if ((FB & FixBitsMask::PositiveInt) == FixBits::PositiveInt) { + Obj.Kind = Type::UInt; + Obj.UInt = FB; + return true; + } + + if ((FB & FixBitsMask::String) == FixBits::String) { + Obj.Kind = Type::String; + uint8_t Size = FB & ~FixBitsMask::String; + return createRaw(Obj, Size); + } + + if ((FB & FixBitsMask::Array) == FixBits::Array) { + Obj.Kind = Type::Array; + Obj.Length = FB & ~FixBitsMask::Array; + return true; + } + + if ((FB & FixBitsMask::Map) == FixBits::Map) { + Obj.Kind = Type::Map; + Obj.Length = FB & ~FixBitsMask::Map; + return true; + } + + return make_error( + "Invalid first byte", std::make_error_code(std::errc::invalid_argument)); +} + +template Expected Reader::readRaw(Object &Obj) { + if (sizeof(T) > remainingSpace()) + return make_error( + "Invalid Raw with insufficient payload", + std::make_error_code(std::errc::invalid_argument)); + T Size = endian::read(Current); + Current += sizeof(T); + return createRaw(Obj, Size); +} + +template Expected Reader::readInt(Object &Obj) { + if (sizeof(T) > remainingSpace()) + return make_error( + "Invalid Int with insufficient payload", + std::make_error_code(std::errc::invalid_argument)); + Obj.Int = static_cast(endian::read(Current)); + Current += sizeof(T); + return true; +} + +template Expected Reader::readUInt(Object &Obj) { + if (sizeof(T) > remainingSpace()) + return make_error( + "Invalid Int with insufficient payload", + std::make_error_code(std::errc::invalid_argument)); + Obj.UInt = static_cast(endian::read(Current)); + Current += sizeof(T); + return true; +} + +template Expected Reader::readLength(Object &Obj) { + if (sizeof(T) > remainingSpace()) + return make_error( + "Invalid Map/Array with invalid length", + std::make_error_code(std::errc::invalid_argument)); + Obj.Length = static_cast(endian::read(Current)); + Current += sizeof(T); + return true; +} + +template Expected Reader::readExt(Object &Obj) { + if (sizeof(T) > remainingSpace()) + return make_error( + "Invalid Ext with invalid length", + std::make_error_code(std::errc::invalid_argument)); + T Size = endian::read(Current); + Current += sizeof(T); + return createExt(Obj, Size); +} + +Expected Reader::createRaw(Object &Obj, uint32_t Size) { + if (Size > remainingSpace()) + return make_error( + "Invalid Raw with insufficient payload", + std::make_error_code(std::errc::invalid_argument)); + Obj.Raw = StringRef(Current, Size); + Current += Size; + return true; +} + +Expected Reader::createExt(Object &Obj, uint32_t Size) { + if (Current == End) + return make_error( + "Invalid Ext with no type", + std::make_error_code(std::errc::invalid_argument)); + Obj.Extension.Type = *Current++; + if (Size > remainingSpace()) + return make_error( + "Invalid Ext with insufficient payload", + std::make_error_code(std::errc::invalid_argument)); + Obj.Extension.Bytes = StringRef(Current, Size); + Current += Size; + return true; +} Index: llvm/trunk/lib/BinaryFormat/MsgPackWriter.cpp =================================================================== --- llvm/trunk/lib/BinaryFormat/MsgPackWriter.cpp +++ llvm/trunk/lib/BinaryFormat/MsgPackWriter.cpp @@ -0,0 +1,208 @@ +//===- MsgPackWriter.cpp - Simple MsgPack writer ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements a MessagePack writer. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/BinaryFormat/MsgPackWriter.h" +#include "llvm/BinaryFormat/MsgPack.h" + +using namespace llvm; +using namespace msgpack; + +Writer::Writer(raw_ostream &OS, bool Compatible) + : EW(OS, Endianness), Compatible(Compatible) {} + +void Writer::writeNil() { EW.write(FirstByte::Nil); } + +void Writer::write(bool b) { EW.write(b ? FirstByte::True : FirstByte::False); } + +void Writer::write(int64_t i) { + if (i >= 0) { + write(static_cast(i)); + return; + } + + if (i >= FixMin::NegativeInt) { + EW.write(static_cast(i)); + return; + } + + if (i >= INT8_MIN) { + EW.write(FirstByte::Int8); + EW.write(static_cast(i)); + return; + } + + if (i >= INT16_MIN) { + EW.write(FirstByte::Int16); + EW.write(static_cast(i)); + return; + } + + if (i >= INT32_MIN) { + EW.write(FirstByte::Int32); + EW.write(static_cast(i)); + return; + } + + EW.write(FirstByte::Int64); + EW.write(i); +} + +void Writer::write(uint64_t u) { + if (u <= FixMax::PositiveInt) { + EW.write(static_cast(u)); + return; + } + + if (u <= UINT8_MAX) { + EW.write(FirstByte::UInt8); + EW.write(static_cast(u)); + return; + } + + if (u <= UINT16_MAX) { + EW.write(FirstByte::UInt16); + EW.write(static_cast(u)); + return; + } + + if (u <= UINT32_MAX) { + EW.write(FirstByte::UInt32); + EW.write(static_cast(u)); + return; + } + + EW.write(FirstByte::UInt64); + EW.write(u); +} + +void Writer::write(double d) { + // If no loss of precision, encode as a Float32. + float f = static_cast(d); + if (static_cast(f) == d) { + EW.write(FirstByte::Float32); + EW.write(f); + } else { + EW.write(FirstByte::Float64); + EW.write(d); + } +} + +void Writer::write(StringRef s) { + size_t Size = s.size(); + + if (Size <= FixMax::String) + EW.write(static_cast(FixBits::String | Size)); + else if (!Compatible && Size <= UINT8_MAX) { + EW.write(FirstByte::Str8); + EW.write(static_cast(Size)); + } else if (Size <= UINT16_MAX) { + EW.write(FirstByte::Str16); + EW.write(static_cast(Size)); + } else { + assert(Size <= UINT32_MAX && "String object too long to be encoded"); + EW.write(FirstByte::Str32); + EW.write(static_cast(Size)); + } + + EW.OS << s; +} + +void Writer::write(MemoryBufferRef Buffer) { + assert(!Compatible && "Attempt to write Bin format in compatible mode"); + + size_t Size = Buffer.getBufferSize(); + + if (Size <= UINT8_MAX) { + EW.write(FirstByte::Bin8); + EW.write(static_cast(Size)); + } else if (Size <= UINT16_MAX) { + EW.write(FirstByte::Bin16); + EW.write(static_cast(Size)); + } else { + assert(Size <= UINT32_MAX && "Binary object too long to be encoded"); + EW.write(FirstByte::Bin32); + EW.write(static_cast(Size)); + } + + EW.OS.write(Buffer.getBufferStart(), Size); +} + +void Writer::writeArraySize(uint32_t Size) { + if (Size <= FixMax::Array) { + EW.write(static_cast(FixBits::Array | Size)); + return; + } + + if (Size <= UINT16_MAX) { + EW.write(FirstByte::Array16); + EW.write(static_cast(Size)); + return; + } + + EW.write(FirstByte::Array32); + EW.write(Size); +} + +void Writer::writeMapSize(uint32_t Size) { + if (Size <= FixMax::Map) { + EW.write(static_cast(FixBits::Map | Size)); + return; + } + + if (Size <= UINT16_MAX) { + EW.write(FirstByte::Map16); + EW.write(static_cast(Size)); + return; + } + + EW.write(FirstByte::Map32); + EW.write(Size); +} + +void Writer::writeExt(int8_t Type, MemoryBufferRef Buffer) { + size_t Size = Buffer.getBufferSize(); + + switch (Size) { + case FixLen::Ext1: + EW.write(FirstByte::FixExt1); + break; + case FixLen::Ext2: + EW.write(FirstByte::FixExt2); + break; + case FixLen::Ext4: + EW.write(FirstByte::FixExt4); + break; + case FixLen::Ext8: + EW.write(FirstByte::FixExt8); + break; + case FixLen::Ext16: + EW.write(FirstByte::FixExt16); + break; + default: + if (Size <= UINT8_MAX) { + EW.write(FirstByte::Ext8); + EW.write(static_cast(Size)); + } else if (Size <= UINT16_MAX) { + EW.write(FirstByte::Ext16); + EW.write(static_cast(Size)); + } else { + assert(Size <= UINT32_MAX && "Ext size too large to be encoded"); + EW.write(FirstByte::Ext32); + EW.write(static_cast(Size)); + } + } + + EW.write(Type); + EW.OS.write(Buffer.getBufferStart(), Size); +} Index: llvm/trunk/unittests/BinaryFormat/CMakeLists.txt =================================================================== --- llvm/trunk/unittests/BinaryFormat/CMakeLists.txt +++ llvm/trunk/unittests/BinaryFormat/CMakeLists.txt @@ -5,6 +5,8 @@ add_llvm_unittest(BinaryFormatTests DwarfTest.cpp MachOTest.cpp + MsgPackReaderTest.cpp + MsgPackWriterTest.cpp TestFileMagic.cpp ) Index: llvm/trunk/unittests/BinaryFormat/MsgPackReaderTest.cpp =================================================================== --- llvm/trunk/unittests/BinaryFormat/MsgPackReaderTest.cpp +++ llvm/trunk/unittests/BinaryFormat/MsgPackReaderTest.cpp @@ -0,0 +1,891 @@ +//===- MsgPackReaderTest.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/BinaryFormat/MsgPackReader.h" +#include "llvm/BinaryFormat/MsgPack.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace llvm::msgpack; + +struct MsgPackReader : testing::Test { + std::string Buffer; + Object Obj; +}; + +TEST_F(MsgPackReader, TestReadMultiple) { + Buffer = "\xc0\xc2"; + Reader MPReader(Buffer); + { + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Nil); + } + { + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Boolean); + EXPECT_EQ(Obj.Bool, false); + } + { + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_FALSE(*ContinueOrErr); + } +} + +TEST_F(MsgPackReader, TestReadNil) { + Buffer = "\xc0"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Nil); +} + +TEST_F(MsgPackReader, TestReadBoolFalse) { + Buffer = "\xc2"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Boolean); + EXPECT_EQ(Obj.Bool, false); +} + +TEST_F(MsgPackReader, TestReadBoolTrue) { + Buffer = "\xc3"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Boolean); + EXPECT_EQ(Obj.Bool, true); +} + +TEST_F(MsgPackReader, TestReadFixNegativeInt) { + // Positive values will be written in a UInt form, so max FixNegativeInt is -1 + // + // FixNegativeInt form bitpattern starts with 111, so min FixNegativeInt + // is 11100000 = -32 + for (int8_t i = -1; i >= -32; --i) { + Buffer.assign(1, static_cast(i)); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Int); + EXPECT_EQ(Obj.Int, i); + } +} + +TEST_F(MsgPackReader, TestReadInt8Max) { + Buffer = "\xd0\x7f"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Int); + EXPECT_EQ(Obj.Int, INT8_MAX); +} + +TEST_F(MsgPackReader, TestReadInt8Zero) { + Buffer.assign("\xd0\x00", 2); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Int); + EXPECT_EQ(Obj.Int, 0); +} + +TEST_F(MsgPackReader, TestReadInt8Min) { + Buffer = "\xd0\x80"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Int); + EXPECT_EQ(Obj.Int, INT8_MIN); +} + +TEST_F(MsgPackReader, TestReadInt16Max) { + Buffer = "\xd1\x7f\xff"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Int); + EXPECT_EQ(Obj.Int, INT16_MAX); +} + +TEST_F(MsgPackReader, TestReadInt16Zero) { + Buffer.assign("\xd1\x00\x00", 3); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Int); + EXPECT_EQ(Obj.Int, 0); +} + +TEST_F(MsgPackReader, TestReadInt16Min) { + Buffer.assign("\xd1\x80\x00", 3); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Int); + EXPECT_EQ(Obj.Int, INT16_MIN); +} + +TEST_F(MsgPackReader, TestReadInt32Max) { + Buffer = "\xd2\x7f\xff\xff\xff"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Int); + EXPECT_EQ(Obj.Int, INT32_MAX); +} + +TEST_F(MsgPackReader, TestReadInt32Zero) { + Buffer.assign("\xd2\x00\x00\x00\x00", 5); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Int); + EXPECT_EQ(Obj.Int, 0); +} + +TEST_F(MsgPackReader, TestReadInt32Min) { + Buffer.assign("\xd2\x80\x00\x00\x00", 5); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Int); + EXPECT_EQ(Obj.Int, INT32_MIN); +} + +TEST_F(MsgPackReader, TestReadInt64Max) { + Buffer = "\xd3\x7f\xff\xff\xff\xff\xff\xff\xff"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Int); + EXPECT_EQ(Obj.Int, INT64_MAX); +} + +TEST_F(MsgPackReader, TestReadInt64Zero) { + Buffer.assign("\xd3\x00\x00\x00\x00\x00\x00\x00\x00", 9); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Int); + EXPECT_EQ(Obj.Int, 0); +} + +TEST_F(MsgPackReader, TestReadInt64Min) { + Buffer.assign("\xd3\x80\x00\x00\x00\x00\x00\x00\x00", 9); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Int); + EXPECT_EQ(Obj.Int, INT64_MIN); +} + +TEST_F(MsgPackReader, TestReadFixPositiveInt) { + // FixPositiveInt form bitpattern starts with 0, so max FixPositiveInt + // is 01111111 = 127 + for (uint64_t u = 0; u <= 127; ++u) { + Buffer.assign(1, static_cast(u)); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::UInt); + EXPECT_EQ(Obj.UInt, u); + } +} + +TEST_F(MsgPackReader, TestReadUInt8Zero) { + Buffer.assign("\xcc\x00", 2); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::UInt); + EXPECT_EQ(Obj.UInt, 0u); +} + +TEST_F(MsgPackReader, TestReadUInt8One) { + Buffer = "\xcc\x01"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::UInt); + EXPECT_EQ(Obj.UInt, 1u); +} + +TEST_F(MsgPackReader, TestReadUInt8Max) { + Buffer = "\xcc\xff"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::UInt); + EXPECT_EQ(Obj.UInt, static_cast(UINT8_MAX)); +} + +TEST_F(MsgPackReader, TestReadUInt16Zero) { + Buffer.assign("\xcd\x00\x00", 3); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::UInt); + EXPECT_EQ(Obj.UInt, 0u); +} + +TEST_F(MsgPackReader, TestReadUInt16One) { + Buffer.assign("\xcd\x00\x01", 3); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::UInt); + EXPECT_EQ(Obj.UInt, 1u); +} + +TEST_F(MsgPackReader, TestReadUInt16Max) { + Buffer = "\xcd\xff\xff"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::UInt); + EXPECT_EQ(Obj.UInt, static_cast(UINT16_MAX)); +} + +TEST_F(MsgPackReader, TestReadUInt32Zero) { + Buffer.assign("\xce\x00\x00\x00\x00", 5); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::UInt); + EXPECT_EQ(Obj.UInt, 0u); +} + +TEST_F(MsgPackReader, TestReadUInt32One) { + Buffer.assign("\xce\x00\x00\x00\x01", 5); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::UInt); + EXPECT_EQ(Obj.UInt, 1u); +} + +TEST_F(MsgPackReader, TestReadUInt32Max) { + Buffer = "\xce\xff\xff\xff\xff"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::UInt); + EXPECT_EQ(Obj.UInt, static_cast(UINT32_MAX)); +} + +TEST_F(MsgPackReader, TestReadUInt64Zero) { + Buffer.assign("\xcf\x00\x00\x00\x00\x00\x00\x00\x00", 9); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::UInt); + EXPECT_EQ(Obj.UInt, 0u); +} + +TEST_F(MsgPackReader, TestReadUInt64One) { + Buffer.assign("\xcf\x00\x00\x00\x00\x00\x00\x00\x01", 9); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::UInt); + EXPECT_EQ(Obj.UInt, 1u); +} + +TEST_F(MsgPackReader, TestReadUInt64Max) { + Buffer = "\xcf\xff\xff\xff\xff\xff\xff\xff\xff"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::UInt); + EXPECT_EQ(Obj.UInt, static_cast(UINT64_MAX)); +} + +TEST_F(MsgPackReader, TestReadFloat32) { + Buffer = "\xca\xee\xee\xee\xef"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Float); + EXPECT_EQ(Obj.Float, -3.6973142664068907e+28f); +} + +TEST_F(MsgPackReader, TestReadFloat64) { + Buffer = "\xcb\xee\xee\xee\xee\xee\xee\xee\xef"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Float); + EXPECT_EQ(Obj.Float, -2.2899894549927042e+226); +} + +TEST_F(MsgPackReader, TestReadFixStrZero) { + Buffer = "\xa0"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::String); + EXPECT_EQ(Obj.Raw, StringRef()); +} + +TEST_F(MsgPackReader, TestReadFixStrOne) { + std::string Result(1, 'a'); + Buffer = std::string("\xa1") + Result; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::String); + EXPECT_EQ(Obj.Raw, Result); +} + +TEST_F(MsgPackReader, TestReadFixStrMax) { + // FixStr format's size is a 5 bit unsigned integer, so max is 11111 = 31 + std::string Result(31, 'a'); + Buffer = std::string("\xbf") + Result; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::String); + EXPECT_EQ(Obj.Raw, Result); +} + +TEST_F(MsgPackReader, TestReadStr8Zero) { + Buffer.assign("\xd9\x00", 2); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::String); + EXPECT_EQ(Obj.Raw, StringRef()); +} + +TEST_F(MsgPackReader, TestReadStr8One) { + std::string Result(1, 'a'); + Buffer = std::string("\xd9\x01") + Result; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::String); + EXPECT_EQ(Obj.Raw, Result); +} + +TEST_F(MsgPackReader, TestReadStr8Max) { + std::string Result(UINT8_MAX, 'a'); + Buffer = std::string("\xd9\xff") + Result; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::String); + EXPECT_EQ(Obj.Raw, Result); +} + +TEST_F(MsgPackReader, TestReadStr16Zero) { + Buffer.assign("\xda\x00\x00", 3); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::String); + EXPECT_EQ(Obj.Raw, StringRef()); +} + +TEST_F(MsgPackReader, TestReadStr16One) { + std::string Result(1, 'a'); + Buffer = std::string("\xda\x00\x01", 3) + Result; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::String); + EXPECT_EQ(Obj.Raw, Result); +} + +TEST_F(MsgPackReader, TestReadStr16Max) { + std::string Result(UINT16_MAX, 'a'); + Buffer = std::string("\xda\xff\xff") + Result; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::String); + EXPECT_EQ(Obj.Raw, Result); +} + +TEST_F(MsgPackReader, TestReadStr32Zero) { + Buffer.assign("\xdb\x00\x00\x00\x00", 5); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::String); + EXPECT_EQ(Obj.Raw, StringRef()); +} + +TEST_F(MsgPackReader, TestReadStr32One) { + std::string Result(1, 'a'); + Buffer = std::string("\xdb\x00\x00\x00\x01", 5) + Result; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::String); + EXPECT_EQ(Obj.Raw, Result); +} + +TEST_F(MsgPackReader, TestReadStr32Max) { + std::string Result(static_cast(UINT16_MAX) + 1, 'a'); + Buffer = std::string("\xdb\x00\x01\x00\x00", 5) + Result; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::String); + EXPECT_EQ(Obj.Raw, Result); +} + +TEST_F(MsgPackReader, TestReadBin8Zero) { + Buffer.assign("\xc4\x00", 2); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Binary); + EXPECT_EQ(Obj.Raw, StringRef()); +} + +TEST_F(MsgPackReader, TestReadBin8One) { + std::string Result(1, 'a'); + Buffer = std::string("\xc4\x01") + Result; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Binary); + EXPECT_EQ(Obj.Raw, Result); +} + +TEST_F(MsgPackReader, TestReadBin8Max) { + std::string Result(UINT8_MAX, 'a'); + Buffer = std::string("\xc4\xff") + Result; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Binary); + EXPECT_EQ(Obj.Raw, Result); +} + +TEST_F(MsgPackReader, TestReadBin16Zero) { + Buffer.assign("\xc5\x00\x00", 3); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Binary); + EXPECT_EQ(Obj.Raw, StringRef()); +} + +TEST_F(MsgPackReader, TestReadBin16One) { + std::string Result(1, 'a'); + Buffer = std::string("\xc5\x00\x01", 3) + Result; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Binary); + EXPECT_EQ(Obj.Raw, Result); +} + +TEST_F(MsgPackReader, TestReadBin16Max) { + std::string Result(UINT16_MAX, 'a'); + Buffer = std::string("\xc5\xff\xff") + Result; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Binary); + EXPECT_EQ(Obj.Raw, Result); +} + +TEST_F(MsgPackReader, TestReadBin32Zero) { + Buffer.assign("\xc6\x00\x00\x00\x00", 5); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Binary); + EXPECT_EQ(Obj.Raw, StringRef()); +} + +TEST_F(MsgPackReader, TestReadBin32One) { + std::string Result(1, 'a'); + Buffer = std::string("\xc6\x00\x00\x00\x01", 5) + Result; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Binary); + EXPECT_EQ(Obj.Raw, Result); +} + +TEST_F(MsgPackReader, TestReadBin32Max) { + std::string Result(static_cast(UINT16_MAX) + 1, 'a'); + Buffer = std::string("\xc6\x00\x01\x00\x00", 5) + Result; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Binary); + EXPECT_EQ(Obj.Raw, Result); +} + +TEST_F(MsgPackReader, TestReadFixArrayZero) { + Buffer = "\x90"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Array); + EXPECT_EQ(Obj.Length, 0u); +} + +TEST_F(MsgPackReader, TestReadFixArrayOne) { + Buffer = "\x91"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Array); + EXPECT_EQ(Obj.Length, 1u); +} + +TEST_F(MsgPackReader, TestReadFixArrayMax) { + Buffer = "\x9f"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Array); + // FixArray format's size is a 4 bit unsigned integer, so max is 1111 = 15 + EXPECT_EQ(Obj.Length, 15u); +} + +TEST_F(MsgPackReader, TestReadArray16Zero) { + Buffer.assign("\xdc\x00\x00", 3); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Array); + EXPECT_EQ(Obj.Length, 0u); +} + +TEST_F(MsgPackReader, TestReadArray16One) { + Buffer.assign("\xdc\x00\x01", 3); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Array); + EXPECT_EQ(Obj.Length, 1u); +} + +TEST_F(MsgPackReader, TestReadArray16Max) { + Buffer = "\xdc\xff\xff"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Array); + EXPECT_EQ(Obj.Length, static_cast(UINT16_MAX)); +} + +TEST_F(MsgPackReader, TestReadArray32Zero) { + Buffer.assign("\xdd\x00\x00\x00\x00", 5); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Array); + EXPECT_EQ(Obj.Length, 0u); +} + +TEST_F(MsgPackReader, TestReadArray32One) { + Buffer.assign("\xdd\x00\x00\x00\x01", 5); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Array); + EXPECT_EQ(Obj.Length, 1u); +} + +TEST_F(MsgPackReader, TestReadArray32Max) { + Buffer = "\xdd\xff\xff\xff\xff"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Array); + EXPECT_EQ(Obj.Length, static_cast(UINT32_MAX)); +} + +TEST_F(MsgPackReader, TestReadFixMapZero) { + Buffer = "\x80"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Map); + EXPECT_EQ(Obj.Length, 0u); +} + +TEST_F(MsgPackReader, TestReadFixMapOne) { + Buffer = "\x81"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Map); + EXPECT_EQ(Obj.Length, 1u); +} + +TEST_F(MsgPackReader, TestReadFixMapMax) { + Buffer = "\x8f"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Map); + // FixMap format's size is a 4 bit unsigned integer, so max is 1111 = 15 + EXPECT_EQ(Obj.Length, 15u); +} + +TEST_F(MsgPackReader, TestReadMap16Zero) { + Buffer.assign("\xde\x00\x00", 3); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Map); + EXPECT_EQ(Obj.Length, 0u); +} + +TEST_F(MsgPackReader, TestReadMap16One) { + Buffer.assign("\xde\x00\x01", 3); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Map); + EXPECT_EQ(Obj.Length, 1u); +} + +TEST_F(MsgPackReader, TestReadMap16Max) { + Buffer = "\xde\xff\xff"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Map); + EXPECT_EQ(Obj.Length, static_cast(UINT16_MAX)); +} + +TEST_F(MsgPackReader, TestReadMap32Zero) { + Buffer.assign("\xdf\x00\x00\x00\x00", 5); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Map); + EXPECT_EQ(Obj.Length, 0u); +} + +TEST_F(MsgPackReader, TestReadMap32One) { + Buffer.assign("\xdf\x00\x00\x00\x01", 5); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Map); + EXPECT_EQ(Obj.Length, 1u); +} + +TEST_F(MsgPackReader, TestReadMap32Max) { + Buffer = "\xdf\xff\xff\xff\xff"; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Map); + EXPECT_EQ(Obj.Length, static_cast(UINT32_MAX)); +} + +// FixExt formats are only available for these specific lengths: 1, 2, 4, 8, 16 + +TEST_F(MsgPackReader, TestReadFixExt1) { + std::string Result(1, 'a'); + Buffer = std::string("\xd4\x01") + Result; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Extension); + EXPECT_EQ(Obj.Extension.Type, 0x01); + EXPECT_EQ(Obj.Extension.Bytes, Result); +} + +TEST_F(MsgPackReader, TestReadFixExt2) { + std::string Result(2, 'a'); + Buffer = std::string("\xd5\x01") + Result; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Extension); + EXPECT_EQ(Obj.Extension.Type, 0x01); + EXPECT_EQ(Obj.Extension.Bytes, Result); +} + +TEST_F(MsgPackReader, TestReadFixExt4) { + std::string Result(4, 'a'); + Buffer = std::string("\xd6\x01") + Result; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Extension); + EXPECT_EQ(Obj.Extension.Type, 0x01); + EXPECT_EQ(Obj.Extension.Bytes, Result); +} + +TEST_F(MsgPackReader, TestReadFixExt8) { + std::string Result(8, 'a'); + Buffer = std::string("\xd7\x01") + Result; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Extension); + EXPECT_EQ(Obj.Extension.Type, 0x01); + EXPECT_EQ(Obj.Extension.Bytes, Result); +} + +TEST_F(MsgPackReader, TestReadFixExt16) { + std::string Result(16, 'a'); + Buffer = std::string("\xd8\x01") + Result; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Extension); + EXPECT_EQ(Obj.Extension.Type, 0x01); + EXPECT_EQ(Obj.Extension.Bytes, Result); +} + +TEST_F(MsgPackReader, TestReadExt8Min) { + // There are fix variants for sizes 1 and 2 + Buffer.assign("\xc7\x00\x01", 3); + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Extension); + EXPECT_EQ(Obj.Extension.Type, 0x01); + EXPECT_EQ(Obj.Extension.Bytes, StringRef()); +} + +TEST_F(MsgPackReader, TestReadExt8Max) { + std::string Result(UINT8_MAX, 'a'); + Buffer = std::string("\xc7\xff\x01", 3) + Result; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Extension); + EXPECT_EQ(Obj.Extension.Type, 0x01); + EXPECT_EQ(Obj.Extension.Bytes, Result); +} + +TEST_F(MsgPackReader, TestReadExt16Min) { + std::string Result(static_cast(UINT8_MAX) + 1, 'a'); + Buffer = std::string("\xc8\x01\x00\x01", 4) + Result; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Extension); + EXPECT_EQ(Obj.Extension.Type, 0x01); + EXPECT_EQ(Obj.Extension.Bytes, Result); +} + +TEST_F(MsgPackReader, TestReadExt16Max) { + std::string Result(UINT16_MAX, 'a'); + Buffer = std::string("\xc8\xff\xff\x01") + Result; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Extension); + EXPECT_EQ(Obj.Extension.Type, 0x01); + EXPECT_EQ(Obj.Extension.Bytes, Result); +} + +TEST_F(MsgPackReader, TestReadExt32Min) { + std::string Result(static_cast(UINT16_MAX) + 1, 'a'); + Buffer = std::string("\xc9\x00\x01\x00\x00\x01", 6) + Result; + Reader MPReader(Buffer); + auto ContinueOrErr = MPReader.read(Obj); + EXPECT_TRUE(static_cast(ContinueOrErr)); + EXPECT_TRUE(*ContinueOrErr); + EXPECT_EQ(Obj.Kind, Type::Extension); + EXPECT_EQ(Obj.Extension.Type, 0x01); + EXPECT_EQ(Obj.Extension.Bytes, Result); +} Index: llvm/trunk/unittests/BinaryFormat/MsgPackWriterTest.cpp =================================================================== --- llvm/trunk/unittests/BinaryFormat/MsgPackWriterTest.cpp +++ llvm/trunk/unittests/BinaryFormat/MsgPackWriterTest.cpp @@ -0,0 +1,523 @@ +//===- MsgPackWriterTest.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/BinaryFormat/MsgPackWriter.h" +#include "llvm/BinaryFormat/MsgPack.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace llvm::msgpack; + +struct MsgPackWriter : testing::Test { + std::string Buffer; + llvm::raw_string_ostream OStream; + Writer MPWriter; + + MsgPackWriter() : OStream(Buffer), MPWriter(OStream) {} +}; + +TEST_F(MsgPackWriter, TestWriteNil) { + MPWriter.writeNil(); + EXPECT_EQ(OStream.str(), "\xc0"); +} + +TEST_F(MsgPackWriter, TestWriteBool) { + MPWriter.write(true); + MPWriter.write(false); + EXPECT_EQ(OStream.str(), "\xc3\xc2"); +} + +TEST_F(MsgPackWriter, TestWriteFixPositiveInt) { + // FixPositiveInt form bitpattern starts with 0, so max FixPositiveInt + // is 01111111 = 127 + for (uint64_t u = 0; u <= 127; ++u) { + Buffer.clear(); + MPWriter.write(u); + std::string Output = OStream.str(); + EXPECT_EQ(Output.size(), 1u); + EXPECT_EQ(Output.data()[0], static_cast(u)); + } +} + +TEST_F(MsgPackWriter, TestWriteUInt8Min) { + // See TestWriteFixPositiveInt for why 128 is the min non-fix Int8 + uint64_t u = 128; + MPWriter.write(u); + EXPECT_EQ(OStream.str(), "\xcc\x80"); +} + +TEST_F(MsgPackWriter, TestWriteUInt8) { + uint64_t u = 221; + MPWriter.write(u); + EXPECT_EQ(OStream.str(), "\xcc\xdd"); +} + +TEST_F(MsgPackWriter, TestWriteUInt8Max) { + uint64_t u = UINT8_MAX; + MPWriter.write(u); + EXPECT_EQ(OStream.str(), "\xcc\xff"); +} + +TEST_F(MsgPackWriter, TestWriteUInt16Min) { + uint64_t u = static_cast(UINT8_MAX) + 1; + MPWriter.write(u); + EXPECT_EQ(OStream.str(), std::string("\xcd\x01\x00", 3)); +} + +TEST_F(MsgPackWriter, TestWriteUInt16) { + uint64_t u = 43981; + MPWriter.write(u); + EXPECT_EQ(OStream.str(), "\xcd\xab\xcd"); +} + +TEST_F(MsgPackWriter, TestWriteUInt16Max) { + uint64_t u = UINT16_MAX; + MPWriter.write(u); + EXPECT_EQ(OStream.str(), "\xcd\xff\xff"); +} + +TEST_F(MsgPackWriter, TestWriteUInt32Min) { + uint64_t u = static_cast(UINT16_MAX) + 1; + MPWriter.write(u); + EXPECT_EQ(OStream.str(), std::string("\xce\x00\x01\x00\x00", 5)); +} + +TEST_F(MsgPackWriter, TestWriteUInt32) { + uint64_t u = 2882400186; + MPWriter.write(u); + EXPECT_EQ(OStream.str(), "\xce\xab\xcd\xef\xba"); +} + +TEST_F(MsgPackWriter, TestWriteUInt32Max) { + uint64_t u = UINT32_MAX; + MPWriter.write(u); + EXPECT_EQ(OStream.str(), "\xce\xff\xff\xff\xff"); +} + +TEST_F(MsgPackWriter, TestWriteUInt64Min) { + uint64_t u = static_cast(UINT32_MAX) + 1; + MPWriter.write(u); + EXPECT_EQ(OStream.str(), + std::string("\xcf\x00\x00\x00\x01\x00\x00\x00\x00", 9)); +} + +TEST_F(MsgPackWriter, TestWriteUInt64) { + uint64_t u = 0x010203040506074a; + MPWriter.write(u); + EXPECT_EQ(OStream.str(), "\xcf\x01\x02\x03\x04\x05\x06\x07\x4a"); +} + +TEST_F(MsgPackWriter, TestWriteUInt64Max) { + uint64_t u = UINT64_MAX; + MPWriter.write(u); + EXPECT_EQ(OStream.str(), "\xcf\xff\xff\xff\xff\xff\xff\xff\xff"); +} + +TEST_F(MsgPackWriter, TestWriteFixNegativeInt) { + // Positive values will be written in a UInt form, so max FixNegativeInt is -1 + // + // FixNegativeInt form bitpattern starts with 111, so min FixNegativeInt + // is 11100000 = -32 + for (int64_t i = -1; i >= -32; --i) { + Buffer.clear(); + MPWriter.write(i); + std::string Output = OStream.str(); + EXPECT_EQ(Output.size(), 1u); + EXPECT_EQ(Output.data()[0], static_cast(i)); + } +} + +TEST_F(MsgPackWriter, TestWriteInt8Max) { + // See TestWriteFixNegativeInt for why -33 is the max non-fix Int8 + int64_t i = -33; + MPWriter.write(i); + EXPECT_EQ(OStream.str(), "\xd0\xdf"); +} + +TEST_F(MsgPackWriter, TestWriteInt8) { + int64_t i = -40; + MPWriter.write(i); + EXPECT_EQ(OStream.str(), "\xd0\xd8"); +} + +TEST_F(MsgPackWriter, TestWriteInt8Min) { + int64_t i = INT8_MIN; + MPWriter.write(i); + EXPECT_EQ(OStream.str(), "\xd0\x80"); +} + +TEST_F(MsgPackWriter, TestWriteInt16Max) { + int64_t i = static_cast(INT8_MIN) - 1; + MPWriter.write(i); + EXPECT_EQ(OStream.str(), "\xd1\xff\x7f"); +} + +TEST_F(MsgPackWriter, TestWriteInt16) { + int64_t i = -4369; + MPWriter.write(i); + EXPECT_EQ(OStream.str(), "\xd1\xee\xef"); +} + +TEST_F(MsgPackWriter, TestWriteInt16Min) { + int64_t i = INT16_MIN; + MPWriter.write(i); + EXPECT_EQ(OStream.str(), std::string("\xd1\x80\x00", 3)); +} + +TEST_F(MsgPackWriter, TestWriteInt32Max) { + int64_t i = static_cast(INT16_MIN) - 1; + MPWriter.write(i); + EXPECT_EQ(OStream.str(), "\xd2\xff\xff\x7f\xff"); +} + +TEST_F(MsgPackWriter, TestWriteInt32) { + int64_t i = -286331153; + MPWriter.write(i); + EXPECT_EQ(OStream.str(), "\xd2\xee\xee\xee\xef"); +} + +TEST_F(MsgPackWriter, TestWriteInt32Min) { + int64_t i = INT32_MIN; + MPWriter.write(i); + EXPECT_EQ(OStream.str(), std::string("\xd2\x80\x00\x00\x00", 5)); +} + +TEST_F(MsgPackWriter, TestWriteInt64Max) { + int64_t i = static_cast(INT32_MIN) - 1; + MPWriter.write(i); + EXPECT_EQ(OStream.str(), "\xd3\xff\xff\xff\xff\x7f\xff\xff\xff"); +} + +TEST_F(MsgPackWriter, TestWriteInt64) { + int64_t i = -1229782938247303441; + MPWriter.write(i); + EXPECT_EQ(OStream.str(), "\xd3\xee\xee\xee\xee\xee\xee\xee\xef"); +} + +TEST_F(MsgPackWriter, TestWriteInt64Min) { + int64_t i = INT64_MIN; + MPWriter.write(i); + EXPECT_EQ(OStream.str(), + std::string("\xd3\x80\x00\x00\x00\x00\x00\x00\x00", 9)); +} + +TEST_F(MsgPackWriter, TestWriteFloat32) { + float f = -3.6973142664068907e+28; + MPWriter.write(f); + EXPECT_EQ(OStream.str(), "\xca\xee\xee\xee\xef"); +} + +TEST_F(MsgPackWriter, TestWriteFloat64) { + double d = -2.2899894549927042e+226; + MPWriter.write(d); + EXPECT_EQ(OStream.str(), "\xcb\xee\xee\xee\xee\xee\xee\xee\xef"); +} + +TEST_F(MsgPackWriter, TestWriteFixStrMin) { + std::string s; + MPWriter.write(s); + EXPECT_EQ(OStream.str(), "\xa0"); +} + +TEST_F(MsgPackWriter, TestWriteFixStr) { + std::string s = "foo"; + MPWriter.write(s); + EXPECT_EQ(OStream.str(), "\xa3" + "foo"); +} + +TEST_F(MsgPackWriter, TestWriteFixStrMax) { + // FixStr format's size is a 5 bit unsigned integer, so max is 11111 = 31 + std::string s(31, 'a'); + MPWriter.write(s); + EXPECT_EQ(OStream.str(), std::string("\xbf") + s); +} + +TEST_F(MsgPackWriter, TestWriteStr8Min) { + // See TestWriteFixStrMax for why 32 is the min non-fix Str8 + std::string s(32, 'a'); + MPWriter.write(s); + EXPECT_EQ(OStream.str(), std::string("\xd9\x20") + s); +} + +TEST_F(MsgPackWriter, TestWriteStr8) { + std::string s(33, 'a'); + MPWriter.write(s); + EXPECT_EQ(OStream.str(), std::string("\xd9\x21") + s); +} + +TEST_F(MsgPackWriter, TestWriteStr8Max) { + std::string s(UINT8_MAX, 'a'); + MPWriter.write(s); + EXPECT_EQ(OStream.str(), std::string("\xd9\xff") + s); +} + +TEST_F(MsgPackWriter, TestWriteStr16Min) { + std::string s(static_cast(UINT8_MAX) + 1, 'a'); + MPWriter.write(s); + EXPECT_EQ(OStream.str(), std::string("\xda\x01\x00", 3) + s); +} + +TEST_F(MsgPackWriter, TestWriteStr16) { + std::string s(511, 'a'); + MPWriter.write(s); + EXPECT_EQ(OStream.str(), std::string("\xda\x01\xff") + s); +} + +TEST_F(MsgPackWriter, TestWriteStr16Max) { + std::string s(UINT16_MAX, 'a'); + MPWriter.write(s); + EXPECT_EQ(OStream.str(), std::string("\xda\xff\xff") + s); +} + +TEST_F(MsgPackWriter, TestWriteStr32Min) { + std::string s(static_cast(UINT16_MAX) + 1, 'a'); + MPWriter.write(s); + EXPECT_EQ(OStream.str(), std::string("\xdb\x00\x01\x00\x00", 5) + s); +} + +TEST_F(MsgPackWriter, TestWriteStr32) { + std::string s(131071, 'a'); + MPWriter.write(s); + EXPECT_EQ(OStream.str(), std::string("\xdb\x00\x01\xff\xff", 5) + s); +} + +TEST_F(MsgPackWriter, TestWriteBin8Min) { + std::string s; + MPWriter.write(MemoryBufferRef(s, "")); + EXPECT_EQ(OStream.str(), std::string("\xc4\x00", 2) + s); +} + +TEST_F(MsgPackWriter, TestWriteBin8) { + std::string s(5, 'a'); + MPWriter.write(MemoryBufferRef(s, "")); + EXPECT_EQ(OStream.str(), std::string("\xc4\x05") + s); +} + +TEST_F(MsgPackWriter, TestWriteBin8Max) { + std::string s(UINT8_MAX, 'a'); + MPWriter.write(MemoryBufferRef(s, "")); + EXPECT_EQ(OStream.str(), std::string("\xc4\xff") + s); +} + +TEST_F(MsgPackWriter, TestWriteBin16Min) { + std::string s(static_cast(UINT8_MAX) + 1, 'a'); + MPWriter.write(MemoryBufferRef(s, "")); + EXPECT_EQ(OStream.str(), std::string("\xc5\x01\x00", 3) + s); +} + +TEST_F(MsgPackWriter, TestWriteBin16) { + std::string s(511, 'a'); + MPWriter.write(MemoryBufferRef(s, "")); + EXPECT_EQ(OStream.str(), "\xc5\x01\xff" + s); +} + +TEST_F(MsgPackWriter, TestWriteBin16Max) { + std::string s(UINT16_MAX, 'a'); + MPWriter.write(MemoryBufferRef(s, "")); + EXPECT_EQ(OStream.str(), std::string("\xc5\xff\xff") + s); +} + +TEST_F(MsgPackWriter, TestWriteBin32Min) { + std::string s(static_cast(UINT16_MAX) + 1, 'a'); + MPWriter.write(MemoryBufferRef(s, "")); + EXPECT_EQ(OStream.str(), std::string("\xc6\x00\x01\x00\x00", 5) + s); +} + +TEST_F(MsgPackWriter, TestWriteBin32) { + std::string s(131071, 'a'); + MPWriter.write(MemoryBufferRef(s, "")); + EXPECT_EQ(OStream.str(), std::string("\xc6\x00\x01\xff\xff", 5) + s); +} + +TEST_F(MsgPackWriter, TestWriteFixArrayMin) { + MPWriter.writeArraySize(0); + EXPECT_EQ(OStream.str(), "\x90"); +} + +TEST_F(MsgPackWriter, TestWriteFixArray) { + MPWriter.writeArraySize(4); + EXPECT_EQ(OStream.str(), "\x94"); +} + +TEST_F(MsgPackWriter, TestWriteFixArrayMax) { + // FixArray format's size is a 4 bit unsigned integer, so max is 1111 = 15 + MPWriter.writeArraySize(15); + EXPECT_EQ(OStream.str(), "\x9f"); +} + +TEST_F(MsgPackWriter, TestWriteArray16Min) { + // See TestWriteFixArrayMax for why 16 is the min non-fix Array16 + MPWriter.writeArraySize(16); + EXPECT_EQ(OStream.str(), std::string("\xdc\x00\x10", 3)); +} + +TEST_F(MsgPackWriter, TestWriteArray16) { + MPWriter.writeArraySize(273); + EXPECT_EQ(OStream.str(), "\xdc\x01\x11"); +} + +TEST_F(MsgPackWriter, TestWriteArray16Max) { + MPWriter.writeArraySize(UINT16_MAX); + EXPECT_EQ(OStream.str(), "\xdc\xff\xff"); +} + +TEST_F(MsgPackWriter, TestWriteArray32Min) { + MPWriter.writeArraySize(static_cast(UINT16_MAX) + 1); + EXPECT_EQ(OStream.str(), std::string("\xdd\x00\x01\x00\x00", 5)); +} + +TEST_F(MsgPackWriter, TestWriteArray32) { + MPWriter.writeArraySize(131071); + EXPECT_EQ(OStream.str(), std::string("\xdd\x00\x01\xff\xff", 5)); +} + +TEST_F(MsgPackWriter, TestWriteArray32Max) { + MPWriter.writeArraySize(UINT32_MAX); + EXPECT_EQ(OStream.str(), "\xdd\xff\xff\xff\xff"); +} + +TEST_F(MsgPackWriter, TestWriteFixMapMin) { + MPWriter.writeMapSize(0); + EXPECT_EQ(OStream.str(), "\x80"); +} + +TEST_F(MsgPackWriter, TestWriteFixMap) { + MPWriter.writeMapSize(4); + EXPECT_EQ(OStream.str(), "\x84"); +} + +TEST_F(MsgPackWriter, TestWriteFixMapMax) { + // FixMap format's size is a 4 bit unsigned integer, so max is 1111 = 15 + MPWriter.writeMapSize(15); + EXPECT_EQ(OStream.str(), "\x8f"); +} + +TEST_F(MsgPackWriter, TestWriteMap16Min) { + // See TestWriteFixMapMax for why 16 is the min non-fix Map16 + MPWriter.writeMapSize(16); + EXPECT_EQ(OStream.str(), std::string("\xde\x00\x10", 3)); +} + +TEST_F(MsgPackWriter, TestWriteMap16) { + MPWriter.writeMapSize(273); + EXPECT_EQ(OStream.str(), "\xde\x01\x11"); +} + +TEST_F(MsgPackWriter, TestWriteMap16Max) { + MPWriter.writeMapSize(UINT16_MAX); + EXPECT_EQ(OStream.str(), "\xde\xff\xff"); +} + +TEST_F(MsgPackWriter, TestWriteMap32Min) { + MPWriter.writeMapSize(static_cast(UINT16_MAX) + 1); + EXPECT_EQ(OStream.str(), std::string("\xdf\x00\x01\x00\x00", 5)); +} + +TEST_F(MsgPackWriter, TestWriteMap32) { + MPWriter.writeMapSize(131071); + EXPECT_EQ(OStream.str(), std::string("\xdf\x00\x01\xff\xff", 5)); +} + +TEST_F(MsgPackWriter, TestWriteMap32Max) { + MPWriter.writeMapSize(UINT32_MAX); + EXPECT_EQ(OStream.str(), std::string("\xdf\xff\xff\xff\xff", 5)); +} + +// FixExt formats are only available for these specific lengths: 1, 2, 4, 8, 16 + +TEST_F(MsgPackWriter, TestWriteFixExt1) { + std::string s(1, 'a'); + MPWriter.writeExt(0x01, MemoryBufferRef(s, "")); + EXPECT_EQ(OStream.str(), std::string("\xd4\x01") + s); +} + +TEST_F(MsgPackWriter, TestWriteFixExt2) { + std::string s(2, 'a'); + MPWriter.writeExt(0x01, MemoryBufferRef(s, "")); + EXPECT_EQ(OStream.str(), std::string("\xd5\x01") + s); +} + +TEST_F(MsgPackWriter, TestWriteFixExt4) { + std::string s(4, 'a'); + MPWriter.writeExt(0x01, MemoryBufferRef(s, "")); + EXPECT_EQ(OStream.str(), std::string("\xd6\x01") + s); +} + +TEST_F(MsgPackWriter, TestWriteFixExt8) { + std::string s(8, 'a'); + MPWriter.writeExt(0x01, MemoryBufferRef(s, "")); + EXPECT_EQ(OStream.str(), std::string("\xd7\x01") + s); +} + +TEST_F(MsgPackWriter, TestWriteFixExt16) { + std::string s(16, 'a'); + MPWriter.writeExt(0x01, MemoryBufferRef(s, "")); + EXPECT_EQ(OStream.str(), std::string("\xd8\x01") + s); +} + +TEST_F(MsgPackWriter, TestWriteExt8Min) { + std::string s; + MPWriter.writeExt(0x01, MemoryBufferRef(s, "")); + EXPECT_EQ(OStream.str(), std::string("\xc7\x00\x01", 3) + s); +} + +TEST_F(MsgPackWriter, TestWriteExt8) { + std::string s(0x2a, 'a'); + MPWriter.writeExt(0x01, MemoryBufferRef(s, "")); + EXPECT_EQ(OStream.str(), std::string("\xc7\x2a\x01") + s); +} + +TEST_F(MsgPackWriter, TestWriteExt8Max) { + std::string s(UINT8_MAX, 'a'); + MPWriter.writeExt(0x01, MemoryBufferRef(s, "")); + EXPECT_EQ(OStream.str(), std::string("\xc7\xff\x01") + s); +} + +TEST_F(MsgPackWriter, TestWriteExt16Min) { + std::string s(static_cast(UINT8_MAX) + 1, 'a'); + MPWriter.writeExt(0x02, MemoryBufferRef(s, "")); + EXPECT_EQ(OStream.str(), std::string("\xc8\x01\x00\x02", 4) + s); +} + +TEST_F(MsgPackWriter, TestWriteExt16) { + std::string s(273, 'a'); + MPWriter.writeExt(0x01, MemoryBufferRef(s, "")); + EXPECT_EQ(OStream.str(), std::string("\xc8\x01\x11\x01") + s); +} + +TEST_F(MsgPackWriter, TestWriteExt16Max) { + std::string s(UINT16_MAX, 'a'); + MPWriter.writeExt(0x01, MemoryBufferRef(s, "")); + EXPECT_EQ(OStream.str(), std::string("\xc8\xff\xff\x01") + s); +} + +TEST_F(MsgPackWriter, TestWriteExt32Min) { + std::string s(static_cast(UINT16_MAX) + 1, 'a'); + MPWriter.writeExt(0x02, MemoryBufferRef(s, "")); + EXPECT_EQ(OStream.str(), std::string("\xc9\x00\x01\x00\x00\x02", 6) + s); +} + +TEST_F(MsgPackWriter, TestWriteCompatibleNoStr8) { + Writer CompatWriter(OStream, true); + std::string s(32, 'a'); + CompatWriter.write(s); + EXPECT_EQ(OStream.str(), std::string("\xda\x00\x20", 3) + s); +} + +TEST_F(MsgPackWriter, TestWriteCompatibleNoBin) { + Writer CompatWriter(OStream, true); + std::string s; + +#ifdef GTEST_HAS_DEATH_TEST +#ifndef NDEBUG + EXPECT_DEATH(CompatWriter.write(MemoryBufferRef(s, "")), "compatible mode"); +#endif +#endif +}