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