1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2021 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 "platform.h"
20 #include "path.h"
21 #include "tinyxml2.h"
22 #include <cstdlib>
23 #include <cstring>
24 #include <limits>
25 #include <vector>
26 
Platform()27 cppcheck::Platform::Platform()
28 {
29     // This assumes the code you are checking is for the same architecture this is compiled on.
30 #if defined(_WIN64)
31     platform(Win64);
32 #elif defined(_WIN32)
33     platform(Win32A);
34 #else
35     platform(Native);
36 #endif
37 }
38 
39 
platform(cppcheck::Platform::PlatformType type)40 bool cppcheck::Platform::platform(cppcheck::Platform::PlatformType type)
41 {
42     switch (type) {
43     case Unspecified: // unknown type sizes (sizes etc are set but are not known)
44     case Native: // same as system this code was compile on
45         platformType = type;
46         sizeof_bool = sizeof(bool);
47         sizeof_short = sizeof(short);
48         sizeof_int = sizeof(int);
49         sizeof_long = sizeof(long);
50         sizeof_long_long = sizeof(long long);
51         sizeof_float = sizeof(float);
52         sizeof_double = sizeof(double);
53         sizeof_long_double = sizeof(long double);
54         sizeof_wchar_t = sizeof(wchar_t);
55         sizeof_size_t = sizeof(std::size_t);
56         sizeof_pointer = sizeof(void *);
57         if (type == Unspecified) {
58             defaultSign = '\0';
59         } else {
60             defaultSign = (std::numeric_limits<char>::is_signed) ? 's' : 'u';
61         }
62         char_bit = 8;
63         short_bit = char_bit * sizeof_short;
64         int_bit = char_bit * sizeof_int;
65         long_bit = char_bit * sizeof_long;
66         long_long_bit = char_bit * sizeof_long_long;
67         return true;
68     case Win32W:
69     case Win32A:
70         platformType = type;
71         sizeof_bool = 1; // 4 in Visual C++ 4.2
72         sizeof_short = 2;
73         sizeof_int = 4;
74         sizeof_long = 4;
75         sizeof_long_long = 8;
76         sizeof_float = 4;
77         sizeof_double = 8;
78         sizeof_long_double = 8;
79         sizeof_wchar_t = 2;
80         sizeof_size_t = 4;
81         sizeof_pointer = 4;
82         defaultSign = '\0';
83         char_bit = 8;
84         short_bit = char_bit * sizeof_short;
85         int_bit = char_bit * sizeof_int;
86         long_bit = char_bit * sizeof_long;
87         long_long_bit = char_bit * sizeof_long_long;
88         return true;
89     case Win64:
90         platformType = type;
91         sizeof_bool = 1;
92         sizeof_short = 2;
93         sizeof_int = 4;
94         sizeof_long = 4;
95         sizeof_long_long = 8;
96         sizeof_float = 4;
97         sizeof_double = 8;
98         sizeof_long_double = 8;
99         sizeof_wchar_t = 2;
100         sizeof_size_t = 8;
101         sizeof_pointer = 8;
102         defaultSign = '\0';
103         char_bit = 8;
104         short_bit = char_bit * sizeof_short;
105         int_bit = char_bit * sizeof_int;
106         long_bit = char_bit * sizeof_long;
107         long_long_bit = char_bit * sizeof_long_long;
108         return true;
109     case Unix32:
110         platformType = type;
111         sizeof_bool = 1;
112         sizeof_short = 2;
113         sizeof_int = 4;
114         sizeof_long = 4;
115         sizeof_long_long = 8;
116         sizeof_float = 4;
117         sizeof_double = 8;
118         sizeof_long_double = 12;
119         sizeof_wchar_t = 4;
120         sizeof_size_t = 4;
121         sizeof_pointer = 4;
122         defaultSign = '\0';
123         char_bit = 8;
124         short_bit = char_bit * sizeof_short;
125         int_bit = char_bit * sizeof_int;
126         long_bit = char_bit * sizeof_long;
127         long_long_bit = char_bit * sizeof_long_long;
128         return true;
129     case Unix64:
130         platformType = type;
131         sizeof_bool = 1;
132         sizeof_short = 2;
133         sizeof_int = 4;
134         sizeof_long = 8;
135         sizeof_long_long = 8;
136         sizeof_float = 4;
137         sizeof_double = 8;
138         sizeof_long_double = 16;
139         sizeof_wchar_t = 4;
140         sizeof_size_t = 8;
141         sizeof_pointer = 8;
142         defaultSign = '\0';
143         char_bit = 8;
144         short_bit = char_bit * sizeof_short;
145         int_bit = char_bit * sizeof_int;
146         long_bit = char_bit * sizeof_long;
147         long_long_bit = char_bit * sizeof_long_long;
148         return true;
149     case PlatformFile:
150         // sizes are not set.
151         return false;
152     }
153     // unsupported platform
154     return false;
155 }
156 
loadPlatformFile(const char exename[],const std::string & filename)157 bool cppcheck::Platform::loadPlatformFile(const char exename[], const std::string &filename)
158 {
159     // open file..
160     tinyxml2::XMLDocument doc;
161     if (doc.LoadFile(filename.c_str()) != tinyxml2::XML_SUCCESS) {
162         std::vector<std::string> filenames;
163         filenames.push_back(filename + ".xml");
164         if (exename && (std::string::npos != Path::fromNativeSeparators(exename).find('/'))) {
165             filenames.push_back(Path::getPathFromFilename(Path::fromNativeSeparators(exename)) + filename);
166             filenames.push_back(Path::getPathFromFilename(Path::fromNativeSeparators(exename)) + filename);
167             filenames.push_back(Path::getPathFromFilename(Path::fromNativeSeparators(exename)) + "platforms/" + filename);
168             filenames.push_back(Path::getPathFromFilename(Path::fromNativeSeparators(exename)) + "platforms/" + filename + ".xml");
169         }
170 #ifdef FILESDIR
171         std::string filesdir = FILESDIR;
172         if (!filesdir.empty() && filesdir[filesdir.size()-1] != '/')
173             filesdir += '/';
174         filenames.push_back(filesdir + ("platforms/" + filename));
175         filenames.push_back(filesdir + ("platforms/" + filename + ".xml"));
176 #endif
177         bool success = false;
178         for (const std::string & f : filenames) {
179             if (doc.LoadFile(f.c_str()) == tinyxml2::XML_SUCCESS) {
180                 success = true;
181                 break;
182             }
183         }
184         if (!success)
185             return false;
186     }
187 
188     return loadFromXmlDocument(&doc);
189 }
190 
loadFromXmlDocument(const tinyxml2::XMLDocument * doc)191 bool cppcheck::Platform::loadFromXmlDocument(const tinyxml2::XMLDocument *doc)
192 {
193     const tinyxml2::XMLElement * const rootnode = doc->FirstChildElement();
194 
195     if (!rootnode || std::strcmp(rootnode->Name(), "platform") != 0)
196         return false;
197 
198     for (const tinyxml2::XMLElement *node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) {
199         if (std::strcmp(node->Name(), "default-sign") == 0)
200             defaultSign = *node->GetText();
201         else if (std::strcmp(node->Name(), "char_bit") == 0)
202             char_bit = std::atoi(node->GetText());
203         else if (std::strcmp(node->Name(), "sizeof") == 0) {
204             for (const tinyxml2::XMLElement *sz = node->FirstChildElement(); sz; sz = sz->NextSiblingElement()) {
205                 if (std::strcmp(sz->Name(), "short") == 0)
206                     sizeof_short = std::atoi(sz->GetText());
207                 else if (std::strcmp(sz->Name(), "bool") == 0)
208                     sizeof_bool = std::atoi(sz->GetText());
209                 else if (std::strcmp(sz->Name(), "int") == 0)
210                     sizeof_int = std::atoi(sz->GetText());
211                 else if (std::strcmp(sz->Name(), "long") == 0)
212                     sizeof_long = std::atoi(sz->GetText());
213                 else if (std::strcmp(sz->Name(), "long-long") == 0)
214                     sizeof_long_long = std::atoi(sz->GetText());
215                 else if (std::strcmp(sz->Name(), "float") == 0)
216                     sizeof_float = std::atoi(sz->GetText());
217                 else if (std::strcmp(sz->Name(), "double") == 0)
218                     sizeof_double = std::atoi(sz->GetText());
219                 else if (std::strcmp(sz->Name(), "long-double") == 0)
220                     sizeof_long_double = std::atoi(sz->GetText());
221                 else if (std::strcmp(sz->Name(), "pointer") == 0)
222                     sizeof_pointer = std::atoi(sz->GetText());
223                 else if (std::strcmp(sz->Name(), "size_t") == 0)
224                     sizeof_size_t = std::atoi(sz->GetText());
225                 else if (std::strcmp(sz->Name(), "wchar_t") == 0)
226                     sizeof_wchar_t = std::atoi(sz->GetText());
227             }
228         }
229     }
230 
231     short_bit = char_bit * sizeof_short;
232     int_bit = char_bit * sizeof_int;
233     long_bit = char_bit * sizeof_long;
234     long_long_bit = char_bit * sizeof_long_long;
235 
236     platformType = PlatformFile;
237     return true;
238 }
239