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