ohmu
·
2026-10-15
1#pragma once
2
3#include "fastfetch.h"
4
5#if FF_HAVE_ZLIB
6
7// Which set of entry points a caller needs. Resolving is per group rather than all at once so that a
8// symbol nobody uses cannot make a caller fail: libz is not one library across the platforms
9// fastfetch builds on, and the gz family in particular is not guaranteed to be present.
10typedef enum FFZlibGroup : uint8_t {
11 FF_ZLIB_COMPRESS = 1 << 0, // compressBound, compress2
12 FF_ZLIB_INFLATE = 1 << 1, // inflateInit2_, inflate, inflateEnd
13 FF_ZLIB_GZFILE = 1 << 2, // gzopen, gzread, gzclose
14} FFZlibGroup;
15
16 #if FF_DISABLE_DLOPEN
17
18 #include <zlib.h>
19
20static inline const char* ffZlibLoad([[maybe_unused]] FFZlibGroup group) {
21 // the library is linked in: nothing to open, nothing to resolve, nothing to fail
22 return nullptr;
23}
24
25 #else
26 // Hack. <zlib.h> declares everything with an extern linkage macro, which prevents us from
27 // implementing the functions ourselves. zlib spells it ZEXTERN/ZEXPORT and zlib-ng's
28 // zlib-compat header spells it Z_EXTERN/Z_EXPORT; both set theirs under `#ifndef`, so
29 // defining all four before the include is what makes the definitions at the bottom of this
30 // header legal -- they inherit the static inline linkage from the declarations zlib.h emits
31 // here. This header must therefore be the first thing in a translation unit to pull in
32 // <zlib.h>; if it is not, the definitions below stop being static and clang reports
33 // `static declaration follows non-static declaration` right there.
34 #undef ZEXTERN
35 #undef ZEXPORT
36 #undef Z_EXTERN
37 #undef Z_EXPORT
38 #define ZEXTERN static inline
39 #define ZEXPORT
40 #define Z_EXTERN static inline
41 #define Z_EXPORT
42
43 // Redeclaring everything as `static inline` above means <zlib.h> now defines entry points
44 // that a given translation unit may not call at all. Silenced for the include only: the
45 // pragma is popped right after, so the rest of the file -- and the rest of the translation
46 // unit that includes this header -- still reports unused functions.
47
48 // Note: `#pragma GCC diagnostic push` is intentionally omitted here.
49 #pragma GCC diagnostic ignored "-Wunused-function"
50
51 #include <zlib.h>
52
53 #include "common/library.h"
54
55extern struct FFZlibData {
56 // Kept open rather than closed once opened: every group resolves against this one mapping, and
57 // re-opening per group would pay the cold load again.
58 void* handle;
59
60 FF_LIBRARY_SYMBOL(compressBound)
61 FF_LIBRARY_SYMBOL(compress2)
62 FF_LIBRARY_SYMBOL(inflateInit2_)
63 FF_LIBRARY_SYMBOL(inflate)
64 FF_LIBRARY_SYMBOL(inflateEnd)
65 FF_LIBRARY_SYMBOL(gzopen)
66 FF_LIBRARY_SYMBOL(gzread)
67 FF_LIBRARY_SYMBOL(gzclose)
68
69 FFZlibGroup attempted;
70} zlibData;
71
72[[gnu::always_inline]] static inline uLong(compressBound)(uLong sourceLen) {
73 return zlibData.ffcompressBound(sourceLen);
74}
75
76[[gnu::always_inline]] static inline int(compress2)(Bytef* dest, uLongf* destLen, const Bytef* source, uLong sourceLen, int level) {
77 return zlibData.ffcompress2(dest, destLen, source, sourceLen, level);
78}
79
80[[gnu::always_inline]] static inline int(inflateInit2_)(z_streamp strm, int windowBits, const char* version, int stream_size) {
81 return zlibData.ffinflateInit2_(strm, windowBits, version, stream_size);
82}
83
84[[gnu::always_inline]] static inline int(inflate)(z_streamp strm, int flush) {
85 return zlibData.ffinflate(strm, flush);
86}
87
88[[gnu::always_inline]] static inline int(inflateEnd)(z_streamp strm) {
89 return zlibData.ffinflateEnd(strm);
90}
91
92[[gnu::always_inline]] static inline gzFile(gzopen)(const char* path, const char* mode) {
93 return zlibData.ffgzopen(path, mode);
94}
95
96[[gnu::always_inline]] static inline int(gzread)(gzFile file, voidp buf, unsigned len) {
97 return zlibData.ffgzread(file, buf, len);
98}
99
100[[gnu::always_inline]] static inline int(gzclose)(gzFile file) {
101 return zlibData.ffgzclose(file);
102}
103
104// Resolves the entry points of `group` and returns nullptr, or an error message. Call it before using
105// that group's functions: until it has succeeded, the forwarders above are null pointers. The library
106// itself is opened once, by whichever group is asked for first, and stays open.
107const char* ffZlibLoad(FFZlibGroup group);
108
109 #endif
110
111#endif