1//===- MsgPackWriter.cpp - Simple MsgPack writer ----------------*- 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 writer.
11///
12//===----------------------------------------------------------------------===//
13
14#include "llvm/BinaryFormat/MsgPackWriter.h"
15#include "llvm/BinaryFormat/MsgPack.h"
16
17using namespace llvm;
18using namespace msgpack;
19
20Writer::Writer(raw_ostream &OS, bool Compatible)
21    : EW(OS, Endianness), Compatible(Compatible) {}
22
23void Writer::writeNil() { EW.write(FirstByte::Nil); }
24
25void Writer::write(bool b) { EW.write(b ? FirstByte::True : FirstByte::False); }
26
27void Writer::write(int64_t i) {
28  if (i >= 0) {
29    write(static_cast<uint64_t>(i));
30    return;
31  }
32
33  if (i >= FixMin::NegativeInt) {
34    EW.write(static_cast<int8_t>(i));
35    return;
36  }
37
38  if (i >= INT8_MIN) {
39    EW.write(FirstByte::Int8);
40    EW.write(static_cast<int8_t>(i));
41    return;
42  }
43
44  if (i >= INT16_MIN) {
45    EW.write(FirstByte::Int16);
46    EW.write(static_cast<int16_t>(i));
47    return;
48  }
49
50  if (i >= INT32_MIN) {
51    EW.write(FirstByte::Int32);
52    EW.write(static_cast<int32_t>(i));
53    return;
54  }
55
56  EW.write(FirstByte::Int64);
57  EW.write(i);
58}
59
60void Writer::write(uint64_t u) {
61  if (u <= FixMax::PositiveInt) {
62    EW.write(static_cast<uint8_t>(u));
63    return;
64  }
65
66  if (u <= UINT8_MAX) {
67    EW.write(FirstByte::UInt8);
68    EW.write(static_cast<uint8_t>(u));
69    return;
70  }
71
72  if (u <= UINT16_MAX) {
73    EW.write(FirstByte::UInt16);
74    EW.write(static_cast<uint16_t>(u));
75    return;
76  }
77
78  if (u <= UINT32_MAX) {
79    EW.write(FirstByte::UInt32);
80    EW.write(static_cast<uint32_t>(u));
81    return;
82  }
83
84  EW.write(FirstByte::UInt64);
85  EW.write(u);
86}
87
88void Writer::write(double d) {
89  // If no loss of precision, encode as a Float32.
90  double a = std::fabs(d);
91  if (a >= std::numeric_limits<float>::min() &&
92      a <= std::numeric_limits<float>::max()) {
93    EW.write(FirstByte::Float32);
94    EW.write(static_cast<float>(d));
95  } else {
96    EW.write(FirstByte::Float64);
97    EW.write(d);
98  }
99}
100
101void Writer::write(StringRef s) {
102  size_t Size = s.size();
103
104  if (Size <= FixMax::String)
105    EW.write(static_cast<uint8_t>(FixBits::String | Size));
106  else if (!Compatible && Size <= UINT8_MAX) {
107    EW.write(FirstByte::Str8);
108    EW.write(static_cast<uint8_t>(Size));
109  } else if (Size <= UINT16_MAX) {
110    EW.write(FirstByte::Str16);
111    EW.write(static_cast<uint16_t>(Size));
112  } else {
113    assert(Size <= UINT32_MAX && "String object too long to be encoded");
114    EW.write(FirstByte::Str32);
115    EW.write(static_cast<uint32_t>(Size));
116  }
117
118  EW.OS << s;
119}
120
121void Writer::write(MemoryBufferRef Buffer) {
122  assert(!Compatible && "Attempt to write Bin format in compatible mode");
123
124  size_t Size = Buffer.getBufferSize();
125
126  if (Size <= UINT8_MAX) {
127    EW.write(FirstByte::Bin8);
128    EW.write(static_cast<uint8_t>(Size));
129  } else if (Size <= UINT16_MAX) {
130    EW.write(FirstByte::Bin16);
131    EW.write(static_cast<uint16_t>(Size));
132  } else {
133    assert(Size <= UINT32_MAX && "Binary object too long to be encoded");
134    EW.write(FirstByte::Bin32);
135    EW.write(static_cast<uint32_t>(Size));
136  }
137
138  EW.OS.write(Buffer.getBufferStart(), Size);
139}
140
141void Writer::writeArraySize(uint32_t Size) {
142  if (Size <= FixMax::Array) {
143    EW.write(static_cast<uint8_t>(FixBits::Array | Size));
144    return;
145  }
146
147  if (Size <= UINT16_MAX) {
148    EW.write(FirstByte::Array16);
149    EW.write(static_cast<uint16_t>(Size));
150    return;
151  }
152
153  EW.write(FirstByte::Array32);
154  EW.write(Size);
155}
156
157void Writer::writeMapSize(uint32_t Size) {
158  if (Size <= FixMax::Map) {
159    EW.write(static_cast<uint8_t>(FixBits::Map | Size));
160    return;
161  }
162
163  if (Size <= UINT16_MAX) {
164    EW.write(FirstByte::Map16);
165    EW.write(static_cast<uint16_t>(Size));
166    return;
167  }
168
169  EW.write(FirstByte::Map32);
170  EW.write(Size);
171}
172
173void Writer::writeExt(int8_t Type, MemoryBufferRef Buffer) {
174  size_t Size = Buffer.getBufferSize();
175
176  switch (Size) {
177  case FixLen::Ext1:
178    EW.write(FirstByte::FixExt1);
179    break;
180  case FixLen::Ext2:
181    EW.write(FirstByte::FixExt2);
182    break;
183  case FixLen::Ext4:
184    EW.write(FirstByte::FixExt4);
185    break;
186  case FixLen::Ext8:
187    EW.write(FirstByte::FixExt8);
188    break;
189  case FixLen::Ext16:
190    EW.write(FirstByte::FixExt16);
191    break;
192  default:
193    if (Size <= UINT8_MAX) {
194      EW.write(FirstByte::Ext8);
195      EW.write(static_cast<uint8_t>(Size));
196    } else if (Size <= UINT16_MAX) {
197      EW.write(FirstByte::Ext16);
198      EW.write(static_cast<uint16_t>(Size));
199    } else {
200      assert(Size <= UINT32_MAX && "Ext size too large to be encoded");
201      EW.write(FirstByte::Ext32);
202      EW.write(static_cast<uint32_t>(Size));
203    }
204  }
205
206  EW.write(Type);
207  EW.OS.write(Buffer.getBufferStart(), Size);
208}
209