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