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