14ced8de1STim Renouf //===-- MsgPackDocument.cpp - MsgPack Document --------------------------*-===//
24ced8de1STim Renouf //
34ced8de1STim Renouf // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44ced8de1STim Renouf // See https://llvm.org/LICENSE.txt for license information.
54ced8de1STim Renouf // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64ced8de1STim Renouf //
74ced8de1STim Renouf //===----------------------------------------------------------------------===//
84ced8de1STim Renouf ///
94ced8de1STim Renouf /// This file implements a class that exposes a simple in-memory representation
104ced8de1STim Renouf /// of a document of MsgPack objects, that can be read from MsgPack, written to
114ced8de1STim Renouf /// MsgPack, and inspected and modified in memory. This is intended to be a
124ced8de1STim Renouf /// lighter-weight (in terms of memory allocations) replacement for
134ced8de1STim Renouf /// MsgPackTypes.
144ced8de1STim Renouf ///
154ced8de1STim Renouf //===----------------------------------------------------------------------===//
164ced8de1STim Renouf
174ced8de1STim Renouf #include "llvm/BinaryFormat/MsgPackDocument.h"
184ced8de1STim Renouf #include "llvm/BinaryFormat/MsgPackWriter.h"
194ced8de1STim Renouf
204ced8de1STim Renouf using namespace llvm;
214ced8de1STim Renouf using namespace msgpack;
224ced8de1STim Renouf
234ced8de1STim Renouf // Convert this DocNode into an empty array.
convertToArray()244ced8de1STim Renouf void DocNode::convertToArray() { *this = getDocument()->getArrayNode(); }
254ced8de1STim Renouf
264ced8de1STim Renouf // Convert this DocNode into an empty map.
convertToMap()274ced8de1STim Renouf void DocNode::convertToMap() { *this = getDocument()->getMapNode(); }
284ced8de1STim Renouf
294ced8de1STim Renouf /// Find the key in the MapDocNode.
find(StringRef S)304ced8de1STim Renouf DocNode::MapTy::iterator MapDocNode::find(StringRef S) {
314ced8de1STim Renouf return find(getDocument()->getNode(S));
324ced8de1STim Renouf }
334ced8de1STim Renouf
344ced8de1STim Renouf /// Member access for MapDocNode. The string data must remain valid for the
354ced8de1STim Renouf /// lifetime of the Document.
operator [](StringRef S)364ced8de1STim Renouf DocNode &MapDocNode::operator[](StringRef S) {
374ced8de1STim Renouf return (*this)[getDocument()->getNode(S)];
384ced8de1STim Renouf }
394ced8de1STim Renouf
404ced8de1STim Renouf /// Member access for MapDocNode.
operator [](DocNode Key)414ced8de1STim Renouf DocNode &MapDocNode::operator[](DocNode Key) {
424ced8de1STim Renouf assert(!Key.isEmpty());
43e79d0023STim Renouf DocNode &N = (*Map)[Key];
44e79d0023STim Renouf if (N.isEmpty()) {
454ced8de1STim Renouf // Ensure a new element has its KindAndDoc initialized.
46e79d0023STim Renouf N = getDocument()->getEmptyNode();
474ced8de1STim Renouf }
48e79d0023STim Renouf return N;
494ced8de1STim Renouf }
504ced8de1STim Renouf
51db16eb33STim Renouf /// Member access for MapDocNode for integer key.
operator [](int Key)52db16eb33STim Renouf DocNode &MapDocNode::operator[](int Key) {
53db16eb33STim Renouf return (*this)[getDocument()->getNode(Key)];
54db16eb33STim Renouf }
operator [](unsigned Key)55db16eb33STim Renouf DocNode &MapDocNode::operator[](unsigned Key) {
56db16eb33STim Renouf return (*this)[getDocument()->getNode(Key)];
57db16eb33STim Renouf }
operator [](int64_t Key)58db16eb33STim Renouf DocNode &MapDocNode::operator[](int64_t Key) {
59db16eb33STim Renouf return (*this)[getDocument()->getNode(Key)];
60db16eb33STim Renouf }
operator [](uint64_t Key)61db16eb33STim Renouf DocNode &MapDocNode::operator[](uint64_t Key) {
62db16eb33STim Renouf return (*this)[getDocument()->getNode(Key)];
63db16eb33STim Renouf }
64db16eb33STim Renouf
654ced8de1STim Renouf /// Array element access. This extends the array if necessary.
operator [](size_t Index)664ced8de1STim Renouf DocNode &ArrayDocNode::operator[](size_t Index) {
674ced8de1STim Renouf if (size() <= Index) {
684ced8de1STim Renouf // Ensure new elements have their KindAndDoc initialized.
69e79d0023STim Renouf Array->resize(Index + 1, getDocument()->getEmptyNode());
704ced8de1STim Renouf }
714ced8de1STim Renouf return (*Array)[Index];
724ced8de1STim Renouf }
734ced8de1STim Renouf
74db16eb33STim Renouf // Convenience assignment operators. This only works if the destination
75db16eb33STim Renouf // DocNode has an associated Document, i.e. it was not constructed using the
76db16eb33STim Renouf // default constructor. The string one does not copy, so the string must
77db16eb33STim Renouf // remain valid for the lifetime of the Document. Use fromString to avoid
78db16eb33STim Renouf // that restriction.
operator =(StringRef Val)79db16eb33STim Renouf DocNode &DocNode::operator=(StringRef Val) {
80db16eb33STim Renouf *this = getDocument()->getNode(Val);
81db16eb33STim Renouf return *this;
82db16eb33STim Renouf }
operator =(bool Val)83db16eb33STim Renouf DocNode &DocNode::operator=(bool Val) {
84db16eb33STim Renouf *this = getDocument()->getNode(Val);
85db16eb33STim Renouf return *this;
86db16eb33STim Renouf }
operator =(int Val)87db16eb33STim Renouf DocNode &DocNode::operator=(int Val) {
88db16eb33STim Renouf *this = getDocument()->getNode(Val);
89db16eb33STim Renouf return *this;
90db16eb33STim Renouf }
operator =(unsigned Val)91db16eb33STim Renouf DocNode &DocNode::operator=(unsigned Val) {
92db16eb33STim Renouf *this = getDocument()->getNode(Val);
93db16eb33STim Renouf return *this;
94db16eb33STim Renouf }
operator =(int64_t Val)95db16eb33STim Renouf DocNode &DocNode::operator=(int64_t Val) {
96db16eb33STim Renouf *this = getDocument()->getNode(Val);
97db16eb33STim Renouf return *this;
98db16eb33STim Renouf }
operator =(uint64_t Val)99db16eb33STim Renouf DocNode &DocNode::operator=(uint64_t Val) {
100db16eb33STim Renouf *this = getDocument()->getNode(Val);
101db16eb33STim Renouf return *this;
102db16eb33STim Renouf }
103db16eb33STim Renouf
1044ced8de1STim Renouf // A level in the document reading stack.
1054ced8de1STim Renouf struct StackLevel {
StackLevelStackLevel106e79d0023STim Renouf StackLevel(DocNode Node, size_t StartIndex, size_t Length,
107e79d0023STim Renouf DocNode *MapEntry = nullptr)
108e79d0023STim Renouf : Node(Node), Index(StartIndex), End(StartIndex + Length),
109e79d0023STim Renouf MapEntry(MapEntry) {}
1104ced8de1STim Renouf DocNode Node;
111e79d0023STim Renouf size_t Index;
112e79d0023STim Renouf size_t End;
1134ced8de1STim Renouf // Points to map entry when we have just processed a map key.
1144ced8de1STim Renouf DocNode *MapEntry;
115e79d0023STim Renouf DocNode MapKey;
1164ced8de1STim Renouf };
1174ced8de1STim Renouf
118e79d0023STim Renouf // Read a document from a binary msgpack blob, merging into anything already in
119e79d0023STim Renouf // the Document.
1204ced8de1STim Renouf // The blob data must remain valid for the lifetime of this Document (because a
1214ced8de1STim Renouf // string object in the document contains a StringRef into the original blob).
1224ced8de1STim Renouf // If Multi, then this sets root to an array and adds top-level objects to it.
1234ced8de1STim Renouf // If !Multi, then it only reads a single top-level object, even if there are
1244ced8de1STim Renouf // more, and sets root to that.
125e79d0023STim Renouf // Returns false if failed due to illegal format or merge error.
126e79d0023STim Renouf
readFromBlob(StringRef Blob,bool Multi,function_ref<int (DocNode * DestNode,DocNode SrcNode,DocNode MapKey)> Merger)127e79d0023STim Renouf bool Document::readFromBlob(
128e79d0023STim Renouf StringRef Blob, bool Multi,
129e79d0023STim Renouf function_ref<int(DocNode *DestNode, DocNode SrcNode, DocNode MapKey)>
130e79d0023STim Renouf Merger) {
1314ced8de1STim Renouf msgpack::Reader MPReader(Blob);
1324ced8de1STim Renouf SmallVector<StackLevel, 4> Stack;
1334ced8de1STim Renouf if (Multi) {
1344ced8de1STim Renouf // Create the array for multiple top-level objects.
1354ced8de1STim Renouf Root = getArrayNode();
136e79d0023STim Renouf Stack.push_back(StackLevel(Root, 0, (size_t)-1));
1374ced8de1STim Renouf }
1384ced8de1STim Renouf do {
1394ced8de1STim Renouf // On to next element (or key if doing a map key next).
1404ced8de1STim Renouf // Read the value.
1414ced8de1STim Renouf Object Obj;
1424ced8de1STim Renouf if (!MPReader.read(Obj)) {
1434ced8de1STim Renouf if (Multi && Stack.size() == 1) {
1444ced8de1STim Renouf // OK to finish here as we've just done a top-level element with Multi
1454ced8de1STim Renouf break;
1464ced8de1STim Renouf }
1474ced8de1STim Renouf return false; // Finished too early
1484ced8de1STim Renouf }
1494ced8de1STim Renouf // Convert it into a DocNode.
1504ced8de1STim Renouf DocNode Node;
1514ced8de1STim Renouf switch (Obj.Kind) {
1524ced8de1STim Renouf case Type::Nil:
1534ced8de1STim Renouf Node = getNode();
1544ced8de1STim Renouf break;
1554ced8de1STim Renouf case Type::Int:
1564ced8de1STim Renouf Node = getNode(Obj.Int);
1574ced8de1STim Renouf break;
1584ced8de1STim Renouf case Type::UInt:
1594ced8de1STim Renouf Node = getNode(Obj.UInt);
1604ced8de1STim Renouf break;
1614ced8de1STim Renouf case Type::Boolean:
1624ced8de1STim Renouf Node = getNode(Obj.Bool);
1634ced8de1STim Renouf break;
1644ced8de1STim Renouf case Type::Float:
1654ced8de1STim Renouf Node = getNode(Obj.Float);
1664ced8de1STim Renouf break;
1674ced8de1STim Renouf case Type::String:
1684ced8de1STim Renouf Node = getNode(Obj.Raw);
1694ced8de1STim Renouf break;
1704ced8de1STim Renouf case Type::Map:
1714ced8de1STim Renouf Node = getMapNode();
1724ced8de1STim Renouf break;
1734ced8de1STim Renouf case Type::Array:
1744ced8de1STim Renouf Node = getArrayNode();
1754ced8de1STim Renouf break;
1764ced8de1STim Renouf default:
1774ced8de1STim Renouf return false; // Raw and Extension not supported
1784ced8de1STim Renouf }
1794ced8de1STim Renouf
1804ced8de1STim Renouf // Store it.
181e79d0023STim Renouf DocNode *DestNode = nullptr;
1824ced8de1STim Renouf if (Stack.empty())
183e79d0023STim Renouf DestNode = &Root;
1844ced8de1STim Renouf else if (Stack.back().Node.getKind() == Type::Array) {
1854ced8de1STim Renouf // Reading an array entry.
1864ced8de1STim Renouf auto &Array = Stack.back().Node.getArray();
187e79d0023STim Renouf DestNode = &Array[Stack.back().Index++];
1884ced8de1STim Renouf } else {
1894ced8de1STim Renouf auto &Map = Stack.back().Node.getMap();
1904ced8de1STim Renouf if (!Stack.back().MapEntry) {
1914ced8de1STim Renouf // Reading a map key.
192e79d0023STim Renouf Stack.back().MapKey = Node;
1934ced8de1STim Renouf Stack.back().MapEntry = &Map[Node];
194e79d0023STim Renouf continue;
195e79d0023STim Renouf }
1964ced8de1STim Renouf // Reading the value for the map key read in the last iteration.
197e79d0023STim Renouf DestNode = Stack.back().MapEntry;
1984ced8de1STim Renouf Stack.back().MapEntry = nullptr;
199e79d0023STim Renouf ++Stack.back().Index;
2004ced8de1STim Renouf }
201e79d0023STim Renouf int MergeResult = 0;
202e79d0023STim Renouf if (!DestNode->isEmpty()) {
203e79d0023STim Renouf // In a merge, there is already a value at this position. Call the
204e79d0023STim Renouf // callback to attempt to resolve the conflict. The resolution must result
205e79d0023STim Renouf // in an array or map if Node is an array or map respectively.
206e79d0023STim Renouf DocNode MapKey = !Stack.empty() && !Stack.back().MapKey.isEmpty()
207e79d0023STim Renouf ? Stack.back().MapKey
208e79d0023STim Renouf : getNode();
209e79d0023STim Renouf MergeResult = Merger(DestNode, Node, MapKey);
210e79d0023STim Renouf if (MergeResult < 0)
211e79d0023STim Renouf return false; // Merge conflict resolution failed
212e79d0023STim Renouf assert(!((Node.isMap() && !DestNode->isMap()) ||
213e79d0023STim Renouf (Node.isArray() && !DestNode->isArray())));
214e79d0023STim Renouf } else
215e79d0023STim Renouf *DestNode = Node;
2164ced8de1STim Renouf
2174ced8de1STim Renouf // See if we're starting a new array or map.
218e79d0023STim Renouf switch (DestNode->getKind()) {
2194ced8de1STim Renouf case msgpack::Type::Array:
2204ced8de1STim Renouf case msgpack::Type::Map:
221e79d0023STim Renouf Stack.push_back(StackLevel(*DestNode, MergeResult, Obj.Length, nullptr));
2224ced8de1STim Renouf break;
2234ced8de1STim Renouf default:
2244ced8de1STim Renouf break;
2254ced8de1STim Renouf }
2264ced8de1STim Renouf
2274ced8de1STim Renouf // Pop finished stack levels.
2284ced8de1STim Renouf while (!Stack.empty()) {
229e79d0023STim Renouf if (Stack.back().MapEntry)
2304ced8de1STim Renouf break;
231e79d0023STim Renouf if (Stack.back().Index != Stack.back().End)
2324ced8de1STim Renouf break;
2334ced8de1STim Renouf Stack.pop_back();
2344ced8de1STim Renouf }
2354ced8de1STim Renouf } while (!Stack.empty());
2364ced8de1STim Renouf return true;
2374ced8de1STim Renouf }
2384ced8de1STim Renouf
2394ced8de1STim Renouf struct WriterStackLevel {
2404ced8de1STim Renouf DocNode Node;
2414ced8de1STim Renouf DocNode::MapTy::iterator MapIt;
2424ced8de1STim Renouf DocNode::ArrayTy::iterator ArrayIt;
2434ced8de1STim Renouf bool OnKey;
2444ced8de1STim Renouf };
2454ced8de1STim Renouf
2464ced8de1STim Renouf /// Write a MsgPack document to a binary MsgPack blob.
writeToBlob(std::string & Blob)2474ced8de1STim Renouf void Document::writeToBlob(std::string &Blob) {
2484ced8de1STim Renouf Blob.clear();
2494ced8de1STim Renouf raw_string_ostream OS(Blob);
2504ced8de1STim Renouf msgpack::Writer MPWriter(OS);
2514ced8de1STim Renouf SmallVector<WriterStackLevel, 4> Stack;
2524ced8de1STim Renouf DocNode Node = getRoot();
2534ced8de1STim Renouf for (;;) {
2544ced8de1STim Renouf switch (Node.getKind()) {
2554ced8de1STim Renouf case Type::Array:
2564ced8de1STim Renouf MPWriter.writeArraySize(Node.getArray().size());
2574ced8de1STim Renouf Stack.push_back(
2584ced8de1STim Renouf {Node, DocNode::MapTy::iterator(), Node.getArray().begin(), false});
2594ced8de1STim Renouf break;
2604ced8de1STim Renouf case Type::Map:
2614ced8de1STim Renouf MPWriter.writeMapSize(Node.getMap().size());
2624ced8de1STim Renouf Stack.push_back(
2634ced8de1STim Renouf {Node, Node.getMap().begin(), DocNode::ArrayTy::iterator(), true});
2644ced8de1STim Renouf break;
2654ced8de1STim Renouf case Type::Nil:
2664ced8de1STim Renouf MPWriter.writeNil();
2674ced8de1STim Renouf break;
2684ced8de1STim Renouf case Type::Boolean:
2694ced8de1STim Renouf MPWriter.write(Node.getBool());
2704ced8de1STim Renouf break;
2714ced8de1STim Renouf case Type::Int:
2724ced8de1STim Renouf MPWriter.write(Node.getInt());
2734ced8de1STim Renouf break;
2744ced8de1STim Renouf case Type::UInt:
2754ced8de1STim Renouf MPWriter.write(Node.getUInt());
2764ced8de1STim Renouf break;
2774ced8de1STim Renouf case Type::String:
2784ced8de1STim Renouf MPWriter.write(Node.getString());
2794ced8de1STim Renouf break;
280*673f2f70SSebastian Neubauer case Type::Empty:
281*673f2f70SSebastian Neubauer llvm_unreachable("unhandled empty msgpack node");
2824ced8de1STim Renouf default:
2834ced8de1STim Renouf llvm_unreachable("unhandled msgpack object kind");
2844ced8de1STim Renouf }
2854ced8de1STim Renouf // Pop finished stack levels.
2864ced8de1STim Renouf while (!Stack.empty()) {
2874ced8de1STim Renouf if (Stack.back().Node.getKind() == Type::Map) {
2884ced8de1STim Renouf if (Stack.back().MapIt != Stack.back().Node.getMap().end())
2894ced8de1STim Renouf break;
2904ced8de1STim Renouf } else {
2914ced8de1STim Renouf if (Stack.back().ArrayIt != Stack.back().Node.getArray().end())
2924ced8de1STim Renouf break;
2934ced8de1STim Renouf }
2944ced8de1STim Renouf Stack.pop_back();
2954ced8de1STim Renouf }
2964ced8de1STim Renouf if (Stack.empty())
2974ced8de1STim Renouf break;
2984ced8de1STim Renouf // Get the next value.
2994ced8de1STim Renouf if (Stack.back().Node.getKind() == Type::Map) {
3004ced8de1STim Renouf if (Stack.back().OnKey) {
3014ced8de1STim Renouf // Do the key of a key,value pair in a map.
3024ced8de1STim Renouf Node = Stack.back().MapIt->first;
3034ced8de1STim Renouf Stack.back().OnKey = false;
3044ced8de1STim Renouf } else {
3054ced8de1STim Renouf Node = Stack.back().MapIt->second;
3064ced8de1STim Renouf ++Stack.back().MapIt;
3074ced8de1STim Renouf Stack.back().OnKey = true;
3084ced8de1STim Renouf }
3094ced8de1STim Renouf } else {
3104ced8de1STim Renouf Node = *Stack.back().ArrayIt;
3114ced8de1STim Renouf ++Stack.back().ArrayIt;
3124ced8de1STim Renouf }
3134ced8de1STim Renouf }
3144ced8de1STim Renouf }
315