| 1400 | } |
| 1401 | |
| 1402 | bool json_check(const JsonNode *node, char errmsg[256]) |
| 1403 | { |
| 1404 | #define problem(...) do { \ |
| 1405 | if (errmsg != nullptr) \ |
| 1406 | snprintf(errmsg, 256, __VA_ARGS__); \ |
| 1407 | return false; \ |
| 1408 | } while (0) |
| 1409 | |
| 1410 | if (node->key != nullptr && !utf8_validate(node->key)) |
| 1411 | problem("key contains invalid UTF-8"); |
| 1412 | |
| 1413 | if (!tag_is_valid(node->tag)) |
| 1414 | problem("tag is invalid (%d)", node->tag); |
| 1415 | |
| 1416 | if (node->tag == JSON_BOOL) |
| 1417 | { |
| 1418 | if (node->bool_ != false && node->bool_ != true) |
| 1419 | problem("bool_ is neither false (%d) nor true (%d)", (int)false, (int)true); |
| 1420 | } |
| 1421 | else if (node->tag == JSON_STRING) |
| 1422 | { |
| 1423 | if (node->string_ == nullptr) |
| 1424 | problem("string_ is nullptr"); |
| 1425 | if (!utf8_validate(node->string_)) |
| 1426 | problem("string_ contains invalid UTF-8"); |
| 1427 | } |
| 1428 | else if (node->tag == JSON_ARRAY || node->tag == JSON_OBJECT) |
| 1429 | { |
| 1430 | JsonNode *head = node->children.head; |
| 1431 | JsonNode *tail = node->children.tail; |
| 1432 | |
| 1433 | if (head == nullptr || tail == nullptr) |
| 1434 | { |
| 1435 | if (head != nullptr) |
| 1436 | problem("tail is nullptr, but head is not"); |
| 1437 | if (tail != nullptr) |
| 1438 | problem("head is nullptr, but tail is not"); |
| 1439 | } |
| 1440 | else |
| 1441 | { |
| 1442 | JsonNode *child; |
| 1443 | JsonNode *last = nullptr; |
| 1444 | |
| 1445 | if (head->prev != nullptr) |
| 1446 | problem("First child's prev pointer is not nullptr"); |
| 1447 | |
| 1448 | for (child = head; child != nullptr; last = child, child = child->next) |
| 1449 | { |
| 1450 | if (child == node) |
| 1451 | problem("node is its own child"); |
| 1452 | if (child->next == child) |
| 1453 | problem("child->next == child (cycle)"); |
| 1454 | if (child->next == head) |
| 1455 | problem("child->next == head (cycle)"); |
| 1456 | |
| 1457 | if (child->parent != node) |
| 1458 | problem("child does not point back to parent"); |
| 1459 | if (child->next != nullptr && child->next->prev != child) |
nothing calls this directly
no test coverage detected