mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-12 10:22:12 +02:00
Binary: support macOS
This commit is contained in:
+6
-6
@@ -482,7 +482,7 @@ if(LINUX)
|
||||
src/detection/wmtheme/wmtheme_linux.c
|
||||
src/detection/camera/camera_linux.c
|
||||
src/util/platform/FFPlatform_unix.c
|
||||
src/util/binary.c
|
||||
src/util/binary_linux.c
|
||||
)
|
||||
elseif(ANDROID)
|
||||
list(APPEND LIBFASTFETCH_SRC
|
||||
@@ -544,7 +544,7 @@ elseif(ANDROID)
|
||||
src/detection/wmtheme/wmtheme_nosupport.c
|
||||
src/detection/camera/camera_android.c
|
||||
src/util/platform/FFPlatform_unix.c
|
||||
src/util/binary.c
|
||||
src/util/binary_linux.c
|
||||
)
|
||||
elseif(FreeBSD)
|
||||
list(APPEND LIBFASTFETCH_SRC
|
||||
@@ -623,7 +623,7 @@ elseif(FreeBSD)
|
||||
src/detection/wmtheme/wmtheme_linux.c
|
||||
src/detection/camera/camera_linux.c
|
||||
src/util/platform/FFPlatform_unix.c
|
||||
src/util/binary.c
|
||||
src/util/binary_linux.c
|
||||
)
|
||||
elseif(APPLE)
|
||||
list(APPEND LIBFASTFETCH_SRC
|
||||
@@ -689,7 +689,7 @@ elseif(APPLE)
|
||||
src/util/apple/cf_helpers.c
|
||||
src/util/apple/osascript.m
|
||||
src/util/platform/FFPlatform_unix.c
|
||||
src/util/binary.c
|
||||
src/util/binary_apple.c
|
||||
)
|
||||
elseif(WIN32)
|
||||
list(APPEND LIBFASTFETCH_SRC
|
||||
@@ -756,7 +756,7 @@ elseif(WIN32)
|
||||
src/util/windows/unicode.c
|
||||
src/util/windows/wmi.cpp
|
||||
src/util/platform/FFPlatform_windows.c
|
||||
src/util/binary.c
|
||||
src/util/binary_linux.c
|
||||
)
|
||||
elseif(SunOS)
|
||||
list(APPEND LIBFASTFETCH_SRC
|
||||
@@ -833,7 +833,7 @@ elseif(SunOS)
|
||||
src/detection/wmtheme/wmtheme_linux.c
|
||||
src/detection/camera/camera_nosupport.c
|
||||
src/util/platform/FFPlatform_unix.c
|
||||
src/util/binary.c
|
||||
src/util/binary_linux.c
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ static inline char* realpath(const char* restrict file_name, char* restrict reso
|
||||
}
|
||||
#endif
|
||||
|
||||
#if __linux__ || __FreeBSD__
|
||||
static bool extractNvimVersion(const char* str, uint32_t len, void* userdata)
|
||||
{
|
||||
if (len < strlen("NVIM v0.0.0")) return true;
|
||||
@@ -38,7 +37,6 @@ static bool extractNanoVersion(const char* str, uint32_t len, void* userdata)
|
||||
ffStrbufSetS((FFstrbuf*) userdata, str + strlen("GNU nano "));
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
const char* ffDetectEditor(FFEditorResult* result)
|
||||
{
|
||||
@@ -90,7 +88,6 @@ const char* ffDetectEditor(FFEditorResult* result)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if __linux__ || __FreeBSD__
|
||||
if (ffStrbufEqualS(&result->exe, "nvim"))
|
||||
ffBinaryExtractStrings(buf, extractNvimVersion, &result->version);
|
||||
else if (ffStrbufEqualS(&result->exe, "vim"))
|
||||
@@ -99,7 +96,6 @@ const char* ffDetectEditor(FFEditorResult* result)
|
||||
ffBinaryExtractStrings(buf, extractNanoVersion, &result->version);
|
||||
|
||||
if (result->version.length > 0) return NULL;
|
||||
#endif
|
||||
|
||||
const char* param = NULL;
|
||||
if (
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
#include "binary.h"
|
||||
#include "common/io/io.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include "util/mallocHelper.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/swap.h>
|
||||
#include <mach-o/fat.h>
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" // swap_fat_arch
|
||||
|
||||
// Ref: https://github.com/AlexDenisov/segment_dumper/blob/master/main.c
|
||||
|
||||
static inline bool readData(FILE *objFile, void *buf, size_t size, off_t offset)
|
||||
{
|
||||
fseek(objFile, offset, SEEK_SET);
|
||||
return fread(buf, 1, size, objFile) == size;
|
||||
}
|
||||
|
||||
static bool handleMachSection(FILE *objFile, const char *name, off_t offset, size_t size, bool (*cb)(const char *str, uint32_t len, void *userdata), void *userdata)
|
||||
{
|
||||
if (!ffStrEquals(name, "__cstring")) return true;
|
||||
|
||||
FF_AUTO_FREE char* data = (char*) malloc(size);
|
||||
if (!readData(objFile, data, size, offset))
|
||||
return true;
|
||||
|
||||
for (size_t off = 0; off < size; ++off)
|
||||
{
|
||||
const char* p = (const char*) data + off;
|
||||
if (*p == '\0') continue;
|
||||
uint32_t len = (uint32_t) strlen(p);
|
||||
if (*p >= ' ' && *p <= '~') // Ignore control characters
|
||||
{
|
||||
if (!cb(p, len, userdata)) return false;
|
||||
}
|
||||
off += len;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char* dumpMachHeader(FILE *objFile, off_t offset, bool is_64, bool (*cb)(const char *str, uint32_t len, void *userdata), void *userdata)
|
||||
{
|
||||
uint32_t ncmds;
|
||||
off_t loadCommandsOffset = offset;
|
||||
|
||||
if (is_64)
|
||||
{
|
||||
struct mach_header_64 header;
|
||||
if (!readData(objFile, &header, sizeof(header), offset))
|
||||
return "read mach header failed";
|
||||
|
||||
ncmds = header.ncmds;
|
||||
loadCommandsOffset += sizeof(header);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct mach_header header;
|
||||
if (!readData(objFile, &header, sizeof(header), offset))
|
||||
return "read mach header failed";
|
||||
|
||||
ncmds = header.ncmds;
|
||||
loadCommandsOffset += sizeof(header);
|
||||
}
|
||||
|
||||
off_t commandOffset = loadCommandsOffset;
|
||||
struct load_command cmd = {};
|
||||
for (uint32_t i = 0U; i < ncmds; i++, commandOffset += cmd.cmdsize)
|
||||
{
|
||||
if (!readData(objFile, &cmd, sizeof(cmd), commandOffset))
|
||||
continue;
|
||||
|
||||
if (cmd.cmd == LC_SEGMENT_64)
|
||||
{
|
||||
struct segment_command_64 segment;
|
||||
if (!readData(objFile, &segment, sizeof(segment), commandOffset))
|
||||
continue;
|
||||
|
||||
if (!ffStrEquals(segment.segname, "__TEXT")) continue;
|
||||
|
||||
for (uint32_t j = 0U; j < segment.nsects; j++)
|
||||
{
|
||||
struct section_64 section;
|
||||
if (!readData(objFile, §ion, sizeof(section), (off_t) ((size_t) commandOffset + sizeof(segment) + j * sizeof(section))))
|
||||
continue;
|
||||
|
||||
if (!handleMachSection(objFile, section.sectname, section.offset, section.size, cb, userdata))
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if (cmd.cmd == LC_SEGMENT)
|
||||
{
|
||||
struct segment_command segment;
|
||||
if (!readData(objFile, &segment, sizeof(segment), commandOffset))
|
||||
continue;
|
||||
|
||||
if (!ffStrEquals(segment.segname, "__TEXT")) continue;
|
||||
|
||||
for (uint32_t j = 0; j < segment.nsects; j++)
|
||||
{
|
||||
struct section section;
|
||||
if (!readData(objFile, §ion, sizeof(section), (off_t) ((size_t) commandOffset + sizeof(segment) + j * sizeof(section))))
|
||||
continue;
|
||||
|
||||
if (!handleMachSection(objFile, section.sectname, section.offset, section.size, cb, userdata))
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* dumpFatHeader(FILE *objFile, bool (*cb)(const char *str, uint32_t len, void *userdata), void *userdata)
|
||||
{
|
||||
struct fat_header header;
|
||||
if (!readData(objFile, &header, sizeof(header), 0))
|
||||
return "read fat header failed";
|
||||
|
||||
bool needSwap = header.magic == FAT_CIGAM || header.magic == FAT_CIGAM_64;
|
||||
|
||||
if (needSwap) swap_fat_header(&header, NX_UnknownByteOrder);
|
||||
|
||||
for (uint32_t i = 0U; i < header.nfat_arch; i++)
|
||||
{
|
||||
off_t machHeaderOffset = 0;
|
||||
if (header.magic == FAT_MAGIC)
|
||||
{
|
||||
struct fat_arch arch;
|
||||
if (!readData(objFile, &arch, sizeof(arch), (off_t) (sizeof(header) + i * sizeof(arch))))
|
||||
continue;
|
||||
|
||||
if (needSwap)
|
||||
swap_fat_arch(&arch, 1, NX_UnknownByteOrder);
|
||||
machHeaderOffset = (off_t)arch.offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct fat_arch_64 arch;
|
||||
if (!readData(objFile, &arch, sizeof(arch), (off_t) (sizeof(header) + i * sizeof(arch))))
|
||||
continue;
|
||||
|
||||
if (needSwap)
|
||||
swap_fat_arch_64(&arch, 1, NX_UnknownByteOrder);
|
||||
|
||||
machHeaderOffset = (off_t)arch.offset;
|
||||
}
|
||||
|
||||
uint32_t magic;
|
||||
if (!readData(objFile, &magic, sizeof(magic), machHeaderOffset))
|
||||
continue;
|
||||
|
||||
if (magic == MH_MAGIC_64 || magic == MH_MAGIC)
|
||||
{
|
||||
dumpMachHeader(objFile, machHeaderOffset, magic == MH_MAGIC_64, cb, userdata);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return "Unsupported fat header";
|
||||
}
|
||||
|
||||
const char *ffBinaryExtractStrings(const char *machoFile, bool (*cb)(const char *str, uint32_t len, void *userdata), void *userdata)
|
||||
{
|
||||
FF_AUTO_CLOSE_FILE FILE *objFile = fopen(machoFile, "rb");
|
||||
if (objFile == NULL)
|
||||
return "File could not be opened";
|
||||
|
||||
uint32_t magic;
|
||||
if (!readData(objFile, &magic, sizeof(magic), 0))
|
||||
return "read magic number failed";
|
||||
|
||||
// MH_CIGAM and MH_CIGAM_64 seem to be no longer used, as `swap_mach_header` is marked as deprecated.
|
||||
// However FAT_CIGAM and FAT_CIGAM_64 are still used (/usr/bin/vim).
|
||||
if (magic != MH_MAGIC && magic != MH_MAGIC_64 && magic != FAT_CIGAM && magic != FAT_CIGAM_64 && magic != FAT_MAGIC && magic != FAT_MAGIC_64)
|
||||
return "Unsupported format or big endian mach-o file";
|
||||
|
||||
if (magic == FAT_MAGIC || magic == FAT_MAGIC_64 || magic == FAT_CIGAM || magic == FAT_CIGAM_64)
|
||||
return dumpFatHeader(objFile, cb, userdata);
|
||||
else
|
||||
return dumpMachHeader(objFile, 0, magic == MH_MAGIC_64, cb, userdata);
|
||||
}
|
||||
Reference in New Issue
Block a user