Cppcheck
addoninfo.cpp
Go to the documentation of this file.
1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2024 Cppcheck team.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "addoninfo.h"
20 
21 #include "path.h"
22 #include "utils.h"
23 
24 #include <fstream>
25 #include <string>
26 #include <vector>
27 
28 #include "json.h"
29 
30 static std::string getFullPath(const std::string &fileName, const std::string &exename) {
31  if (Path::isFile(fileName))
32  return fileName;
33 
34  const std::string exepath = Path::getPathFromFilename(exename);
35  if (Path::isFile(exepath + fileName))
36  return exepath + fileName;
37  if (Path::isFile(exepath + "addons/" + fileName))
38  return exepath + "addons/" + fileName;
39 
40 #ifdef FILESDIR
41  if (Path::isFile(FILESDIR + ("/" + fileName)))
42  return FILESDIR + ("/" + fileName);
43  if (Path::isFile(FILESDIR + ("/addons/" + fileName)))
44  return FILESDIR + ("/addons/" + fileName);
45 #endif
46  return "";
47 }
48 
49 static std::string parseAddonInfo(AddonInfo& addoninfo, const picojson::value &json, const std::string &fileName, const std::string &exename) {
50  const std::string& json_error = picojson::get_last_error();
51  if (!json_error.empty()) {
52  return "Loading " + fileName + " failed. " + json_error;
53  }
54  if (!json.is<picojson::object>())
55  return "Loading " + fileName + " failed. JSON is not an object.";
56 
57  // TODO: remove/complete default value handling for missing fields
58  const picojson::object& obj = json.get<picojson::object>();
59  {
60  const auto it = obj.find("args");
61  if (it != obj.cend()) {
62  const auto& val = it->second;
63  if (!val.is<picojson::array>())
64  return "Loading " + fileName + " failed. 'args' must be an array.";
65  for (const picojson::value &v : val.get<picojson::array>()) {
66  if (!v.is<std::string>())
67  return "Loading " + fileName + " failed. 'args' entry is not a string.";
68  addoninfo.args += " " + v.get<std::string>();
69  }
70  }
71  }
72 
73  {
74  const auto it = obj.find("ctu");
75  if (it != obj.cend()) {
76  const auto& val = it->second;
77  // ctu is specified in the config file
78  if (!val.is<bool>())
79  return "Loading " + fileName + " failed. 'ctu' must be a boolean.";
80  addoninfo.ctu = val.get<bool>();
81  }
82  else {
83  addoninfo.ctu = false;
84  }
85  }
86 
87  {
88  const auto it = obj.find("python");
89  if (it != obj.cend()) {
90  const auto& val = it->second;
91  // Python was defined in the config file
92  if (!val.is<std::string>()) {
93  return "Loading " + fileName +" failed. 'python' must be a string.";
94  }
95  addoninfo.python = val.get<std::string>();
96  }
97  else {
98  addoninfo.python = "";
99  }
100  }
101 
102  {
103  const auto it = obj.find("executable");
104  if (it != obj.cend()) {
105  const auto& val = it->second;
106  if (!val.is<std::string>())
107  return "Loading " + fileName + " failed. 'executable' must be a string.";
108  const std::string e = val.get<std::string>();
109  addoninfo.executable = getFullPath(e, fileName);
110  if (addoninfo.executable.empty())
111  addoninfo.executable = e;
112  return ""; // <- do not load both "executable" and "script".
113  }
114  }
115 
116  const auto it = obj.find("script");
117  if (it == obj.cend())
118  return "Loading " + fileName + " failed. 'script' is missing.";
119 
120  const auto& val = it->second;
121  if (!val.is<std::string>())
122  return "Loading " + fileName + " failed. 'script' must be a string.";
123 
124  return addoninfo.getAddonInfo(val.get<std::string>(), exename);
125 }
126 
127 std::string AddonInfo::getAddonInfo(const std::string &fileName, const std::string &exename) {
128  if (fileName[0] == '{') {
129  picojson::value json;
130  const std::string err = picojson::parse(json, fileName);
131  (void)err; // TODO: report
132  return parseAddonInfo(*this, json, fileName, exename);
133  }
134  if (fileName.find('.') == std::string::npos)
135  return getAddonInfo(fileName + ".py", exename);
136 
137  if (endsWith(fileName, ".py")) {
138  scriptFile = Path::fromNativeSeparators(getFullPath(fileName, exename));
139  if (scriptFile.empty())
140  return "Did not find addon " + fileName;
141 
142  std::string::size_type pos1 = scriptFile.rfind('/');
143  if (pos1 == std::string::npos)
144  pos1 = 0;
145  else
146  pos1++;
147  std::string::size_type pos2 = scriptFile.rfind('.');
148  if (pos2 < pos1)
149  pos2 = std::string::npos;
150  name = scriptFile.substr(pos1, pos2 - pos1);
151 
152  runScript = getFullPath("runaddon.py", exename);
153 
154  return "";
155  }
156 
157  if (!endsWith(fileName, ".json"))
158  return "Failed to open addon " + fileName;
159 
160  std::ifstream fin(fileName);
161  if (!fin.is_open())
162  return "Failed to open " + fileName;
163  if (name.empty()) {
164  name = Path::fromNativeSeparators(fileName);
165  if (name.find('/') != std::string::npos)
166  name = name.substr(name.rfind('/') + 1);
167  }
168  picojson::value json;
169  fin >> json;
170  return parseAddonInfo(*this, json, fileName, exename);
171 }
static std::string getFullPath(const std::string &fileName, const std::string &exename)
Definition: addoninfo.cpp:30
static std::string parseAddonInfo(AddonInfo &addoninfo, const picojson::value &json, const std::string &fileName, const std::string &exename)
Definition: addoninfo.cpp:49
static bool isFile(const std::string &path)
Checks if given path is a file.
Definition: path.cpp:329
static std::string fromNativeSeparators(std::string path)
Convert path to use internal path separators.
Definition: path.cpp:75
static std::string getPathFromFilename(const std::string &filename)
Lookup the path part from a filename (e.g., '/tmp/a.h' -> '/tmp/', 'a.h' -> '')
Definition: path.cpp:88
std::string args
Definition: addoninfo.h:30
std::string scriptFile
Definition: addoninfo.h:28
std::string name
Definition: addoninfo.h:27
std::string getAddonInfo(const std::string &fileName, const std::string &exename)
Definition: addoninfo.cpp:127
bool ctu
Definition: addoninfo.h:32
std::string python
Definition: addoninfo.h:31
std::string runScript
Definition: addoninfo.h:33
std::string executable
Definition: addoninfo.h:29
bool endsWith(const std::string &str, char c)
Definition: utils.h:110