/src/exiv2/src/version.cpp
Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | |
3 | | #include "version.hpp" |
4 | | #include "config.h" |
5 | | #include "futils.hpp" |
6 | | #include "image_int.hpp" |
7 | | #include "makernote_int.hpp" |
8 | | |
9 | | // + standard includes |
10 | | #include <fstream> |
11 | | #include <set> |
12 | | |
13 | | // Adobe XMP Toolkit |
14 | | #ifdef EXV_HAVE_XMP_TOOLKIT |
15 | | #include "properties.hpp" |
16 | | #endif |
17 | | |
18 | | #ifdef EXV_USE_CURL |
19 | | #include <curl/curl.h> |
20 | | #endif |
21 | | |
22 | | // #1147 |
23 | | #ifndef _WIN32 |
24 | | #include <sys/types.h> |
25 | | #include <unistd.h> |
26 | | #endif |
27 | | |
28 | | #ifndef _MAX_PATH |
29 | | #define _MAX_PATH 512 |
30 | | #endif |
31 | | |
32 | | // platform specific support for getLoadedLibraries |
33 | | #if defined(_WIN32) || defined(__CYGWIN__) |
34 | | // clang-format off |
35 | | #include <winapifamily.h> |
36 | | #include <windows.h> |
37 | | #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_APP) |
38 | | #include <psapi.h> |
39 | | #endif |
40 | | // clang-format on |
41 | | #if __LP64__ |
42 | | #ifdef _WIN64 |
43 | | #undef _WIN64 |
44 | | #endif |
45 | | #define _WIN64 1 |
46 | | #endif |
47 | | #ifdef _MSC_VER |
48 | | #include <array> |
49 | | #endif |
50 | | #elif defined(__APPLE__) |
51 | | #include <mach-o/dyld.h> |
52 | | #elif defined(__FreeBSD__) |
53 | | // clang-format off |
54 | | #include <sys/param.h> |
55 | | #include <sys/queue.h> |
56 | | #include <sys/socket.h> |
57 | | #include <sys/sysctl.h> |
58 | | #include <unistd.h> |
59 | | #include <libprocstat.h> |
60 | | // clang-format on |
61 | | #elif defined(__sun__) |
62 | | #include <dlfcn.h> |
63 | | #include <link.h> |
64 | | #endif |
65 | | |
66 | | namespace Exiv2 { |
67 | 0 | uint32_t versionNumber() { |
68 | 0 | return EXIV2_MAKE_VERSION(EXIV2_MAJOR_VERSION, EXIV2_MINOR_VERSION, EXIV2_PATCH_VERSION); |
69 | 0 | } |
70 | | |
71 | 0 | std::string versionString() { |
72 | 0 | return stringFormat("{}.{}.{}", EXIV2_MAJOR_VERSION, EXIV2_MINOR_VERSION, EXIV2_PATCH_VERSION); |
73 | 0 | } |
74 | | |
75 | 0 | std::string versionNumberHexString() { |
76 | 0 | return stringFormat("{:06x}", Exiv2::versionNumber()); |
77 | 0 | } |
78 | | |
79 | 0 | const char* version() { |
80 | 0 | return EXV_PACKAGE_VERSION; |
81 | 0 | } |
82 | | |
83 | 0 | bool testVersion(uint32_t major, uint32_t minor, uint32_t patch) { |
84 | 0 | return versionNumber() >= EXIV2_MAKE_VERSION(major, minor, patch); |
85 | 0 | } |
86 | | } // namespace Exiv2 |
87 | | |
88 | 0 | static bool shouldOutput(const std::vector<std::regex>& greps, const char* key, const std::string& value) { |
89 | 0 | bool bPrint = greps.empty(); |
90 | 0 | for (auto const& g : greps) { |
91 | 0 | bPrint = std::regex_search(key, g) || std::regex_search(value, g); |
92 | 0 | if (bPrint) { |
93 | 0 | break; |
94 | 0 | } |
95 | 0 | } |
96 | 0 | return bPrint; |
97 | 0 | } |
98 | | |
99 | 0 | static void output(std::ostream& os, const std::vector<std::regex>& greps, const char* name, const std::string& value) { |
100 | 0 | if (shouldOutput(greps, name, value)) |
101 | 0 | os << name << "=" << value << '\n'; |
102 | 0 | } |
103 | | |
104 | 0 | static void output(std::ostream& os, const std::vector<std::regex>& greps, const char* name, int value) { |
105 | 0 | output(os, greps, name, std::to_string(value)); |
106 | 0 | } |
107 | | |
108 | 0 | static bool pushPath(const std::string& path, std::vector<std::string>& libs, std::set<std::string>& paths) { |
109 | 0 | bool result = Exiv2::fileExists(path) && !paths.contains(path) && path != "/"; |
110 | 0 | if (result) { |
111 | 0 | paths.insert(path); |
112 | 0 | libs.push_back(path); |
113 | 0 | } |
114 | 0 | return result; |
115 | 0 | } |
116 | | |
117 | 0 | static std::vector<std::string> getLoadedLibraries() { |
118 | 0 | std::vector<std::string> libs; |
119 | 0 | std::set<std::string> paths; |
120 | 0 | std::string path; |
121 | |
|
122 | | #if defined(_WIN32) || defined(__CYGWIN__) |
123 | | // enumerate loaded libraries and determine path to executable (unsupported on UWP) |
124 | | #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_APP) |
125 | | HMODULE handles[200]; |
126 | | DWORD cbNeeded; |
127 | | if (EnumProcessModules(GetCurrentProcess(), handles, static_cast<DWORD>(std::size(handles)), &cbNeeded)) { |
128 | | char szFilename[_MAX_PATH]; |
129 | | for (DWORD h = 0; h < cbNeeded / sizeof(handles[0]); h++) { |
130 | | GetModuleFileNameA(handles[h], szFilename, static_cast<DWORD>(std::size(szFilename))); |
131 | | pushPath(szFilename, libs, paths); |
132 | | } |
133 | | } |
134 | | #endif |
135 | | #elif defined(__APPLE__) |
136 | | // man 3 dyld |
137 | | uint32_t count = _dyld_image_count(); |
138 | | for (uint32_t image = 0; image < count; image++) { |
139 | | std::string path(_dyld_get_image_name(image)); |
140 | | pushPath(path, libs, paths); |
141 | | } |
142 | | #elif defined(__FreeBSD__) |
143 | | { |
144 | | unsigned int n; |
145 | | struct procstat* procstat = procstat_open_sysctl(); |
146 | | struct kinfo_proc* procs = procstat ? procstat_getprocs(procstat, KERN_PROC_PID, getpid(), &n) : nullptr; |
147 | | struct filestat_list* files = procs ? procstat_getfiles(procstat, procs, true) : nullptr; |
148 | | if (files) { |
149 | | filestat* entry; |
150 | | STAILQ_FOREACH(entry, files, next) { |
151 | | if (entry && PS_FST_TYPE_VNODE == entry->fs_type && entry->fs_path) { |
152 | | std::string path(entry->fs_path); |
153 | | pushPath(path, libs, paths); |
154 | | } |
155 | | } |
156 | | } |
157 | | // free resources |
158 | | if (files) |
159 | | procstat_freefiles(procstat, files); |
160 | | if (procs) |
161 | | procstat_freeprocs(procstat, procs); |
162 | | if (procstat) |
163 | | procstat_close(procstat); |
164 | | } |
165 | | #elif defined(__sun__) || defined(__unix__) |
166 | | // http://stackoverflow.com/questions/606041/how-do-i-get-the-path-of-a-process-in-unix-linux |
167 | 0 | char procsz[100]; |
168 | 0 | char pathsz[500]; |
169 | 0 | snprintf(procsz, sizeof(procsz), "/proc/%d/path/a.out", getpid()); |
170 | 0 | if (auto l = readlink(procsz, pathsz, sizeof(pathsz) - 1); l > 0) { |
171 | 0 | pathsz[l] = '\0'; |
172 | 0 | path.assign(pathsz); |
173 | 0 | libs.push_back(path); |
174 | 0 | } |
175 | | |
176 | | // read file /proc/self/maps which has a list of files in memory |
177 | | // (this doesn't yield anything on __sun__) |
178 | 0 | std::ifstream maps("/proc/self/maps"); |
179 | 0 | std::string string; |
180 | 0 | while (std::getline(maps, string)) { |
181 | 0 | std::size_t pos = string.find_last_of(' '); |
182 | 0 | if (pos != std::string::npos) { |
183 | 0 | path = string.substr(pos + 1); |
184 | 0 | pushPath(path, libs, paths); |
185 | 0 | } |
186 | 0 | } |
187 | 0 | #endif |
188 | 0 | if (libs.empty()) |
189 | 0 | libs.emplace_back("unknown"); |
190 | |
|
191 | 0 | return libs; |
192 | 0 | } |
193 | | |
194 | 0 | void Exiv2::dumpLibraryInfo(std::ostream& os, const std::vector<std::regex>& keys) { |
195 | 0 | int bits = 8 * sizeof(void*); |
196 | 0 | #ifdef NDEBUG |
197 | 0 | int debug = 0; |
198 | | #else |
199 | | int debug = 1; |
200 | | #endif |
201 | |
|
202 | | #ifdef exiv2lib_EXPORTS |
203 | | int dll = 1; |
204 | | #else |
205 | 0 | int dll = 0; |
206 | 0 | #endif |
207 | |
|
208 | 0 | const char* compiler = |
209 | | #ifdef _MSC_VER |
210 | | "MSVC"; |
211 | | |
212 | | #ifndef __VERSION__ |
213 | | char version[40]; |
214 | | snprintf(version, sizeof(version), "%d.%02d", (_MSC_VER - 600) / 100, _MSC_VER % 100); |
215 | | |
216 | | // add edition in brackets |
217 | | // 7.10 = 2003 8.00 = 2005 etc 12.00 = 2013 13.00 = 2015 (yet the installer labels it as 14.0!) |
218 | | size_t edition = (_MSC_VER - 600) / 100; |
219 | | constexpr auto editions = std::array{ |
220 | | "0", "1", "2", "3", "4", "5", "6", "2003", "2005", "2008", "2010", "2012", "2013", "2015", "2017", "2019", |
221 | | }; |
222 | | if (edition == 13 && _MSC_VER >= 1910) |
223 | | edition++; // 2017 _MSC_VAR == 1910 |
224 | | if (edition == 14 && _MSC_VER >= 1920) |
225 | | edition++; // 2019 _MSC_VAR == 1920 |
226 | | |
227 | | if (edition > editions.size()) |
228 | | edition = 0; |
229 | | if (edition) { |
230 | | const size_t len = ::strlen(version); |
231 | | snprintf(version + len, sizeof(version) - len, " (%s/%s)", editions[edition], bits == 64 ? "x64" : "x86"); |
232 | | } |
233 | | #define __VERSION__ version |
234 | | #endif |
235 | | |
236 | | #elif defined(__clang__) |
237 | | "Clang"; |
238 | | #elif defined(__GNUG__) |
239 | | "G++"; |
240 | | #elif defined(__GNUC__) |
241 | | "GCC"; |
242 | | #elif defined(__SUNPRO_CC) |
243 | | "CC (oracle)"; |
244 | | #elif defined(__SUNPRO_C) |
245 | | "cc (oracle)"; |
246 | | #elif defined(__sun__) |
247 | | "cc (solaris)"; |
248 | | #else |
249 | | "unknown"; |
250 | | #endif |
251 | |
|
252 | | #ifndef __VERSION__ |
253 | | #ifdef __clang__version__ |
254 | | #define __VERSION__ __clang__version__ |
255 | | #else |
256 | | #define __VERSION__ "unknown" |
257 | | #endif |
258 | | #endif |
259 | |
|
260 | 0 | const char* platform = |
261 | | #ifdef __MSYS__ |
262 | | "msys"; |
263 | | #elif defined(__CYGWIN__) |
264 | | "cygwin"; |
265 | | #elif defined(_MSC_VER) |
266 | | "windows"; |
267 | | #elif defined(__APPLE__) |
268 | | "apple"; |
269 | | #elif defined(__MINGW64__) |
270 | | "mingw64"; |
271 | | #elif defined(__MINGW32__) |
272 | | "mingw32"; |
273 | | #elif defined(__sun__) |
274 | | "solaris"; |
275 | | #elif defined(__NetBSD__) |
276 | | "netbsd"; |
277 | | #elif defined(__FreeBSD__) |
278 | | "freebsd"; |
279 | | #elif defined(__linux__) |
280 | | "linux"; |
281 | | #else |
282 | | "unknown"; |
283 | | #endif |
284 | |
|
285 | 0 | int have_inttypes = 0; |
286 | 0 | int have_libintl = 0; |
287 | 0 | int have_lensdata = 0; |
288 | 0 | int have_iconv = 0; |
289 | 0 | int have_memory = 0; |
290 | 0 | int have_stdbool = 0; |
291 | 0 | int have_stdint = 0; |
292 | 0 | int have_stdlib = 0; |
293 | 0 | int have_strlib = 0; |
294 | 0 | int have_strerror_r = 0; |
295 | 0 | int have_strings_h = 0; |
296 | 0 | int have_mmap = 0; |
297 | 0 | int have_munmap = 0; |
298 | 0 | int have_sys_stat = 0; |
299 | 0 | int have_unistd_h = 0; |
300 | 0 | int have_sys_mman = 0; |
301 | 0 | int have_libz = 0; |
302 | 0 | int have_brotli = 0; |
303 | 0 | int have_xmptoolkit = 0; |
304 | 0 | int adobe_xmpsdk = 0; |
305 | 0 | int have_bool = 0; |
306 | 0 | int have_strings = 0; |
307 | 0 | int have_sys_types = 0; |
308 | 0 | int have_unistd = 0; |
309 | |
|
310 | 0 | int enable_bmff = 0; |
311 | 0 | int enable_webready = 0; |
312 | 0 | int enable_nls = 0; |
313 | 0 | int enable_video = 0; |
314 | 0 | int use_curl = 0; |
315 | |
|
316 | 0 | #if __has_include(<inttypes.h>) |
317 | 0 | have_inttypes = 1; |
318 | 0 | #endif |
319 | |
|
320 | 0 | #ifdef EXV_HAVE_LENSDATA |
321 | 0 | have_lensdata = 1; |
322 | 0 | #endif |
323 | |
|
324 | 0 | #ifdef EXV_HAVE_ICONV |
325 | 0 | have_iconv = 1; |
326 | 0 | #endif |
327 | |
|
328 | 0 | #if __has_include(<libintl.h>) |
329 | 0 | have_libintl = 1; |
330 | 0 | #endif |
331 | |
|
332 | 0 | #if __has_include(<memory.h>) |
333 | 0 | have_memory = 1; |
334 | 0 | #endif |
335 | |
|
336 | 0 | #if __has_include(<stdbool.h>) |
337 | 0 | have_stdbool = 1; |
338 | 0 | #endif |
339 | |
|
340 | 0 | #if __has_include(<stdint.h>) |
341 | 0 | have_stdint = 1; |
342 | 0 | #endif |
343 | |
|
344 | 0 | #if __has_include(<stdlib.h>) |
345 | 0 | have_stdlib = 1; |
346 | 0 | #endif |
347 | |
|
348 | 0 | #ifdef EXV_HAVE_STRERROR_R |
349 | 0 | have_strerror_r = 1; |
350 | 0 | #endif |
351 | |
|
352 | 0 | #if __has_include(<strings.h>) |
353 | 0 | have_strings = 1; |
354 | 0 | #endif |
355 | |
|
356 | 0 | #if __has_include(<sys/mman.h>) |
357 | 0 | have_mmap = 1; |
358 | 0 | #endif |
359 | |
|
360 | 0 | #if __has_include(<sys/mman.h>) |
361 | 0 | have_munmap = 1; |
362 | 0 | #endif |
363 | |
|
364 | 0 | #if __has_include(<sys/stat.h>) |
365 | 0 | have_sys_stat = 1; |
366 | 0 | #endif |
367 | |
|
368 | 0 | #if __has_include(<sys/types.h>) |
369 | 0 | have_sys_types = 1; |
370 | 0 | #endif |
371 | |
|
372 | 0 | #if __has_include(<unistd.h>) |
373 | 0 | have_unistd = 1; |
374 | 0 | #endif |
375 | |
|
376 | 0 | #if __has_include(<sys/mman.h>) |
377 | 0 | have_sys_mman = 1; |
378 | 0 | #endif |
379 | |
|
380 | 0 | #ifdef EXV_HAVE_LIBZ |
381 | 0 | have_libz = 1; |
382 | 0 | #endif |
383 | |
|
384 | 0 | #ifdef EXV_HAVE_BROTLI |
385 | 0 | have_brotli = 1; |
386 | 0 | #endif |
387 | |
|
388 | 0 | #ifdef EXV_HAVE_XMP_TOOLKIT |
389 | 0 | have_xmptoolkit = 1; |
390 | 0 | #endif |
391 | |
|
392 | | #ifdef EXV_ADOBE_XMPSDK |
393 | | adobe_xmpsdk = EXV_ADOBE_XMPSDK; |
394 | | #endif |
395 | |
|
396 | 0 | #ifdef EXV_ENABLE_BMFF |
397 | 0 | enable_bmff = 1; |
398 | 0 | #endif |
399 | |
|
400 | 0 | #ifdef EXV_ENABLE_WEBREADY |
401 | 0 | enable_webready = 1; |
402 | 0 | #endif |
403 | |
|
404 | | #ifdef EXV_ENABLE_NLS |
405 | | enable_nls = 1; |
406 | | #endif |
407 | |
|
408 | 0 | #ifdef EXV_ENABLE_VIDEO |
409 | 0 | enable_video = 1; |
410 | 0 | #endif |
411 | |
|
412 | | #ifdef EXV_USE_CURL |
413 | | use_curl = 1; |
414 | | #endif |
415 | |
|
416 | 0 | std::vector<std::string> libs = getLoadedLibraries(); |
417 | |
|
418 | 0 | output(os, keys, "exiv2", Exiv2::versionString()); |
419 | 0 | output(os, keys, "platform", platform); |
420 | 0 | output(os, keys, "compiler", compiler); |
421 | 0 | output(os, keys, "bits", bits); |
422 | 0 | output(os, keys, "dll", dll); |
423 | 0 | output(os, keys, "debug", debug); |
424 | 0 | output(os, keys, "cplusplus", __cplusplus); |
425 | 0 | output(os, keys, "version", __VERSION__); |
426 | 0 | output(os, keys, "date", __DATE__); |
427 | 0 | output(os, keys, "time", __TIME__); |
428 | 0 | output(os, keys, "processpath", Exiv2::getProcessPath()); |
429 | | #ifdef EXV_ENABLE_NLS |
430 | | output(os, keys, "localedir", EXV_LOCALEDIR); |
431 | | #endif |
432 | 0 | output(os, keys, "package_name", EXV_PACKAGE_NAME); |
433 | |
|
434 | | #ifdef EXV_USE_CURL |
435 | | std::string curl_protocols; |
436 | | auto vinfo = curl_version_info(CURLVERSION_NOW); |
437 | | for (int i = 0; vinfo->protocols[i]; i++) { |
438 | | curl_protocols += vinfo->protocols[i]; |
439 | | curl_protocols += " "; |
440 | | } |
441 | | output(os, keys, "curlprotocols", curl_protocols); |
442 | | #endif |
443 | |
|
444 | 0 | output(os, keys, "curl", use_curl); |
445 | 0 | if (libs.begin() != libs.end()) { |
446 | 0 | output(os, keys, "executable", *libs.begin()); |
447 | 0 | for (auto lib = libs.begin() + 1; lib != libs.end(); ++lib) |
448 | 0 | output(os, keys, "library", *lib); |
449 | 0 | } |
450 | |
|
451 | 0 | output(os, keys, "have_inttypes", have_inttypes); |
452 | 0 | output(os, keys, "have_libintl", have_libintl); |
453 | 0 | output(os, keys, "have_lensdata", have_lensdata); |
454 | 0 | output(os, keys, "have_iconv", have_iconv); |
455 | 0 | output(os, keys, "have_memory", have_memory); |
456 | 0 | output(os, keys, "have_stdbool", have_stdbool); |
457 | 0 | output(os, keys, "have_stdint", have_stdint); |
458 | 0 | output(os, keys, "have_stdlib", have_stdlib); |
459 | 0 | output(os, keys, "have_strlib", have_strlib); |
460 | 0 | output(os, keys, "have_strerror_r", have_strerror_r); |
461 | 0 | output(os, keys, "have_strings_h", have_strings_h); |
462 | 0 | output(os, keys, "have_mmap", have_mmap); |
463 | 0 | output(os, keys, "have_munmap", have_munmap); |
464 | 0 | output(os, keys, "have_sys_stat", have_sys_stat); |
465 | 0 | output(os, keys, "have_unistd_h", have_unistd_h); |
466 | 0 | output(os, keys, "have_sys_mman", have_sys_mman); |
467 | 0 | output(os, keys, "have_libz", have_libz); |
468 | 0 | output(os, keys, "have_brotli", have_brotli); |
469 | 0 | output(os, keys, "have_xmptoolkit", have_xmptoolkit); |
470 | 0 | output(os, keys, "adobe_xmpsdk", adobe_xmpsdk); |
471 | 0 | output(os, keys, "have_bool", have_bool); |
472 | 0 | output(os, keys, "have_strings", have_strings); |
473 | 0 | output(os, keys, "have_sys_types", have_sys_types); |
474 | 0 | output(os, keys, "have_unistd", have_unistd); |
475 | 0 | output(os, keys, "enable_bmff", enable_bmff); |
476 | 0 | output(os, keys, "enable_webready", enable_webready); |
477 | 0 | output(os, keys, "enable_nls", enable_nls); |
478 | 0 | output(os, keys, "enable_video", enable_video); |
479 | 0 | output(os, keys, "use_curl", use_curl); |
480 | |
|
481 | 0 | output(os, keys, "config_path", Exiv2::Internal::getExiv2ConfigPath()); |
482 | | |
483 | | // #1147 |
484 | 0 | #ifndef _WIN32 |
485 | 0 | uid_t uid = getuid(); |
486 | 0 | output(os, keys, "uid", uid); |
487 | 0 | uid_t euid = geteuid(); |
488 | 0 | output(os, keys, "euid", euid); |
489 | 0 | uid_t gid = getgid(); |
490 | 0 | output(os, keys, "gid", gid); |
491 | 0 | #endif |
492 | |
|
493 | 0 | #ifdef EXV_HAVE_XMP_TOOLKIT |
494 | 0 | const char* name = "xmlns"; |
495 | |
|
496 | 0 | Exiv2::Dictionary ns; |
497 | 0 | Exiv2::XmpProperties::registeredNamespaces(ns); |
498 | 0 | for (const auto& [xmlns, uri] : ns) { |
499 | 0 | output(os, keys, name, xmlns + ":" + uri); |
500 | 0 | } |
501 | 0 | #endif |
502 | 0 | } |