diff options
Diffstat (limited to 'extensions/dict_json/dict-json-diff.cc')
| -rw-r--r-- | extensions/dict_json/dict-json-diff.cc | 352 |
1 files changed, 352 insertions, 0 deletions
diff --git a/extensions/dict_json/dict-json-diff.cc b/extensions/dict_json/dict-json-diff.cc new file mode 100644 index 0000000..a8e799d --- /dev/null +++ b/extensions/dict_json/dict-json-diff.cc @@ -0,0 +1,352 @@ +/********************************************************************************************************** + * Software License Agreement (BSD License) * + * Author: Thomas Klausner <tk@giga.or.at> * + * * + * Copyright (c) 2016, 2017, 2019 Thomas Klausner * + * All rights reserved. * + * * + * Written under contract by nfotex IT GmbH, http://nfotex.com/ * + * * + * Redistribution and use of this software in source and binary forms, with or without modification, are * + * permitted provided that the following conditions are met: * + * * + * * Redistributions of source code must retain the above * + * copyright notice, this list of conditions and the * + * following disclaimer. * + * * + * * Redistributions in binary form must reproduce the above * + * copyright notice, this list of conditions and the * + * following disclaimer in the documentation and/or other * + * materials provided with the distribution. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + **********************************************************************************************************/ + +/* + * Show what was added from one dictionary dump JSON file compared to a second one + */ +#include <json/json.h> + +#include <fstream> +#include <iostream> +#include <sstream> + +using namespace std; + +void json_compare_arrays(Json::Value &base, Json::Value &big, Json::Value &diff, string name, string key, string key2); + +void +json_compare_objects(Json::Value &base, Json::Value &big, Json::Value &diff, string name) +{ + Json::Value::Members members = big[name].getMemberNames(); + for (auto it = members.begin() ; it != members.end(); ++it) { + if (!base[name].isMember(*it) || + (base[name][*it] != big[name][*it])) { + diff[name][*it] = big[name][*it]; + } + } +} + +void +json_compare_avps(Json::Value &base, Json::Value &big, Json::Value &diff, string name) +{ + Json::Value left = base[name]; + Json::Value right = big[name]; + + if (left.type() != right.type() || left.empty()) { + if (!right.empty()) { + diff[name] = right; + } + return; + } + + if (!left.isArray()) { + cerr << name << " member not an array\n"; + return; + } + + for (unsigned int i=0; i<right.size(); i++) { + bool found = false; + /* find matching entry in base */ + for (unsigned int j=0; j<left.size(); j++) { + Json::Value temp = Json::Value::null; + if (left[j]["Code"] != right[i]["Code"] || + (left[j]["Vendor"] != right[i]["Vendor"])) { + continue; + } + Json::Value::Members members = right[i].getMemberNames(); + for (auto it = members.begin() ; it != members.end(); ++it) { + if (*it == "Flags") { + json_compare_objects(left[j], right[i], temp, *it); + continue; + } + if (*it == "EnumValues") { + std::string none; + json_compare_arrays(left[j], right[i], temp, *it, "Code", none); + continue; + } + if (left[j].isMember(*it)) { + if (left[j][*it] != right[i][*it]) { + temp[*it] = right[i][*it]; + } + } else { + temp[*it] = right[i][*it]; + } + } + if (!temp.isNull()) { + temp["Code"] = right[i]["Code"]; + if (!right[i]["Vendor"].isNull()) { + temp["Vendor"] = right[i]["Vendor"]; + } + if (temp.isMember("EnumValues")) { + temp["Name"] = right[i]["Name"]; + temp["Type"] = right[i]["Type"]; + } + diff[name].append(temp); + } + found = true; + break; + } + if (!found) { + diff[name].append(right[i]); + } + } + + +} + +void +json_compare_commands(Json::Value &base, Json::Value &big, Json::Value &diff, string name) +{ + Json::Value left = base[name]; + Json::Value right = big[name]; + + if (left.type() != right.type() || left.empty()) { + if (!right.empty()) { + diff[name] = right; + } + return; + } + + if (!left.isArray()) { + cerr << name << " member not an array\n"; + return; + } + + for (unsigned int i=0; i<right.size(); i++) { + bool found = false; + /* find matching entry in base */ + for (unsigned int j=0; j<left.size(); j++) { + Json::Value temp = Json::Value::null; + if (left[j]["Code"] != right[i]["Code"] || + left[j]["Flags"]["Must"] != right[i]["Flags"]["Must"]) { + continue; + } + Json::Value::Members members = right[i].getMemberNames(); + for (auto it = members.begin() ; it != members.end(); ++it) { + if (*it == "Flags") { + json_compare_objects(left[j], right[i], temp, *it); + continue; + } + if (left[j].isMember(*it)) { + if (left[j][*it] != right[i][*it]) { + temp[*it] = right[i][*it]; + } + } else { + temp[*it] = right[i][*it]; + } + } + if (!temp.isNull()) { + temp["Code"] = right[i]["Code"]; + if (!right[i]["Flags"]["Must"].isNull()) { + temp["Flags"]["Must"] = right[i]["Flags"]["Must"]; + } + diff[name].append(temp); + } + found = true; + break; + } + if (!found) { + diff[name].append(right[i]); + } + } + + +} + +void +json_compare_rules(Json::Value &base, Json::Value &big, Json::Value &diff, string name) +{ + Json::Value left = base[name]; + Json::Value right = big[name]; + + if (left.type() != right.type() || left.empty()) { + if (!right.empty()) { + diff[name] = right; + } + return; + } + + if (!left.isArray()) { + cerr << name << " member not an array\n"; + return; + } + + for (unsigned int i=0; i<right.size(); i++) { + bool found = false; + /* find matching entry in base */ + for (unsigned int j=0; j<left.size(); j++) { + Json::Value temp = Json::Value::null; + if (name == "AVPRules") { + if (left[j]["AVP"] != right[i]["AVP"] + || left[j]["Vendor"] != right[i]["Vendor"]) { + continue; + } + } else { + if (left[j]["Command"] != right[i]["Command"]) { + continue; + } + } + json_compare_arrays(left[j], right[i], temp, "Content", "AVP", "Vendor"); + if (!temp.isNull()) { + if (name == "AVPRules") { + temp["AVP"] = right[i]["AVP"]; + if (!right[i]["Vendor"].isNull()) { + temp["Vendor"] = right[i]["Vendor"]; + } + } else { + temp["Command"] = right[i]["Command"]; + if (!right[i]["Flags"]["Must"].isNull()) { + temp["Flags"]["Must"] = right[i]["Flags"]["Must"]; + } + } + diff[name].append(temp); + } + found = true; + break; + } + if (!found) { + diff[name].append(right[i]); + } + } +} + +void +json_compare_arrays(Json::Value &base, Json::Value &big, Json::Value &diff, string name, string key, string key2) +{ + Json::Value left = base[name]; + Json::Value right = big[name]; + + if (left.type() != right.type() || left.empty()) { + if (!right.empty()) { + diff[name] = right; + } + return; + } + + if (!left.isArray()) { + cerr << name << " member not an array\n"; + return; + } + + for (unsigned int i=0; i<right.size(); i++) { + bool found = false; + /* find matching entry in base */ + for (unsigned int j=0; j<left.size(); j++) { + Json::Value temp = Json::Value::null; + if (left[j][key] != right[i][key]) { + continue; + } + if (!key2.empty() && left[j][key2] != right[i][key2]) { + continue; + } + Json::Value::Members members = right[i].getMemberNames(); + for (auto it = members.begin() ; it != members.end(); ++it) { + if (left[j].isMember(*it)) { + if (left[j][*it] != right[i][*it]) { + temp[*it] = right[i][*it]; + } + } else { + temp[*it] = right[i][*it]; + } + } + if (!temp.isNull()) { + temp[key] = right[i][key]; + if (key == "AVP" && !right[i]["Vendor"].isNull()) { + temp["Vendor"] = right[i]["Vendor"]; + } + diff[name].append(temp); + } + found = true; + break; + } + if (!found) { + diff[name].append(right[i]); + } + } +} + +void +compare_all(Json::Value &base, Json::Value &big, Json::Value &diff) +{ + std::string none; + json_compare_arrays(base, big, diff, "Applications", "Code", none); + json_compare_avps(base, big, diff, "AVPs"); + json_compare_rules(base, big, diff, "AVPRules"); + json_compare_commands(base, big, diff, "Commands"); + json_compare_rules(base, big, diff, "CommandRules"); + json_compare_arrays(base, big, diff, "Types", "Name", none); + json_compare_arrays(base, big, diff, "Vendors", "Code", none); +} + +int +main(int argc, char *argv[]) +{ + Json::Value base = Json::Value::null; + Json::Value big = Json::Value::null; + Json::Value diff = Json::Value::null; + Json::Value reverse_diff = Json::Value::null; + Json::Reader reader; + Json::StyledWriter writer; + ifstream input; + + if (argc != 3) { + cout << "usage: " << argv[0] << " small big" << endl; + cout << endl << "Prints added and changed entries that are in 'big' but not in 'small'," << endl << "or have changed between the two." << endl; + exit(1); + } + + input.open(argv[1]); + if (!reader.parse(input, base)) { + cerr << "error parsing JSON file '" << argv[1] << "'\n"; + exit(1); + } + input.close(); + + input.open(argv[2]); + if (!reader.parse(input, big)) { + cerr << "error parsing JSON file '" << argv[2] << "'\n"; + exit(1); + } + input.close(); + + compare_all(base, big, diff); + if (diff != Json::Value::null) { + std::string value_str = writer.write(diff); + cout << value_str << endl; + } + + compare_all(big, base, reverse_diff); + if (reverse_diff != Json::Value::null) { + cerr << argv[2] << " is missing entries that are in " << argv[1] << " -- please call " << argv[0] << " with swapped arguments" << endl; + } + + return 0; +} |
