master ohmu/fastfetch-openbsd / src / common / windows / version.c
ohmu  ·  2026-10-15
 1#include "common/debug.h"
 2#include "common/mallocHelper.h"
 3#include "common/windows/version.h"
 4#include "common/windows/unicode.h"
 5
 6#include <windows.h>
 7
 8bool ffGetFileVersion(const wchar_t* filePath, const wchar_t* stringName, FFstrbuf* version) {
 9    FF_DEBUG("ffGetFileVersion: enter filePath=%ls stringName=%ls", filePath, stringName);
10
11    DWORD handle;
12    DWORD size = GetFileVersionInfoSizeW(filePath, &handle);
13    if (size == 0) {
14        FF_DEBUG("GetFileVersionInfoSizeW failed: %s", ffDebugWin32Error(GetLastError()));
15        return false;
16    }
17
18    FF_DEBUG("GetFileVersionInfoSizeW ok: size=%lu handle=%lu",
19        (unsigned long) size,
20        (unsigned long) handle);
21
22    FF_AUTO_FREE void* versionData = malloc(size);
23    if (!versionData) {
24        FF_DEBUG("malloc failed: size=%lu", (unsigned long) size);
25        return false;
26    }
27
28    if (!GetFileVersionInfoW(filePath, handle, size, versionData)) {
29        FF_DEBUG("GetFileVersionInfoW failed: %s", ffDebugWin32Error(GetLastError()));
30        return false;
31    }
32
33    FF_DEBUG("GetFileVersionInfoW ok");
34
35    if (!stringName) {
36        VS_FIXEDFILEINFO* verInfo;
37        UINT len;
38        if (VerQueryValueW(versionData, L"\\", (void**) &verInfo, &len) &&
39            len &&
40            verInfo->dwSignature == 0xFEEF04BD) {
41            ffStrbufSetF(version, "%u.%u.%u.%u", (unsigned) ((verInfo->dwProductVersionMS >> 16) & 0xffff), (unsigned) ((verInfo->dwProductVersionMS >> 0) & 0xffff), (unsigned) ((verInfo->dwProductVersionLS >> 16) & 0xffff), (unsigned) ((verInfo->dwProductVersionLS >> 0) & 0xffff));
42            FF_DEBUG("fixed version resolved: %s", version->chars);
43            return true;
44        }
45
46        FF_DEBUG("fixed version query failed or invalid signature");
47        return false;
48    }
49
50    struct {
51        WORD language;
52        WORD codePage;
53    }* translations;
54    UINT translationsLen;
55
56    if (VerQueryValueW(versionData, L"\\VarFileInfo\\Translation", (void**) &translations, &translationsLen) &&
57        translationsLen >= sizeof(*translations)) {
58        wchar_t subBlock[128];
59        snwprintf(subBlock, ARRAY_SIZE(subBlock), L"\\StringFileInfo\\%04x%04x\\%ls", translations[0].language, translations[0].codePage, stringName);
60        FF_DEBUG("query version string with translation: %ls", subBlock);
61
62        wchar_t* value;
63        UINT valueLen; // Number of characters, including null terminator
64        if (VerQueryValueW(versionData, subBlock, (void**) &value, &valueLen) && valueLen > 0) {
65            ffStrbufSetNWS(version, valueLen - 1, value);
66            FF_DEBUG("version string resolved (translation fallback): %s", version->chars);
67            return true;
68        }
69
70        FF_DEBUG("translation fallback query failed");
71    } else {
72        FF_DEBUG("no translation table found in version resource");
73    }
74
75    FF_DEBUG("ffGetFileVersion failed");
76    return false;
77}