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 : */
|