1 //===-- MsgPackDocument.cpp - MsgPack Document --------------------------*-===// 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 /// 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 13 /// MsgPackTypes. 14 /// 15 //===----------------------------------------------------------------------===// 16 17 #include "llvm/BinaryFormat/MsgPackDocument.h" 18 #include "llvm/BinaryFormat/MsgPackWriter.h" 19 20 using namespace llvm; 21 using namespace msgpack; 22 23 // Convert this DocNode into an empty array. 24 void DocNode::convertToArray() { *this = getDocument()->getArrayNode(); } 25 26 // Convert this DocNode into an empty map. 27 void DocNode::convertToMap() { *this = getDocument()->getMapNode(); } 28 29 /// Find the key in the MapDocNode. 30 DocNode::MapTy::iterator MapDocNode::find(StringRef S) { 31 return find(getDocument()->getNode(S)); 32 } 33 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)]; 38 } 39 40 /// Member access for MapDocNode. 41 DocNode &MapDocNode::operator[](DocNode Key) { 42 assert(!Key.isEmpty()); 43 DocNode &N = (*Map)[Key]; 44 if (N.isEmpty()) { 45 // Ensure a new element has its KindAndDoc initialized. 46 N = getDocument()->getEmptyNode(); 47 } 48 return N; 49 } 50 51 /// Member access for MapDocNode for integer key. 52 DocNode &MapDocNode::operator[](int Key) { 53 return (*this)[getDocument()->getNode(Key)]; 54 } 55 DocNode &MapDocNode::operator[](unsigned Key) { 56 return (*this)[getDocument()->getNode(Key)]; 57 } 58 DocNode &MapDocNode::operator[](int64_t Key) { 59 return (*this)[getDocument()->getNode(Key)]; 60 } 61 DocNode &MapDocNode::operator[](uint64_t Key) { 62 return (*this)[getDocument()->getNode(Key)]; 63 } 64 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()); 70 } 71 return (*Array)[Index]; 72 } 73 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 78 // that restriction. 79 DocNode &DocNode::operator=(StringRef Val) { 80 *this = getDocument()->getNode(Val); 81 return *this; 82 } 83 DocNode &DocNode::operator=(MemoryBufferRef Val) { 84 *this = getDocument()->getNode(Val); 85 return *this; 86 } 87 DocNode &DocNode::operator=(bool Val) { 88 *this = getDocument()->getNode(Val); 89 return *this; 90 } 91 DocNode &DocNode::operator=(int Val) { 92 *this = getDocument()->getNode(Val); 93 return *this; 94 } 95 DocNode &DocNode::operator=(unsigned Val) { 96 *this = getDocument()->getNode(Val); 97 return *this; 98 } 99 DocNode &DocNode::operator=(int64_t Val) { 100 *this = getDocument()->getNode(Val); 101 return *this; 102 } 103 DocNode &DocNode::operator=(uint64_t Val) { 104 *this = getDocument()->getNode(Val); 105 return *this; 106 } 107 108 // A level in the document reading stack. 109 struct StackLevel { 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) {} 114 DocNode Node; 115 size_t Index; 116 size_t End; 117 // Points to map entry when we have just processed a map key. 118 DocNode *MapEntry; 119 DocNode MapKey; 120 }; 121 122 // Read a document from a binary msgpack blob, merging into anything already in 123 // the Document. 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. 130 131 bool Document::readFromBlob( 132 StringRef Blob, bool Multi, 133 function_ref<int(DocNode *DestNode, DocNode SrcNode, DocNode MapKey)> 134 Merger) { 135 msgpack::Reader MPReader(Blob); 136 SmallVector<StackLevel, 4> Stack; 137 if (Multi) { 138 // Create the array for multiple top-level objects. 139 Root = getArrayNode(); 140 Stack.push_back(StackLevel(Root, 0, (size_t)-1)); 141 } 142 do { 143 // On to next element (or key if doing a map key next). 144 // Read the value. 145 Object Obj; 146 if (!MPReader.read(Obj)) { 147 if (Multi && Stack.size() == 1) { 148 // OK to finish here as we've just done a top-level element with Multi 149 break; 150 } 151 return false; // Finished too early 152 } 153 // Convert it into a DocNode. 154 DocNode Node; 155 switch (Obj.Kind) { 156 case Type::Nil: 157 Node = getNode(); 158 break; 159 case Type::Int: 160 Node = getNode(Obj.Int); 161 break; 162 case Type::UInt: 163 Node = getNode(Obj.UInt); 164 break; 165 case Type::Boolean: 166 Node = getNode(Obj.Bool); 167 break; 168 case Type::Float: 169 Node = getNode(Obj.Float); 170 break; 171 case Type::String: 172 Node = getNode(Obj.Raw); 173 break; 174 case Type::Binary: 175 Node = getNode(MemoryBufferRef(Obj.Raw, "")); 176 break; 177 case Type::Map: 178 Node = getMapNode(); 179 break; 180 case Type::Array: 181 Node = getArrayNode(); 182 break; 183 default: 184 return false; // Raw and Extension not supported 185 } 186 187 // Store it. 188 DocNode *DestNode = nullptr; 189 if (Stack.empty()) 190 DestNode = &Root; 191 else if (Stack.back().Node.getKind() == Type::Array) { 192 // Reading an array entry. 193 auto &Array = Stack.back().Node.getArray(); 194 DestNode = &Array[Stack.back().Index++]; 195 } else { 196 auto &Map = Stack.back().Node.getMap(); 197 if (!Stack.back().MapEntry) { 198 // Reading a map key. 199 Stack.back().MapKey = Node; 200 Stack.back().MapEntry = &Map[Node]; 201 continue; 202 } 203 // Reading the value for the map key read in the last iteration. 204 DestNode = Stack.back().MapEntry; 205 Stack.back().MapEntry = nullptr; 206 ++Stack.back().Index; 207 } 208 int MergeResult = 0; 209 if (!DestNode->isEmpty()) { 210 // In a merge, there is already a value at this position. Call the 211 // callback to attempt to resolve the conflict. The resolution must result 212 // in an array or map if Node is an array or map respectively. 213 DocNode MapKey = !Stack.empty() && !Stack.back().MapKey.isEmpty() 214 ? Stack.back().MapKey 215 : getNode(); 216 MergeResult = Merger(DestNode, Node, MapKey); 217 if (MergeResult < 0) 218 return false; // Merge conflict resolution failed 219 assert(!((Node.isMap() && !DestNode->isMap()) || 220 (Node.isArray() && !DestNode->isArray()))); 221 } else 222 *DestNode = Node; 223 224 // See if we're starting a new array or map. 225 switch (DestNode->getKind()) { 226 case msgpack::Type::Array: 227 case msgpack::Type::Map: 228 Stack.push_back(StackLevel(*DestNode, MergeResult, Obj.Length, nullptr)); 229 break; 230 default: 231 break; 232 } 233 234 // Pop finished stack levels. 235 while (!Stack.empty()) { 236 if (Stack.back().MapEntry) 237 break; 238 if (Stack.back().Index != Stack.back().End) 239 break; 240 Stack.pop_back(); 241 } 242 } while (!Stack.empty()); 243 return true; 244 } 245 246 struct WriterStackLevel { 247 DocNode Node; 248 DocNode::MapTy::iterator MapIt; 249 DocNode::ArrayTy::iterator ArrayIt; 250 bool OnKey; 251 }; 252 253 /// Write a MsgPack document to a binary MsgPack blob. 254 void Document::writeToBlob(std::string &Blob) { 255 Blob.clear(); 256 raw_string_ostream OS(Blob); 257 msgpack::Writer MPWriter(OS); 258 SmallVector<WriterStackLevel, 4> Stack; 259 DocNode Node = getRoot(); 260 for (;;) { 261 switch (Node.getKind()) { 262 case Type::Array: 263 MPWriter.writeArraySize(Node.getArray().size()); 264 Stack.push_back( 265 {Node, DocNode::MapTy::iterator(), Node.getArray().begin(), false}); 266 break; 267 case Type::Map: 268 MPWriter.writeMapSize(Node.getMap().size()); 269 Stack.push_back( 270 {Node, Node.getMap().begin(), DocNode::ArrayTy::iterator(), true}); 271 break; 272 case Type::Nil: 273 MPWriter.writeNil(); 274 break; 275 case Type::Boolean: 276 MPWriter.write(Node.getBool()); 277 break; 278 case Type::Int: 279 MPWriter.write(Node.getInt()); 280 break; 281 case Type::UInt: 282 MPWriter.write(Node.getUInt()); 283 break; 284 case Type::String: 285 MPWriter.write(Node.getString()); 286 break; 287 case Type::Binary: 288 MPWriter.write(Node.getBinary()); 289 break; 290 case Type::Empty: 291 llvm_unreachable("unhandled empty msgpack node"); 292 default: 293 llvm_unreachable("unhandled msgpack object kind"); 294 } 295 // Pop finished stack levels. 296 while (!Stack.empty()) { 297 if (Stack.back().Node.getKind() == Type::Map) { 298 if (Stack.back().MapIt != Stack.back().Node.getMap().end()) 299 break; 300 } else { 301 if (Stack.back().ArrayIt != Stack.back().Node.getArray().end()) 302 break; 303 } 304 Stack.pop_back(); 305 } 306 if (Stack.empty()) 307 break; 308 // Get the next value. 309 if (Stack.back().Node.getKind() == Type::Map) { 310 if (Stack.back().OnKey) { 311 // Do the key of a key,value pair in a map. 312 Node = Stack.back().MapIt->first; 313 Stack.back().OnKey = false; 314 } else { 315 Node = Stack.back().MapIt->second; 316 ++Stack.back().MapIt; 317 Stack.back().OnKey = true; 318 } 319 } else { 320 Node = *Stack.back().ArrayIt; 321 ++Stack.back().ArrayIt; 322 } 323 } 324 } 325