// Copyright (c) 2012-2017 VideoStitch SAS // Copyright (c) 2018 stitchEm #include "ptvMerger.hpp" #include "libvideostitch/ptv.hpp" #include "libvideostitch/parse.hpp" namespace VideoStitch { namespace Helper { void PtvMerger::mergeValue(Ptv::Value* originalValue, Ptv::Value* templateValue) { for (int i = 0; i < templateValue->size(); i++) { std::pair<const std::string*, const Ptv::Value*> pair = templateValue->get(i); switch (pair.second->getType()) { case Ptv::Value::NIL: originalValue->get(*pair.first); break; case Ptv::Value::BOOL: originalValue->get(*pair.first)->asBool() = pair.second->asBool(); break; case Ptv::Value::INT: originalValue->get(*pair.first)->asInt() = pair.second->asInt(); break; case Ptv::Value::DOUBLE: originalValue->get(*pair.first)->asDouble() = pair.second->asDouble(); break; case Ptv::Value::STRING: originalValue->get(*pair.first)->asString() = pair.second->asString(); break; case Ptv::Value::OBJECT: { Ptv::Value* templateObject = templateValue->get(*pair.first); Ptv::Value& originalObject = originalValue->get(*pair.first)->asObject(); if (templateObject->size() >= 1) { mergeValue(&originalObject, templateObject); originalValue->push(*pair.first, &originalObject); } break; } case Ptv::Value::LIST: // merge lists recursively std::vector<Ptv::Value*>& originalList = originalValue->get(*pair.first)->asList(); std::vector<Ptv::Value*> templateList = templateValue->get(*pair.first)->asList(); if (originalList.size() == templateList.size()) { for (size_t j = 0; j < originalList.size(); j++) { mergeValue(originalList[j], templateList[j]); } } else { // recursive merging not possible, just replace for (auto valPtr : originalList) { delete valPtr; } originalList.clear(); for (Ptv::Value* val : templateList) { originalList.push_back(val->clone()); } } break; } } } void PtvMerger::removeFrom(Ptv::Value* originalValue, Ptv::Value* toRemove) { for (int i = 0; i < toRemove->size(); i++) { std::pair<const std::string*, const Ptv::Value*> pair = toRemove->get(i); if (originalValue->has(*pair.first)) { originalValue->remove(*pair.first); } } } std::unique_ptr<Ptv::Value> PtvMerger::getMergedValue(const std::string& currentPtv, const std::string& templatePtv) { Potential<Ptv::Parser> currentParser = Ptv::Parser::create(); if (!currentParser.ok()) { Logger::get(Logger::Error) << "Error: Could not create a PTV parser for " << currentPtv << std::endl; return std::unique_ptr<Ptv::Value>(Ptv::Value::emptyObject()); } bool ret = currentParser->parse(currentPtv); if (!ret) { Logger::get(Logger::Error) << "Error: Cannot parse PTV file: " << currentPtv << std::endl; Logger::get(Logger::Error) << currentParser->getErrorMessage() << std::endl; return std::unique_ptr<Ptv::Value>(Ptv::Value::emptyObject()); } Potential<Ptv::Parser> templateParser = Ptv::Parser::create(); if (!templateParser.ok()) { Logger::get(Logger::Error) << "Error: Could not create a PTV parser for " << templatePtv << std::endl; return std::unique_ptr<Ptv::Value>(Ptv::Value::emptyObject()); } ret = templateParser->parse(templatePtv); if (!ret) { Logger::get(Logger::Error) << "Error: Cannot parse PTV file: " << templatePtv << std::endl; Logger::get(Logger::Error) << templateParser->getErrorMessage() << std::endl; return std::unique_ptr<Ptv::Value>(Ptv::Value::emptyObject()); } std::unique_ptr<Ptv::Value> currentProjectRoot(currentParser->getRoot().clone()); std::unique_ptr<Ptv::Value> templateProjectRoot(templateParser->getRoot().clone()); mergeValue(currentProjectRoot.get(), templateProjectRoot.get()); return currentProjectRoot; } void PtvMerger::saveMergedPtv(const std::string& currentPtv, const std::string& templatePtv, const std::string& outputPtv) { std::string outputFile; outputFile = (outputPtv == "") ? currentPtv : outputPtv; std::unique_ptr<Ptv::Value> root(getMergedValue(currentPtv, templatePtv)); std::unique_ptr<Ptv::Value> empty(Ptv::Value::emptyObject()); if (root.get() == empty.get()) { Logger::get(Logger::Error) << "Error: could not merge " << currentPtv << " with " << templatePtv << std::endl; return; } std::ofstream ofs(outputFile.c_str(), std::ios_base::out); if (!ofs.is_open()) { Logger::get(Logger::Error) << "Error: cannot open '" << outputFile << "' for writing." << std::endl; return; } assert(root); root->printJson(ofs); } } // namespace Helper } // namespace VideoStitch