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 =(MemoryBufferRef Val)839d52f69aSMartin Dinkov DocNode &DocNode::operator=(MemoryBufferRef Val) {
849d52f69aSMartin Dinkov *this = getDocument()->getNode(Val);
859d52f69aSMartin Dinkov return *this;
869d52f69aSMartin Dinkov }
operator =(bool Val)87db16eb33STim Renouf DocNode &DocNode::operator=(bool Val) {
88db16eb33STim Renouf *this = getDocument()->getNode(Val);
89db16eb33STim Renouf return *this;
90db16eb33STim Renouf }
operator =(int Val)91db16eb33STim Renouf DocNode &DocNode::operator=(int Val) {
92db16eb33STim Renouf *this = getDocument()->getNode(Val);
93db16eb33STim Renouf return *this;
94db16eb33STim Renouf }
operator =(unsigned Val)95db16eb33STim Renouf DocNode &DocNode::operator=(unsigned Val) {
96db16eb33STim Renouf *this = getDocument()->getNode(Val);
97db16eb33STim Renouf return *this;
98db16eb33STim Renouf }
operator =(int64_t Val)99db16eb33STim Renouf DocNode &DocNode::operator=(int64_t Val) {
100db16eb33STim Renouf *this = getDocument()->getNode(Val);
101db16eb33STim Renouf return *this;
102db16eb33STim Renouf }
operator =(uint64_t Val)103db16eb33STim Renouf DocNode &DocNode::operator=(uint64_t Val) {
104db16eb33STim Renouf *this = getDocument()->getNode(Val);
105db16eb33STim Renouf return *this;
106db16eb33STim Renouf }
107db16eb33STim Renouf
1084ced8de1STim Renouf // A level in the document reading stack.
1094ced8de1STim Renouf struct StackLevel {
StackLevelStackLevel110e79d0023STim Renouf StackLevel(DocNode Node, size_t StartIndex, size_t Length,
111e79d0023STim Renouf DocNode *MapEntry = nullptr)
112e79d0023STim Renouf : Node(Node), Index(StartIndex), End(StartIndex + Length),
113e79d0023STim Renouf MapEntry(MapEntry) {}
1144ced8de1STim Renouf DocNode Node;
115e79d0023STim Renouf size_t Index;
116e79d0023STim Renouf size_t End;
1174ced8de1STim Renouf // Points to map entry when we have just processed a map key.
1184ced8de1STim Renouf DocNode *MapEntry;
119e79d0023STim Renouf DocNode MapKey;
1204ced8de1STim Renouf };
1214ced8de1STim Renouf
122e79d0023STim Renouf // Read a document from a binary msgpack blob, merging into anything already in
123e79d0023STim Renouf // the Document.
1244ced8de1STim Renouf // The blob data must remain valid for the lifetime of this Document (because a
1254ced8de1STim Renouf // string object in the document contains a StringRef into the original blob).
1264ced8de1STim Renouf // If Multi, then this sets root to an array and adds top-level objects to it.
1274ced8de1STim Renouf // If !Multi, then it only reads a single top-level object, even if there are
1284ced8de1STim Renouf // more, and sets root to that.
129e79d0023STim Renouf // Returns false if failed due to illegal format or merge error.
130e79d0023STim Renouf
readFromBlob(StringRef Blob,bool Multi,function_ref<int (DocNode * DestNode,DocNode SrcNode,DocNode MapKey)> Merger)131e79d0023STim Renouf bool Document::readFromBlob(
132e79d0023STim Renouf StringRef Blob, bool Multi,
133e79d0023STim Renouf function_ref<int(DocNode *DestNode, DocNode SrcNode, DocNode MapKey)>
134e79d0023STim Renouf Merger) {
1354ced8de1STim Renouf msgpack::Reader MPReader(Blob);
1364ced8de1STim Renouf SmallVector<StackLevel, 4> Stack;
1374ced8de1STim Renouf if (Multi) {
1384ced8de1STim Renouf // Create the array for multiple top-level objects.
1394ced8de1STim Renouf Root = getArrayNode();
140e79d0023STim Renouf Stack.push_back(StackLevel(Root, 0, (size_t)-1));
1414ced8de1STim Renouf }
1424ced8de1STim Renouf do {
1434ced8de1STim Renouf // On to next element (or key if doing a map key next).
1444ced8de1STim Renouf // Read the value.
1454ced8de1STim Renouf Object Obj;
146*6c62f7cbSEmma Pilkington Expected<bool> ReadObj = MPReader.read(Obj);
147*6c62f7cbSEmma Pilkington if (!ReadObj) {
148*6c62f7cbSEmma Pilkington // FIXME: Propagate the Error to the caller.
149*6c62f7cbSEmma Pilkington consumeError(ReadObj.takeError());
150*6c62f7cbSEmma Pilkington return false;
151*6c62f7cbSEmma Pilkington }
152*6c62f7cbSEmma Pilkington if (!ReadObj.get()) {
1534ced8de1STim Renouf if (Multi && Stack.size() == 1) {
1544ced8de1STim Renouf // OK to finish here as we've just done a top-level element with Multi
1554ced8de1STim Renouf break;
1564ced8de1STim Renouf }
1574ced8de1STim Renouf return false; // Finished too early
1584ced8de1STim Renouf }
1594ced8de1STim Renouf // Convert it into a DocNode.
1604ced8de1STim Renouf DocNode Node;
1614ced8de1STim Renouf switch (Obj.Kind) {
1624ced8de1STim Renouf case Type::Nil:
1634ced8de1STim Renouf Node = getNode();
1644ced8de1STim Renouf break;
1654ced8de1STim Renouf case Type::Int:
1664ced8de1STim Renouf Node = getNode(Obj.Int);
1674ced8de1STim Renouf break;
1684ced8de1STim Renouf case Type::UInt:
1694ced8de1STim Renouf Node = getNode(Obj.UInt);
1704ced8de1STim Renouf break;
1714ced8de1STim Renouf case Type::Boolean:
1724ced8de1STim Renouf Node = getNode(Obj.Bool);
1734ced8de1STim Renouf break;
1744ced8de1STim Renouf case Type::Float:
1754ced8de1STim Renouf Node = getNode(Obj.Float);
1764ced8de1STim Renouf break;
1774ced8de1STim Renouf case Type::String:
1784ced8de1STim Renouf Node = getNode(Obj.Raw);
1794ced8de1STim Renouf break;
1809d52f69aSMartin Dinkov case Type::Binary:
1819d52f69aSMartin Dinkov Node = getNode(MemoryBufferRef(Obj.Raw, ""));
1829d52f69aSMartin Dinkov break;
1834ced8de1STim Renouf case Type::Map:
1844ced8de1STim Renouf Node = getMapNode();
1854ced8de1STim Renouf break;
1864ced8de1STim Renouf case Type::Array:
1874ced8de1STim Renouf Node = getArrayNode();
1884ced8de1STim Renouf break;
1894ced8de1STim Renouf default:
1904ced8de1STim Renouf return false; // Raw and Extension not supported
1914ced8de1STim Renouf }
1924ced8de1STim Renouf
1934ced8de1STim Renouf // Store it.
194e79d0023STim Renouf DocNode *DestNode = nullptr;
1954ced8de1STim Renouf if (Stack.empty())
196e79d0023STim Renouf DestNode = &Root;
1974ced8de1STim Renouf else if (Stack.back().Node.getKind() == Type::Array) {
1984ced8de1STim Renouf // Reading an array entry.
1994ced8de1STim Renouf auto &Array = Stack.back().Node.getArray();
200e79d0023STim Renouf DestNode = &Array[Stack.back().Index++];
2014ced8de1STim Renouf } else {
2024ced8de1STim Renouf auto &Map = Stack.back().Node.getMap();
2034ced8de1STim Renouf if (!Stack.back().MapEntry) {
2044ced8de1STim Renouf // Reading a map key.
205e79d0023STim Renouf Stack.back().MapKey = Node;
2064ced8de1STim Renouf Stack.back().MapEntry = &Map[Node];
207e79d0023STim Renouf continue;
208e79d0023STim Renouf }
2094ced8de1STim Renouf // Reading the value for the map key read in the last iteration.
210e79d0023STim Renouf DestNode = Stack.back().MapEntry;
2114ced8de1STim Renouf Stack.back().MapEntry = nullptr;
212e79d0023STim Renouf ++Stack.back().Index;
2134ced8de1STim Renouf }
214e79d0023STim Renouf int MergeResult = 0;
215e79d0023STim Renouf if (!DestNode->isEmpty()) {
216e79d0023STim Renouf // In a merge, there is already a value at this position. Call the
217e79d0023STim Renouf // callback to attempt to resolve the conflict. The resolution must result
218e79d0023STim Renouf // in an array or map if Node is an array or map respectively.
219e79d0023STim Renouf DocNode MapKey = !Stack.empty() && !Stack.back().MapKey.isEmpty()
220e79d0023STim Renouf ? Stack.back().MapKey
221e79d0023STim Renouf : getNode();
222e79d0023STim Renouf MergeResult = Merger(DestNode, Node, MapKey);
223e79d0023STim Renouf if (MergeResult < 0)
224e79d0023STim Renouf return false; // Merge conflict resolution failed
225e79d0023STim Renouf assert(!((Node.isMap() && !DestNode->isMap()) ||
226e79d0023STim Renouf (Node.isArray() && !DestNode->isArray())));
227e79d0023STim Renouf } else
228e79d0023STim Renouf *DestNode = Node;
2294ced8de1STim Renouf
2304ced8de1STim Renouf // See if we're starting a new array or map.
231e79d0023STim Renouf switch (DestNode->getKind()) {
2324ced8de1STim Renouf case msgpack::Type::Array:
2334ced8de1STim Renouf case msgpack::Type::Map:
234e79d0023STim Renouf Stack.push_back(StackLevel(*DestNode, MergeResult, Obj.Length, nullptr));
2354ced8de1STim Renouf break;
2364ced8de1STim Renouf default:
2374ced8de1STim Renouf break;
2384ced8de1STim Renouf }
2394ced8de1STim Renouf
2404ced8de1STim Renouf // Pop finished stack levels.
2414ced8de1STim Renouf while (!Stack.empty()) {
242e79d0023STim Renouf if (Stack.back().MapEntry)
2434ced8de1STim Renouf break;
244e79d0023STim Renouf if (Stack.back().Index != Stack.back().End)
2454ced8de1STim Renouf break;
2464ced8de1STim Renouf Stack.pop_back();
2474ced8de1STim Renouf }
2484ced8de1STim Renouf } while (!Stack.empty());
2494ced8de1STim Renouf return true;
2504ced8de1STim Renouf }
2514ced8de1STim Renouf
2524ced8de1STim Renouf struct WriterStackLevel {
2534ced8de1STim Renouf DocNode Node;
2544ced8de1STim Renouf DocNode::MapTy::iterator MapIt;
2554ced8de1STim Renouf DocNode::ArrayTy::iterator ArrayIt;
2564ced8de1STim Renouf bool OnKey;
2574ced8de1STim Renouf };
2584ced8de1STim Renouf
2594ced8de1STim Renouf /// Write a MsgPack document to a binary MsgPack blob.
writeToBlob(std::string & Blob)2604ced8de1STim Renouf void Document::writeToBlob(std::string &Blob) {
2614ced8de1STim Renouf Blob.clear();
2624ced8de1STim Renouf raw_string_ostream OS(Blob);
2634ced8de1STim Renouf msgpack::Writer MPWriter(OS);
2644ced8de1STim Renouf SmallVector<WriterStackLevel, 4> Stack;
2654ced8de1STim Renouf DocNode Node = getRoot();
2664ced8de1STim Renouf for (;;) {
2674ced8de1STim Renouf switch (Node.getKind()) {
2684ced8de1STim Renouf case Type::Array:
2694ced8de1STim Renouf MPWriter.writeArraySize(Node.getArray().size());
2704ced8de1STim Renouf Stack.push_back(
2714ced8de1STim Renouf {Node, DocNode::MapTy::iterator(), Node.getArray().begin(), false});
2724ced8de1STim Renouf break;
2734ced8de1STim Renouf case Type::Map:
2744ced8de1STim Renouf MPWriter.writeMapSize(Node.getMap().size());
2754ced8de1STim Renouf Stack.push_back(
2764ced8de1STim Renouf {Node, Node.getMap().begin(), DocNode::ArrayTy::iterator(), true});
2774ced8de1STim Renouf break;
2784ced8de1STim Renouf case Type::Nil:
2794ced8de1STim Renouf MPWriter.writeNil();
2804ced8de1STim Renouf break;
2814ced8de1STim Renouf case Type::Boolean:
2824ced8de1STim Renouf MPWriter.write(Node.getBool());
2834ced8de1STim Renouf break;
2844ced8de1STim Renouf case Type::Int:
2854ced8de1STim Renouf MPWriter.write(Node.getInt());
2864ced8de1STim Renouf break;
2874ced8de1STim Renouf case Type::UInt:
2884ced8de1STim Renouf MPWriter.write(Node.getUInt());
2894ced8de1STim Renouf break;
2904ced8de1STim Renouf case Type::String:
2914ced8de1STim Renouf MPWriter.write(Node.getString());
2924ced8de1STim Renouf break;
2939d52f69aSMartin Dinkov case Type::Binary:
2949d52f69aSMartin Dinkov MPWriter.write(Node.getBinary());
2959d52f69aSMartin Dinkov break;
296673f2f70SSebastian Neubauer case Type::Empty:
297673f2f70SSebastian Neubauer llvm_unreachable("unhandled empty msgpack node");
2984ced8de1STim Renouf default:
2994ced8de1STim Renouf llvm_unreachable("unhandled msgpack object kind");
3004ced8de1STim Renouf }
3014ced8de1STim Renouf // Pop finished stack levels.
3024ced8de1STim Renouf while (!Stack.empty()) {
3034ced8de1STim Renouf if (Stack.back().Node.getKind() == Type::Map) {
3044ced8de1STim Renouf if (Stack.back().MapIt != Stack.back().Node.getMap().end())
3054ced8de1STim Renouf break;
3064ced8de1STim Renouf } else {
3074ced8de1STim Renouf if (Stack.back().ArrayIt != Stack.back().Node.getArray().end())
3084ced8de1STim Renouf break;
3094ced8de1STim Renouf }
3104ced8de1STim Renouf Stack.pop_back();
3114ced8de1STim Renouf }
3124ced8de1STim Renouf if (Stack.empty())
3134ced8de1STim Renouf break;
3144ced8de1STim Renouf // Get the next value.
3154ced8de1STim Renouf if (Stack.back().Node.getKind() == Type::Map) {
3164ced8de1STim Renouf if (Stack.back().OnKey) {
3174ced8de1STim Renouf // Do the key of a key,value pair in a map.
3184ced8de1STim Renouf Node = Stack.back().MapIt->first;
3194ced8de1STim Renouf Stack.back().OnKey = false;
3204ced8de1STim Renouf } else {
3214ced8de1STim Renouf Node = Stack.back().MapIt->second;
3224ced8de1STim Renouf ++Stack.back().MapIt;
3234ced8de1STim Renouf Stack.back().OnKey = true;
3244ced8de1STim Renouf }
3254ced8de1STim Renouf } else {
3264ced8de1STim Renouf Node = *Stack.back().ArrayIt;
3274ced8de1STim Renouf ++Stack.back().ArrayIt;
3284ced8de1STim Renouf }
3294ced8de1STim Renouf }
3304ced8de1STim Renouf }
331