//===- 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" #include "llvm/Support/MathExtras.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 = llvm::bit_cast(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 = llvm::bit_cast(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; }