Coverage Report

Created: 2026-01-10 06:22

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 "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
}