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 using namespace llvm;
18 using namespace msgpack;
19 
20 Writer::Writer(raw_ostream &OS, bool Compatible)
21     : EW(OS, Endianness), Compatible(Compatible) {}
22 
23 void Writer::writeNil() { EW.write(FirstByte::Nil); }
24 
25 void Writer::write(bool b) { EW.write(b ? FirstByte::True : FirstByte::False); }
26 
27 void 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 
60 void 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 
88 void 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 
101 void 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 
121 void 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 
141 void 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 
157 void 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 
173 void 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