Home | History | Annotate | Line # | Download | only in BinaryFormat
      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=(bool Val) {
     84   *this = getDocument()->getNode(Val);
     85   return *this;
     86 }
     87 DocNode &DocNode::operator=(int Val) {
     88   *this = getDocument()->getNode(Val);
     89   return *this;
     90 }
     91 DocNode &DocNode::operator=(unsigned Val) {
     92   *this = getDocument()->getNode(Val);
     93   return *this;
     94 }
     95 DocNode &DocNode::operator=(int64_t Val) {
     96   *this = getDocument()->getNode(Val);
     97   return *this;
     98 }
     99 DocNode &DocNode::operator=(uint64_t Val) {
    100   *this = getDocument()->getNode(Val);
    101   return *this;
    102 }
    103 
    104 // A level in the document reading stack.
    105 struct StackLevel {
    106   StackLevel(DocNode Node, size_t StartIndex, size_t Length,
    107              DocNode *MapEntry = nullptr)
    108       : Node(Node), Index(StartIndex), End(StartIndex + Length),
    109         MapEntry(MapEntry) {}
    110   DocNode Node;
    111   size_t Index;
    112   size_t End;
    113   // Points to map entry when we have just processed a map key.
    114   DocNode *MapEntry;
    115   DocNode MapKey;
    116 };
    117 
    118 // Read a document from a binary msgpack blob, merging into anything already in
    119 // the Document.
    120 // The blob data must remain valid for the lifetime of this Document (because a
    121 // string object in the document contains a StringRef into the original blob).
    122 // If Multi, then this sets root to an array and adds top-level objects to it.
    123 // If !Multi, then it only reads a single top-level object, even if there are
    124 // more, and sets root to that.
    125 // Returns false if failed due to illegal format or merge error.
    126 
    127 bool Document::readFromBlob(
    128     StringRef Blob, bool Multi,
    129     function_ref<int(DocNode *DestNode, DocNode SrcNode, DocNode MapKey)>
    130         Merger) {
    131   msgpack::Reader MPReader(Blob);
    132   SmallVector<StackLevel, 4> Stack;
    133   if (Multi) {
    134     // Create the array for multiple top-level objects.
    135     Root = getArrayNode();
    136     Stack.push_back(StackLevel(Root, 0, (size_t)-1));
    137   }
    138   do {
    139     // On to next element (or key if doing a map key next).
    140     // Read the value.
    141     Object Obj;
    142     if (!MPReader.read(Obj)) {
    143       if (Multi && Stack.size() == 1) {
    144         // OK to finish here as we've just done a top-level element with Multi
    145         break;
    146       }
    147       return false; // Finished too early
    148     }
    149     // Convert it into a DocNode.
    150     DocNode Node;
    151     switch (Obj.Kind) {
    152     case Type::Nil:
    153       Node = getNode();
    154       break;
    155     case Type::Int:
    156       Node = getNode(Obj.Int);
    157       break;
    158     case Type::UInt:
    159       Node = getNode(Obj.UInt);
    160       break;
    161     case Type::Boolean:
    162       Node = getNode(Obj.Bool);
    163       break;
    164     case Type::Float:
    165       Node = getNode(Obj.Float);
    166       break;
    167     case Type::String:
    168       Node = getNode(Obj.Raw);
    169       break;
    170     case Type::Map:
    171       Node = getMapNode();
    172       break;
    173     case Type::Array:
    174       Node = getArrayNode();
    175       break;
    176     default:
    177       return false; // Raw and Extension not supported
    178     }
    179 
    180     // Store it.
    181     DocNode *DestNode = nullptr;
    182     if (Stack.empty())
    183       DestNode = &Root;
    184     else if (Stack.back().Node.getKind() == Type::Array) {
    185       // Reading an array entry.
    186       auto &Array = Stack.back().Node.getArray();
    187       DestNode = &Array[Stack.back().Index++];
    188     } else {
    189       auto &Map = Stack.back().Node.getMap();
    190       if (!Stack.back().MapEntry) {
    191         // Reading a map key.
    192         Stack.back().MapKey = Node;
    193         Stack.back().MapEntry = &Map[Node];
    194         continue;
    195       }
    196       // Reading the value for the map key read in the last iteration.
    197       DestNode = Stack.back().MapEntry;
    198       Stack.back().MapEntry = nullptr;
    199       ++Stack.back().Index;
    200     }
    201     int MergeResult = 0;
    202     if (!DestNode->isEmpty()) {
    203       // In a merge, there is already a value at this position. Call the
    204       // callback to attempt to resolve the conflict. The resolution must result
    205       // in an array or map if Node is an array or map respectively.
    206       DocNode MapKey = !Stack.empty() && !Stack.back().MapKey.isEmpty()
    207                            ? Stack.back().MapKey
    208                            : getNode();
    209       MergeResult = Merger(DestNode, Node, MapKey);
    210       if (MergeResult < 0)
    211         return false; // Merge conflict resolution failed
    212       assert(!((Node.isMap() && !DestNode->isMap()) ||
    213                (Node.isArray() && !DestNode->isArray())));
    214     } else
    215       *DestNode = Node;
    216 
    217     // See if we're starting a new array or map.
    218     switch (DestNode->getKind()) {
    219     case msgpack::Type::Array:
    220     case msgpack::Type::Map:
    221       Stack.push_back(StackLevel(*DestNode, MergeResult, Obj.Length, nullptr));
    222       break;
    223     default:
    224       break;
    225     }
    226 
    227     // Pop finished stack levels.
    228     while (!Stack.empty()) {
    229       if (Stack.back().MapEntry)
    230         break;
    231       if (Stack.back().Index != Stack.back().End)
    232         break;
    233       Stack.pop_back();
    234     }
    235   } while (!Stack.empty());
    236   return true;
    237 }
    238 
    239 struct WriterStackLevel {
    240   DocNode Node;
    241   DocNode::MapTy::iterator MapIt;
    242   DocNode::ArrayTy::iterator ArrayIt;
    243   bool OnKey;
    244 };
    245 
    246 /// Write a MsgPack document to a binary MsgPack blob.
    247 void Document::writeToBlob(std::string &Blob) {
    248   Blob.clear();
    249   raw_string_ostream OS(Blob);
    250   msgpack::Writer MPWriter(OS);
    251   SmallVector<WriterStackLevel, 4> Stack;
    252   DocNode Node = getRoot();
    253   for (;;) {
    254     switch (Node.getKind()) {
    255     case Type::Array:
    256       MPWriter.writeArraySize(Node.getArray().size());
    257       Stack.push_back(
    258           {Node, DocNode::MapTy::iterator(), Node.getArray().begin(), false});
    259       break;
    260     case Type::Map:
    261       MPWriter.writeMapSize(Node.getMap().size());
    262       Stack.push_back(
    263           {Node, Node.getMap().begin(), DocNode::ArrayTy::iterator(), true});
    264       break;
    265     case Type::Nil:
    266       MPWriter.writeNil();
    267       break;
    268     case Type::Boolean:
    269       MPWriter.write(Node.getBool());
    270       break;
    271     case Type::Int:
    272       MPWriter.write(Node.getInt());
    273       break;
    274     case Type::UInt:
    275       MPWriter.write(Node.getUInt());
    276       break;
    277     case Type::String:
    278       MPWriter.write(Node.getString());
    279       break;
    280     case Type::Empty:
    281       llvm_unreachable("unhandled empty msgpack node");
    282     default:
    283       llvm_unreachable("unhandled msgpack object kind");
    284     }
    285     // Pop finished stack levels.
    286     while (!Stack.empty()) {
    287       if (Stack.back().Node.getKind() == Type::Map) {
    288         if (Stack.back().MapIt != Stack.back().Node.getMap().end())
    289           break;
    290       } else {
    291         if (Stack.back().ArrayIt != Stack.back().Node.getArray().end())
    292           break;
    293       }
    294       Stack.pop_back();
    295     }
    296     if (Stack.empty())
    297       break;
    298     // Get the next value.
    299     if (Stack.back().Node.getKind() == Type::Map) {
    300       if (Stack.back().OnKey) {
    301         // Do the key of a key,value pair in a map.
    302         Node = Stack.back().MapIt->first;
    303         Stack.back().OnKey = false;
    304       } else {
    305         Node = Stack.back().MapIt->second;
    306         ++Stack.back().MapIt;
    307         Stack.back().OnKey = true;
    308       }
    309     } else {
    310       Node = *Stack.back().ArrayIt;
    311       ++Stack.back().ArrayIt;
    312     }
    313   }
    314 }
    315