master ohmu/fastfetch-openbsd / src / common / zlib.h
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