LCOV - code coverage report
Current view: top level - mvodb - mjsonodb.cxx (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 338 0
Test Date: 2025-11-11 10:26:08 Functions: 0.0 % 80 0

            Line data    Source code
       1              : //
       2              : // ALPHA ROOT analyzer
       3              : //
       4              : // Access to ODB stored in JSON odb save file or ODB JSON dump in MIDAS data file.
       5              : //
       6              : // Name: mjsonodb.cxx
       7              : // Author: K.Olchanski, 28-May-2019
       8              : //
       9              : 
      10              : #include <stdio.h>
      11              : #include <assert.h>
      12              : #include <stdlib.h>
      13              : #include <string.h> // memset()
      14              : #include <errno.h> // errno
      15              : 
      16              : #include "mvodb.h"
      17              : #include "mjson.h"
      18              : 
      19            0 : static std::string toString(int i)
      20              : {
      21              :    char buf[256];
      22            0 :    snprintf(buf, sizeof(buf), "%d", i);
      23            0 :    return buf;
      24              : }
      25              : 
      26              : /// Access to ODB saved in JSON format inside midas .mid files
      27              : 
      28              : class JsonOdb : public MVOdb
      29              : {
      30              : public:
      31              :    MJsonNode* fRoot; // root of JSON document, NULL if we are a subdirectory
      32              :    MJsonNode* fDir;  // current ODB directory
      33              :    std::string fPath; // path to correct ODB directory
      34              :    bool fPrintError;
      35              : 
      36              : public:
      37            0 :    JsonOdb(MJsonNode* root, MJsonNode* dir, MVOdbError* error) // ctor
      38            0 :    {
      39            0 :       fPrintError = false;
      40            0 :       fRoot = root;
      41            0 :       fDir  = dir;
      42            0 :       fPath = "";
      43            0 :       SetOk(error);
      44            0 :    }
      45              : 
      46            0 :    ~JsonOdb() // dtor
      47            0 :    {
      48            0 :       if (fRoot) {
      49            0 :          delete fRoot;
      50            0 :          fRoot = NULL;
      51              :       }
      52            0 :       fDir = NULL;
      53            0 :    }
      54              : 
      55              : public:
      56            0 :    void SetPrintError(bool v)
      57              :    {
      58            0 :       fPrintError = true;
      59            0 :    }
      60              : 
      61            0 :    bool GetPrintError() const
      62              :    {
      63            0 :       return fPrintError;
      64              :    }
      65              : 
      66            0 :    void SetNotFound(MVOdbError* error, const char* varname)
      67              :    {
      68            0 :       std::string msg;
      69            0 :       msg += "Cannot find ";
      70            0 :       msg += "\"";
      71            0 :       msg += varname;
      72            0 :       msg += "\"";
      73            0 :       SetError(error, fPrintError, fPath, msg);
      74            0 :    }
      75              : 
      76            0 :    void SetVarError(MVOdbError* error, const char* varname, std::string msg)
      77              :    {
      78            0 :       std::string path;
      79            0 :       path += fPath;
      80            0 :       path += "/";
      81            0 :       path += varname;
      82            0 :       SetError(error, fPrintError, path, msg);
      83            0 :    }
      84              : 
      85            0 :    void SetWrongType(MVOdbError* error, const char* varname, const MJsonNode* node, const char* wanted_type)
      86              :    {
      87            0 :       std::string path;
      88            0 :       path += fPath;
      89            0 :       path += "/";
      90            0 :       path += varname;
      91            0 :       std::string msg;
      92            0 :       msg += "JSON node type mismatch: cannot convert node type ";
      93            0 :       msg += MJsonNode::TypeToString(node->GetType());
      94            0 :       msg += " to c++ type ";
      95            0 :       msg += "\"";
      96            0 :       msg += wanted_type;
      97            0 :       msg += "\"";
      98            0 :       SetError(error, fPrintError, path, msg);
      99            0 :    }
     100              : 
     101            0 :    bool IsReadOnly() const
     102              :    {
     103            0 :       return true;
     104              :    }
     105              : 
     106              :    template <typename T>
     107              :    bool GetJsonValue(const char* varname, const MJsonNode* node, T* value, MVOdbError *error);
     108              : 
     109              :    /// Follow the ODB path through the JSON tree
     110            0 :    static MJsonNode* FindPath(MJsonNode* dir, const char* path)
     111              :    {
     112            0 :       assert(dir);
     113              :       
     114              :       while (1) {
     115              :          // skip leading slashes
     116            0 :          while (*path == '/')
     117            0 :             path++;
     118              :          
     119            0 :          if (*path == 0)
     120            0 :             return dir;
     121              :          
     122            0 :          std::string elem;
     123              :          
     124              :          // copy the next path element into "elem"-
     125              :          // copy "path" until we hit "/" or end of string
     126              :          while (1) {
     127            0 :             if (*path==0 || *path=='/')
     128              :                break;
     129            0 :             elem += *path++;
     130              :          }
     131              :       
     132              :          //printf("looking for \"%s\" more \"%s\"\n", elem.c_str(), path);
     133              : 
     134            0 :          MJsonNode* found = NULL;
     135              : 
     136            0 :          const MJsonStringVector* s = dir->GetObjectNames();
     137            0 :          const MJsonNodeVector*   n = dir->GetObjectNodes();
     138            0 :          assert(s->size() == n->size());
     139              : 
     140            0 :          for (unsigned i=0; i<s->size(); i++) {
     141            0 :             if (strcasecmp(elem.c_str(), (*s)[i].c_str()) == 0) {
     142            0 :                if (dir->GetType() == MJSON_OBJECT) {
     143              :                   // found the right subdirectory, descend into it
     144            0 :                   found = (*n)[i];
     145            0 :                   break;
     146              :                } else {
     147            0 :                   return (*n)[i];
     148              :                }
     149              :             }
     150              :          }
     151              : 
     152            0 :          if (!found)
     153            0 :             return NULL;
     154            0 :          dir = found;
     155            0 :       }
     156              :    }
     157              :    
     158            0 :    MVOdb* Chdir(const char* subdir, bool create, MVOdbError* error)
     159              :    {
     160            0 :       MJsonNode* node = FindPath(fDir, subdir);
     161            0 :       if (!node) {
     162            0 :          SetNotFound(error, subdir);
     163            0 :          if (create) {
     164            0 :             return MakeNullOdb();
     165              :          } else {
     166            0 :             return NULL;
     167              :          }
     168              :       }
     169              : 
     170            0 :       if (node->GetType() != MJSON_OBJECT) {
     171            0 :          std::string msg;
     172            0 :          msg += "\"";
     173            0 :          msg += subdir;
     174            0 :          msg += "\"";
     175            0 :          msg += " JSON node is ";
     176            0 :          msg += "\"";
     177            0 :          msg += MJsonNode::TypeToString(node->GetType());
     178            0 :          msg += "\"";
     179            0 :          msg += " instead of subdirectory";
     180            0 :          SetError(error, fPrintError, fPath, msg);
     181            0 :          if (create)
     182            0 :             return MakeNullOdb();
     183              :          else
     184            0 :             return NULL;
     185            0 :       }
     186              : 
     187              :       //printf("Found subdir [%s]\n", subdir);
     188              :       //DumpTree(node);
     189              : 
     190            0 :       JsonOdb* x = new JsonOdb(NULL, node, error);
     191            0 :       x->fPath = fPath + "/" + subdir;
     192              :       
     193            0 :       SetOk(error);
     194            0 :       return x;
     195              :    }
     196              : 
     197            0 :    void ReadKey(const char* varname, int *tid, int *num_values, int *total_size, int *item_size, MVOdbError* error)
     198              :    {
     199            0 :       if (tid) *tid = 0;
     200            0 :       if (num_values) *num_values = 0;
     201            0 :       if (total_size) *total_size = 0;
     202            0 :       if (item_size)  *item_size = 0;
     203              :       // FIXME: not implemented
     204            0 :       SetOk(error);
     205            0 :    }
     206              : 
     207            0 :    void ReadKeyLastWritten(const char* varname, int *last_written, MVOdbError* error)
     208              :    {
     209            0 :       if (last_written) *last_written = 0;
     210              :       // FIXME: not implemented
     211            0 :       SetOk(error);
     212            0 :    }
     213              : 
     214            0 :    void ReadDir(std::vector<std::string>* varname, std::vector<int> *tid, std::vector<int> *num_values, std::vector<int> *total_size, std::vector<int> *item_size, MVOdbError* error)
     215              :    {
     216              :       // FIXME: not implemented
     217            0 :       SetOk(error);
     218            0 :    }
     219              : 
     220            0 :    void RB(const char* varname, bool   *value, bool create, MVOdbError* error)
     221              :    {
     222            0 :       RBAI(varname, 0, value, error);
     223            0 :    };
     224              : 
     225            0 :    void RI(const char* varname, int    *value, bool create, MVOdbError* error)
     226              :    {
     227            0 :       RIAI(varname, 0, value, error);
     228            0 :    };
     229              : 
     230            0 :    void RD(const char* varname, double *value, bool create, MVOdbError* error)
     231              :    {
     232            0 :       RDAI(varname, 0, value, error);
     233            0 :    };
     234              :       
     235            0 :    void RF(const char* varname, float  *value, bool create, MVOdbError* error)
     236              :    {
     237            0 :       RFAI(varname, 0, value, error);
     238            0 :    };
     239              :       
     240            0 :    void RS(const char* varname, std::string *value, bool create, int create_string_length, MVOdbError* error)
     241              :    {
     242            0 :       RSAI(varname, 0, value, error);
     243            0 :    };
     244              : 
     245            0 :    void RU16(const char* varname, uint16_t *value, bool create, MVOdbError* error)
     246              :    {
     247            0 :       RU16AI(varname, 0, value, error);
     248            0 :    };
     249              : 
     250            0 :    void RU32(const char* varname, uint32_t *value, bool create, MVOdbError* error)
     251              :    {
     252            0 :       RU32AI(varname, 0, value, error);
     253            0 :    };
     254              : 
     255              :    template <typename T>
     256            0 :    void RXA(const char* varname, std::vector<T> *value, MVOdbError* error)
     257              :    {
     258            0 :       if (!value) {
     259            0 :          SetOk(error);
     260            0 :          return;
     261              :       }
     262              : 
     263            0 :       MJsonNode* node = FindPath(fDir, varname);
     264            0 :       if (!node) {
     265            0 :          SetNotFound(error, varname);
     266            0 :          return;
     267              :       }
     268              : 
     269              :       //DumpTree(node);
     270              : 
     271            0 :       if (node->GetType() == MJSON_OBJECT) {
     272            0 :          SetVarError(error, varname, "JSON node is a subdirectory");
     273            0 :          return;
     274            0 :       } else if (node->GetType() == MJSON_ARRAY) {
     275              : 
     276            0 :          const MJsonNodeVector* a = node->GetArray();
     277              : 
     278            0 :          int num_values = a->size();
     279              : 
     280            0 :          value->clear();
     281              : 
     282            0 :          for (int i=0; i<num_values; i++) {
     283            0 :             const MJsonNode* elem = (*a)[i];
     284            0 :             T v;
     285            0 :             bool ok = GetJsonValue<T>(varname, elem, &v, error);
     286            0 :             if (!ok)
     287            0 :                break;
     288            0 :             value->push_back(v);
     289              :          }
     290              :       } else {
     291            0 :          T v;
     292            0 :          bool ok = GetJsonValue<T>(varname, node, &v, error);
     293            0 :          if (!ok)
     294            0 :             return;
     295            0 :          value->clear();
     296            0 :          value->push_back(v);
     297            0 :       }
     298              :    };
     299              : 
     300            0 :    void RBA(const char* varname, std::vector<bool> *value, bool create, int create_size, MVOdbError* error)
     301              :    {
     302            0 :       RXA(varname, value, error);
     303            0 :    }
     304              : 
     305            0 :    void RIA(const char* varname, std::vector<int> *value,  bool create, int create_size, MVOdbError* error)
     306              :    {
     307            0 :       RXA(varname, value, error);
     308            0 :    }
     309              : 
     310            0 :    void RDA(const char* varname, std::vector<double> *value,  bool create, int create_size, MVOdbError* error)
     311              :    {
     312            0 :       RXA(varname, value, error);
     313            0 :    }
     314              :    
     315            0 :    void RFA(const char* varname, std::vector<float>  *value,  bool create, int create_size, MVOdbError* error)
     316              :    {
     317            0 :       RXA(varname, value, error);
     318            0 :    }
     319              :    
     320            0 :    void RSA(const char* varname, std::vector<std::string> *value, bool create, int create_size, int create_string_length, MVOdbError* error)
     321              :    {
     322            0 :       RXA(varname, value, error);
     323            0 :    }
     324              : 
     325            0 :    void RU16A(const char* varname, std::vector<uint16_t> *value,  bool create, int create_size, MVOdbError* error)
     326              :    {
     327            0 :       RXA(varname, value, error);
     328            0 :    }
     329              : 
     330            0 :    void RU32A(const char* varname, std::vector<uint32_t> *value,  bool create, int create_size, MVOdbError* error)
     331              :    {
     332            0 :       RXA(varname, value, error);
     333            0 :    }
     334              : 
     335              :    template <typename T>
     336            0 :    void RXAI(const char* varname, int index, T* value, MVOdbError* error)
     337              :    {
     338            0 :       if (!value) {
     339            0 :          SetOk(error);
     340            0 :          return;
     341              :       }
     342              : 
     343            0 :       MJsonNode* node = FindPath(fDir, varname);
     344            0 :       if (!node) {
     345            0 :          SetNotFound(error, varname);
     346            0 :          return;
     347              :       }
     348              : 
     349              :       //printf("varname [%s] index %d, found node %p:\n", varname, index, node);
     350              :       //node->Dump();
     351              : 
     352            0 :       if (node->GetType() == MJSON_OBJECT) {
     353            0 :          SetVarError(error, varname, "JSON node is a subdirectory");
     354            0 :          return;
     355            0 :       } else if (node->GetType() == MJSON_ARRAY) {
     356              :          //DumpTree(node);
     357              : 
     358            0 :          const MJsonNodeVector* a = node->GetArray();
     359              : 
     360            0 :          int num_values = a->size();
     361              :          
     362            0 :          if (index < 0) {
     363            0 :             std::string msg;
     364            0 :             msg += "bad index ";
     365            0 :             msg += toString(index);
     366            0 :             msg += " for array of size ";
     367            0 :             msg += toString(num_values);
     368            0 :             SetVarError(error, varname, msg);
     369            0 :             return;
     370            0 :          }
     371              :          
     372            0 :          if (index >= num_values) {
     373            0 :             std::string msg;
     374            0 :             msg += "bad index ";
     375            0 :             msg += toString(index);
     376            0 :             msg += " for array of size ";
     377            0 :             msg += toString(num_values);
     378            0 :             SetVarError(error, varname, msg);
     379            0 :             return;
     380            0 :          }
     381              :          
     382            0 :          MJsonNode* elem = (*a)[index];
     383              : 
     384            0 :          GetJsonValue<T>(varname, elem, value, error);
     385            0 :          return;
     386              :       } else {
     387            0 :          if (index != 0) {
     388            0 :             std::string msg;
     389            0 :             msg += "non-zero index ";
     390            0 :             msg += toString(index);
     391            0 :             msg += " for non-array";
     392            0 :             SetVarError(error, varname, msg);
     393            0 :             return;
     394            0 :          }
     395              : 
     396            0 :          GetJsonValue<T>(varname, node, value, error);
     397            0 :          return;
     398              :       }
     399              :    }
     400              : 
     401            0 :    void RBAI(const char* varname, int index, bool   *value, MVOdbError* error)
     402              :    {
     403            0 :       RXAI(varname, index, value, error);
     404            0 :    }
     405              : 
     406            0 :    void RIAI(const char* varname, int index, int    *value, MVOdbError* error)
     407              :    {
     408            0 :       RXAI(varname, index, value, error);
     409            0 :    }
     410              :    
     411            0 :    void RDAI(const char* varname, int index, double *value, MVOdbError* error)
     412              :    {
     413            0 :       RXAI(varname, index, value, error);
     414            0 :    }
     415              :    
     416            0 :    void RFAI(const char* varname, int index, float  *value, MVOdbError* error)
     417              :    {
     418            0 :       RXAI(varname, index, value, error);
     419            0 :    }
     420              :    
     421            0 :    void RSAI(const char* varname, int index, std::string *value, MVOdbError* error)
     422              :    {
     423            0 :       RXAI(varname, index, value, error);
     424            0 :    }
     425              :    
     426            0 :    void RU16AI(const char* varname, int index, uint16_t *value, MVOdbError* error)
     427              :    {
     428            0 :       RXAI(varname, index, value, error);
     429            0 :    }
     430              : 
     431            0 :    void RU32AI(const char* varname, int index, uint32_t *value, MVOdbError* error)
     432              :    {
     433            0 :       RXAI(varname, index, value, error);
     434            0 :    }
     435              : 
     436              :    // write functions do nothing
     437              : 
     438            0 :    void WB(const char* varname, bool v,   MVOdbError* error) { SetOk(error); };
     439            0 :    void WI(const char* varname, int v,    MVOdbError* error)  { SetOk(error); };
     440            0 :    void WD(const char* varname, double v, MVOdbError* error) { SetOk(error); };
     441            0 :    void WF(const char* varname, float  v, MVOdbError* error) { SetOk(error); };
     442            0 :    void WS(const char* varname, const char* v, int string_length, MVOdbError* error) { SetOk(error); };
     443            0 :    void WU16(const char* varname, uint16_t v, MVOdbError* error) { SetOk(error); };
     444            0 :    void WU32(const char* varname, uint32_t v, MVOdbError* error) { SetOk(error); };
     445              : 
     446            0 :    void WBA(const char* varname, const std::vector<bool>& v, MVOdbError* error) { SetOk(error); };
     447            0 :    void WIA(const char* varname, const std::vector<int>& v, MVOdbError* error) { SetOk(error); };
     448            0 :    void WDA(const char* varname, const std::vector<double>& v, MVOdbError* error) { SetOk(error); };
     449            0 :    void WFA(const char* varname, const std::vector<float>& v, MVOdbError* error) { SetOk(error); };
     450            0 :    void WSA(const char* varname, const std::vector<std::string>& data, int odb_string_length, MVOdbError* error) { SetOk(error); };
     451            0 :    void WU16A(const char* varname, const std::vector<uint16_t>& v, MVOdbError* error) { SetOk(error); };
     452            0 :    void WU32A(const char* varname, const std::vector<uint32_t>& v, MVOdbError* error) { SetOk(error); };
     453              : 
     454            0 :    void WBAI(const char* varname, int index, bool v,   MVOdbError* error) { SetOk(error); };
     455            0 :    void WIAI(const char* varname, int index, int v,    MVOdbError* error)  { SetOk(error); };
     456            0 :    void WDAI(const char* varname, int index, double v, MVOdbError* error) { SetOk(error); };
     457            0 :    void WFAI(const char* varname, int index, float  v, MVOdbError* error) { SetOk(error); };
     458            0 :    void WSAI(const char* varname, int index, const char* v, MVOdbError* error) { SetOk(error); };
     459            0 :    void WU16AI(const char* varname, int index, uint16_t v, MVOdbError* error) { SetOk(error); };
     460            0 :    void WU32AI(const char* varname, int index, uint32_t v, MVOdbError* error) { SetOk(error); };
     461              : 
     462              :    // delete function does nothing
     463              : 
     464            0 :    void Delete(const char* odbname, MVOdbError* error) { SetOk(error); };
     465              : };
     466              : 
     467              : template<>
     468            0 : bool JsonOdb::GetJsonValue<int>(const char* varname, const MJsonNode* node, int* value, MVOdbError* error)
     469              : {
     470            0 :    switch (node->GetType()) {
     471            0 :    case MJSON_INT: *value = node->GetInt(); SetOk(error); return true;
     472            0 :    default: SetWrongType(error, varname, node, "int"); return false;
     473              :    }
     474              : }
     475              : 
     476              : template<>
     477            0 : bool JsonOdb::GetJsonValue<double>(const char* varname, const MJsonNode* node, double* value, MVOdbError* error)
     478              : {
     479            0 :    switch (node->GetType()) {
     480            0 :    case MJSON_INT: *value = (double)node->GetInt(); SetOk(error); return true;
     481            0 :    case MJSON_NUMBER: *value = node->GetDouble(); SetOk(error); return true;
     482            0 :    default: SetWrongType(error, varname, node, "double"); return false;
     483              :    }
     484              : }
     485              : 
     486              : template<>
     487            0 : bool JsonOdb::GetJsonValue<float>(const char* varname, const MJsonNode* node, float* value, MVOdbError* error)
     488              : {
     489            0 :    switch (node->GetType()) {
     490            0 :    case MJSON_INT: *value = (float)node->GetInt(); SetOk(error); return true;
     491            0 :    case MJSON_NUMBER: *value = node->GetDouble(); SetOk(error); return true;
     492            0 :    default: SetWrongType(error, varname, node, "float"); return false;
     493              :    }
     494              : }
     495              : 
     496              : template<>
     497            0 : bool JsonOdb::GetJsonValue<bool>(const char* varname, const MJsonNode* node, bool* value, MVOdbError* error)
     498              : {
     499            0 :    switch (node->GetType()) {
     500              :    //case MJSON_INT: *value = node->GetInt(); SetOk(error); return true;
     501              :    //case MJSON_NUMBER: *value = node->GetDouble(); SetOk(error); return true;
     502            0 :    case MJSON_BOOL: *value = node->GetBool(); SetOk(error); return true;
     503            0 :    default: SetWrongType(error, varname, node, "bool"); return false;
     504              :    }
     505              : }
     506              : 
     507              : template<>
     508            0 : bool JsonOdb::GetJsonValue<uint16_t>(const char* varname, const MJsonNode* node, uint16_t* value, MVOdbError* error)
     509              : {
     510            0 :    switch (node->GetType()) {
     511            0 :    case MJSON_INT: *value = (0xFFFF & node->GetInt()); SetOk(error); return true;
     512            0 :    case MJSON_STRING: *value = (0xFFFF & strtoul(node->GetString().c_str(), NULL, 0)); SetOk(error); return true;
     513            0 :    default: SetWrongType(error, varname, node, "uint16_t"); return false;
     514              :    }
     515              : }
     516              : 
     517              : template<>
     518            0 : bool JsonOdb::GetJsonValue<uint32_t>(const char* varname, const MJsonNode* node, uint32_t* value, MVOdbError* error)
     519              : {
     520            0 :    switch (node->GetType()) {
     521            0 :    case MJSON_INT: *value = node->GetInt(); SetOk(error); return true;
     522            0 :    case MJSON_STRING: *value = strtoul(node->GetString().c_str(), NULL, 0); SetOk(error); return true;
     523            0 :    default: SetWrongType(error, varname, node, "uint32_t"); return false;
     524              :    }
     525              : }
     526              : 
     527              : template<>
     528            0 : bool JsonOdb::GetJsonValue<std::string>(const char* varname, const MJsonNode* node, std::string* value, MVOdbError* error)
     529              : {
     530            0 :    switch (node->GetType()) {
     531            0 :    case MJSON_STRING: *value = node->GetString(); SetOk(error); return true;
     532            0 :    default: SetWrongType(error, varname, node, "std::string"); return false;
     533              :    }
     534              : }
     535              : 
     536            0 : MVOdb* MakeJsonFileOdb(const char* filename, MVOdbError* error)
     537              : {
     538            0 :    std::string data;
     539              : 
     540              :    {
     541            0 :       FILE *fp = fopen(filename, "r");
     542            0 :       if (!fp) {
     543            0 :          std::string msg;
     544            0 :          msg += "Cannot open file ";
     545            0 :          msg += "\"";
     546            0 :          msg += filename;
     547            0 :          msg += "\"";
     548            0 :          msg += " fopen() errno: ";
     549            0 :          msg += toString(errno);
     550            0 :          msg += " (";
     551            0 :          msg += strerror(errno);
     552            0 :          msg += ")";
     553            0 :          SetError(error, true, filename, msg);
     554            0 :          return MakeNullOdb();
     555            0 :       }
     556              :       
     557              :       while (1) {
     558              :          char buf[1024*1024];
     559            0 :          const char* s = fgets(buf, sizeof(buf), fp);
     560            0 :          if (!s)
     561            0 :             break;
     562            0 :          data += s;
     563            0 :       }
     564              :       
     565            0 :       fclose(fp);
     566            0 :       fp = NULL;
     567              :    }
     568              : 
     569            0 :    MJsonNode* root = MJsonNode::Parse(data.c_str());
     570              :    //root->Dump();
     571            0 :    return new JsonOdb(root, root, error);
     572            0 : }
     573              : 
     574            0 : MVOdb* MakeJsonBufferOdb(const char* buf, int bufsize, MVOdbError* error)
     575              : {
     576            0 :    MJsonNode* root = MJsonNode::Parse(buf);
     577              :    //root->Dump();
     578            0 :    return new JsonOdb(root, root, error);
     579              :    //return MakeNullOdb();
     580              : }
     581              : 
     582              : /* emacs
     583              :  * Local Variables:
     584              :  * tab-width: 8
     585              :  * c-basic-offset: 3
     586              :  * indent-tabs-mode: nil
     587              :  * End:
     588              :  */
        

Generated by: LCOV version 2.0-1