Coverage Report

Created: 2026-04-01 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}