164 lines
5.5 KiB
C++
164 lines
5.5 KiB
C++
/*
|
|
* Cppcheck - A tool for static C/C++ code analysis
|
|
* Copyright (C) 2007-2023 Cppcheck team.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "addoninfo.h"
|
|
|
|
#include "path.h"
|
|
#include "utils.h"
|
|
|
|
#include <fstream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "json.h"
|
|
|
|
static std::string getFullPath(const std::string &fileName, const std::string &exename) {
|
|
if (Path::isFile(fileName))
|
|
return fileName;
|
|
|
|
const std::string exepath = Path::getPathFromFilename(exename);
|
|
if (Path::isFile(exepath + fileName))
|
|
return exepath + fileName;
|
|
if (Path::isFile(exepath + "addons/" + fileName))
|
|
return exepath + "addons/" + fileName;
|
|
|
|
#ifdef FILESDIR
|
|
if (Path::isFile(FILESDIR + ("/" + fileName)))
|
|
return FILESDIR + ("/" + fileName);
|
|
if (Path::isFile(FILESDIR + ("/addons/" + fileName)))
|
|
return FILESDIR + ("/addons/" + fileName);
|
|
#endif
|
|
return "";
|
|
}
|
|
|
|
static std::string parseAddonInfo(AddonInfo& addoninfo, const picojson::value &json, const std::string &fileName, const std::string &exename) {
|
|
const std::string& json_error = picojson::get_last_error();
|
|
if (!json_error.empty()) {
|
|
return "Loading " + fileName + " failed. " + json_error;
|
|
}
|
|
if (!json.is<picojson::object>())
|
|
return "Loading " + fileName + " failed. JSON is not an object.";
|
|
|
|
// TODO: remove/complete default value handling for missing fields
|
|
const picojson::object& obj = json.get<picojson::object>();
|
|
{
|
|
const auto it = obj.find("args");
|
|
if (it != obj.cend()) {
|
|
const auto& val = it->second;
|
|
if (!val.is<picojson::array>())
|
|
return "Loading " + fileName + " failed. 'args' must be an array.";
|
|
for (const picojson::value &v : val.get<picojson::array>()) {
|
|
if (!v.is<std::string>())
|
|
return "Loading " + fileName + " failed. 'args' entry is not a string.";
|
|
addoninfo.args += " " + v.get<std::string>();
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
const auto it = obj.find("ctu");
|
|
if (it != obj.cend()) {
|
|
const auto& val = it->second;
|
|
// ctu is specified in the config file
|
|
if (!val.is<bool>())
|
|
return "Loading " + fileName + " failed. 'ctu' must be a boolean.";
|
|
addoninfo.ctu = val.get<bool>();
|
|
}
|
|
else {
|
|
addoninfo.ctu = false;
|
|
}
|
|
}
|
|
|
|
{
|
|
const auto it = obj.find("python");
|
|
if (it != obj.cend()) {
|
|
const auto& val = it->second;
|
|
// Python was defined in the config file
|
|
if (!val.is<std::string>()) {
|
|
return "Loading " + fileName +" failed. 'python' must be a string.";
|
|
}
|
|
addoninfo.python = val.get<std::string>();
|
|
}
|
|
else {
|
|
addoninfo.python = "";
|
|
}
|
|
}
|
|
|
|
{
|
|
const auto it = obj.find("executable");
|
|
if (it != obj.cend()) {
|
|
const auto& val = it->second;
|
|
if (!val.is<std::string>())
|
|
return "Loading " + fileName + " failed. 'executable' must be a string.";
|
|
addoninfo.executable = getFullPath(val.get<std::string>(), fileName);
|
|
return ""; // TODO: why bail out?
|
|
}
|
|
}
|
|
|
|
const auto it = obj.find("script");
|
|
if (it == obj.cend())
|
|
return "Loading " + fileName + " failed. 'script' is missing.";
|
|
|
|
const auto& val = it->second;
|
|
if (!val.is<std::string>())
|
|
return "Loading " + fileName + " failed. 'script' must be a string.";
|
|
|
|
return addoninfo.getAddonInfo(val.get<std::string>(), exename);
|
|
}
|
|
|
|
std::string AddonInfo::getAddonInfo(const std::string &fileName, const std::string &exename) {
|
|
if (fileName[0] == '{') {
|
|
picojson::value json;
|
|
const std::string err = picojson::parse(json, fileName);
|
|
(void)err; // TODO: report
|
|
return parseAddonInfo(*this, json, fileName, exename);
|
|
}
|
|
if (fileName.find('.') == std::string::npos)
|
|
return getAddonInfo(fileName + ".py", exename);
|
|
|
|
if (endsWith(fileName, ".py")) {
|
|
scriptFile = Path::fromNativeSeparators(getFullPath(fileName, exename));
|
|
if (scriptFile.empty())
|
|
return "Did not find addon " + fileName;
|
|
|
|
std::string::size_type pos1 = scriptFile.rfind('/');
|
|
if (pos1 == std::string::npos)
|
|
pos1 = 0;
|
|
else
|
|
pos1++;
|
|
std::string::size_type pos2 = scriptFile.rfind('.');
|
|
if (pos2 < pos1)
|
|
pos2 = std::string::npos;
|
|
name = scriptFile.substr(pos1, pos2 - pos1);
|
|
|
|
runScript = getFullPath("runaddon.py", exename);
|
|
|
|
return "";
|
|
}
|
|
|
|
if (!endsWith(fileName, ".json"))
|
|
return "Failed to open addon " + fileName;
|
|
|
|
std::ifstream fin(fileName);
|
|
if (!fin.is_open())
|
|
return "Failed to open " + fileName;
|
|
picojson::value json;
|
|
fin >> json;
|
|
return parseAddonInfo(*this, json, fileName, exename);
|
|
}
|