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 
19 using namespace llvm;
20 using namespace msgpack;
21 
22 Writer::Writer(raw_ostream &OS, bool Compatible)
23     : EW(OS, Endianness), Compatible(Compatible) {}
24 
25 void Writer::writeNil() { EW.write(FirstByte::Nil); }
26 
27 void Writer::write(bool b) { EW.write(b ? FirstByte::True : FirstByte::False); }
28 
29 void 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 
62 void 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 
90 void 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 
103 void 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 
123 void 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 
143 void 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 
159 void 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 
175 void 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