mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-10-28 07:44:06 +01:00
Common: adds zlib helpers
This commit is contained in:
@@ -506,6 +506,7 @@ set(LIBFASTFETCH_SRC
|
||||
src/common/impl/FFPlatform.c
|
||||
src/common/impl/smbios.c
|
||||
src/common/impl/strutil.c
|
||||
src/common/impl/zlib.c
|
||||
src/detection/bluetoothradio/bluetoothradio.c
|
||||
src/detection/bootmgr/bootmgr.c
|
||||
src/detection/chassis/chassis.c
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
#include "common/library.h"
|
||||
#include <zlib.h>
|
||||
#include "common/zlib.h"
|
||||
#endif
|
||||
|
||||
// Offsets into the dex header, from https://source.android.com/docs/core/runtime/dex-format.
|
||||
@@ -543,10 +542,11 @@ static const uint8_t* findDexMagic(const uint8_t* jar, size_t jarSize, size_t* d
|
||||
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
static const char* inflateDex(const uint8_t* data, size_t dataSize, uint32_t uncompressedSize, uint8_t** out) {
|
||||
FF_LIBRARY_LOAD(zlib, "dlopen(libz) failed", "libz" FF_LIBRARY_EXTENSION, 2)
|
||||
FF_LIBRARY_LOAD_SYMBOL(zlib, inflateInit2_, "dlsym(inflateInit2_) failed")
|
||||
FF_LIBRARY_LOAD_SYMBOL(zlib, inflate, "dlsym(inflate) failed")
|
||||
FF_LIBRARY_LOAD_SYMBOL(zlib, inflateEnd, "dlsym(inflateEnd) failed")
|
||||
const char* error = ffZlibLoad(FF_ZLIB_INFLATE);
|
||||
if (error != nullptr) {
|
||||
FF_DEBUG("The dex cannot be inflated: %s", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
// Released by the cleanup on every path out below; ownership moves to the caller by clearing
|
||||
// the pointer, which is also why no failure path has to free it by hand.
|
||||
@@ -565,13 +565,13 @@ static const char* inflateDex(const uint8_t* data, size_t dataSize, uint32_t unc
|
||||
stream.next_out = buffer;
|
||||
stream.avail_out = (uInt) uncompressedSize;
|
||||
|
||||
const int initStatus = ffinflateInit2_(&stream, -MAX_WBITS, ZLIB_VERSION, (int) sizeof(z_stream));
|
||||
const int initStatus = inflateInit2(&stream, -MAX_WBITS);
|
||||
if (initStatus != Z_OK) {
|
||||
FF_DEBUG("inflateInit2() failed: zlib status %d", initStatus);
|
||||
return "inflateInit2 failed";
|
||||
}
|
||||
const int status = ffinflate(&stream, Z_FINISH);
|
||||
ffinflateEnd(&stream);
|
||||
const int status = inflate(&stream, Z_FINISH);
|
||||
inflateEnd(&stream);
|
||||
if (status != Z_STREAM_END || stream.total_out != (uLong) uncompressedSize) {
|
||||
FF_DEBUG("inflate() returned %d, produced %lu of %u bytes",
|
||||
status, stream.total_out, uncompressedSize);
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
#include "common/zlib.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
#if FF_HAVE_ZLIB && !FF_DISABLE_DLOPEN
|
||||
|
||||
struct FFZlibData zlibData;
|
||||
|
||||
// Opens the library and leaves the handle in zlibData, so the groups that follow resolve against the
|
||||
// same mapping instead of opening their own.
|
||||
static const char* openZlib(void) {
|
||||
#ifdef _WIN32
|
||||
FF_LIBRARY_LOAD_MESSAGE(zlib, "zlib1" FF_LIBRARY_EXTENSION, 2)
|
||||
#else
|
||||
FF_LIBRARY_LOAD_MESSAGE(zlib, "libz" FF_LIBRARY_EXTENSION, 2)
|
||||
#endif
|
||||
|
||||
zlibData.handle = zlib;
|
||||
zlib = nullptr; // the handle is kept in zlibData, so the cleanup must not close it
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* ffZlibLoad(FFZlibGroup group) {
|
||||
FF_DEBUG("Loading zlib group: %x", group);
|
||||
|
||||
// Opened once, by whichever group is asked for first; the later ones reuse that mapping. A
|
||||
// failed open is retried by the next group rather than cached, so a system without libz pays at
|
||||
// most one attempt per group -- not one per call.
|
||||
if (zlibData.handle == nullptr) {
|
||||
if (zlibData.attempted == UINT8_MAX) {
|
||||
return "Previous attempt to open zlib failed";
|
||||
}
|
||||
|
||||
const char* error = openZlib();
|
||||
if (error != nullptr) {
|
||||
static_assert(sizeof(zlibData.attempted) == 1, "zlibData.attempted must be 1 byte");
|
||||
zlibData.attempted = UINT8_MAX;
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
if (group & FF_ZLIB_COMPRESS) {
|
||||
if (zlibData.attempted & FF_ZLIB_COMPRESS) {
|
||||
if (!zlibData.ffcompress2) {
|
||||
return "Previous attempt to load compress failed";
|
||||
}
|
||||
} else {
|
||||
zlibData.attempted |= FF_ZLIB_COMPRESS;
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlibData.handle, zlibData, compressBound)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlibData.handle, zlibData, compress2)
|
||||
}
|
||||
}
|
||||
if (group & FF_ZLIB_INFLATE) {
|
||||
if (zlibData.attempted & FF_ZLIB_INFLATE) {
|
||||
if (!zlibData.ffinflateEnd) {
|
||||
return "Previous attempt to load inflate failed";
|
||||
}
|
||||
} else {
|
||||
zlibData.attempted |= FF_ZLIB_INFLATE;
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlibData.handle, zlibData, inflateInit2_)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlibData.handle, zlibData, inflate)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlibData.handle, zlibData, inflateEnd)
|
||||
}
|
||||
}
|
||||
|
||||
if (group & FF_ZLIB_GZFILE) {
|
||||
if (zlibData.attempted & FF_ZLIB_GZFILE) {
|
||||
if (!zlibData.ffgzclose) {
|
||||
return "Previous attempt to load gzfile failed";
|
||||
}
|
||||
} else {
|
||||
zlibData.attempted |= FF_ZLIB_GZFILE;
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlibData.handle, zlibData, gzopen)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlibData.handle, zlibData, gzread)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlibData.handle, zlibData, gzclose)
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,106 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
|
||||
#if FF_HAVE_ZLIB
|
||||
|
||||
// Which set of entry points a caller needs. Resolving is per group rather than all at once so that a
|
||||
// symbol nobody uses cannot make a caller fail: libz is not one library across the platforms
|
||||
// fastfetch builds on, and the gz family in particular is not guaranteed to be present.
|
||||
typedef enum FFZlibGroup : uint8_t {
|
||||
FF_ZLIB_COMPRESS = 1 << 0, // compressBound, compress2
|
||||
FF_ZLIB_INFLATE = 1 << 1, // inflateInit2_, inflate, inflateEnd
|
||||
FF_ZLIB_GZFILE = 1 << 2, // gzopen, gzread, gzclose
|
||||
} FFZlibGroup;
|
||||
|
||||
#if FF_DISABLE_DLOPEN
|
||||
|
||||
#define Z_LARGE64 1
|
||||
#include <zlib.h>
|
||||
|
||||
const char* ffZlibLoad([[maybe_unused]] FFZlibGroup group) {
|
||||
// the library is linked in: nothing to open, nothing to resolve, nothing to fail
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#else
|
||||
// Hack. <zlib.h> declares everything with an extern linkage macro, which prevents us from
|
||||
// implementing the functions ourselves. zlib spells it ZEXTERN/ZEXPORT and zlib-ng's
|
||||
// zlib-compat header spells it Z_EXTERN/Z_EXPORT; both set theirs under `#ifndef`, so
|
||||
// defining all four before the include is what makes the definitions at the bottom of this
|
||||
// header legal -- they inherit the static inline linkage from the declarations zlib.h emits
|
||||
// here. This header must therefore be the first thing in a translation unit to pull in
|
||||
// <zlib.h>; if it is not, the definitions below stop being static and clang reports
|
||||
// `static declaration follows non-static declaration` right there.
|
||||
#undef ZEXTERN
|
||||
#undef ZEXPORT
|
||||
#undef Z_EXTERN
|
||||
#undef Z_EXPORT
|
||||
#define ZEXTERN static inline
|
||||
#define ZEXPORT
|
||||
#define Z_EXTERN static inline
|
||||
#define Z_EXPORT
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include "common/library.h"
|
||||
|
||||
extern struct FFZlibData {
|
||||
// Kept open rather than closed once opened: every group resolves against this one mapping, and
|
||||
// re-opening per group would pay the cold load again.
|
||||
void* handle;
|
||||
|
||||
FF_LIBRARY_SYMBOL(compressBound)
|
||||
FF_LIBRARY_SYMBOL(compress2)
|
||||
FF_LIBRARY_SYMBOL(inflateInit2_)
|
||||
FF_LIBRARY_SYMBOL(inflate)
|
||||
FF_LIBRARY_SYMBOL(inflateEnd)
|
||||
FF_LIBRARY_SYMBOL(gzopen)
|
||||
FF_LIBRARY_SYMBOL(gzread)
|
||||
FF_LIBRARY_SYMBOL(gzclose)
|
||||
|
||||
FFZlibGroup attempted;
|
||||
} zlibData;
|
||||
|
||||
[[gnu::always_inline]] static inline uLong(compressBound)(uLong sourceLen) {
|
||||
return zlibData.ffcompressBound(sourceLen);
|
||||
}
|
||||
|
||||
[[gnu::always_inline]] static inline int(compress2)(Bytef* dest, uLongf* destLen, const Bytef* source, uLong sourceLen, int level) {
|
||||
return zlibData.ffcompress2(dest, destLen, source, sourceLen, level);
|
||||
}
|
||||
|
||||
[[gnu::always_inline]] static inline int(inflateInit2_)(z_streamp strm, int windowBits, const char* version, int stream_size) {
|
||||
return zlibData.ffinflateInit2_(strm, windowBits, version, stream_size);
|
||||
}
|
||||
|
||||
[[gnu::always_inline]] static inline int(inflate)(z_streamp strm, int flush) {
|
||||
return zlibData.ffinflate(strm, flush);
|
||||
}
|
||||
|
||||
[[gnu::always_inline]] static inline int(inflateEnd)(z_streamp strm) {
|
||||
return zlibData.ffinflateEnd(strm);
|
||||
}
|
||||
|
||||
[[gnu::always_inline]] static inline gzFile(gzopen)(const char* path, const char* mode) {
|
||||
return zlibData.ffgzopen(path, mode);
|
||||
}
|
||||
|
||||
[[gnu::always_inline]] static inline int(gzread)(gzFile file, voidp buf, unsigned len) {
|
||||
return zlibData.ffgzread(file, buf, len);
|
||||
}
|
||||
|
||||
[[gnu::always_inline]] static inline int(gzclose)(gzFile file) {
|
||||
return zlibData.ffgzclose(file);
|
||||
}
|
||||
|
||||
// Resolves the entry points of `group` and returns nullptr, or an error message. Call it before using
|
||||
// that group's functions: until it has succeeded, the forwarders above are null pointers. The library
|
||||
// itself is opened once, by whichever group is asked for first, and stays open.
|
||||
const char* ffZlibLoad(FFZlibGroup group);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+13
-16
@@ -55,35 +55,32 @@ static const char* getSshdVersion(FFstrbuf* version) {
|
||||
}
|
||||
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
#include "common/library.h"
|
||||
#include "common/path.h"
|
||||
#include "common/zlib.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <zlib.h>
|
||||
|
||||
static const char* getSddmVersion(FFstrbuf* version) {
|
||||
FF_LIBRARY_LOAD_MESSAGE(zlib, "libz" FF_LIBRARY_EXTENSION, 2)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(zlib, gzopen)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(zlib, gzread)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(zlib, gzerror)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(zlib, gztell)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(zlib, gzrewind)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(zlib, gzclose)
|
||||
const char* error = ffZlibLoad(FF_ZLIB_GZFILE);
|
||||
if (error != nullptr) {
|
||||
FF_DEBUG("The sddm version cannot be read: %s", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
gzFile file = ffgzopen(FF_PATH_PKG_BASE "/share/man/man1/sddm.1.gz", "rb");
|
||||
gzFile file = gzopen(FF_PATH_PKG_BASE "/share/man/man1/sddm.1.gz", "rb");
|
||||
if (file == Z_NULL) {
|
||||
FF_DEBUG("ffgzopen(\"/usr/share/man/man1/sddm.1.gz\", \"rb\") failed: %s", strerror(errno));
|
||||
return "ffgzopen(\"/usr/share/man/man1/sddm.1.gz\", \"rb\") failed";
|
||||
FF_DEBUG("gzopen(\"/usr/share/man/man1/sddm.1.gz\", \"rb\") failed: %s", strerror(errno));
|
||||
return "gzopen(\"/usr/share/man/man1/sddm.1.gz\", \"rb\") failed";
|
||||
}
|
||||
|
||||
ffStrbufEnsureFree(version, 2047);
|
||||
memset(version->chars, 0, version->allocated);
|
||||
int size = ffgzread(file, version->chars, version->allocated - 1);
|
||||
ffgzclose(file);
|
||||
int size = gzread(file, version->chars, version->allocated - 1);
|
||||
gzclose(file);
|
||||
|
||||
if (size <= 0) {
|
||||
FF_DEBUG("ffgzread(file, version->chars, version->length) failed");
|
||||
return "ffgzread(file, version->chars, version->length) failed";
|
||||
FF_DEBUG("gzread(file, version->chars, version->length) failed");
|
||||
return "gzread(file, version->chars, version->length) failed";
|
||||
}
|
||||
|
||||
version->length = (uint32_t) size;
|
||||
|
||||
+9
-13
@@ -489,6 +489,7 @@ static bool printImageKittyDirect(bool printError) {
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "common/time.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/ioctl.h>
|
||||
@@ -498,19 +499,14 @@ static bool printImageKittyDirect(bool printError) {
|
||||
#endif
|
||||
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
#include <zlib.h>
|
||||
#include "common/zlib.h"
|
||||
|
||||
static bool compressBlob(void** blob, size_t* length) {
|
||||
FF_LIBRARY_LOAD(zlib, false,
|
||||
#ifdef _WIN32
|
||||
"zlib1"
|
||||
#else
|
||||
"libz"
|
||||
#endif
|
||||
FF_LIBRARY_EXTENSION,
|
||||
2)
|
||||
FF_LIBRARY_LOAD_SYMBOL(zlib, compressBound, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL(zlib, compress2, false)
|
||||
const char* error = ffZlibLoad(FF_ZLIB_COMPRESS);
|
||||
if (error != nullptr) {
|
||||
FF_DEBUG("The logo stays uncompressed: %s", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if _WIN32
|
||||
// zlib's uLong is 32-bit on Windows (LLP64), so a >4 GiB source can't be
|
||||
@@ -520,7 +516,7 @@ static bool compressBlob(void** blob, size_t* length) {
|
||||
}
|
||||
#endif
|
||||
|
||||
uLong compressedLength = ffcompressBound((uLong) *length);
|
||||
uLong compressedLength = compressBound((uLong) *length);
|
||||
void* compressed = malloc(compressedLength);
|
||||
if (compressed == nullptr) {
|
||||
return false;
|
||||
@@ -534,7 +530,7 @@ static bool compressBlob(void** blob, size_t* length) {
|
||||
// The gap is far wider on Windows, where the same frames cost 37.7 ms each at level 9 against
|
||||
// 6.4 at level 6: raising this back to 9 now that the DLL name above actually loads is a 4.2x
|
||||
// slowdown there (398 ms -> 1692 ms). Re-measure both platforms before touching it.
|
||||
if (ffcompress2(compressed, &compressedLength, *blob, (uLong) *length, Z_DEFAULT_COMPRESSION) != Z_OK) {
|
||||
if (compress2(compressed, &compressedLength, *blob, (uLong) *length, Z_DEFAULT_COMPRESSION) != Z_OK) {
|
||||
free(compressed);
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user