1 //===-- MsgPackDocument.cpp - MsgPack Document --------------------------*-===//
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
7 //===----------------------------------------------------------------------===//
9 /// This file implements a class that exposes a simple in-memory representation
10 /// of a document of MsgPack objects, that can be read from MsgPack, written to
11 /// MsgPack, and inspected and modified in memory. This is intended to be a
12 /// lighter-weight (in terms of memory allocations) replacement for
15 //===----------------------------------------------------------------------===//
17 #include "llvm/BinaryFormat/MsgPackDocument.h"
18 #include "llvm/BinaryFormat/MsgPackWriter.h"
21 using namespace msgpack
;
23 // Convert this DocNode into an empty array.
24 void DocNode::convertToArray() { *this = getDocument()->getArrayNode(); }
26 // Convert this DocNode into an empty map.
27 void DocNode::convertToMap() { *this = getDocument()->getMapNode(); }
29 /// Find the key in the MapDocNode.
30 DocNode::MapTy::iterator
MapDocNode::find(StringRef S
) {
31 return find(getDocument()->getNode(S
));
34 /// Member access for MapDocNode. The string data must remain valid for the
35 /// lifetime of the Document.
36 DocNode
&MapDocNode::operator[](StringRef S
) {
37 return (*this)[getDocument()->getNode(S
)];
40 /// Member access for MapDocNode.
41 DocNode
&MapDocNode::operator[](DocNode Key
) {
42 assert(!Key
.isEmpty());
43 DocNode
&N
= (*Map
)[Key
];
45 // Ensure a new element has its KindAndDoc initialized.
46 N
= getDocument()->getEmptyNode();
51 /// Member access for MapDocNode for integer key.
52 DocNode
&MapDocNode::operator[](int Key
) {
53 return (*this)[getDocument()->getNode(Key
)];
55 DocNode
&MapDocNode::operator[](unsigned Key
) {
56 return (*this)[getDocument()->getNode(Key
)];
58 DocNode
&MapDocNode::operator[](int64_t Key
) {
59 return (*this)[getDocument()->getNode(Key
)];
61 DocNode
&MapDocNode::operator[](uint64_t Key
) {
62 return (*this)[getDocument()->getNode(Key
)];
65 /// Array element access. This extends the array if necessary.
66 DocNode
&ArrayDocNode::operator[](size_t Index
) {
67 if (size() <= Index
) {
68 // Ensure new elements have their KindAndDoc initialized.
69 Array
->resize(Index
+ 1, getDocument()->getEmptyNode());
71 return (*Array
)[Index
];
74 // Convenience assignment operators. This only works if the destination
75 // DocNode has an associated Document, i.e. it was not constructed using the
76 // default constructor. The string one does not copy, so the string must
77 // remain valid for the lifetime of the Document. Use fromString to avoid
79 DocNode
&DocNode::operator=(StringRef Val
) {
80 *this = getDocument()->getNode(Val
);
83 DocNode
&DocNode::operator=(MemoryBufferRef Val
) {
84 *this = getDocument()->getNode(Val
);
87 DocNode
&DocNode::operator=(bool Val
) {
88 *this = getDocument()->getNode(Val
);
91 DocNode
&DocNode::operator=(int Val
) {
92 *this = getDocument()->getNode(Val
);
95 DocNode
&DocNode::operator=(unsigned Val
) {
96 *this = getDocument()->getNode(Val
);
99 DocNode
&DocNode::operator=(int64_t Val
) {
100 *this = getDocument()->getNode(Val
);
103 DocNode
&DocNode::operator=(uint64_t Val
) {
104 *this = getDocument()->getNode(Val
);
108 // A level in the document reading stack.
110 StackLevel(DocNode Node
, size_t StartIndex
, size_t Length
,
111 DocNode
*MapEntry
= nullptr)
112 : Node(Node
), Index(StartIndex
), End(StartIndex
+ Length
),
113 MapEntry(MapEntry
) {}
117 // Points to map entry when we have just processed a map key.
122 // Read a document from a binary msgpack blob, merging into anything already in
124 // The blob data must remain valid for the lifetime of this Document (because a
125 // string object in the document contains a StringRef into the original blob).
126 // If Multi, then this sets root to an array and adds top-level objects to it.
127 // If !Multi, then it only reads a single top-level object, even if there are
128 // more, and sets root to that.
129 // Returns false if failed due to illegal format or merge error.
131 bool Document::readFromBlob(
132 StringRef Blob
, bool Multi
,
133 function_ref
<int(DocNode
*DestNode
, DocNode SrcNode
, DocNode MapKey
)>
135 msgpack::Reader
MPReader(Blob
);
136 SmallVector
<StackLevel
, 4> Stack
;
138 // Create the array for multiple top-level objects.
139 Root
= getArrayNode();
140 Stack
.push_back(StackLevel(Root
, 0, (size_t)-1));
143 // On to next element (or key if doing a map key next).
146 Expected
<bool> ReadObj
= MPReader
.read(Obj
);
148 // FIXME: Propagate the Error to the caller.
149 consumeError(ReadObj
.takeError());
152 if (!ReadObj
.get()) {
153 if (Multi
&& Stack
.size() == 1) {
154 // OK to finish here as we've just done a top-level element with Multi
157 return false; // Finished too early
159 // Convert it into a DocNode.
166 Node
= getNode(Obj
.Int
);
169 Node
= getNode(Obj
.UInt
);
172 Node
= getNode(Obj
.Bool
);
175 Node
= getNode(Obj
.Float
);
178 Node
= getNode(Obj
.Raw
);
181 Node
= getNode(MemoryBufferRef(Obj
.Raw
, ""));
187 Node
= getArrayNode();
190 return false; // Raw and Extension not supported
194 DocNode
*DestNode
= nullptr;
197 else if (Stack
.back().Node
.getKind() == Type::Array
) {
198 // Reading an array entry.
199 auto &Array
= Stack
.back().Node
.getArray();
200 DestNode
= &Array
[Stack
.back().Index
++];
202 auto &Map
= Stack
.back().Node
.getMap();
203 if (!Stack
.back().MapEntry
) {
204 // Reading a map key.
205 Stack
.back().MapKey
= Node
;
206 Stack
.back().MapEntry
= &Map
[Node
];
209 // Reading the value for the map key read in the last iteration.
210 DestNode
= Stack
.back().MapEntry
;
211 Stack
.back().MapEntry
= nullptr;
212 ++Stack
.back().Index
;
215 if (!DestNode
->isEmpty()) {
216 // In a merge, there is already a value at this position. Call the
217 // callback to attempt to resolve the conflict. The resolution must result
218 // in an array or map if Node is an array or map respectively.
219 DocNode MapKey
= !Stack
.empty() && !Stack
.back().MapKey
.isEmpty()
220 ? Stack
.back().MapKey
222 MergeResult
= Merger(DestNode
, Node
, MapKey
);
224 return false; // Merge conflict resolution failed
225 assert(!((Node
.isMap() && !DestNode
->isMap()) ||
226 (Node
.isArray() && !DestNode
->isArray())));
230 // See if we're starting a new array or map.
231 switch (DestNode
->getKind()) {
232 case msgpack::Type::Array
:
233 case msgpack::Type::Map
:
234 Stack
.push_back(StackLevel(*DestNode
, MergeResult
, Obj
.Length
, nullptr));
240 // Pop finished stack levels.
241 while (!Stack
.empty()) {
242 if (Stack
.back().MapEntry
)
244 if (Stack
.back().Index
!= Stack
.back().End
)
248 } while (!Stack
.empty());
252 struct WriterStackLevel
{
254 DocNode::MapTy::iterator MapIt
;
255 DocNode::ArrayTy::iterator ArrayIt
;
259 /// Write a MsgPack document to a binary MsgPack blob.
260 void Document::writeToBlob(std::string
&Blob
) {
262 raw_string_ostream
OS(Blob
);
263 msgpack::Writer
MPWriter(OS
);
264 SmallVector
<WriterStackLevel
, 4> Stack
;
265 DocNode Node
= getRoot();
267 switch (Node
.getKind()) {
269 MPWriter
.writeArraySize(Node
.getArray().size());
271 {Node
, DocNode::MapTy::iterator(), Node
.getArray().begin(), false});
274 MPWriter
.writeMapSize(Node
.getMap().size());
276 {Node
, Node
.getMap().begin(), DocNode::ArrayTy::iterator(), true});
282 MPWriter
.write(Node
.getBool());
285 MPWriter
.write(Node
.getInt());
288 MPWriter
.write(Node
.getUInt());
291 MPWriter
.write(Node
.getString());
294 MPWriter
.write(Node
.getBinary());
297 llvm_unreachable("unhandled empty msgpack node");
299 llvm_unreachable("unhandled msgpack object kind");
301 // Pop finished stack levels.
302 while (!Stack
.empty()) {
303 if (Stack
.back().Node
.getKind() == Type::Map
) {
304 if (Stack
.back().MapIt
!= Stack
.back().Node
.getMap().end())
307 if (Stack
.back().ArrayIt
!= Stack
.back().Node
.getArray().end())
314 // Get the next value.
315 if (Stack
.back().Node
.getKind() == Type::Map
) {
316 if (Stack
.back().OnKey
) {
317 // Do the key of a key,value pair in a map.
318 Node
= Stack
.back().MapIt
->first
;
319 Stack
.back().OnKey
= false;
321 Node
= Stack
.back().MapIt
->second
;
322 ++Stack
.back().MapIt
;
323 Stack
.back().OnKey
= true;
326 Node
= *Stack
.back().ArrayIt
;
327 ++Stack
.back().ArrayIt
;