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

            Line data    Source code
       1              : /********************************************************************\
       2              : 
       3              :   Name:         json_paste.cxx
       4              :   Created by:   Konstantin Olchanski
       5              : 
       6              :   Contents:     JSON decoder for ODB
       7              : 
       8              : \********************************************************************/
       9              : 
      10              : #include "midas.h"
      11              : #include "msystem.h"
      12              : #include "mjson.h"
      13              : #include "mstrlcpy.h"
      14              : 
      15            0 : INT EXPRT db_load_json(HNDLE hDB, HNDLE hKey, const char *filename)
      16              : {
      17              :    int status;
      18              :    //printf("db_load_json: filename [%s], handle %d\n", filename, hKey);
      19              : 
      20            0 :    FILE* fp = fopen(filename, "r");
      21            0 :    if (!fp) {
      22            0 :       cm_msg(MERROR, "db_load_json", "file \"%s\" not found", filename);
      23            0 :       return DB_FILE_ERROR;
      24              :    }
      25              : 
      26            0 :    std::string data;
      27              : 
      28              :    while (1) {
      29              :       char buf[102400];
      30            0 :       int rd = read(fileno(fp), buf, sizeof(buf)-1);
      31            0 :       if (rd == 0)
      32            0 :          break; // end of file
      33            0 :       if (rd < 0) {
      34              :          // error
      35            0 :          cm_msg(MERROR, "db_load_json", "file \"%s\" read error %d (%s)", filename, errno, strerror(errno));
      36            0 :          fclose(fp);
      37            0 :          return DB_FILE_ERROR;
      38              :       }
      39              :       // make sure string is nul terminated
      40            0 :       buf[sizeof(buf)-1] = 0;
      41            0 :       data += buf;
      42            0 :    }
      43              : 
      44            0 :    fclose(fp);
      45            0 :    fp = NULL;
      46              : 
      47              :    //printf("file contents: [%s]\n", data.c_str());
      48              : 
      49            0 :    const char* jptr = strchr(data.c_str(), '{');
      50              : 
      51            0 :    if (!jptr) {
      52            0 :       cm_msg(MERROR, "db_load_json", "file \"%s\" does not look like JSON data", filename);
      53            0 :       return DB_FILE_ERROR;
      54              :    }
      55              : 
      56            0 :    status = db_paste_json(hDB, hKey, jptr);
      57              : 
      58            0 :    if (status != DB_SUCCESS) {
      59            0 :       cm_msg(MERROR, "db_load_json", "error loading JSON data from file \"%s\"", filename);
      60            0 :       return status;
      61              :    }
      62              : 
      63            0 :    return status;
      64            0 : }
      65              : 
      66            0 : static int tid_from_key(const MJsonNode* key)
      67              : {
      68            0 :    if (!key)
      69            0 :       return 0;
      70            0 :    const MJsonNode* n = key->FindObjectNode("type");
      71            0 :    if (!n)
      72            0 :       return 0;
      73            0 :    int tid = n->GetInt();
      74            0 :    if (tid > 0)
      75            0 :       return tid;
      76            0 :    return 0;
      77              : }
      78              : 
      79            0 : static int item_size_from_key(const MJsonNode* key)
      80              : {
      81            0 :    if (!key)
      82            0 :       return 0;
      83            0 :    const MJsonNode* n = key->FindObjectNode("item_size");
      84            0 :    if (!n)
      85            0 :       return 0;
      86            0 :    int item_size = n->GetInt();
      87            0 :    if (item_size > 0)
      88            0 :       return item_size;
      89            0 :    return 0;
      90              : }
      91              : 
      92            0 : static int guess_tid(const MJsonNode* node)
      93              : {
      94            0 :    switch (node->GetType()) {
      95            0 :    case MJSON_ARRAY:  { const MJsonNodeVector* a = node->GetArray(); if (a && a->size()>0) return guess_tid((*a)[0]); else return 0; }
      96            0 :    case MJSON_OBJECT: return TID_KEY;
      97            0 :    case MJSON_STRING: {
      98            0 :       std::string v = node->GetString();
      99            0 :       if (v == "NaN")
     100            0 :          return TID_DOUBLE;
     101            0 :       else if (v == "Infinity")
     102            0 :          return TID_DOUBLE;
     103            0 :       else if (v == "-Infinity")
     104            0 :          return TID_DOUBLE;
     105            0 :       else if (v[0]=='0' && v[1]=='x' && isxdigit(v[2]) && v.length() > 10)
     106            0 :          return TID_UINT64;
     107            0 :       else if (v[0]=='0' && v[1]=='x' && isxdigit(v[2]))
     108            0 :          return TID_DWORD;
     109              :       else
     110            0 :          return TID_STRING;
     111            0 :    }
     112            0 :    case MJSON_INT:    return TID_INT;
     113            0 :    case MJSON_NUMBER: return TID_DOUBLE;
     114            0 :    case MJSON_BOOL:   return TID_BOOL;
     115            0 :    default: return 0;
     116              :    }
     117              : }
     118              : 
     119              : static int paste_node(HNDLE hDB, HNDLE hKey, const char* path, bool is_array, int index, const MJsonNode* node, int tid, int string_length, const MJsonNode* key);
     120              : 
     121            0 : static int paste_array(HNDLE hDB, HNDLE hKey, const char* path, const MJsonNode* node, int tid, int string_length, const MJsonNode* key)
     122              : {
     123            0 :    int status, slength = 0;
     124            0 :    const MJsonNodeVector* a = node->GetArray();
     125              : 
     126            0 :    if (a==NULL) {
     127            0 :       cm_msg(MERROR, "db_paste_json", "invalid array at \"%s\"", path);
     128            0 :       return DB_FILE_ERROR;
     129              :    }
     130              : 
     131            0 :    if (string_length == 0) {
     132            0 :       int slength = item_size_from_key(key);
     133            0 :       if (slength == 0)
     134            0 :          slength = NAME_LENGTH;
     135              :    } else {
     136            0 :       slength = string_length;
     137              :    }
     138              : 
     139              :    KEY odbkey;
     140            0 :    status = db_get_key(hDB, hKey, &odbkey);
     141            0 :    if (status != DB_SUCCESS) {
     142            0 :       cm_msg(MERROR, "db_paste_json", "cannot get odb key at \"%s\", status %d", path, status);
     143            0 :       return DB_FILE_ERROR;
     144              :    }
     145              : 
     146            0 :    if (odbkey.item_size > 0 && (INT) a->size() != odbkey.num_values) {
     147            0 :       status = db_set_num_values(hDB, hKey, a->size());
     148            0 :       if (status != DB_SUCCESS) {
     149            0 :          cm_msg(MERROR, "db_paste_json", "cannot resize key \"%s\", status = %d", path, status);
     150            0 :          return status;
     151              :       }
     152              :    }
     153              : 
     154            0 :    bool is_array = (a->size() > 1);
     155            0 :    for (unsigned i=a->size(); ;) {
     156            0 :       if (i==0)
     157            0 :          break;
     158            0 :       i--;
     159            0 :       MJsonNode* n = (*a)[i];
     160            0 :       if (!n)
     161            0 :          continue;
     162            0 :       status = paste_node(hDB, hKey, path, is_array, i, n, tid, slength, key);
     163            0 :       if (status == DB_NO_ACCESS) {
     164            0 :          cm_msg(MERROR, "db_paste_json", "skipping write-protected array \"%s\"", path);
     165            0 :          return DB_SUCCESS;
     166            0 :       } else if (status != DB_SUCCESS)
     167            0 :          return status;
     168            0 :    }
     169              : 
     170            0 :    return DB_SUCCESS;
     171              : }
     172              : 
     173            0 : static int paste_object(HNDLE hDB, HNDLE hKey, const char* path, const MJsonNode* objnode)
     174              : {
     175            0 :    if (equal_ustring(path, "/system/clients")) {
     176              :       // do not reload ODB /system/clients
     177            0 :       return DB_SUCCESS;
     178              :    }
     179              :    int status;
     180            0 :    const MJsonStringVector* names = objnode->GetObjectNames();
     181            0 :    const MJsonNodeVector* nodes = objnode->GetObjectNodes();
     182            0 :    if (names==NULL||nodes==NULL||names->size()!=nodes->size()) {
     183            0 :       cm_msg(MERROR, "db_paste_json", "invalid object at \"%s\"", path);
     184            0 :       return DB_FILE_ERROR;
     185              :    }
     186            0 :    for(unsigned i=0; i<names->size(); i++) {
     187            0 :       const char* name = (*names)[i].c_str();
     188            0 :       const MJsonNode* node = (*nodes)[i];
     189            0 :       const MJsonNode* key = NULL;
     190            0 :       if (strchr(name, '/')) // skip special entries
     191            0 :          continue;
     192            0 :       int tid = 0;
     193            0 :       if (node->GetType() == MJSON_OBJECT)
     194            0 :          tid = TID_KEY;
     195              :       else {
     196            0 :          key = objnode->FindObjectNode((std::string(name) + "/key").c_str());
     197            0 :          if (key)
     198            0 :             tid = tid_from_key(key);
     199            0 :          if (!tid)
     200            0 :             tid = guess_tid(node);
     201              :          //printf("entry [%s] type %s, tid %d\n", name, MJsonNode::TypeToString(node->GetType()), tid);
     202              :       }
     203              : 
     204            0 :       status = db_create_key(hDB, hKey, name, tid);
     205              : 
     206            0 :       if (status == DB_KEY_EXIST) {
     207              :          HNDLE hSubkey;
     208              :          KEY key;
     209            0 :          status = db_find_link(hDB, hKey, name, &hSubkey);
     210            0 :          if (status != DB_SUCCESS) {
     211            0 :             cm_msg(MERROR, "db_paste_json", "key exists, but cannot find it \"%s\" of type %d in \"%s\", db_find_link() status %d", name, tid, path, status);
     212            0 :             return status;
     213              :          }
     214              : 
     215            0 :          status = db_get_key(hDB, hSubkey, &key);
     216            0 :          if (status != DB_SUCCESS) {
     217            0 :             cm_msg(MERROR, "db_paste_json", "cannot create \"%s\" of type %d in \"%s\", db_create_key() status %d", name, tid, path, status);
     218            0 :             return status;
     219              :          }
     220              : 
     221            0 :          if ((int)key.type == tid) {
     222              :             // existing item is of the same type, continue with overwriting it
     223            0 :             status = DB_SUCCESS;
     224              :          } else {
     225              :             // FIXME: delete wrong item, create item with correct tid
     226            0 :             cm_msg(MERROR, "db_paste_json", "cannot overwrite existing item \"%s\" of type %d in \"%s\" with new tid %d", name, key.type, path, tid);
     227            0 :             return status;
     228              :          }
     229              :       }
     230              : 
     231            0 :       if (status != DB_SUCCESS) {
     232            0 :          cm_msg(MERROR, "db_paste_json", "cannot create \"%s\" of type %d in \"%s\", db_create_key() status %d", name, tid, path, status);
     233            0 :          return status;
     234              :       }
     235              : 
     236              :       HNDLE hSubkey;
     237            0 :       status = db_find_link(hDB, hKey, name, &hSubkey);
     238            0 :       if (status != DB_SUCCESS) {
     239            0 :          cm_msg(MERROR, "db_paste_json", "cannot find \"%s\" of type %d in \"%s\", db_find_link() status %d", name, tid, path, status);
     240            0 :          return status;
     241              :       }
     242              : 
     243            0 :       std::string node_name;
     244            0 :       if (strcmp(path, "/") != 0) {
     245            0 :          node_name += path;
     246              :       }
     247            0 :       node_name += "/";
     248            0 :       node_name += name;
     249              : 
     250            0 :       status = paste_node(hDB, hSubkey, node_name.c_str(), false, 0, node, tid, 0, key);
     251            0 :       if (status == DB_NO_ACCESS) {
     252            0 :          cm_msg(MERROR, "db_paste_json", "skipping write-protected node \"%s\"", node_name.c_str());
     253            0 :       } else if (status != DB_SUCCESS) {
     254            0 :          cm_msg(MERROR, "db_paste_json", "paste of \"%s\" is incomplete", node_name.c_str());
     255              :          //cm_msg(MERROR, "db_paste_json", "cannot..."); // paste_node() reports it's own failures
     256            0 :          return status;
     257              :       }
     258            0 :    }
     259            0 :    return DB_SUCCESS;
     260              : }
     261              : 
     262            0 : static int paste_bool(HNDLE hDB, HNDLE hKey, const char* path, int index, const MJsonNode* node)
     263              : {
     264              :    int status;
     265            0 :    BOOL value = node->GetBool();
     266            0 :    int size = sizeof(value);
     267            0 :    status = db_set_data_index(hDB, hKey, &value, size, index, TID_BOOL);
     268            0 :    if (status != DB_SUCCESS) {
     269            0 :       cm_msg(MERROR, "db_paste_json", "cannot set TID_BOOL value for \"%s\", db_set_data_index() status %d", path, status);
     270            0 :       return status;
     271              :    }
     272            0 :    return DB_SUCCESS;
     273              : }
     274              : 
     275            0 : static int GetDWORD(const MJsonNode* node, const char* path, DWORD* dw)
     276              : {
     277            0 :    switch (node->GetType()) {
     278            0 :    default:
     279            0 :       cm_msg(MERROR, "db_paste_json", "GetDWORD: unexpected node type %d at \"%s\"", node->GetType(), path);
     280            0 :       *dw = 0;
     281            0 :       return DB_FILE_ERROR;
     282            0 :    case MJSON_INT:
     283            0 :       *dw = node->GetInt();
     284            0 :       return SUCCESS;
     285            0 :    case MJSON_NUMBER:
     286            0 :       *dw = (DWORD)node->GetDouble();
     287            0 :       return SUCCESS;
     288            0 :    case MJSON_STRING:
     289            0 :       std::string s = node->GetString();
     290            0 :       errno = 0;
     291            0 :       if (s[0] == '0' && s[1] == 'x') { // hex encoded number
     292            0 :          *dw = strtoul(s.c_str(), NULL, 16);
     293            0 :       } else if (s.back() == 'b') { // binary number
     294            0 :          *dw = strtoul(s.c_str(), NULL, 2);
     295            0 :       } else if (isdigit(s[0]) || (s[0]=='-' && isdigit(s[1]))) { // probably a number
     296            0 :          *dw = strtoul(s.c_str(), NULL, 0);
     297              :       } else {
     298            0 :          cm_msg(MERROR, "db_paste_json", "GetDWORD: MJSON_STRING node invalid numeric value \'%s\' at \"%s\"", s.c_str(), path);
     299            0 :          *dw = 0;
     300            0 :          return DB_FILE_ERROR;
     301              :       }
     302            0 :       if (errno != 0) {
     303            0 :          cm_msg(MERROR, "db_paste_json", "GetDWORD: MJSON_STRING node invalid numeric value \'%s\', strtoul() errno %d (%s) at \"%s\"", s.c_str(), errno, strerror(errno), path);
     304            0 :          *dw = 0;
     305            0 :          return DB_FILE_ERROR;
     306              :       }
     307            0 :       return SUCCESS;
     308              :    }
     309              :    // NOT REACHED
     310              : }
     311              : 
     312            0 : static int GetQWORD(const MJsonNode* node, const char* path, UINT64* qw)
     313              : {
     314            0 :    switch (node->GetType()) {
     315            0 :    default:
     316            0 :       cm_msg(MERROR, "db_paste_json", "GetQWORD: unexpected node type %d at \"%s\"", node->GetType(), path);
     317            0 :       *qw = 0;
     318            0 :       return DB_FILE_ERROR;
     319            0 :    case MJSON_INT:
     320            0 :       *qw = node->GetLL();
     321            0 :       return SUCCESS;
     322            0 :    case MJSON_NUMBER:
     323            0 :       *qw = node->GetDouble();
     324            0 :       return SUCCESS;
     325            0 :    case MJSON_STRING:
     326            0 :       std::string s = node->GetString();
     327            0 :       errno = 0;
     328            0 :       if (s[0] == '0' && s[1] == 'x') { // hex encoded number
     329            0 :          *qw = strtoull(s.c_str(), NULL, 16);
     330            0 :       } else if (s.back() == 'b') { // binary number
     331            0 :          *qw = strtoull(s.c_str(), NULL, 2);
     332            0 :       } else if (isdigit(s[0]) || (s[0]=='-' && isdigit(s[1]))) { // probably a number
     333            0 :          *qw = strtoull(s.c_str(), NULL, 0);
     334              :       } else {
     335            0 :          cm_msg(MERROR, "db_paste_json", "GetQWORD: MJSON_STRING node invalid numeric value \'%s\' at \"%s\"", s.c_str(), path);
     336            0 :          *qw = 0;
     337            0 :          return DB_FILE_ERROR;
     338              :       }
     339            0 :       if (errno != 0) {
     340            0 :          cm_msg(MERROR, "db_paste_json", "GetQWORD: MJSON_STRING node invalid numeric value \'%s\', strtoul() errno %d (%s) at \"%s\"", s.c_str(), errno, strerror(errno), path);
     341            0 :          *qw = 0;
     342            0 :          return DB_FILE_ERROR;
     343              :       }
     344            0 :       return SUCCESS;
     345              :    }
     346              :    // NOT REACHED
     347              : }
     348              : 
     349            0 : static int GetDOUBLE(const MJsonNode* node, const char* path, double* dw)
     350              : {
     351            0 :    switch (node->GetType()) {
     352            0 :    default:
     353            0 :       cm_msg(MERROR, "db_paste_json", "GetDOUBLE: unexpected node type %d at \"%s\"", node->GetType(), path);
     354            0 :       *dw = 0;
     355            0 :       return DB_FILE_ERROR;
     356            0 :    case MJSON_INT:
     357            0 :       *dw = node->GetInt();
     358            0 :       return SUCCESS;
     359            0 :    case MJSON_NUMBER:
     360            0 :       *dw = node->GetDouble();
     361            0 :       return SUCCESS;
     362            0 :    case MJSON_STRING:
     363            0 :       std::string s = node->GetString();
     364            0 :       errno = 0;
     365            0 :       if (s == "NaN" || s == "Infinity" || s == "-Infinity") {
     366            0 :          *dw = node->GetDouble();
     367            0 :       } else if (s[0] == '0' && s[1] == 'x') { // hex encoded number
     368            0 :          *dw = strtoul(s.c_str(), NULL, 16);
     369            0 :       } else if (isdigit(s[0]) || (s[0]=='-' && isdigit(s[1]))) { // probably a number
     370            0 :          *dw = strtod(s.c_str(), NULL);
     371              :       } else {
     372            0 :          cm_msg(MERROR, "db_paste_json", "GetDOUBLE: MJSON_STRING node invalid numeric value \'%s\' at \"%s\"", s.c_str(), path);
     373            0 :          *dw = 0;
     374            0 :          return DB_FILE_ERROR;
     375              :       }
     376            0 :       if (errno != 0) {
     377            0 :          cm_msg(MERROR, "db_paste_json", "GetDOUBLE: MJSON_STRING node invalid numeric value \'%s\', strtoul() errno %d (%s) at \"%s\"", s.c_str(), errno, strerror(errno), path);
     378            0 :          *dw = 0;
     379            0 :          return DB_FILE_ERROR;
     380              :       }
     381            0 :       return SUCCESS;
     382              :    }
     383              :    // NOT REACHED
     384              : }
     385              : 
     386            0 : static int paste_value(HNDLE hDB, HNDLE hKey, const char* path, bool is_array, int index, const MJsonNode* node, int tid, int string_length, const MJsonNode* key)
     387              : {
     388              :    int status;
     389              :    //printf("paste_value: path [%s], index %d, tid %d, slength %d, key %p\n", path, index, tid, string_length, key);
     390              : 
     391            0 :    switch (tid) {
     392            0 :    default:
     393            0 :       cm_msg(MERROR, "db_paste_json", "do not know what to do with tid %d at \"%s\"", tid, path);
     394              :       // keep loading remaining data, ignore this error return DB_FILE_ERROR;
     395            0 :       return DB_SUCCESS;
     396            0 :    case TID_ARRAY:
     397            0 :       cm_msg(MERROR, "db_paste_json", "paste of TID_ARRAY is not implemented at \"%s\"", path);
     398            0 :       return DB_SUCCESS;
     399            0 :    case TID_STRUCT:
     400            0 :       cm_msg(MERROR, "db_paste_json", "paste of TID_STRUCT is not implemented at \"%s\"", path);
     401            0 :       return DB_SUCCESS;
     402            0 :    case TID_BITFIELD:
     403            0 :       cm_msg(MERROR, "db_paste_json", "paste of TID_BITFIELD is not implemented at \"%s\"", path);
     404            0 :       return DB_SUCCESS;
     405            0 :    case TID_CHAR: {
     406            0 :       const std::string value = node->GetString();
     407            0 :       int size = 1;
     408            0 :       status = db_set_data_index(hDB, hKey, value.c_str(), size, index, TID_CHAR);
     409            0 :       if (status != DB_SUCCESS) {
     410            0 :          cm_msg(MERROR, "db_paste_json", "cannot set TID_CHAR value for \"%s\", db_set_data_index() status %d", path, status);
     411            0 :          return status;
     412              :       }
     413            0 :       return DB_SUCCESS;
     414            0 :    }
     415            0 :    case TID_BOOL: {
     416              :       BOOL v;
     417            0 :       if (node->GetType() == MJSON_STRING && node->GetString() == "true") {
     418            0 :          v = true;
     419            0 :       } else if (node->GetType() == MJSON_STRING && node->GetString() == "false") {
     420            0 :          v = false;
     421            0 :       } else if (node->GetType() == MJSON_STRING && node->GetString()[0] == 'y') {
     422            0 :          v = true;
     423            0 :       } else if (node->GetType() == MJSON_STRING && node->GetString()[0] == 'n') {
     424            0 :          v = false;
     425            0 :       } else if (node->GetType() == MJSON_STRING && node->GetString()[0] == 'Y') {
     426            0 :          v = true;
     427            0 :       } else if (node->GetType() == MJSON_STRING && node->GetString()[0] == 'N') {
     428            0 :          v = false;
     429            0 :       } else if (node->GetType() == MJSON_STRING && node->GetString()[0] == 't') {
     430            0 :          v = true;
     431            0 :       } else if (node->GetType() == MJSON_STRING && node->GetString()[0] == 'f') {
     432            0 :          v = false;
     433            0 :       } else if (node->GetType() == MJSON_STRING && node->GetString()[0] == 'T') {
     434            0 :          v = true;
     435            0 :       } else if (node->GetType() == MJSON_STRING && node->GetString()[0] == 'F') {
     436            0 :          v = false;
     437              :       } else {
     438              :          DWORD dw;
     439            0 :          status = GetDWORD(node, path, &dw);
     440            0 :          if (status != SUCCESS)
     441            0 :             return status;
     442            0 :          if (dw) v = TRUE;
     443            0 :          else v = FALSE;
     444              :       }
     445            0 :       int size = sizeof(v);
     446            0 :       status = db_set_data_index(hDB, hKey, &v, size, index, TID_BOOL);
     447            0 :       if (status != DB_SUCCESS) {
     448            0 :          cm_msg(MERROR, "db_paste_json", "cannot set TID_BOOL value for \"%s\", db_set_data_index() status %d", path, status);
     449            0 :          return status;
     450              :       }
     451            0 :       return DB_SUCCESS;
     452              :    }
     453            0 :    case TID_BYTE:
     454              :    case TID_SBYTE: {
     455              :       DWORD dw;
     456            0 :       status = GetDWORD(node, path, &dw);
     457            0 :       if (status != SUCCESS)
     458            0 :          return status;
     459            0 :       BYTE b = (BYTE)dw;
     460            0 :       int size = sizeof(b);
     461            0 :       status = db_set_data_index(hDB, hKey, &b, size, index, tid);
     462            0 :       if (status != DB_SUCCESS) {
     463            0 :          cm_msg(MERROR, "db_paste_json", "cannot set TID_BYTE/TID_SBYTE value for \"%s\", db_set_data_index() status %d", path, status);
     464            0 :          return status;
     465              :       }
     466            0 :       return DB_SUCCESS;
     467              :    }
     468            0 :    case TID_WORD:
     469              :    case TID_SHORT: {
     470              :       DWORD dw;
     471            0 :       status = GetDWORD(node, path, &dw);
     472            0 :       if (status != SUCCESS)
     473            0 :          return status;
     474            0 :       WORD v = (WORD)dw;
     475            0 :       int size = sizeof(v);
     476            0 :       status = db_set_data_index(hDB, hKey, &v, size, index, tid);
     477            0 :       if (status != DB_SUCCESS) {
     478            0 :          cm_msg(MERROR, "db_paste_json", "cannot set TID_WORD/TID_SHORT value for \"%s\", db_set_data_index() status %d", path, status);
     479            0 :          return status;
     480              :       }
     481            0 :       return DB_SUCCESS;
     482              :    }
     483            0 :    case TID_DWORD: {
     484              :       DWORD v;
     485            0 :       status = GetDWORD(node, path, &v);
     486            0 :       if (status != SUCCESS)
     487            0 :          return status;
     488            0 :       int size = sizeof(v);
     489            0 :       status = db_set_data_index(hDB, hKey, &v, size, index, TID_DWORD);
     490            0 :       if (status != DB_SUCCESS) {
     491            0 :          cm_msg(MERROR, "db_paste_json", "cannot set TID_DWORD value for \"%s\", db_set_data_index() status %d", path, status);
     492            0 :          return status;
     493              :       }
     494            0 :       return DB_SUCCESS;
     495              :    }
     496            0 :    case TID_INT: {
     497            0 :       int v = 0;
     498            0 :       switch (node->GetType()) {
     499            0 :       default:
     500            0 :          cm_msg(MERROR, "db_paste_json", "unexpected node type %d at \"%s\"", node->GetType(), path);
     501            0 :          return DB_FILE_ERROR;
     502            0 :       case MJSON_INT: {
     503            0 :          v = node->GetInt();
     504            0 :          break;
     505              :       }
     506            0 :       case MJSON_NUMBER: {
     507            0 :          double dv = node->GetDouble();
     508            0 :          if (dv > INT_MAX || dv < INT_MIN) {
     509            0 :             cm_msg(MERROR, "db_paste_json", "numeric value %f out of range at \"%s\"", dv, path);
     510            0 :             return DB_FILE_ERROR;
     511              :          }
     512            0 :          v = (int)dv;
     513            0 :          break;
     514              :       }
     515            0 :       case MJSON_STRING: {
     516            0 :          status = GetDWORD(node, path, (DWORD*)&v);
     517            0 :          if (status != SUCCESS)
     518            0 :             return status;
     519            0 :          break;
     520              :       }
     521              :       }
     522            0 :       int size = sizeof(v);
     523            0 :       status = db_set_data_index(hDB, hKey, &v, size, index, TID_INT);
     524            0 :       if (status != DB_SUCCESS) {
     525            0 :          cm_msg(MERROR, "db_paste_json", "cannot set TID_INT value for \"%s\", db_set_data_index() status %d", path, status);
     526            0 :          return status;
     527              :       }
     528            0 :       return DB_SUCCESS;
     529              :    }
     530              : 
     531            0 :    case TID_UINT64: {
     532              :       UINT64 v;
     533            0 :       status = GetQWORD(node, path, &v);
     534            0 :       if (status != SUCCESS)
     535            0 :          return status;
     536            0 :       int size = sizeof(v);
     537            0 :       status = db_set_data_index(hDB, hKey, &v, size, index, TID_UINT64);
     538            0 :       if (status != DB_SUCCESS) {
     539            0 :          cm_msg(MERROR, "db_paste_json", "cannot set TID_UINT64 value for \"%s\", db_set_data_index() status %d", path, status);
     540            0 :          return status;
     541              :       }
     542            0 :       return DB_SUCCESS;
     543              :    }
     544              : 
     545            0 :    case TID_INT64: {
     546              :       INT64 v;
     547            0 :       status = GetQWORD(node, path, (UINT64 *)&v);
     548            0 :       if (status != SUCCESS)
     549            0 :          return status;
     550            0 :       int size = sizeof(v);
     551            0 :       status = db_set_data_index(hDB, hKey, &v, size, index, TID_INT64);
     552            0 :       if (status != DB_SUCCESS) {
     553            0 :          cm_msg(MERROR, "db_paste_json", "cannot set TID_INT64 value for \"%s\", db_set_data_index() status %d", path, status);
     554            0 :          return status;
     555              :       }
     556            0 :       return DB_SUCCESS;
     557              :    }
     558              : 
     559            0 :    case TID_FLOAT: {
     560              :       double dv;
     561            0 :       status = GetDOUBLE(node, path, &dv);
     562            0 :       if (status != SUCCESS)
     563            0 :          return status;
     564            0 :       float v = dv;
     565            0 :       int size = sizeof(v);
     566            0 :       status = db_set_data_index(hDB, hKey, &v, size, index, TID_FLOAT);
     567            0 :       if (status != DB_SUCCESS) {
     568            0 :          cm_msg(MERROR, "db_paste_json", "cannot set TID_FLOAT value for \"%s\", db_set_data_index() status %d", path, status);
     569            0 :          return status;
     570              :       }
     571            0 :       return DB_SUCCESS;
     572              :    }
     573            0 :    case TID_DOUBLE: {
     574              :       double v;
     575            0 :       status = GetDOUBLE(node, path, &v);
     576            0 :       if (status != SUCCESS)
     577            0 :          return status;
     578            0 :       int size = sizeof(v);
     579            0 :       status = db_set_data_index(hDB, hKey, &v, size, index, TID_DOUBLE);
     580            0 :       if (status != DB_SUCCESS) {
     581            0 :          cm_msg(MERROR, "db_paste_json", "cannot set TID_DOUBLE value for \"%s\", db_set_data_index() status %d", path, status);
     582            0 :          return status;
     583              :       }
     584            0 :       return DB_SUCCESS;
     585              :    }
     586            0 :    case TID_STRING: {
     587            0 :       char* buf = NULL;
     588            0 :       const char* ptr = NULL;
     589            0 :       int size = 0;
     590            0 :       const std::string value = node->GetString();
     591            0 :       if (string_length == 0)
     592            0 :          string_length = item_size_from_key(key);
     593              :       //printf("string_length %d\n", string_length);
     594            0 :       if (string_length) {
     595            0 :          buf = new char[string_length];
     596            0 :          mstrlcpy(buf, value.c_str(), string_length);
     597            0 :          ptr = buf;
     598            0 :          size = string_length;
     599              :       } else {
     600            0 :          ptr = value.c_str();
     601            0 :          size = strlen(ptr) + 1;
     602              :       }
     603              : 
     604            0 :       if (is_array) {
     605              :          KEY key;
     606            0 :          status = db_get_key(hDB, hKey, &key);
     607            0 :          if (status != DB_SUCCESS) {
     608            0 :             cm_msg(MERROR, "db_paste_json", "cannot get key of string array for \"%s\", db_get_key() status %d", path, status);
     609            0 :             return status;
     610              :          }
     611              :          
     612            0 :          if (key.item_size < size) {
     613            0 :             status = db_resize_string(hDB, hKey, NULL, key.num_values, size);
     614            0 :             if (status != DB_SUCCESS) {
     615            0 :                cm_msg(MERROR, "db_paste_json", "cannot change array string length from %d to %d for \"%s\", db_resize_string() status %d", key.item_size, size, path, status);
     616            0 :                return status;
     617              :             }
     618              :          }
     619              :       }
     620              : 
     621              :       //printf("set_data_index index %d, size %d\n", index, size);
     622              : 
     623            0 :       if (string_length > 0) {
     624            0 :          if (is_array) {
     625            0 :             status = db_set_data_index(hDB, hKey, ptr, size, index, TID_STRING);
     626              :          } else {
     627            0 :             status = db_set_data(hDB, hKey, ptr, size, 1, TID_STRING);
     628              :          }
     629            0 :       } else if (index != 0) {
     630            0 :          cm_msg(MERROR, "db_paste_json", "cannot set TID_STRING value for \"%s\" index %d, it is not an array", path, index);
     631            0 :          status = DB_OUT_OF_RANGE;
     632              :       } else {
     633            0 :          status = db_set_data(hDB, hKey, ptr, size, 1, TID_STRING);
     634              :       }
     635              : 
     636            0 :       if (buf)
     637            0 :          delete[] buf;
     638              : 
     639            0 :       if (status != DB_SUCCESS) {
     640            0 :          cm_msg(MERROR, "db_paste_json", "cannot set TID_STRING value for \"%s\", db_set_data_index() status %d", path, status);
     641            0 :          return status;
     642              :       }
     643              : 
     644            0 :       return DB_SUCCESS;
     645            0 :    }
     646            0 :    case TID_LINK: {
     647            0 :       std::string value_string = node->GetString();
     648            0 :       const char* value = value_string.c_str();
     649            0 :       int size = strlen(value) + 1;
     650              : 
     651            0 :       status = db_set_data(hDB, hKey, value, size, 1, TID_LINK);
     652              : 
     653            0 :       if (status != DB_SUCCESS) {
     654            0 :          cm_msg(MERROR, "db_paste_json", "cannot set TID_LINK value for \"%s\", db_set_data() status %d", path, status);
     655            0 :          return status;
     656              :       }
     657              : 
     658            0 :       return DB_SUCCESS;
     659            0 :    }
     660              :    }
     661              :    // NOT REACHED
     662              : }
     663              : 
     664            0 : static int paste_node(HNDLE hDB, HNDLE hKey, const char* path, bool is_array, int index, const MJsonNode* node, int tid, int string_length, const MJsonNode* key)
     665              : {
     666              :    //node->Dump();
     667            0 :    switch (node->GetType()) {
     668            0 :    case MJSON_ARRAY:  return paste_array(hDB, hKey, path, node, tid, string_length, key);
     669            0 :    case MJSON_OBJECT: return paste_object(hDB, hKey, path, node);
     670            0 :    case MJSON_STRING: return paste_value(hDB, hKey, path, is_array, index, node, tid, string_length, key);
     671            0 :    case MJSON_INT:    return paste_value(hDB, hKey, path, is_array, index, node, tid, 0, key);
     672            0 :    case MJSON_NUMBER: return paste_value(hDB, hKey, path, is_array, index, node, tid, 0, key);
     673            0 :    case MJSON_BOOL:   return paste_bool(hDB, hKey, path, index, node);
     674            0 :    case MJSON_ERROR:
     675            0 :       cm_msg(MERROR, "db_paste_json", "JSON parse error: \"%s\" at \"%s\"", node->GetError().c_str(), path);
     676            0 :       return DB_FILE_ERROR;
     677            0 :    case MJSON_NULL:
     678            0 :       cm_msg(MERROR, "db_paste_json", "unexpected JSON null value at \"%s\"", path);
     679            0 :       return DB_FILE_ERROR;
     680            0 :    default:
     681            0 :       cm_msg(MERROR, "db_paste_json", "unexpected JSON node type %d (%s) at \"%s\"", node->GetType(), MJsonNode::TypeToString(node->GetType()), path);
     682            0 :       return DB_FILE_ERROR;
     683              :    }
     684              :    // NOT REACHED
     685              : }
     686              : 
     687            0 : INT EXPRT db_paste_json(HNDLE hDB, HNDLE hKeyRoot, const char *buffer)
     688              : {
     689            0 :    std::string path = db_get_path(hDB, hKeyRoot);
     690              : 
     691              :    //printf("db_paste_json: handle %d, path [%s]\n", hKeyRoot, path.c_str());
     692              : 
     693            0 :    MJsonNode* node = MJsonNode::Parse(buffer);
     694            0 :    int status = paste_node(hDB, hKeyRoot, path.c_str(), false, 0, node, 0, 0, NULL);
     695            0 :    delete node;
     696              : 
     697            0 :    return status;
     698            0 : }
     699              : 
     700            0 : INT EXPRT db_paste_json_node(HNDLE hDB, HNDLE hKeyRoot, int index, const MJsonNode *node)
     701              : {
     702              :    int status;
     703              :    KEY key;
     704              : 
     705            0 :    status = db_get_key(hDB, hKeyRoot, &key);
     706            0 :    if (status != DB_SUCCESS)
     707            0 :       return status;
     708              : 
     709            0 :    std::string path = db_get_path(hDB, hKeyRoot);
     710              : 
     711            0 :    int tid = key.type;
     712            0 :    int string_length = 0;
     713            0 :    bool is_array = (key.num_values > 1);
     714            0 :    if (tid == TID_STRING) {
     715              :       // do not truncate strings, only extend if necessary
     716            0 :       if ((int)node->GetString().length()+1 > key.item_size)
     717            0 :          string_length = node->GetString().length()+1;
     718              :       else
     719            0 :          string_length = key.item_size;
     720              :    }
     721              : 
     722            0 :    status = paste_node(hDB, hKeyRoot, path.c_str(), is_array, index, node, tid, string_length, NULL);
     723              : 
     724            0 :    return status;
     725            0 : }
     726              : 
     727              : /* emacs
     728              :  * Local Variables:
     729              :  * tab-width: 8
     730              :  * c-basic-offset: 3
     731              :  * indent-tabs-mode: nil
     732              :  * End:
     733              :  */
        

Generated by: LCOV version 2.0-1