#pragma once
#ifndef _DEARXAN_H
#define _DEARXAN_H
#ifdef __cplusplus
#include <cstddef>
#include <cstring>
#include <functional>
#include <memory>
#include <string>
#include <utility>
#if __cplusplus >= 201703 || _MSVC_LANG >= 201703
#include <optional>
#else
#include <stdexcept>
#endif
namespace dearxan {
namespace detail {
extern "C" {
#else
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#define DEARXAN_RESULT_SIZE offsetof(DearxanResult, _last_for_offsetof)
#define DEARXAN_RESULT_FIELD(ptr, field, then_expr, else_expr) do { \
if (offsetof(DearxanResult, field) < ptr->result_size) { \
then_expr; \
} else { \
else_expr; \
} \
} while(0)
#endif
typedef enum DearxanStatus {
DearxanInvalid,
DearxanSuccess,
DearxanError,
DearxanPanic,
DearxanMaxStatus
} DearxanStatus;
typedef struct DearxanResult {
size_t result_size;
int status;
const char* error_msg;
size_t error_msg_size;
bool is_arxan_detected;
bool is_executing_entrypoint;
char _last_for_offsetof;
} DearxanResult;
typedef void (*DearxanUserCallback)(const DearxanResult* result, void* opaque);
extern void dearxan_neuter_arxan(DearxanUserCallback callback, void* opaque);
#ifdef __cplusplus
}
}
using DearxanStatus = detail::DearxanStatus;
#define DEARXAN_RESULT_SIZE \
offsetof(detail::DearxanResult, _last_for_offsetof)
#define DEARXAN_RESULT_FIELD(ptr, field, then_expr, else_expr) do { \
if (offsetof(detail::DearxanResult, field) < ptr->result_size) { \
then_expr; \
} else { \
else_expr; \
} \
} while(0)
#if __cplusplus >= 201703 || _MSVC_LANG >= 201703
#define DEARXAN_DECLARE_FIELD(field) auto field() const { \
DEARXAN_RESULT_FIELD( \
static_cast<const detail::DearxanResult*>(this), \
field, \
return std::optional(detail::DearxanResult::field), \
return std::optional<decltype(detail::DearxanResult::field)>() \
); \
}
#else
#define DEARXAN_DECLARE_FIELD(field) auto field() const { \
DEARXAN_RESULT_FIELD( \
static_cast<const detail::DearxanResult*>(this), \
field, \
return detail::DearxanResult::field, \
throw std::length_error( \
"old DearxanResult layout lacks field " #field) \
); \
}
#endif
struct DearxanResult : private detail::DearxanResult {
explicit DearxanResult(const detail::DearxanResult* ptr) : detail::DearxanResult{} {
if (ptr == nullptr) {
return;
}
size_t result_size = DEARXAN_RESULT_SIZE < ptr->result_size
? DEARXAN_RESULT_SIZE : ptr->result_size;
std::memcpy(
static_cast<void*>(static_cast<detail::DearxanResult*>(this)),
static_cast<const void*>(ptr),
result_size
);
this->result_size = result_size;
}
DearxanStatus status() const noexcept {
return static_cast<DearxanStatus>(detail::DearxanResult::status);
}
std::string error_msg() const noexcept {
return std::string(detail::DearxanResult::error_msg,
detail::DearxanResult::error_msg_size);
}
bool is_arxan_detected() const noexcept {
return detail::DearxanResult::is_arxan_detected;
}
bool is_executing_entrypoint() const noexcept {
return detail::DearxanResult::is_executing_entrypoint;
}
};
using DearxanUserCallback = std::function<void(const DearxanResult&)>;
inline void neuter_arxan(DearxanUserCallback f) {
auto boxed_function =
std::make_unique<DearxanUserCallback>(std::move(f)).release();
auto callback = +[](const detail::DearxanResult* result, void* opaque) {
auto boxed_function =
std::unique_ptr<DearxanUserCallback>(reinterpret_cast<DearxanUserCallback*>(opaque));
(*boxed_function.get())(DearxanResult(result));
};
detail::dearxan_neuter_arxan(callback, static_cast<void*>(boxed_function));
}
}
#undef DEARXAN_RESULT_SIZE
#undef DEARXAN_RESULT_FIELD
#undef DEARXAN_DECLARE_FIELD
#endif
#endif