1343171Sdim//===- MsgPackReader.cpp - Simple MsgPack reader ----------------*- C++ -*-===// 2343171Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6343171Sdim// 7343171Sdim//===----------------------------------------------------------------------===// 8343171Sdim/// 9343171Sdim/// \file 10343171Sdim/// This file implements a MessagePack reader. 11343171Sdim/// 12343171Sdim//===----------------------------------------------------------------------===// 13343171Sdim 14343171Sdim#include "llvm/BinaryFormat/MsgPackReader.h" 15343171Sdim#include "llvm/BinaryFormat/MsgPack.h" 16343171Sdim#include "llvm/Support/Endian.h" 17343171Sdim 18343171Sdimusing namespace llvm; 19343171Sdimusing namespace llvm::support; 20343171Sdimusing namespace msgpack; 21343171Sdim 22343171SdimReader::Reader(MemoryBufferRef InputBuffer) 23343171Sdim : InputBuffer(InputBuffer), Current(InputBuffer.getBufferStart()), 24343171Sdim End(InputBuffer.getBufferEnd()) {} 25343171Sdim 26343171SdimReader::Reader(StringRef Input) : Reader({Input, "MsgPack"}) {} 27343171Sdim 28343171SdimExpected<bool> Reader::read(Object &Obj) { 29343171Sdim if (Current == End) 30343171Sdim return false; 31343171Sdim 32343171Sdim uint8_t FB = static_cast<uint8_t>(*Current++); 33343171Sdim 34343171Sdim switch (FB) { 35343171Sdim case FirstByte::Nil: 36343171Sdim Obj.Kind = Type::Nil; 37343171Sdim return true; 38343171Sdim case FirstByte::True: 39343171Sdim Obj.Kind = Type::Boolean; 40343171Sdim Obj.Bool = true; 41343171Sdim return true; 42343171Sdim case FirstByte::False: 43343171Sdim Obj.Kind = Type::Boolean; 44343171Sdim Obj.Bool = false; 45343171Sdim return true; 46343171Sdim case FirstByte::Int8: 47343171Sdim Obj.Kind = Type::Int; 48343171Sdim return readInt<int8_t>(Obj); 49343171Sdim case FirstByte::Int16: 50343171Sdim Obj.Kind = Type::Int; 51343171Sdim return readInt<int16_t>(Obj); 52343171Sdim case FirstByte::Int32: 53343171Sdim Obj.Kind = Type::Int; 54343171Sdim return readInt<int32_t>(Obj); 55343171Sdim case FirstByte::Int64: 56343171Sdim Obj.Kind = Type::Int; 57343171Sdim return readInt<int64_t>(Obj); 58343171Sdim case FirstByte::UInt8: 59343171Sdim Obj.Kind = Type::UInt; 60343171Sdim return readUInt<uint8_t>(Obj); 61343171Sdim case FirstByte::UInt16: 62343171Sdim Obj.Kind = Type::UInt; 63343171Sdim return readUInt<uint16_t>(Obj); 64343171Sdim case FirstByte::UInt32: 65343171Sdim Obj.Kind = Type::UInt; 66343171Sdim return readUInt<uint32_t>(Obj); 67343171Sdim case FirstByte::UInt64: 68343171Sdim Obj.Kind = Type::UInt; 69343171Sdim return readUInt<uint64_t>(Obj); 70343171Sdim case FirstByte::Float32: 71343171Sdim Obj.Kind = Type::Float; 72343171Sdim if (sizeof(float) > remainingSpace()) 73343171Sdim return make_error<StringError>( 74343171Sdim "Invalid Float32 with insufficient payload", 75343171Sdim std::make_error_code(std::errc::invalid_argument)); 76343171Sdim Obj.Float = BitsToFloat(endian::read<uint32_t, Endianness>(Current)); 77343171Sdim Current += sizeof(float); 78343171Sdim return true; 79343171Sdim case FirstByte::Float64: 80343171Sdim Obj.Kind = Type::Float; 81343171Sdim if (sizeof(double) > remainingSpace()) 82343171Sdim return make_error<StringError>( 83343171Sdim "Invalid Float64 with insufficient payload", 84343171Sdim std::make_error_code(std::errc::invalid_argument)); 85343171Sdim Obj.Float = BitsToDouble(endian::read<uint64_t, Endianness>(Current)); 86343171Sdim Current += sizeof(double); 87343171Sdim return true; 88343171Sdim case FirstByte::Str8: 89343171Sdim Obj.Kind = Type::String; 90343171Sdim return readRaw<uint8_t>(Obj); 91343171Sdim case FirstByte::Str16: 92343171Sdim Obj.Kind = Type::String; 93343171Sdim return readRaw<uint16_t>(Obj); 94343171Sdim case FirstByte::Str32: 95343171Sdim Obj.Kind = Type::String; 96343171Sdim return readRaw<uint32_t>(Obj); 97343171Sdim case FirstByte::Bin8: 98343171Sdim Obj.Kind = Type::Binary; 99343171Sdim return readRaw<uint8_t>(Obj); 100343171Sdim case FirstByte::Bin16: 101343171Sdim Obj.Kind = Type::Binary; 102343171Sdim return readRaw<uint16_t>(Obj); 103343171Sdim case FirstByte::Bin32: 104343171Sdim Obj.Kind = Type::Binary; 105343171Sdim return readRaw<uint32_t>(Obj); 106343171Sdim case FirstByte::Array16: 107343171Sdim Obj.Kind = Type::Array; 108343171Sdim return readLength<uint16_t>(Obj); 109343171Sdim case FirstByte::Array32: 110343171Sdim Obj.Kind = Type::Array; 111343171Sdim return readLength<uint32_t>(Obj); 112343171Sdim case FirstByte::Map16: 113343171Sdim Obj.Kind = Type::Map; 114343171Sdim return readLength<uint16_t>(Obj); 115343171Sdim case FirstByte::Map32: 116343171Sdim Obj.Kind = Type::Map; 117343171Sdim return readLength<uint32_t>(Obj); 118343171Sdim case FirstByte::FixExt1: 119343171Sdim Obj.Kind = Type::Extension; 120343171Sdim return createExt(Obj, FixLen::Ext1); 121343171Sdim case FirstByte::FixExt2: 122343171Sdim Obj.Kind = Type::Extension; 123343171Sdim return createExt(Obj, FixLen::Ext2); 124343171Sdim case FirstByte::FixExt4: 125343171Sdim Obj.Kind = Type::Extension; 126343171Sdim return createExt(Obj, FixLen::Ext4); 127343171Sdim case FirstByte::FixExt8: 128343171Sdim Obj.Kind = Type::Extension; 129343171Sdim return createExt(Obj, FixLen::Ext8); 130343171Sdim case FirstByte::FixExt16: 131343171Sdim Obj.Kind = Type::Extension; 132343171Sdim return createExt(Obj, FixLen::Ext16); 133343171Sdim case FirstByte::Ext8: 134343171Sdim Obj.Kind = Type::Extension; 135343171Sdim return readExt<uint8_t>(Obj); 136343171Sdim case FirstByte::Ext16: 137343171Sdim Obj.Kind = Type::Extension; 138343171Sdim return readExt<uint16_t>(Obj); 139343171Sdim case FirstByte::Ext32: 140343171Sdim Obj.Kind = Type::Extension; 141343171Sdim return readExt<uint32_t>(Obj); 142343171Sdim } 143343171Sdim 144343171Sdim if ((FB & FixBitsMask::NegativeInt) == FixBits::NegativeInt) { 145343171Sdim Obj.Kind = Type::Int; 146343171Sdim int8_t I; 147343171Sdim static_assert(sizeof(I) == sizeof(FB), "Unexpected type sizes"); 148343171Sdim memcpy(&I, &FB, sizeof(FB)); 149343171Sdim Obj.Int = I; 150343171Sdim return true; 151343171Sdim } 152343171Sdim 153343171Sdim if ((FB & FixBitsMask::PositiveInt) == FixBits::PositiveInt) { 154343171Sdim Obj.Kind = Type::UInt; 155343171Sdim Obj.UInt = FB; 156343171Sdim return true; 157343171Sdim } 158343171Sdim 159343171Sdim if ((FB & FixBitsMask::String) == FixBits::String) { 160343171Sdim Obj.Kind = Type::String; 161343171Sdim uint8_t Size = FB & ~FixBitsMask::String; 162343171Sdim return createRaw(Obj, Size); 163343171Sdim } 164343171Sdim 165343171Sdim if ((FB & FixBitsMask::Array) == FixBits::Array) { 166343171Sdim Obj.Kind = Type::Array; 167343171Sdim Obj.Length = FB & ~FixBitsMask::Array; 168343171Sdim return true; 169343171Sdim } 170343171Sdim 171343171Sdim if ((FB & FixBitsMask::Map) == FixBits::Map) { 172343171Sdim Obj.Kind = Type::Map; 173343171Sdim Obj.Length = FB & ~FixBitsMask::Map; 174343171Sdim return true; 175343171Sdim } 176343171Sdim 177343171Sdim return make_error<StringError>( 178343171Sdim "Invalid first byte", std::make_error_code(std::errc::invalid_argument)); 179343171Sdim} 180343171Sdim 181343171Sdimtemplate <class T> Expected<bool> Reader::readRaw(Object &Obj) { 182343171Sdim if (sizeof(T) > remainingSpace()) 183343171Sdim return make_error<StringError>( 184343171Sdim "Invalid Raw with insufficient payload", 185343171Sdim std::make_error_code(std::errc::invalid_argument)); 186343171Sdim T Size = endian::read<T, Endianness>(Current); 187343171Sdim Current += sizeof(T); 188343171Sdim return createRaw(Obj, Size); 189343171Sdim} 190343171Sdim 191343171Sdimtemplate <class T> Expected<bool> Reader::readInt(Object &Obj) { 192343171Sdim if (sizeof(T) > remainingSpace()) 193343171Sdim return make_error<StringError>( 194343171Sdim "Invalid Int with insufficient payload", 195343171Sdim std::make_error_code(std::errc::invalid_argument)); 196343171Sdim Obj.Int = static_cast<int64_t>(endian::read<T, Endianness>(Current)); 197343171Sdim Current += sizeof(T); 198343171Sdim return true; 199343171Sdim} 200343171Sdim 201343171Sdimtemplate <class T> Expected<bool> Reader::readUInt(Object &Obj) { 202343171Sdim if (sizeof(T) > remainingSpace()) 203343171Sdim return make_error<StringError>( 204343171Sdim "Invalid Int with insufficient payload", 205343171Sdim std::make_error_code(std::errc::invalid_argument)); 206343171Sdim Obj.UInt = static_cast<uint64_t>(endian::read<T, Endianness>(Current)); 207343171Sdim Current += sizeof(T); 208343171Sdim return true; 209343171Sdim} 210343171Sdim 211343171Sdimtemplate <class T> Expected<bool> Reader::readLength(Object &Obj) { 212343171Sdim if (sizeof(T) > remainingSpace()) 213343171Sdim return make_error<StringError>( 214343171Sdim "Invalid Map/Array with invalid length", 215343171Sdim std::make_error_code(std::errc::invalid_argument)); 216343171Sdim Obj.Length = static_cast<size_t>(endian::read<T, Endianness>(Current)); 217343171Sdim Current += sizeof(T); 218343171Sdim return true; 219343171Sdim} 220343171Sdim 221343171Sdimtemplate <class T> Expected<bool> Reader::readExt(Object &Obj) { 222343171Sdim if (sizeof(T) > remainingSpace()) 223343171Sdim return make_error<StringError>( 224343171Sdim "Invalid Ext with invalid length", 225343171Sdim std::make_error_code(std::errc::invalid_argument)); 226343171Sdim T Size = endian::read<T, Endianness>(Current); 227343171Sdim Current += sizeof(T); 228343171Sdim return createExt(Obj, Size); 229343171Sdim} 230343171Sdim 231343171SdimExpected<bool> Reader::createRaw(Object &Obj, uint32_t Size) { 232343171Sdim if (Size > remainingSpace()) 233343171Sdim return make_error<StringError>( 234343171Sdim "Invalid Raw with insufficient payload", 235343171Sdim std::make_error_code(std::errc::invalid_argument)); 236343171Sdim Obj.Raw = StringRef(Current, Size); 237343171Sdim Current += Size; 238343171Sdim return true; 239343171Sdim} 240343171Sdim 241343171SdimExpected<bool> Reader::createExt(Object &Obj, uint32_t Size) { 242343171Sdim if (Current == End) 243343171Sdim return make_error<StringError>( 244343171Sdim "Invalid Ext with no type", 245343171Sdim std::make_error_code(std::errc::invalid_argument)); 246343171Sdim Obj.Extension.Type = *Current++; 247343171Sdim if (Size > remainingSpace()) 248343171Sdim return make_error<StringError>( 249343171Sdim "Invalid Ext with insufficient payload", 250343171Sdim std::make_error_code(std::errc::invalid_argument)); 251343171Sdim Obj.Extension.Bytes = StringRef(Current, Size); 252343171Sdim Current += Size; 253343171Sdim return true; 254343171Sdim} 255