| //===- MsgPackReader.cpp - Simple MsgPack reader ----------------*- C++ -*-===// | |
| // | |
| // 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 | |
| // | |
| //===----------------------------------------------------------------------===// | |
| /// | |
| /// \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<bool> Reader::read(Object &Obj) { | |
| if (Current == End) | |
| return false; | |
| uint8_t FB = static_cast<uint8_t>(*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<int8_t>(Obj); | |
| case FirstByte::Int16: | |
| Obj.Kind = Type::Int; | |
| return readInt<int16_t>(Obj); | |
| case FirstByte::Int32: | |
| Obj.Kind = Type::Int; | |
| return readInt<int32_t>(Obj); | |
| case FirstByte::Int64: | |
| Obj.Kind = Type::Int; | |
| return readInt<int64_t>(Obj); | |
| case FirstByte::UInt8: | |
| Obj.Kind = Type::UInt; | |
| return readUInt<uint8_t>(Obj); | |
| case FirstByte::UInt16: | |
| Obj.Kind = Type::UInt; | |
| return readUInt<uint16_t>(Obj); | |
| case FirstByte::UInt32: | |
| Obj.Kind = Type::UInt; | |
| return readUInt<uint32_t>(Obj); | |
| case FirstByte::UInt64: | |
| Obj.Kind = Type::UInt; | |
| return readUInt<uint64_t>(Obj); | |
| case FirstByte::Float32: | |
| Obj.Kind = Type::Float; | |
| if (sizeof(float) > remainingSpace()) | |
| return make_error<StringError>( | |
| "Invalid Float32 with insufficient payload", | |
| std::make_error_code(std::errc::invalid_argument)); | |
| Obj.Float = | |
| llvm::bit_cast<float>(endian::read<uint32_t, Endianness>(Current)); | |
| Current += sizeof(float); | |
| return true; | |
| case FirstByte::Float64: | |
| Obj.Kind = Type::Float; | |
| if (sizeof(double) > remainingSpace()) | |
| return make_error<StringError>( | |
| "Invalid Float64 with insufficient payload", | |
| std::make_error_code(std::errc::invalid_argument)); | |
| Obj.Float = | |
| llvm::bit_cast<double>(endian::read<uint64_t, Endianness>(Current)); | |
| Current += sizeof(double); | |
| return true; | |
| case FirstByte::Str8: | |
| Obj.Kind = Type::String; | |
| return readRaw<uint8_t>(Obj); | |
| case FirstByte::Str16: | |
| Obj.Kind = Type::String; | |
| return readRaw<uint16_t>(Obj); | |
| case FirstByte::Str32: | |
| Obj.Kind = Type::String; | |
| return readRaw<uint32_t>(Obj); | |
| case FirstByte::Bin8: | |
| Obj.Kind = Type::Binary; | |
| return readRaw<uint8_t>(Obj); | |
| case FirstByte::Bin16: | |
| Obj.Kind = Type::Binary; | |
| return readRaw<uint16_t>(Obj); | |
| case FirstByte::Bin32: | |
| Obj.Kind = Type::Binary; | |
| return readRaw<uint32_t>(Obj); | |
| case FirstByte::Array16: | |
| Obj.Kind = Type::Array; | |
| return readLength<uint16_t>(Obj); | |
| case FirstByte::Array32: | |
| Obj.Kind = Type::Array; | |
| return readLength<uint32_t>(Obj); | |
| case FirstByte::Map16: | |
| Obj.Kind = Type::Map; | |
| return readLength<uint16_t>(Obj); | |
| case FirstByte::Map32: | |
| Obj.Kind = Type::Map; | |
| return readLength<uint32_t>(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<uint8_t>(Obj); | |
| case FirstByte::Ext16: | |
| Obj.Kind = Type::Extension; | |
| return readExt<uint16_t>(Obj); | |
| case FirstByte::Ext32: | |
| Obj.Kind = Type::Extension; | |
| return readExt<uint32_t>(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<StringError>( | |
| "Invalid first byte", std::make_error_code(std::errc::invalid_argument)); | |
| } | |
| template <class T> Expected<bool> Reader::readRaw(Object &Obj) { | |
| if (sizeof(T) > remainingSpace()) | |
| return make_error<StringError>( | |
| "Invalid Raw with insufficient payload", | |
| std::make_error_code(std::errc::invalid_argument)); | |
| T Size = endian::read<T, Endianness>(Current); | |
| Current += sizeof(T); | |
| return createRaw(Obj, Size); | |
| } | |
| template <class T> Expected<bool> Reader::readInt(Object &Obj) { | |
| if (sizeof(T) > remainingSpace()) | |
| return make_error<StringError>( | |
| "Invalid Int with insufficient payload", | |
| std::make_error_code(std::errc::invalid_argument)); | |
| Obj.Int = static_cast<int64_t>(endian::read<T, Endianness>(Current)); | |
| Current += sizeof(T); | |
| return true; | |
| } | |
| template <class T> Expected<bool> Reader::readUInt(Object &Obj) { | |
| if (sizeof(T) > remainingSpace()) | |
| return make_error<StringError>( | |
| "Invalid Int with insufficient payload", | |
| std::make_error_code(std::errc::invalid_argument)); | |
| Obj.UInt = static_cast<uint64_t>(endian::read<T, Endianness>(Current)); | |
| Current += sizeof(T); | |
| return true; | |
| } | |
| template <class T> Expected<bool> Reader::readLength(Object &Obj) { | |
| if (sizeof(T) > remainingSpace()) | |
| return make_error<StringError>( | |
| "Invalid Map/Array with invalid length", | |
| std::make_error_code(std::errc::invalid_argument)); | |
| Obj.Length = static_cast<size_t>(endian::read<T, Endianness>(Current)); | |
| Current += sizeof(T); | |
| return true; | |
| } | |
| template <class T> Expected<bool> Reader::readExt(Object &Obj) { | |
| if (sizeof(T) > remainingSpace()) | |
| return make_error<StringError>( | |
| "Invalid Ext with invalid length", | |
| std::make_error_code(std::errc::invalid_argument)); | |
| T Size = endian::read<T, Endianness>(Current); | |
| Current += sizeof(T); | |
| return createExt(Obj, Size); | |
| } | |
| Expected<bool> Reader::createRaw(Object &Obj, uint32_t Size) { | |
| if (Size > remainingSpace()) | |
| return make_error<StringError>( | |
| "Invalid Raw with insufficient payload", | |
| std::make_error_code(std::errc::invalid_argument)); | |
| Obj.Raw = StringRef(Current, Size); | |
| Current += Size; | |
| return true; | |
| } | |
| Expected<bool> Reader::createExt(Object &Obj, uint32_t Size) { | |
| if (Current == End) | |
| return make_error<StringError>( | |
| "Invalid Ext with no type", | |
| std::make_error_code(std::errc::invalid_argument)); | |
| Obj.Extension.Type = *Current++; | |
| if (Size > remainingSpace()) | |
| return make_error<StringError>( | |
| "Invalid Ext with insufficient payload", | |
| std::make_error_code(std::errc::invalid_argument)); | |
| Obj.Extension.Bytes = StringRef(Current, Size); | |
| Current += Size; | |
| return true; | |
| } |