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