1//===- MsgPackReader.cpp - Simple MsgPack reader ----------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9///  \file
10///  This file implements a MessagePack reader.
11///
12//===----------------------------------------------------------------------===//
13
14#include "llvm/BinaryFormat/MsgPackReader.h"
15#include "llvm/BinaryFormat/MsgPack.h"
16#include "llvm/Support/Endian.h"
17
18using namespace llvm;
19using namespace llvm::support;
20using namespace msgpack;
21
22Reader::Reader(MemoryBufferRef InputBuffer)
23    : InputBuffer(InputBuffer), Current(InputBuffer.getBufferStart()),
24      End(InputBuffer.getBufferEnd()) {}
25
26Reader::Reader(StringRef Input) : Reader({Input, "MsgPack"}) {}
27
28Expected<bool> Reader::read(Object &Obj) {
29  if (Current == End)
30    return false;
31
32  uint8_t FB = static_cast<uint8_t>(*Current++);
33
34  switch (FB) {
35  case FirstByte::Nil:
36    Obj.Kind = Type::Nil;
37    return true;
38  case FirstByte::True:
39    Obj.Kind = Type::Boolean;
40    Obj.Bool = true;
41    return true;
42  case FirstByte::False:
43    Obj.Kind = Type::Boolean;
44    Obj.Bool = false;
45    return true;
46  case FirstByte::Int8:
47    Obj.Kind = Type::Int;
48    return readInt<int8_t>(Obj);
49  case FirstByte::Int16:
50    Obj.Kind = Type::Int;
51    return readInt<int16_t>(Obj);
52  case FirstByte::Int32:
53    Obj.Kind = Type::Int;
54    return readInt<int32_t>(Obj);
55  case FirstByte::Int64:
56    Obj.Kind = Type::Int;
57    return readInt<int64_t>(Obj);
58  case FirstByte::UInt8:
59    Obj.Kind = Type::UInt;
60    return readUInt<uint8_t>(Obj);
61  case FirstByte::UInt16:
62    Obj.Kind = Type::UInt;
63    return readUInt<uint16_t>(Obj);
64  case FirstByte::UInt32:
65    Obj.Kind = Type::UInt;
66    return readUInt<uint32_t>(Obj);
67  case FirstByte::UInt64:
68    Obj.Kind = Type::UInt;
69    return readUInt<uint64_t>(Obj);
70  case FirstByte::Float32:
71    Obj.Kind = Type::Float;
72    if (sizeof(float) > remainingSpace())
73      return make_error<StringError>(
74          "Invalid Float32 with insufficient payload",
75          std::make_error_code(std::errc::invalid_argument));
76    Obj.Float = BitsToFloat(endian::read<uint32_t, Endianness>(Current));
77    Current += sizeof(float);
78    return true;
79  case FirstByte::Float64:
80    Obj.Kind = Type::Float;
81    if (sizeof(double) > remainingSpace())
82      return make_error<StringError>(
83          "Invalid Float64 with insufficient payload",
84          std::make_error_code(std::errc::invalid_argument));
85    Obj.Float = BitsToDouble(endian::read<uint64_t, Endianness>(Current));
86    Current += sizeof(double);
87    return true;
88  case FirstByte::Str8:
89    Obj.Kind = Type::String;
90    return readRaw<uint8_t>(Obj);
91  case FirstByte::Str16:
92    Obj.Kind = Type::String;
93    return readRaw<uint16_t>(Obj);
94  case FirstByte::Str32:
95    Obj.Kind = Type::String;
96    return readRaw<uint32_t>(Obj);
97  case FirstByte::Bin8:
98    Obj.Kind = Type::Binary;
99    return readRaw<uint8_t>(Obj);
100  case FirstByte::Bin16:
101    Obj.Kind = Type::Binary;
102    return readRaw<uint16_t>(Obj);
103  case FirstByte::Bin32:
104    Obj.Kind = Type::Binary;
105    return readRaw<uint32_t>(Obj);
106  case FirstByte::Array16:
107    Obj.Kind = Type::Array;
108    return readLength<uint16_t>(Obj);
109  case FirstByte::Array32:
110    Obj.Kind = Type::Array;
111    return readLength<uint32_t>(Obj);
112  case FirstByte::Map16:
113    Obj.Kind = Type::Map;
114    return readLength<uint16_t>(Obj);
115  case FirstByte::Map32:
116    Obj.Kind = Type::Map;
117    return readLength<uint32_t>(Obj);
118  case FirstByte::FixExt1:
119    Obj.Kind = Type::Extension;
120    return createExt(Obj, FixLen::Ext1);
121  case FirstByte::FixExt2:
122    Obj.Kind = Type::Extension;
123    return createExt(Obj, FixLen::Ext2);
124  case FirstByte::FixExt4:
125    Obj.Kind = Type::Extension;
126    return createExt(Obj, FixLen::Ext4);
127  case FirstByte::FixExt8:
128    Obj.Kind = Type::Extension;
129    return createExt(Obj, FixLen::Ext8);
130  case FirstByte::FixExt16:
131    Obj.Kind = Type::Extension;
132    return createExt(Obj, FixLen::Ext16);
133  case FirstByte::Ext8:
134    Obj.Kind = Type::Extension;
135    return readExt<uint8_t>(Obj);
136  case FirstByte::Ext16:
137    Obj.Kind = Type::Extension;
138    return readExt<uint16_t>(Obj);
139  case FirstByte::Ext32:
140    Obj.Kind = Type::Extension;
141    return readExt<uint32_t>(Obj);
142  }
143
144  if ((FB & FixBitsMask::NegativeInt) == FixBits::NegativeInt) {
145    Obj.Kind = Type::Int;
146    int8_t I;
147    static_assert(sizeof(I) == sizeof(FB), "Unexpected type sizes");
148    memcpy(&I, &FB, sizeof(FB));
149    Obj.Int = I;
150    return true;
151  }
152
153  if ((FB & FixBitsMask::PositiveInt) == FixBits::PositiveInt) {
154    Obj.Kind = Type::UInt;
155    Obj.UInt = FB;
156    return true;
157  }
158
159  if ((FB & FixBitsMask::String) == FixBits::String) {
160    Obj.Kind = Type::String;
161    uint8_t Size = FB & ~FixBitsMask::String;
162    return createRaw(Obj, Size);
163  }
164
165  if ((FB & FixBitsMask::Array) == FixBits::Array) {
166    Obj.Kind = Type::Array;
167    Obj.Length = FB & ~FixBitsMask::Array;
168    return true;
169  }
170
171  if ((FB & FixBitsMask::Map) == FixBits::Map) {
172    Obj.Kind = Type::Map;
173    Obj.Length = FB & ~FixBitsMask::Map;
174    return true;
175  }
176
177  return make_error<StringError>(
178      "Invalid first byte", std::make_error_code(std::errc::invalid_argument));
179}
180
181template <class T> Expected<bool> Reader::readRaw(Object &Obj) {
182  if (sizeof(T) > remainingSpace())
183    return make_error<StringError>(
184        "Invalid Raw with insufficient payload",
185        std::make_error_code(std::errc::invalid_argument));
186  T Size = endian::read<T, Endianness>(Current);
187  Current += sizeof(T);
188  return createRaw(Obj, Size);
189}
190
191template <class T> Expected<bool> Reader::readInt(Object &Obj) {
192  if (sizeof(T) > remainingSpace())
193    return make_error<StringError>(
194        "Invalid Int with insufficient payload",
195        std::make_error_code(std::errc::invalid_argument));
196  Obj.Int = static_cast<int64_t>(endian::read<T, Endianness>(Current));
197  Current += sizeof(T);
198  return true;
199}
200
201template <class T> Expected<bool> Reader::readUInt(Object &Obj) {
202  if (sizeof(T) > remainingSpace())
203    return make_error<StringError>(
204        "Invalid Int with insufficient payload",
205        std::make_error_code(std::errc::invalid_argument));
206  Obj.UInt = static_cast<uint64_t>(endian::read<T, Endianness>(Current));
207  Current += sizeof(T);
208  return true;
209}
210
211template <class T> Expected<bool> Reader::readLength(Object &Obj) {
212  if (sizeof(T) > remainingSpace())
213    return make_error<StringError>(
214        "Invalid Map/Array with invalid length",
215        std::make_error_code(std::errc::invalid_argument));
216  Obj.Length = static_cast<size_t>(endian::read<T, Endianness>(Current));
217  Current += sizeof(T);
218  return true;
219}
220
221template <class T> Expected<bool> Reader::readExt(Object &Obj) {
222  if (sizeof(T) > remainingSpace())
223    return make_error<StringError>(
224        "Invalid Ext with invalid length",
225        std::make_error_code(std::errc::invalid_argument));
226  T Size = endian::read<T, Endianness>(Current);
227  Current += sizeof(T);
228  return createExt(Obj, Size);
229}
230
231Expected<bool> Reader::createRaw(Object &Obj, uint32_t Size) {
232  if (Size > remainingSpace())
233    return make_error<StringError>(
234        "Invalid Raw with insufficient payload",
235        std::make_error_code(std::errc::invalid_argument));
236  Obj.Raw = StringRef(Current, Size);
237  Current += Size;
238  return true;
239}
240
241Expected<bool> Reader::createExt(Object &Obj, uint32_t Size) {
242  if (Current == End)
243    return make_error<StringError>(
244        "Invalid Ext with no type",
245        std::make_error_code(std::errc::invalid_argument));
246  Obj.Extension.Type = *Current++;
247  if (Size > remainingSpace())
248    return make_error<StringError>(
249        "Invalid Ext with insufficient payload",
250        std::make_error_code(std::errc::invalid_argument));
251  Obj.Extension.Bytes = StringRef(Current, Size);
252  Current += Size;
253  return true;
254}
255