Initial re-upload of spice2x-24-08-24
This commit is contained in:
501
avs/automap.cpp
Normal file
501
avs/automap.cpp
Normal file
@@ -0,0 +1,501 @@
|
||||
#include "automap.h"
|
||||
#include <fstream>
|
||||
#include "external/tinyxml2/tinyxml2.h"
|
||||
#include "util/logging.h"
|
||||
#include "util/detour.h"
|
||||
#include "util/utils.h"
|
||||
#include "util/fileutils.h"
|
||||
#include "./core.h"
|
||||
|
||||
// macro for easy hooking
|
||||
#define AUTOMAP_HOOK(s) detour::iat_try_proc(avs::core::DLL_NAME.c_str(), avs::core::s, s)
|
||||
|
||||
namespace avs::automap {
|
||||
|
||||
// state
|
||||
bool ENABLED = false;
|
||||
bool DUMP = false;
|
||||
bool PATCH = false;
|
||||
bool JSON = false;
|
||||
bool RESTRICT_NETWORK = false;
|
||||
std::string DUMP_FILENAME = "";
|
||||
|
||||
// logging
|
||||
static std::ofstream LOGFILE;
|
||||
static std::vector<std::pair<AutomapHook_t, void*>> HOOKS;
|
||||
|
||||
|
||||
static bool property_is_network(avs::core::property_ptr prop, avs::core::node_ptr node = nullptr) {
|
||||
avs::core::node_ptr root_node = nullptr;
|
||||
|
||||
/*
|
||||
* on failure to detect, we must return true
|
||||
* most of the time, no prop is specified
|
||||
*/
|
||||
|
||||
// get root node
|
||||
if (prop) {
|
||||
|
||||
// when prop is specified, this is easy
|
||||
root_node = avs::core::property_search(prop, nullptr, "/");
|
||||
|
||||
} else if (node) {
|
||||
|
||||
|
||||
// otherwise we need to traverse
|
||||
root_node = node;
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
auto parent_node = avs::core::property_node_traversal(node, avs::core::TRAVERSE_PARENT);
|
||||
if (parent_node == root_node || parent_node == nullptr) {
|
||||
break;
|
||||
} else {
|
||||
root_node = parent_node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// verify root node
|
||||
if (!root_node) {
|
||||
if (prop != nullptr) {
|
||||
avs::core::property_clear_error(prop);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// check name
|
||||
char root_name[256] {};
|
||||
if (avs::core::property_node_name(root_node, root_name, sizeof(root_name)) >= 0) {
|
||||
return !strcmp(root_name, "call") || !strcmp(root_name, "response");
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool property_patches_enabled(avs::core::property_ptr prop, avs::core::node_ptr node = nullptr,
|
||||
bool force = false) {
|
||||
if (!ENABLED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if patches are enabled first
|
||||
if (!PATCH) {
|
||||
return false;
|
||||
} else if (force) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// check if restricted to network
|
||||
if (RESTRICT_NETWORK) {
|
||||
return property_is_network(prop, node);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool property_dump_enabled(avs::core::property_ptr prop, avs::core::node_ptr node = nullptr) {
|
||||
if (!ENABLED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if dumps are enabled first
|
||||
if (!DUMP && HOOKS.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if restricted to network
|
||||
if (RESTRICT_NETWORK) {
|
||||
return property_is_network(prop, node);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t property_get_error(avs::core::property_ptr prop) {
|
||||
auto error = avs::core::property_get_error(prop);
|
||||
if (error != 0 && prop != nullptr) {
|
||||
log_misc("automap", "detected error: {}", error);
|
||||
avs::core::property_clear_error(prop);
|
||||
return avs::core::property_get_error(prop);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
avs::core::node_ptr property_search(avs::core::property_ptr prop, avs::core::node_ptr node, const char *path) {
|
||||
|
||||
// call original
|
||||
auto result = avs::core::property_search(prop, node, path);
|
||||
if (result != nullptr) {
|
||||
return result;
|
||||
} else if (!property_patches_enabled(prop, node)) {
|
||||
log_misc("automap", "property_search error: {}", path ? path : "?");
|
||||
return result;
|
||||
}
|
||||
|
||||
// create node
|
||||
log_misc("automap", "property_search error: {}", path ? path : "?");
|
||||
static const uint8_t zero_buffer[64] {};
|
||||
avs::core::property_node_create(prop, node, avs::core::NODE_TYPE_node, path, zero_buffer);
|
||||
|
||||
// clear error
|
||||
if (prop) {
|
||||
avs::core::property_clear_error(prop);
|
||||
}
|
||||
|
||||
// now try again
|
||||
return avs::core::property_search(prop, node, path);
|
||||
}
|
||||
|
||||
int property_node_refer(avs::core::property_ptr prop, avs::core::node_ptr node, const char *path,
|
||||
avs::core::node_type type, void *data, uint32_t data_size) {
|
||||
auto result = avs::core::property_node_refer(prop, node, path, type, data, data_size);
|
||||
if (result >= 0) {
|
||||
return result;
|
||||
} else if (!property_patches_enabled(prop, node)) {
|
||||
log_misc("automap", "property_node_refer error: {}", path ? path : "?");
|
||||
return result;
|
||||
}
|
||||
|
||||
// check if accessed by path
|
||||
if (!path) {
|
||||
|
||||
// print log without path
|
||||
log_misc("automap", "node refer error: {}", result);
|
||||
|
||||
} else {
|
||||
std::string path_str(path);
|
||||
|
||||
// prevent infinite loop in cardmng
|
||||
if (string_begins_with(path_str, "/card_allow/card")) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// print log with path
|
||||
log_misc("automap", "node refer error ({}): {}", path, result);
|
||||
if (path_str == "/") {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// maybe it *does* exist, but with the wrong type
|
||||
auto find_node = avs::core::property_search(prop, node, path);
|
||||
if (find_node != nullptr) {
|
||||
|
||||
// now get rid of it
|
||||
avs::core::property_node_remove(find_node);
|
||||
}
|
||||
|
||||
// fake buffer if required
|
||||
uint8_t *buffer = reinterpret_cast<uint8_t *>(data);
|
||||
auto buffer_size = data_size;
|
||||
if (buffer == nullptr || buffer_size == 0) {
|
||||
static uint8_t zero_buffer[64];
|
||||
buffer = zero_buffer;
|
||||
buffer_size = sizeof(zero_buffer);
|
||||
}
|
||||
|
||||
// initialize field
|
||||
memset(buffer, 0, buffer_size);
|
||||
if ((type == avs::core::NODE_TYPE_attr || type == avs::core::NODE_TYPE_str) && buffer_size > 1) {
|
||||
|
||||
// init attributes and strings with "0" by default - useful for "status" or "error" fields
|
||||
buffer[0] = '0';
|
||||
buffer[1] = '\x00';
|
||||
}
|
||||
if (path) {
|
||||
|
||||
// for numbers and counts we fake a 1 to get a single entry
|
||||
if (string_ends_with(path, "num") || string_ends_with(path, "count")) {
|
||||
if ((type == avs::core::NODE_TYPE_attr || type == avs::core::NODE_TYPE_str) && buffer_size > 1) {
|
||||
buffer[0] = '1';
|
||||
buffer[1] = '\x00';
|
||||
} else if (buffer_size > 0) {
|
||||
buffer[0] = 0x01;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add to property
|
||||
avs::core::property_node_create(prop, node, type, path, buffer);
|
||||
|
||||
// clear error
|
||||
if (prop) {
|
||||
avs::core::property_clear_error(prop);
|
||||
}
|
||||
|
||||
// try again
|
||||
return avs::core::property_node_refer(prop, node, path, type, data, data_size);
|
||||
}
|
||||
|
||||
avs::core::avs_error_t property_get_attribute_u32(
|
||||
avs::core::property_ptr prop,
|
||||
avs::core::node_ptr node,
|
||||
const char *path,
|
||||
uint32_t *value)
|
||||
{
|
||||
auto result = avs::core::property_get_attribute_u32(prop, node, path, value);
|
||||
if (result < 0 && property_patches_enabled(prop, node, true)) {
|
||||
log_warning("automap", "property_get_attribute_u32 failed: {}", path ? path : "?");
|
||||
const char *data = "0";
|
||||
avs::core::property_node_create(prop, node, avs::core::NODE_TYPE_attr, path, data);
|
||||
return avs::core::property_get_attribute_u32(prop, node, path, value);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
avs::core::avs_error_t property_get_attribute_s32(
|
||||
avs::core::property_ptr prop,
|
||||
avs::core::node_ptr node,
|
||||
const char *path,
|
||||
int32_t *value)
|
||||
{
|
||||
auto result = avs::core::property_get_attribute_s32(prop, node, path, value);
|
||||
if (result < 0 && property_patches_enabled(prop, node, true)) {
|
||||
log_warning("automap", "property_get_attribute_s32 failed: {}", path ? path : "?");
|
||||
const char *data = "0";
|
||||
avs::core::property_node_create(prop, node, avs::core::NODE_TYPE_attr, path, data);
|
||||
return avs::core::property_get_attribute_s32(prop, node, path, value);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
int property_node_read(avs::core::node_ptr node, avs::core::node_type type, void *data, uint32_t data_size) {
|
||||
auto result = avs::core::property_node_read(node, type, data, data_size);
|
||||
if (result < 0 && property_patches_enabled(nullptr, node)) {
|
||||
log_warning("automap", "property_node_read failed ({}): {}", type, result);
|
||||
|
||||
// probably wrong type
|
||||
memset(data, 0, data_size);
|
||||
if ((type == avs::core::NODE_TYPE_attr || type == avs::core::NODE_TYPE_str) && data_size > 1) {
|
||||
((char *) data)[0] = '0';
|
||||
((char *) data)[1] = '\x00';
|
||||
data_size = 2;
|
||||
}
|
||||
|
||||
// recreate the node with the correct type (probably invalidates the pointer, how to fix?)
|
||||
auto parent_node = avs::core::property_node_traversal(node, avs::core::TRAVERSE_PARENT);
|
||||
if (parent_node && parent_node != node) {
|
||||
char name_buf[256] {};
|
||||
if (avs::core::property_node_name(node, name_buf, sizeof(name_buf)) >= 0) {
|
||||
log_warning("automap", "property_node_read replace type ({}): {}", type, result);
|
||||
avs::core::property_node_remove(node);
|
||||
avs::core::property_node_create(nullptr, parent_node, type, name_buf, data);
|
||||
}
|
||||
}
|
||||
|
||||
// return input data size
|
||||
return data_size;
|
||||
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
bool property_psmap_export(avs::core::property_ptr prop, avs::core::node_ptr node, uint8_t *data,
|
||||
avs::core::psmap_data_ptr psmap) {
|
||||
|
||||
// check if enabled
|
||||
if (property_patches_enabled(prop, node)) {
|
||||
|
||||
// iterate psmap
|
||||
for (size_t i = 0; psmap[i].type != 0xFF; i++) {
|
||||
auto &cur_entry = psmap[i];
|
||||
|
||||
// determine node type
|
||||
avs::core::node_type node_type;
|
||||
switch (cur_entry.type) {
|
||||
case avs::core::PSMAP_TYPE_s8:
|
||||
node_type = avs::core::NODE_TYPE_s8;
|
||||
break;
|
||||
case avs::core::PSMAP_TYPE_u8:
|
||||
node_type = avs::core::NODE_TYPE_u8;
|
||||
break;
|
||||
case avs::core::PSMAP_TYPE_s16:
|
||||
node_type = avs::core::NODE_TYPE_s16;
|
||||
break;
|
||||
case avs::core::PSMAP_TYPE_u16:
|
||||
node_type = avs::core::NODE_TYPE_u16;
|
||||
break;
|
||||
case avs::core::PSMAP_TYPE_s32:
|
||||
node_type = avs::core::NODE_TYPE_s32;
|
||||
break;
|
||||
case avs::core::PSMAP_TYPE_u32:
|
||||
node_type = avs::core::NODE_TYPE_u32;
|
||||
break;
|
||||
case avs::core::PSMAP_TYPE_s64:
|
||||
node_type = avs::core::NODE_TYPE_s64;
|
||||
break;
|
||||
case avs::core::PSMAP_TYPE_u64:
|
||||
node_type = avs::core::NODE_TYPE_u64;
|
||||
break;
|
||||
case avs::core::PSMAP_TYPE_str:
|
||||
case avs::core::PSMAP_TYPE_str2:
|
||||
node_type = avs::core::NODE_TYPE_str;
|
||||
break;
|
||||
case avs::core::PSMAP_TYPE_attr:
|
||||
node_type = avs::core::NODE_TYPE_attr;
|
||||
break;
|
||||
case avs::core::PSMAP_TYPE_bool:
|
||||
node_type = avs::core::NODE_TYPE_bool;
|
||||
break;
|
||||
default:
|
||||
node_type = (avs::core::node_type) 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// check if node type was found
|
||||
if (node_type != 0) {
|
||||
|
||||
// get rid of existing nodes with type mismatch
|
||||
auto node_search = avs::core::property_search(prop, node, cur_entry.path);
|
||||
if (node_search) {
|
||||
auto node_search_type = avs::core::property_node_type(node_search);
|
||||
if (node_type != node_search_type) {
|
||||
log_misc("automap", "psmap type mismatch, replacing node: {}", cur_entry.path);
|
||||
avs::core::property_node_remove(node_search);
|
||||
} else {
|
||||
|
||||
// this one seems to be fine actually!
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// generate node
|
||||
log_misc("automap", "generating psmap node: {}", cur_entry.path);
|
||||
uint8_t node_data[64]{};
|
||||
if (node_type == avs::core::NODE_TYPE_attr || node_type == avs::core::NODE_TYPE_str) {
|
||||
node_data[0] = '0';
|
||||
node_data[1] = '\x00';
|
||||
}
|
||||
avs::core::property_node_create(prop, node, node_type, cur_entry.path, node_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now we call the original
|
||||
return avs::core::property_psmap_export(prop, node, data, psmap);
|
||||
}
|
||||
|
||||
avs::core::avs_error_t property_destroy(avs::core::property_ptr prop) {
|
||||
|
||||
// we definitely need a property for this to work
|
||||
if (prop == NULL) {
|
||||
log_warning("automap", "property_destroy called on NULL");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check if dump is enabled
|
||||
if (property_dump_enabled(prop)) {
|
||||
|
||||
// convert to XML
|
||||
avs::core::property_set_flag(prop, avs::core::PROP_XML, avs::core::PROP_BINARY);
|
||||
|
||||
// optionally reconvert to JSON
|
||||
if (JSON) {
|
||||
avs::core::property_set_flag(prop, avs::core::PROP_JSON, avs::core::PROP_XML);
|
||||
}
|
||||
|
||||
// query size
|
||||
auto size = avs::core::property_query_size(prop);
|
||||
if (size < 0) {
|
||||
log_warning("automap", "couldn't query property size");
|
||||
} else {
|
||||
log_misc("automap", "writing property to file: {} bytes", size);
|
||||
|
||||
// get XML
|
||||
std::vector<uint8_t> data(size);
|
||||
if (avs::core::property_mem_write(prop, &data[0], data.size()) >= 0) {
|
||||
|
||||
// initialize log
|
||||
if (DUMP && !LOGFILE.is_open()) {
|
||||
|
||||
// try filenames with IDs starting at 0
|
||||
for (int i = 0; i < 10000 && !LOGFILE.is_open(); i++) {
|
||||
std::string path = "automap_" + to_string(i) + ".xml";
|
||||
|
||||
// check if this one is available to use
|
||||
if (!fileutils::file_exists(path)) {
|
||||
|
||||
// try creating the file
|
||||
LOGFILE.open(path, std::ios::out | std::ios::binary);
|
||||
if (LOGFILE.is_open()) {
|
||||
DUMP_FILENAME = path;
|
||||
log_info("automap", "using logfile: {}", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// prettify
|
||||
tinyxml2::XMLDocument document;
|
||||
if (!JSON && document.Parse((const char*) &data[0],
|
||||
data.size()) == tinyxml2::XMLError::XML_SUCCESS) {
|
||||
|
||||
// write pretty output to log
|
||||
tinyxml2::XMLPrinter xml_printer;
|
||||
document.Print(&xml_printer);
|
||||
for (auto &hook : HOOKS) {
|
||||
hook.first(hook.second, xml_printer.CStr());
|
||||
}
|
||||
if (DUMP && LOGFILE.is_open()) {
|
||||
LOGFILE << xml_printer.CStr() << std::endl;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// write avs output to log
|
||||
for (auto &hook : HOOKS) {
|
||||
hook.first(hook.second, std::string((const char *) &data[0], data.size()).c_str());
|
||||
}
|
||||
if (DUMP && LOGFILE.is_open()) {
|
||||
LOGFILE << std::string((const char *) &data[0], data.size());
|
||||
}
|
||||
}
|
||||
|
||||
// flush
|
||||
LOGFILE.flush();
|
||||
|
||||
} else {
|
||||
log_warning("automap", "couldn't write property to memory");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// kill it with fire
|
||||
return avs::core::property_destroy(prop);
|
||||
}
|
||||
|
||||
void enable() {
|
||||
log_info("automap", "enable");
|
||||
ENABLED = true;
|
||||
|
||||
// check if optional imports are supported for this avs version
|
||||
if (!avs::core::property_node_read || !avs::core::property_get_error) {
|
||||
log_fatal("automap", "missing optional avs imports which are required for this module to work");
|
||||
}
|
||||
|
||||
// apply hooks
|
||||
AUTOMAP_HOOK(property_get_error);
|
||||
AUTOMAP_HOOK(property_search);
|
||||
AUTOMAP_HOOK(property_node_refer);
|
||||
AUTOMAP_HOOK(property_get_attribute_u32);
|
||||
AUTOMAP_HOOK(property_get_attribute_s32);
|
||||
AUTOMAP_HOOK(property_node_read);
|
||||
AUTOMAP_HOOK(property_psmap_export);
|
||||
AUTOMAP_HOOK(property_destroy);
|
||||
}
|
||||
|
||||
void disable() {
|
||||
log_info("automap", "disable");
|
||||
ENABLED = false;
|
||||
}
|
||||
|
||||
void hook_add(AutomapHook_t hook, void *user) {
|
||||
HOOKS.push_back(std::pair(hook, user));
|
||||
}
|
||||
|
||||
void hook_remove(AutomapHook_t hook, void *user) {
|
||||
HOOKS.erase(std::remove(HOOKS.begin(), HOOKS.end(), std::pair(hook, user)), HOOKS.end());
|
||||
}
|
||||
}
|
||||
21
avs/automap.h
Normal file
21
avs/automap.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace avs::automap {
|
||||
|
||||
extern bool ENABLED;
|
||||
extern bool DUMP;
|
||||
extern bool PATCH;
|
||||
extern bool JSON;
|
||||
extern bool RESTRICT_NETWORK;
|
||||
extern std::string DUMP_FILENAME;
|
||||
|
||||
void enable();
|
||||
void disable();
|
||||
|
||||
// log hooks
|
||||
typedef void (*AutomapHook_t)(void *user, const char *data);
|
||||
void hook_add(AutomapHook_t hook, void *user);
|
||||
void hook_remove(AutomapHook_t hook, void *user);
|
||||
}
|
||||
2172
avs/core.cpp
Normal file
2172
avs/core.cpp
Normal file
File diff suppressed because it is too large
Load Diff
766
avs/core.h
Normal file
766
avs/core.h
Normal file
@@ -0,0 +1,766 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <windows.h>
|
||||
|
||||
namespace avs {
|
||||
namespace core {
|
||||
|
||||
/*
|
||||
* enums
|
||||
*/
|
||||
enum node_type {
|
||||
NODE_TYPE_node = 1,
|
||||
NODE_TYPE_s8 = 2,
|
||||
NODE_TYPE_u8 = 3,
|
||||
NODE_TYPE_s16 = 4,
|
||||
NODE_TYPE_u16 = 5,
|
||||
NODE_TYPE_s32 = 6,
|
||||
NODE_TYPE_u32 = 7,
|
||||
NODE_TYPE_s64 = 8,
|
||||
NODE_TYPE_u64 = 9,
|
||||
NODE_TYPE_bin = 10,
|
||||
NODE_TYPE_str = 11,
|
||||
NODE_TYPE_ip4 = 12,
|
||||
NODE_TYPE_time = 13,
|
||||
NODE_TYPE_float = 14,
|
||||
NODE_TYPE_double = 15,
|
||||
NODE_TYPE_2s8 = 16,
|
||||
NODE_TYPE_2u8 = 17,
|
||||
NODE_TYPE_2s16 = 18,
|
||||
NODE_TYPE_2u16 = 19,
|
||||
NODE_TYPE_2s32 = 20,
|
||||
NODE_TYPE_2u32 = 21,
|
||||
NODE_TYPE_2s64 = 22,
|
||||
NODE_TYPE_2u64 = 23,
|
||||
NODE_TYPE_2f = 24,
|
||||
NODE_TYPE_2d = 25,
|
||||
NODE_TYPE_3s8 = 26,
|
||||
NODE_TYPE_3u8 = 27,
|
||||
NODE_TYPE_3s16 = 28,
|
||||
NODE_TYPE_3u16 = 29,
|
||||
NODE_TYPE_3s32 = 30,
|
||||
NODE_TYPE_3u32 = 31,
|
||||
NODE_TYPE_3s64 = 32,
|
||||
NODE_TYPE_3u64 = 33,
|
||||
NODE_TYPE_3f = 34,
|
||||
NODE_TYPE_3d = 35,
|
||||
NODE_TYPE_4s8 = 36,
|
||||
NODE_TYPE_4u8 = 37,
|
||||
NODE_TYPE_4s16 = 38,
|
||||
NODE_TYPE_4u16 = 39,
|
||||
NODE_TYPE_4s32 = 40,
|
||||
NODE_TYPE_4u32 = 41,
|
||||
NODE_TYPE_4s64 = 42,
|
||||
NODE_TYPE_4u64 = 43,
|
||||
NODE_TYPE_4f = 44,
|
||||
NODE_TYPE_4d = 45,
|
||||
NODE_TYPE_attr = 46,
|
||||
NODE_TYPE_attr_and_node = 47,
|
||||
NODE_TYPE_vs8 = 48,
|
||||
NODE_TYPE_vu8 = 49,
|
||||
NODE_TYPE_vs16 = 50,
|
||||
NODE_TYPE_vu16 = 51,
|
||||
NODE_TYPE_bool = 52,
|
||||
NODE_TYPE_2b = 53,
|
||||
NODE_TYPE_3b = 54,
|
||||
NODE_TYPE_4b = 55,
|
||||
NODE_TYPE_vb = 56,
|
||||
};
|
||||
|
||||
enum psmap_type {
|
||||
PSMAP_TYPE_s8 = 2,
|
||||
PSMAP_TYPE_u8 = 3,
|
||||
PSMAP_TYPE_s16 = 4,
|
||||
PSMAP_TYPE_u16 = 5,
|
||||
PSMAP_TYPE_s32 = 6,
|
||||
PSMAP_TYPE_u32 = 7,
|
||||
PSMAP_TYPE_s64 = 8,
|
||||
PSMAP_TYPE_u64 = 9,
|
||||
PSMAP_TYPE_str = 10,
|
||||
PSMAP_TYPE_str2 = 11,
|
||||
PSMAP_TYPE_attr = 45,
|
||||
PSMAP_TYPE_bool = 50,
|
||||
};
|
||||
|
||||
enum property_node_traversal_option {
|
||||
TRAVERSE_PARENT = 0,
|
||||
TRAVERSE_FIRST_CHILD = 1,
|
||||
TRAVERSE_FIRST_ATTR = 2,
|
||||
TRAVERSE_FIRST_SIBLING = 3,
|
||||
TRAVERSE_NEXT_SIBLING = 4,
|
||||
TRAVERSE_PREVIOUS_SIBLING = 5,
|
||||
TRAVERSE_LAST_SIBLING = 6,
|
||||
TRAVERSE_NEXT_SEARCH_RESULT = 7,
|
||||
TRAVERSE_PREV_SEARCH_RESULT = 8,
|
||||
};
|
||||
|
||||
enum property_flag {
|
||||
PROP_XML = 0x000,
|
||||
PROP_READ = 0x001,
|
||||
PROP_WRITE = 0x002,
|
||||
PROP_CREATE = 0x004,
|
||||
PROP_BINARY = 0x008,
|
||||
PROP_APPEND = 0x010,
|
||||
PROP_DEBUG_VERBOSE = 0x400,
|
||||
PROP_JSON = 0x800,
|
||||
PROP_BIN_PLAIN_NODE_NAMES = 0x1000,
|
||||
};
|
||||
|
||||
enum cstream_type {
|
||||
CSTREAM_AVSLZ_DECOMPRESS = 0,
|
||||
CSTREAM_AVSLZ_COMPRESS = 1,
|
||||
};
|
||||
|
||||
/*
|
||||
* structs
|
||||
*/
|
||||
|
||||
struct node_stat {
|
||||
int nodes;
|
||||
int data;
|
||||
int unk1, unk2, unk3;
|
||||
};
|
||||
typedef node_stat *node_stat_ptr;
|
||||
|
||||
struct property_info {
|
||||
uint8_t dummy[560];
|
||||
uint32_t error_code;
|
||||
uint32_t has_error;
|
||||
uint32_t unk;
|
||||
int8_t buffer_offset;
|
||||
};
|
||||
typedef property_info *property_ptr;
|
||||
|
||||
struct node_info {
|
||||
uint8_t dummy[47];
|
||||
node_type type;
|
||||
};
|
||||
typedef node_info *node_ptr;
|
||||
|
||||
struct psmap_data {
|
||||
uint8_t type;
|
||||
uint8_t flags;
|
||||
uint16_t offset;
|
||||
uint32_t size;
|
||||
const char *path;
|
||||
void *xdefault;
|
||||
};
|
||||
typedef psmap_data *psmap_data_ptr;
|
||||
|
||||
struct avs_stat {
|
||||
uint64_t st_atime;
|
||||
uint64_t st_mtime;
|
||||
uint64_t st_ctime;
|
||||
uint32_t unk1;
|
||||
uint32_t filesize;
|
||||
struct stat padding;
|
||||
};
|
||||
struct cstream_data {
|
||||
unsigned char *out_buf;
|
||||
unsigned char *in_buf;
|
||||
uint32_t out_size;
|
||||
uint32_t in_size;
|
||||
};
|
||||
struct avs_iovec {
|
||||
void *iov_base;
|
||||
size_t iov_len;
|
||||
};
|
||||
|
||||
/*
|
||||
* net
|
||||
*/
|
||||
|
||||
constexpr int AVS_NET_PROTOCOL_MAGIC = 0x1b55fa1;
|
||||
constexpr int AVS_NET_POLL_POLLIN = 0x0001;
|
||||
constexpr int AVS_NET_PROTOCOL_SSL_TLS_V1_1 = 2;
|
||||
|
||||
constexpr int T_NET_PROTO_ID_DEFAULT = 0;
|
||||
|
||||
enum avs_net_sock_opts {
|
||||
AVS_SO_SNDTIMEO = 2,
|
||||
AVS_SO_RCVTIMEO = 3,
|
||||
AVS_SO_NONBLOCK = 9,
|
||||
AVS_SO_SSL_PROTOCOL = 10,
|
||||
AVS_SO_SSL_VERIFY_CN = 13,
|
||||
};
|
||||
|
||||
typedef uint32_t avs_net_size_t;
|
||||
typedef uint16_t avs_net_port_t;
|
||||
typedef int avs_net_pollfds_size_t;
|
||||
|
||||
typedef uint64_t avs_net_timeout_t;
|
||||
|
||||
struct avs_net_poll_fd_opaque;
|
||||
struct avs_net_proto_desc_work;
|
||||
struct avs_net_sock_desc_work;
|
||||
|
||||
struct avs_net_poll_fd {
|
||||
int socket;
|
||||
uint16_t events;
|
||||
uint16_t r_events;
|
||||
int error;
|
||||
};
|
||||
|
||||
struct avs_net_protocol_ops {
|
||||
int (*protocol_initialize)(struct avs_net_proto_desc_work *work);
|
||||
int (*protocol_finalize)(struct avs_net_proto_desc_work *work);
|
||||
int (*allocate_socket)(struct avs_net_sock_desc_work *work);
|
||||
void (*free_socket)(struct avs_net_sock_desc_work *work);
|
||||
int (*initialize_socket)(struct avs_net_sock_desc_work *work);
|
||||
void (*finalize_socket)(struct avs_net_sock_desc_work *work);
|
||||
int (*setsockopt)(
|
||||
struct avs_net_sock_desc_work *work,
|
||||
unsigned int option_name,
|
||||
const void *option_value,
|
||||
avs_net_size_t option_len);
|
||||
int (*getsockopt)(
|
||||
struct avs_net_sock_desc_work *work,
|
||||
unsigned int option_name,
|
||||
void *option_value,
|
||||
avs_net_size_t *option_len);
|
||||
int (*bind)(
|
||||
struct avs_net_sock_desc_work *work,
|
||||
uint32_t address,
|
||||
avs_net_port_t port);
|
||||
int (*connect)(
|
||||
struct avs_net_sock_desc_work *work,
|
||||
uint32_t address,
|
||||
avs_net_port_t port);
|
||||
int (*listen)(struct avs_net_sock_desc_work *work, int backlog);
|
||||
int (*accept)(
|
||||
struct avs_net_sock_desc_work *work,
|
||||
void *new_sock,
|
||||
uint32_t *address,
|
||||
avs_net_port_t *port);
|
||||
int (*close)(struct avs_net_sock_desc_work *work);
|
||||
int (*shutdown)(struct avs_net_sock_desc_work *work, int how);
|
||||
int (*sendtov)(
|
||||
struct avs_net_sock_desc_work *work,
|
||||
const struct avs_iovec *iovec,
|
||||
int iov_count,
|
||||
uint32_t address,
|
||||
avs_net_port_t port);
|
||||
int (*recvfromv)(
|
||||
struct avs_net_sock_desc_work *work,
|
||||
struct avs_iovec *iovec,
|
||||
int iov_count,
|
||||
uint32_t *address,
|
||||
avs_net_port_t *port);
|
||||
int (*pollfds_add)(
|
||||
struct avs_net_sock_desc_work *work,
|
||||
struct avs_net_poll_fd_opaque *fds,
|
||||
avs_net_pollfds_size_t fds_size,
|
||||
struct avs_net_poll_fd *events);
|
||||
int (*pollfds_get)(
|
||||
struct avs_net_sock_desc_work *work,
|
||||
struct avs_net_poll_fd *events,
|
||||
struct avs_net_poll_fd_opaque *fds);
|
||||
int (*sockpeer)(
|
||||
struct avs_net_sock_desc_work *work,
|
||||
bool peer_name,
|
||||
uint32_t *address,
|
||||
avs_net_port_t *port);
|
||||
};
|
||||
|
||||
struct avs_net_protocol {
|
||||
struct avs_net_protocol_ops *ops;
|
||||
uint32_t magic;
|
||||
uint32_t protocol_id;
|
||||
uint32_t proto_work_size;
|
||||
uint32_t sock_work_size;
|
||||
};
|
||||
|
||||
struct avs_net_protocol_legacy {
|
||||
struct avs_net_protocol_ops *ops;
|
||||
uint32_t protocol_id;
|
||||
uint32_t mystery;
|
||||
uint32_t sz_work;
|
||||
};
|
||||
|
||||
/*
|
||||
* error
|
||||
*/
|
||||
|
||||
typedef int32_t avs_error_t;
|
||||
|
||||
constexpr avs_error_t AVS_ERROR_MASK = 0x80000000;
|
||||
constexpr avs_error_t AVS_ERROR_FACILITY_MASK = 0x7fff;
|
||||
|
||||
enum avs_error_class {
|
||||
AVS_ERROR_CLASS_NET = 8,
|
||||
};
|
||||
|
||||
enum avs_error_subclass {
|
||||
AVS_ERROR_SUBCLASS_SC_INVAL = 0x00000016,
|
||||
AVS_ERROR_SUBCLASS_SC_BADMSG = 0x0000004a,
|
||||
AVS_ERROR_SUBCLASS_NET_TIMEOUT = 0x00001000,
|
||||
};
|
||||
|
||||
inline avs_error_t avs_error_make(avs_error_class error_class, avs_error_subclass error_subclass) {
|
||||
return static_cast<avs_error_t>(
|
||||
AVS_ERROR_MASK |
|
||||
((error_class & AVS_ERROR_FACILITY_MASK) << 16) |
|
||||
(error_subclass & AVS_ERROR_FACILITY_MASK));
|
||||
}
|
||||
|
||||
/*
|
||||
* misc
|
||||
*/
|
||||
|
||||
typedef int (*avs_reader_t)(uint32_t, void *, size_t);
|
||||
typedef uint32_t avs_file_t;
|
||||
|
||||
// import mapping
|
||||
struct avs_core_import {
|
||||
|
||||
// required functions
|
||||
const char *version;
|
||||
const char *property_search;
|
||||
const char *boot;
|
||||
const char *shutdown;
|
||||
const char *property_desc_to_buffer;
|
||||
const char *property_destroy;
|
||||
const char *property_read_query_memsize;
|
||||
const char *property_create;
|
||||
const char *property_insert_read;
|
||||
const char *property_node_create;
|
||||
const char *property_node_remove;
|
||||
const char *property_node_refer;
|
||||
const char *std_setenv;
|
||||
|
||||
// optional functions
|
||||
const char *avs_fs_open = "?";
|
||||
const char *avs_fs_copy = "?";
|
||||
const char *avs_fs_close = "?";
|
||||
const char *avs_fs_dump_mountpoint = "?";
|
||||
const char *avs_fs_mount = "?";
|
||||
const char *avs_fs_fstat = "?";
|
||||
const char *avs_fs_lstat = "?";
|
||||
const char *avs_fs_lseek = "?";
|
||||
const char *avs_fs_read = "?";
|
||||
const char *avs_fs_opendir = "?";
|
||||
const char *avs_fs_readdir = "?";
|
||||
const char *avs_fs_closedir = "?";
|
||||
const char *cstream_create = "?";
|
||||
const char *cstream_operate = "?";
|
||||
const char *cstream_finish = "?";
|
||||
const char *cstream_destroy = "?";
|
||||
const char *property_node_read = "?";
|
||||
const char *property_node_write = "?";
|
||||
const char *property_file_write = "?";
|
||||
const char *property_node_traversal = "?";
|
||||
const char *property_psmap_export = "?";
|
||||
const char *property_psmap_import = "?";
|
||||
const char *property_node_name = "?";
|
||||
const char *property_node_get_desc = "?";
|
||||
const char *property_get_error = "?";
|
||||
const char *property_node_clone = "?";
|
||||
const char *property_query_size = "?";
|
||||
const char *property_node_query_stat = "?";
|
||||
const char *property_node_datasize = "?";
|
||||
const char *property_mem_write = "?";
|
||||
const char *property_part_write = "?";
|
||||
const char *property_node_absolute_path = "?";
|
||||
const char *property_node_has = "?";
|
||||
const char *property_node_is_array = "?";
|
||||
const char *property_node_type = "?";
|
||||
const char *property_get_attribute_bool = "?";
|
||||
const char *property_node_get_attribute_bool = "?";
|
||||
const char *property_node_get_attribute_u32 = "?";
|
||||
const char *property_node_get_attribute_s32 = "?";
|
||||
const char *property_node_rename = "?";
|
||||
const char *property_query_freesize = "?";
|
||||
const char *property_clear_error = "?";
|
||||
const char *property_lookup_encode = "?";
|
||||
const char *property_unlock_flag = "?";
|
||||
const char *property_lock_flag = "?";
|
||||
const char *property_set_flag = "?";
|
||||
const char *property_part_write_meta = "?";
|
||||
const char *property_part_write_meta2 = "?";
|
||||
const char *property_read_data = "?";
|
||||
const char *property_read_meta = "?";
|
||||
const char *property_get_attribute_u32 = "?";
|
||||
const char *property_get_attribute_s32 = "?";
|
||||
const char *property_get_fingerprint = "?";
|
||||
const char *property_node_refdata = "?";
|
||||
const char *property_insert_read_with_filename = "?";
|
||||
const char *property_mem_read = "?";
|
||||
const char *property_read_query_memsize_long = "?";
|
||||
const char *property_clear = "?";
|
||||
const char *avs_net_add_protocol = "?";
|
||||
const char *avs_net_del_protocol = "?";
|
||||
const char *avs_net_addrinfobyaddr = "?";
|
||||
const char *avs_net_socket = "?";
|
||||
const char *avs_net_setsockopt = "?";
|
||||
const char *avs_net_getsockopt = "?";
|
||||
const char *avs_net_connect = "?";
|
||||
const char *avs_net_send = "?";
|
||||
const char *avs_net_recv = "?";
|
||||
const char *avs_net_poll = "?";
|
||||
const char *avs_net_pollfds_add = "?";
|
||||
const char *avs_net_pollfds_get = "?";
|
||||
const char *avs_net_bind = "?";
|
||||
const char *avs_net_close = "?";
|
||||
const char *avs_net_shutdown = "?";
|
||||
const char *avs_net_get_peername = "?";
|
||||
const char *avs_net_get_sockname = "?";
|
||||
};
|
||||
extern avs_core_import IMPORT_NAMES;
|
||||
|
||||
// settings
|
||||
enum Version {
|
||||
AVSLEGACY,
|
||||
AVS21360,
|
||||
AVS21430,
|
||||
AVS21580,
|
||||
AVS21610,
|
||||
AVS21630,
|
||||
AVS21651,
|
||||
AVS21671,
|
||||
AVS21681,
|
||||
AVS21700,
|
||||
AVS21730,
|
||||
AVS_VERSION_COUNT
|
||||
};
|
||||
extern Version VERSION;
|
||||
extern std::string VERSION_STR;
|
||||
extern size_t HEAP_SIZE;
|
||||
extern bool DEFAULT_HEAP_SIZE_SET;
|
||||
extern std::string LOG_PATH;
|
||||
extern std::string CFG_PATH;
|
||||
extern std::string LOG_LEVEL_CUSTOM;
|
||||
|
||||
// handle
|
||||
extern HINSTANCE DLL_INSTANCE;
|
||||
extern std::string DLL_NAME;
|
||||
|
||||
// helpers
|
||||
property_ptr config_read(const std::string &filename, size_t extra_space = 0, bool allow_fail = false);
|
||||
property_ptr config_read_string(const char* input);
|
||||
node_ptr property_search_safe(property_ptr prop, node_ptr node, const char *name);
|
||||
void property_search_remove_safe(property_ptr prop, node_ptr node, const char *name);
|
||||
bool file_exists(const char* filename);
|
||||
void config_destroy(property_ptr prop);
|
||||
std::string error_str(int32_t error);
|
||||
|
||||
// functions
|
||||
void set_default_heap_size(const std::string &dll_name);
|
||||
void create_log();
|
||||
bool load_dll();
|
||||
void boot();
|
||||
void copy_defaults();
|
||||
void shutdown();
|
||||
|
||||
/*
|
||||
* library functions
|
||||
*/
|
||||
|
||||
typedef int (*AVS215_BOOT_T)(void *, void *, size_t, void *, size_t, void *, HANDLE);
|
||||
typedef int (*AVS216_BOOT_T)(void *, void *, size_t, void *, void *, HANDLE);
|
||||
extern AVS215_BOOT_T avs215_boot;
|
||||
extern AVS216_BOOT_T avs216_boot;
|
||||
|
||||
typedef void (*AVS_SHUTDOWN_T)(void);
|
||||
extern AVS_SHUTDOWN_T avs_shutdown;
|
||||
|
||||
typedef void *(*PROPERTY_DESC_TO_BUFFER_T)(property_ptr prop);
|
||||
extern PROPERTY_DESC_TO_BUFFER_T property_desc_to_buffer;
|
||||
|
||||
typedef node_ptr (*PROPERTY_SEARCH_T)(property_ptr prop, node_ptr node, const char *path);
|
||||
extern PROPERTY_SEARCH_T property_search;
|
||||
|
||||
typedef avs_error_t (*PROPERTY_DESTROY_T)(property_ptr prop);
|
||||
extern PROPERTY_DESTROY_T property_destroy;
|
||||
|
||||
typedef int (*PROPERTY_READ_QUERY_MEMSIZE_T)(avs_reader_t reader, avs_file_t file, DWORD *, DWORD *);
|
||||
extern PROPERTY_READ_QUERY_MEMSIZE_T property_read_query_memsize;
|
||||
|
||||
typedef property_ptr (*PROPERTY_CREATE_T)(int flags, void *buffer, uint32_t buffer_size);
|
||||
extern PROPERTY_CREATE_T property_create;
|
||||
|
||||
typedef avs_error_t (*PROPERTY_INSERT_READ_T)(property_ptr prop, node_ptr node, avs_reader_t reader,
|
||||
avs_file_t file);
|
||||
extern PROPERTY_INSERT_READ_T property_insert_read;
|
||||
|
||||
typedef node_ptr (*PROPERTY_NODE_CREATE_T)(property_ptr prop, node_ptr node, node_type type, const char *path,
|
||||
...);
|
||||
extern PROPERTY_NODE_CREATE_T property_node_create;
|
||||
|
||||
typedef avs_error_t (*PROPERTY_NODE_REMOVE_T)(node_ptr node);
|
||||
extern PROPERTY_NODE_REMOVE_T property_node_remove;
|
||||
|
||||
typedef int (*PROPERTY_NODE_REFER_T)(property_ptr prop, node_ptr node, const char *path, node_type type,
|
||||
void *data, uint32_t data_size);
|
||||
extern PROPERTY_NODE_REFER_T property_node_refer;
|
||||
|
||||
typedef int (*STD_SETENV_T)(const char *key, const char *value);
|
||||
extern STD_SETENV_T avs_std_setenv;
|
||||
|
||||
/*
|
||||
* optional functions
|
||||
*/
|
||||
|
||||
typedef avs_file_t (*AVS_FS_OPEN_T)(const char *name, uint16_t mode, int flags);
|
||||
extern AVS_FS_OPEN_T avs_fs_open;
|
||||
|
||||
typedef void (*AVS_FS_CLOSE_T)(avs_file_t file);
|
||||
extern AVS_FS_CLOSE_T avs_fs_close;
|
||||
|
||||
typedef int (*AVS_FS_DUMP_MOUNTPOINT_T)(void);
|
||||
extern AVS_FS_DUMP_MOUNTPOINT_T avs_fs_dump_mountpoint;
|
||||
|
||||
typedef int (*AVS_FS_MOUNT_T)(const char *mountpoint, const char *fsroot, const char *fstype, void *data);
|
||||
extern AVS_FS_MOUNT_T avs_fs_mount;
|
||||
|
||||
typedef int (*AVS_FS_COPY_T)(const char *sname, const char *dname);
|
||||
extern AVS_FS_COPY_T avs_fs_copy;
|
||||
|
||||
typedef int (*AVS_FS_FSTAT_T)(avs_file_t file, struct avs_stat *stat);
|
||||
extern AVS_FS_FSTAT_T avs_fs_fstat;
|
||||
|
||||
typedef int (*AVS_FS_LSTAT_T)(const char *path, struct avs_stat *stat);
|
||||
extern AVS_FS_LSTAT_T avs_fs_lstat;
|
||||
|
||||
typedef int (*AVS_FS_LSEEK_T)(avs_file_t file, long offset, int origin);
|
||||
extern AVS_FS_LSEEK_T avs_fs_lseek;
|
||||
|
||||
typedef size_t (*AVS_FS_READ_T)(avs_file_t file, uint8_t *data, uint32_t data_size);
|
||||
extern AVS_FS_READ_T avs_fs_read;
|
||||
|
||||
typedef avs_file_t (*AVS_FS_OPENDIR_T)(const char *path);
|
||||
extern AVS_FS_OPENDIR_T avs_fs_opendir;
|
||||
|
||||
typedef const char* (*AVS_FS_READDIR_T)(avs_file_t dir);
|
||||
extern AVS_FS_READDIR_T avs_fs_readdir;
|
||||
|
||||
typedef void (*AVS_FS_CLOSEDIR_T)(avs_file_t dir);
|
||||
extern AVS_FS_CLOSEDIR_T avs_fs_closedir;
|
||||
|
||||
typedef struct cstream_data *(*CSTREAM_CREATE_T)(cstream_type type);
|
||||
extern CSTREAM_CREATE_T cstream_create;
|
||||
|
||||
typedef bool (*CSTREAM_OPERATE_T)(struct cstream_data *data);
|
||||
extern CSTREAM_OPERATE_T cstream_operate;
|
||||
|
||||
typedef bool (*CSTREAM_FINISH_T)(struct cstream_data *data);
|
||||
extern CSTREAM_FINISH_T cstream_finish;
|
||||
|
||||
typedef bool (*CSTREAM_DESTROY_T)(struct cstream_data *data);
|
||||
extern CSTREAM_DESTROY_T cstream_destroy;
|
||||
|
||||
typedef int (*PROPERTY_NODE_READ_T)(node_ptr node, node_type type, void *data, uint32_t data_size);
|
||||
extern PROPERTY_NODE_READ_T property_node_read;
|
||||
|
||||
typedef uint32_t (*PROPERTY_NODE_WRITE_T)(node_ptr node, node_type type, void *data);
|
||||
extern PROPERTY_NODE_WRITE_T property_node_write;
|
||||
|
||||
typedef int (*PROPERTY_FILE_WRITE_T)(property_ptr prop, const char *path);
|
||||
extern PROPERTY_FILE_WRITE_T property_file_write;
|
||||
|
||||
typedef node_ptr (*PROPERTY_NODE_TRAVERSAL_T)(node_ptr node, enum property_node_traversal_option direction);
|
||||
extern PROPERTY_NODE_TRAVERSAL_T property_node_traversal;
|
||||
|
||||
typedef bool (*PROPERTY_PSMAP_EXPORT_T)(property_ptr prop, node_ptr node, uint8_t *data, psmap_data_ptr psmap);
|
||||
extern PROPERTY_PSMAP_EXPORT_T property_psmap_export;
|
||||
|
||||
typedef bool (*PROPERTY_PSMAP_IMPORT_T)(property_ptr prop, node_ptr node, uint8_t *data, psmap_data_ptr psmap);
|
||||
extern PROPERTY_PSMAP_IMPORT_T property_psmap_import;
|
||||
|
||||
typedef avs_error_t (*PROPERTY_NODE_NAME_T)(node_ptr node, char *buffer, uint32_t buffer_size);
|
||||
extern PROPERTY_NODE_NAME_T property_node_name;
|
||||
|
||||
typedef void *(*PROPERTY_NODE_GET_DESC_T)(node_ptr node);
|
||||
extern PROPERTY_NODE_GET_DESC_T property_node_get_desc;
|
||||
|
||||
typedef uint32_t (*PROPERTY_GET_ERROR_T)(property_ptr prop);
|
||||
extern PROPERTY_GET_ERROR_T property_get_error;
|
||||
|
||||
typedef bool (*PROPERTY_NODE_CLONE_T)(property_ptr dst_prop, node_ptr dst_node, node_ptr src_node, bool deep);
|
||||
extern PROPERTY_NODE_CLONE_T property_node_clone;
|
||||
|
||||
typedef avs_error_t (*PROPERTY_QUERY_SIZE_T)(property_ptr prop);
|
||||
extern PROPERTY_QUERY_SIZE_T property_query_size;
|
||||
|
||||
typedef avs_error_t (*PROPERTY_NODE_QUERY_STAT_T)(property_ptr prop, node_ptr node, node_stat_ptr stat);
|
||||
extern PROPERTY_NODE_QUERY_STAT_T property_node_query_stat;
|
||||
|
||||
typedef int32_t (*PROPERTY_NODE_DATASIZE_T)(node_ptr node);
|
||||
extern PROPERTY_NODE_DATASIZE_T property_node_datasize;
|
||||
|
||||
typedef int32_t (*PROPERTY_MEM_WRITE_T)(property_ptr prop, uint8_t *data, uint32_t data_size);
|
||||
extern PROPERTY_MEM_WRITE_T property_mem_write;
|
||||
|
||||
typedef int32_t (*PROPERTY_PART_WRITE_T)(property_ptr prop, node_ptr node, uint8_t *data, uint32_t data_size);
|
||||
extern PROPERTY_PART_WRITE_T property_part_write;
|
||||
|
||||
typedef avs_error_t (*PROPERTY_NODE_ABSOLUTE_PATH_T)(node_ptr node, char *buffer, uint32_t buffer_size,
|
||||
bool attr);
|
||||
extern PROPERTY_NODE_ABSOLUTE_PATH_T property_node_absolute_path;
|
||||
|
||||
typedef int32_t (*PROPERTY_NODE_HAS_T)(property_ptr prop, node_ptr node, int ukn);
|
||||
extern PROPERTY_NODE_HAS_T property_node_has;
|
||||
|
||||
typedef bool (*PROPERTY_NODE_IS_ARRAY_T)(node_ptr node);
|
||||
extern PROPERTY_NODE_IS_ARRAY_T property_node_is_array;
|
||||
|
||||
typedef node_type (*PROPERTY_NODE_TYPE_T)(node_ptr node);
|
||||
extern PROPERTY_NODE_TYPE_T property_node_type;
|
||||
|
||||
typedef avs_error_t (*PROPERTY_GET_ATTRIBUTE_BOOL_T)(property_ptr prop, node_ptr node,
|
||||
const char *path, bool *value);
|
||||
extern PROPERTY_GET_ATTRIBUTE_BOOL_T property_get_attribute_bool;
|
||||
|
||||
typedef avs_error_t (*PROPERTY_NODE_GET_ATTRIBUTE_BOOL_T)(node_ptr node, bool *value);
|
||||
extern PROPERTY_NODE_GET_ATTRIBUTE_BOOL_T property_node_get_attribute_bool;
|
||||
|
||||
typedef avs_error_t (*PROPERTY_NODE_GET_ATTRIBUTE_U32_T)(node_ptr node, uint32_t *value);
|
||||
extern PROPERTY_NODE_GET_ATTRIBUTE_U32_T property_node_get_attribute_u32;
|
||||
|
||||
typedef avs_error_t (*PROPERTY_NODE_GET_ATTRIBUTE_S32_T)(node_ptr node, int32_t *value);
|
||||
extern PROPERTY_NODE_GET_ATTRIBUTE_S32_T property_node_get_attribute_s32;
|
||||
|
||||
typedef avs_error_t (*PROPERTY_NODE_RENAME_T)(node_ptr node, const char *name);
|
||||
extern PROPERTY_NODE_RENAME_T property_node_rename;
|
||||
|
||||
typedef avs_error_t (*PROPERTY_QUERY_FREESIZE_T)(property_ptr prop, uint32_t freesize);
|
||||
extern PROPERTY_QUERY_FREESIZE_T property_query_freesize;
|
||||
|
||||
typedef property_ptr (*PROPERTY_CLEAR_ERROR_T)(property_ptr prop);
|
||||
extern PROPERTY_CLEAR_ERROR_T property_clear_error;
|
||||
|
||||
typedef uint32_t (*PROPERTY_LOOKUP_ENCODE_T)(property_ptr prop);
|
||||
extern PROPERTY_LOOKUP_ENCODE_T property_lookup_encode;
|
||||
|
||||
typedef avs_error_t (*PROPERTY_UNLOCK_FLAG_T)(property_ptr prop, uint32_t flags);
|
||||
extern PROPERTY_UNLOCK_FLAG_T property_unlock_flag;
|
||||
|
||||
typedef avs_error_t (*PROPERTY_LOCK_FLAG_T)(property_ptr prop, uint32_t flags);
|
||||
extern PROPERTY_LOCK_FLAG_T property_lock_flag;
|
||||
|
||||
typedef uint32_t (*PROPERTY_SET_FLAG_T)(property_ptr prop, uint32_t set_flags, uint32_t clear_flags);
|
||||
extern PROPERTY_SET_FLAG_T property_set_flag;
|
||||
|
||||
typedef int32_t (*PROPERTY_PART_WRITE_META_T)(property_ptr prop, node_ptr node, uint8_t buffer,
|
||||
uint32_t buffer_size, int ukn1, int ukn2);
|
||||
extern PROPERTY_PART_WRITE_META_T property_part_write_meta;
|
||||
|
||||
typedef int32_t (*PROPERTY_PART_WRITE_META2_T)(property_ptr prop, node_ptr node, uint8_t buffer,
|
||||
uint32_t buffer_size);
|
||||
extern PROPERTY_PART_WRITE_META2_T property_part_write_meta2;
|
||||
|
||||
typedef int32_t (*PROPERTY_READ_DATA_T)(property_ptr prop, node_ptr node, avs_reader_t read_func,
|
||||
uint32_t context);
|
||||
extern PROPERTY_READ_DATA_T property_read_data;
|
||||
|
||||
typedef int32_t (*PROPERTY_READ_META_T)(property_ptr prop, node_ptr node, avs_reader_t read_func,
|
||||
uint32_t context);
|
||||
extern PROPERTY_READ_META_T property_read_meta;
|
||||
|
||||
typedef avs_error_t (*PROPERTY_GET_ATTRIBUTE_U32_T)(property_ptr prop, node_ptr node, const char *path,
|
||||
uint32_t *value);
|
||||
extern PROPERTY_GET_ATTRIBUTE_U32_T property_get_attribute_u32;
|
||||
|
||||
typedef avs_error_t (*PROPERTY_GET_ATTRIBUTE_S32_T)(property_ptr prop, node_ptr node, const char *path,
|
||||
int32_t *value);
|
||||
extern PROPERTY_GET_ATTRIBUTE_S32_T property_get_attribute_s32;
|
||||
|
||||
typedef avs_error_t (*PROPERTY_GET_FINGERPRINT_T)(property_ptr prop, node_ptr node,
|
||||
uint8_t *data, uint32_t data_size);
|
||||
extern PROPERTY_GET_FINGERPRINT_T property_get_fingerprint;
|
||||
|
||||
typedef uint8_t *(*PROPERTY_NODE_REFDATA_T)(node_ptr node);
|
||||
extern PROPERTY_NODE_REFDATA_T property_node_refdata;
|
||||
|
||||
// TODO probably invalid signature
|
||||
typedef int32_t *(*PROPERTY_INSERT_READ_WITH_FILENAME_T)(property_ptr prop, node_ptr node, uint8_t *buffer,
|
||||
uint32_t buffer_size);
|
||||
extern PROPERTY_INSERT_READ_WITH_FILENAME_T property_insert_read_with_filename;
|
||||
|
||||
// TODO probably invalid signature
|
||||
typedef int32_t *(*PROPERTY_MEM_READ_T)(property_ptr prop, node_ptr node, int flags, uint8_t *buffer,
|
||||
uint32_t buffer_size);
|
||||
extern PROPERTY_MEM_READ_T property_mem_read;
|
||||
|
||||
typedef int (*PROPERTY_READ_QUERY_MEMSIZE_LONG_T)(avs_reader_t reader, avs_file_t file,
|
||||
DWORD *, DWORD *, DWORD *);
|
||||
extern PROPERTY_READ_QUERY_MEMSIZE_LONG_T property_read_query_memsize_long;
|
||||
|
||||
typedef property_ptr (*PROPERTY_CLEAR_T)(property_ptr prop);
|
||||
extern PROPERTY_CLEAR_T property_clear;
|
||||
|
||||
typedef avs_error_t (*AVS_NET_ADDRINFOBYADDR_T)(uint32_t addr, char* hostname, int hostname_size, int);
|
||||
extern AVS_NET_ADDRINFOBYADDR_T avs_net_addrinfobyaddr;
|
||||
|
||||
typedef avs_error_t (*AVS_NET_ADD_PROTOCOL_T)(struct avs_net_protocol *protocol);
|
||||
extern AVS_NET_ADD_PROTOCOL_T avs_net_add_protocol;
|
||||
|
||||
typedef avs_error_t (*AVS_NET_ADD_PROTOCOL_LEGACY_T)(struct avs_net_protocol_legacy *protocol);
|
||||
extern AVS_NET_ADD_PROTOCOL_LEGACY_T avs_net_add_protocol_legacy;
|
||||
|
||||
typedef avs_error_t (*AVS_NET_DEL_PROTOCOL_T)(int protocol_id);
|
||||
extern AVS_NET_DEL_PROTOCOL_T avs_net_del_protocol;
|
||||
|
||||
typedef int64_t (*AVS_NET_SOCKET_T)(int protocol_id);
|
||||
extern AVS_NET_SOCKET_T avs_net_socket;
|
||||
|
||||
typedef avs_error_t (*AVS_NET_SETSOCKOPT_T)(
|
||||
int socket,
|
||||
int option_name,
|
||||
const void *option_value,
|
||||
avs_net_size_t option_len);
|
||||
extern AVS_NET_SETSOCKOPT_T avs_net_setsockopt;
|
||||
|
||||
typedef avs_error_t (*AVS_NET_GETSOCKOPT_T)(
|
||||
int socket,
|
||||
unsigned int option_name,
|
||||
void *option_value,
|
||||
avs_net_size_t *option_len);
|
||||
extern AVS_NET_GETSOCKOPT_T avs_net_getsockopt;
|
||||
|
||||
typedef avs_error_t (*AVS_NET_CONNECT_T)(int socket, uint32_t address, avs_net_port_t port);
|
||||
extern AVS_NET_CONNECT_T avs_net_connect;
|
||||
|
||||
typedef avs_error_t (*AVS_NET_SEND_T)(int socket, uint8_t *buf, uint32_t buf_size);
|
||||
extern AVS_NET_SEND_T avs_net_send;
|
||||
|
||||
typedef avs_error_t (*AVS_NET_RECV_T)(int socket, uint8_t *buf, uint32_t buf_size);
|
||||
extern AVS_NET_RECV_T avs_net_recv;
|
||||
|
||||
typedef avs_error_t (*AVS_NET_POLL_T)(
|
||||
struct avs_net_poll_fd *fds,
|
||||
uint32_t num_fds,
|
||||
int timeout);
|
||||
extern AVS_NET_POLL_T avs_net_poll;
|
||||
|
||||
typedef avs_error_t (*AVS_NET_POLLFDS_ADD_T)(
|
||||
int socket,
|
||||
struct avs_net_poll_fd_opaque *fds,
|
||||
avs_net_pollfds_size_t fds_size,
|
||||
struct avs_net_poll_fd *events);
|
||||
extern AVS_NET_POLLFDS_ADD_T avs_net_pollfds_add;
|
||||
|
||||
typedef avs_error_t (*AVS_NET_POLLFDS_GET_T)(
|
||||
int socket,
|
||||
struct avs_net_poll_fd *events,
|
||||
struct avs_net_poll_fd_opaque *fds);
|
||||
extern AVS_NET_POLLFDS_GET_T avs_net_pollfds_get;
|
||||
|
||||
typedef avs_error_t (*AVS_NET_BIND_T)(int socket, uint32_t address, avs_net_port_t port);
|
||||
extern AVS_NET_BIND_T avs_net_bind;
|
||||
|
||||
typedef avs_error_t (*AVS_NET_CLOSE_T)(int socket);
|
||||
extern AVS_NET_CLOSE_T avs_net_close;
|
||||
|
||||
typedef avs_error_t (*AVS_NET_SHUTDOWN_T)(int fd, int how);
|
||||
extern AVS_NET_SHUTDOWN_T avs_net_shutdown;
|
||||
|
||||
typedef avs_error_t (*AVS_NET_GET_PEERNAME_T)(int fd, uint32_t *address, avs_net_port_t *port);
|
||||
extern AVS_NET_GET_PEERNAME_T avs_net_get_peername;
|
||||
|
||||
typedef avs_error_t (*AVS_NET_GET_SOCKNAME_T)(int fd, uint32_t *address, avs_net_port_t *port);
|
||||
extern AVS_NET_GET_SOCKNAME_T avs_net_get_sockname;
|
||||
}
|
||||
}
|
||||
650
avs/ea3.cpp
Normal file
650
avs/ea3.cpp
Normal file
@@ -0,0 +1,650 @@
|
||||
#include "ea3.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "build/defs.h"
|
||||
#include "easrv/easrv.h"
|
||||
#include "easrv/smartea.h"
|
||||
#include "games/mfc/mfc.h"
|
||||
#include "hooks/avshook.h"
|
||||
#include "util/detour.h"
|
||||
#include "util/fileutils.h"
|
||||
#include "util/libutils.h"
|
||||
#include "util/logging.h"
|
||||
#include "util/utils.h"
|
||||
#include "launcher/logger.h"
|
||||
|
||||
#include "core.h"
|
||||
#include "game.h"
|
||||
|
||||
namespace avs {
|
||||
|
||||
typedef void (*ssl_protocol_init_t)();
|
||||
typedef void (*ssl_protocol_fini_t)();
|
||||
static ssl_protocol_init_t ssl_protocol_init = nullptr;
|
||||
static ssl_protocol_fini_t ssl_protocol_fini = nullptr;
|
||||
|
||||
// functions
|
||||
AVS_EA3_BOOT_STARTUP_T avs_ea3_boot_startup;
|
||||
AVS_EA3_SHUTDOWN_T avs_ea3_shutdown;
|
||||
|
||||
namespace ea3 {
|
||||
|
||||
// settings
|
||||
std::string CFG_PATH;
|
||||
std::string APP_PATH;
|
||||
std::string BOOTSTRAP_PATH;
|
||||
std::string PCBID_CUSTOM = "";
|
||||
std::string SOFTID_CUSTOM = "";
|
||||
std::string ACCOUNTID_CUSTOM = "";
|
||||
std::string URL_CUSTOM = "";
|
||||
int HTTP11 = -1;
|
||||
int URL_SLASH = -1;
|
||||
int PCB_TYPE = -1;
|
||||
|
||||
// handle
|
||||
std::string VERSION_STR = "unknown";
|
||||
HINSTANCE DLL_INSTANCE = nullptr;
|
||||
std::string DLL_NAME = "";
|
||||
std::string EA3_BOOT_URL = "";
|
||||
std::string EA3_BOOT_PCBID = "";
|
||||
std::string EA3_BOOT_ACCOUNTID = "";
|
||||
|
||||
// static fields
|
||||
static constexpr struct avs_ea3_import IMPORT_LEGACY {
|
||||
.version = "legacy",
|
||||
.boot = "ea3_boot",
|
||||
.shutdown = "ea3_shutdown",
|
||||
};
|
||||
static constexpr struct avs_ea3_import IMPORT_AVS21360 {
|
||||
.version = "2.13.6.0",
|
||||
.boot = "XEb552d500005d",
|
||||
.shutdown = "XEb552d5000060",
|
||||
};
|
||||
static constexpr struct avs_ea3_import IMPORT_AVS21430 {
|
||||
.version = "2.14.3.0",
|
||||
.boot = "XE7aee11000070",
|
||||
.shutdown = "XE7aee11000074",
|
||||
};
|
||||
static constexpr struct avs_ea3_import IMPORT_AVS21580 {
|
||||
.version = "2.15.8.0",
|
||||
.boot = "XE592acd00008c",
|
||||
.shutdown = "XE592acd00005a",
|
||||
};
|
||||
static constexpr struct avs_ea3_import IMPORT_AVS21610 {
|
||||
.version = "2.16.1.0",
|
||||
.boot = "XEyy2igh000006",
|
||||
.shutdown = "XEyy2igh000007",
|
||||
};
|
||||
static constexpr struct avs_ea3_import IMPORT_AVS21630 {
|
||||
.version = "2.16.3.0",
|
||||
.boot = "XEyy2igh000007",
|
||||
.shutdown = "XEyy2igh000008",
|
||||
};
|
||||
static constexpr struct avs_ea3_import IMPORT_AVS21651 {
|
||||
.version = "2.16.5.1",
|
||||
.boot = "XEyy2igh000007",
|
||||
.shutdown = "XEyy2igh000008",
|
||||
};
|
||||
static constexpr struct avs_ea3_import IMPORT_AVS21671 {
|
||||
.version = "2.16.7.1",
|
||||
.boot = "XEyy2igh000007",
|
||||
.shutdown = "XEyy2igh000008",
|
||||
};
|
||||
static constexpr struct avs_ea3_import IMPORT_AVS21681 {
|
||||
.version = "2.16.8.1",
|
||||
.boot = "XEyy2igh000007",
|
||||
.shutdown = "XEyy2igh000008",
|
||||
};
|
||||
static constexpr struct avs_ea3_import IMPORT_AVS21700 {
|
||||
.version = "2.17.0.0",
|
||||
.boot = "XEmdwapa000024",
|
||||
.shutdown = "XEmdwapa000025",
|
||||
};
|
||||
static constexpr struct avs_ea3_import IMPORT_AVS21730 {
|
||||
.version = "2.17.3.0",
|
||||
.boot = "XEmdwapa000024",
|
||||
.shutdown = "XEmdwapa000025",
|
||||
};
|
||||
static const struct avs_ea3_import IMPORTS[core::AVS_VERSION_COUNT] = {
|
||||
IMPORT_LEGACY,
|
||||
IMPORT_AVS21360,
|
||||
IMPORT_AVS21430,
|
||||
IMPORT_AVS21580,
|
||||
IMPORT_AVS21610,
|
||||
IMPORT_AVS21630,
|
||||
IMPORT_AVS21651,
|
||||
IMPORT_AVS21671,
|
||||
IMPORT_AVS21681,
|
||||
IMPORT_AVS21700,
|
||||
IMPORT_AVS21730,
|
||||
};
|
||||
|
||||
|
||||
void load_dll() {
|
||||
log_info("avs-ea3", "loading DLL");
|
||||
|
||||
// detect DLL name
|
||||
if (fileutils::file_exists(MODULE_PATH / "avs2-ea3.dll")) {
|
||||
DLL_NAME = "avs2-ea3.dll";
|
||||
} else {
|
||||
#ifdef SPICE64
|
||||
DLL_NAME = "libavs-win64-ea3.dll";
|
||||
#else
|
||||
DLL_NAME = "libavs-win32-ea3.dll";
|
||||
#endif
|
||||
}
|
||||
|
||||
// load library
|
||||
DLL_INSTANCE = libutils::load_library(MODULE_PATH / DLL_NAME);
|
||||
|
||||
// check by version string
|
||||
std::optional<size_t> ver;
|
||||
char version[32] {};
|
||||
if (fileutils::version_pe(MODULE_PATH / DLL_NAME, version)) {
|
||||
for (size_t i = 0; i < core::AVS_VERSION_COUNT; i++) {
|
||||
if (strcmp(IMPORTS[i].version, version) == 0) {
|
||||
ver = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check version by brute force
|
||||
if (!ver.has_value()) {
|
||||
for (size_t i = 0; i < core::AVS_VERSION_COUNT; i++) {
|
||||
if (GetProcAddress(DLL_INSTANCE, IMPORTS[i].boot) != nullptr) {
|
||||
ver = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if version was found
|
||||
if (!ver.has_value()) {
|
||||
log_fatal("avs-ea3", "Unknown {}", DLL_NAME);
|
||||
}
|
||||
size_t i = ver.value();
|
||||
|
||||
// print version
|
||||
VERSION_STR = IMPORTS[i].version;
|
||||
log_info("avs-ea3", "Found AVS2 EA3 {}", IMPORTS[i].version);
|
||||
|
||||
// load functions
|
||||
avs_ea3_boot_startup = libutils::get_proc<AVS_EA3_BOOT_STARTUP_T>(
|
||||
DLL_INSTANCE, IMPORTS[i].boot);
|
||||
avs_ea3_shutdown = libutils::get_proc<AVS_EA3_SHUTDOWN_T>(
|
||||
DLL_INSTANCE, IMPORTS[i].shutdown);
|
||||
}
|
||||
|
||||
void boot(unsigned short easrv_port, bool easrv_maint, bool easrv_smart) {
|
||||
// detect ea3-config file name
|
||||
const char *ea3_config_name;
|
||||
if (CFG_PATH.size()) {
|
||||
ea3_config_name = CFG_PATH.c_str();
|
||||
} else if (fileutils::file_exists("prop/ea3-config.xml")) {
|
||||
ea3_config_name = "prop/ea3-config.xml";
|
||||
} else if (fileutils::file_exists("prop/ea3-cfg.xml")) {
|
||||
ea3_config_name = "prop/ea3-cfg.xml";
|
||||
} else if (avs::game::DLL_NAME == "beatstream1.dll" && fileutils::file_exists("prop/ea3-config-1.xml")) {
|
||||
ea3_config_name = "prop/ea3-config-1.xml";
|
||||
} else if (avs::game::DLL_NAME == "beatstream2.dll" && fileutils::file_exists("prop/ea3-config-2.xml")) {
|
||||
ea3_config_name = "prop/ea3-config-2.xml";
|
||||
} else {
|
||||
ea3_config_name = "prop/eamuse-config.xml";
|
||||
}
|
||||
|
||||
log_info("avs-ea3", "booting (using {})", ea3_config_name);
|
||||
|
||||
// remember new config path
|
||||
CFG_PATH = ea3_config_name;
|
||||
|
||||
// detect app-config file name
|
||||
APP_PATH = APP_PATH.size() ? APP_PATH : "prop/app-config.xml";
|
||||
|
||||
// detect bootstrap file name
|
||||
BOOTSTRAP_PATH = BOOTSTRAP_PATH.size() ? BOOTSTRAP_PATH : "prop/bootstrap.xml";
|
||||
|
||||
// read configuration
|
||||
auto ea3_config = avs::core::config_read(ea3_config_name, 0x40000);
|
||||
auto app_config = fileutils::file_exists(APP_PATH.c_str())
|
||||
? avs::core::config_read(APP_PATH.c_str())
|
||||
: avs::core::config_read_string("<param/>");
|
||||
|
||||
// get nodes
|
||||
auto ea3 = avs::core::property_search_safe(ea3_config, nullptr, "/ea3");
|
||||
auto ea3_id = avs::core::property_search(ea3_config, nullptr, "/ea3/id");
|
||||
auto ea3_id_hard = avs::core::property_search(ea3_config, nullptr, "/ea3/id/hardid");
|
||||
auto ea3_id_soft = avs::core::property_search(ea3_config, nullptr, "/ea3/id/softid");
|
||||
auto ea3_id_account = avs::core::property_search(ea3_config, nullptr, "/ea3/id/accountid");
|
||||
auto ea3_soft = avs::core::property_search(ea3_config, nullptr, "/ea3/soft");
|
||||
auto ea3_network = avs::core::property_search_safe(ea3_config, nullptr, "/ea3/network");
|
||||
|
||||
// node values
|
||||
char EA3_PCBID[21] { 0 };
|
||||
char EA3_HARDID[21] { 0 };
|
||||
char EA3_SOFTID[21] { 0 };
|
||||
char EA3_ACCOUNTID[21] { 0 };
|
||||
char EA3_MODEL[4] { 0 };
|
||||
char EA3_DEST[2] { 0 };
|
||||
char EA3_SPEC[2] { 0 };
|
||||
char EA3_REV[2] { 0 };
|
||||
char EA3_EXT[11] { 0 };
|
||||
|
||||
// read id nodes
|
||||
if (ea3_id != nullptr) {
|
||||
avs::core::property_node_refer(ea3_config, ea3_id, "pcbid",
|
||||
avs::core::NODE_TYPE_str, EA3_PCBID, 21);
|
||||
avs::core::property_node_refer(ea3_config, ea3_id, "hardid",
|
||||
avs::core::NODE_TYPE_str, EA3_HARDID, 21);
|
||||
avs::core::property_node_refer(ea3_config, ea3_id, "softid",
|
||||
avs::core::NODE_TYPE_str, EA3_SOFTID, 21);
|
||||
avs::core::property_node_refer(ea3_config, ea3_id, "accountid",
|
||||
avs::core::NODE_TYPE_str, EA3_ACCOUNTID, 21);
|
||||
}
|
||||
|
||||
// set hard ID
|
||||
if (ea3_id_hard == nullptr) {
|
||||
strncpy(EA3_HARDID, "0100DEADBEEF", sizeof(EA3_HARDID));
|
||||
EA3_HARDID[20] = '\0';
|
||||
avs::core::property_node_create(ea3_config, nullptr,
|
||||
avs::core::NODE_TYPE_str, "/ea3/id/hardid", EA3_HARDID);
|
||||
}
|
||||
|
||||
// set soft ID
|
||||
if (ea3_id_soft == nullptr) {
|
||||
strncpy(EA3_SOFTID, "012199999999", sizeof(EA3_SOFTID));
|
||||
EA3_SOFTID[20] = '\0';
|
||||
avs::core::property_node_create(ea3_config, nullptr,
|
||||
avs::core::NODE_TYPE_str, "/ea3/id/softid", EA3_SOFTID);
|
||||
}
|
||||
|
||||
// read software nodes
|
||||
if (ea3_soft != nullptr) {
|
||||
avs::core::property_node_refer(ea3_config, ea3_soft, "model",
|
||||
avs::core::NODE_TYPE_str, EA3_MODEL, 4);
|
||||
avs::core::property_node_refer(ea3_config, ea3_soft, "dest",
|
||||
avs::core::NODE_TYPE_str, EA3_DEST, 2);
|
||||
avs::core::property_node_refer(ea3_config, ea3_soft, "spec",
|
||||
avs::core::NODE_TYPE_str, EA3_SPEC, 2);
|
||||
avs::core::property_node_refer(ea3_config, ea3_soft, "rev",
|
||||
avs::core::NODE_TYPE_str, EA3_REV, 2);
|
||||
avs::core::property_node_refer(ea3_config, ea3_soft, "ext",
|
||||
avs::core::NODE_TYPE_str, EA3_EXT, 11);
|
||||
} else if (fileutils::file_exists("prop/ea3-ident.xml")) {
|
||||
|
||||
// read ident config
|
||||
auto ea3_ident = avs::core::config_read("prop/ea3-ident.xml");
|
||||
if (ea3_ident == nullptr) {
|
||||
log_fatal("avs-ea3", "'prop/ea3-ident.xml' could not be read as property list");
|
||||
}
|
||||
|
||||
ea3_soft = avs::core::property_search_safe(ea3_ident, nullptr, "/ea3_conf/soft");
|
||||
|
||||
avs::core::property_node_refer(ea3_ident, ea3_soft, "model",
|
||||
avs::core::NODE_TYPE_str, EA3_MODEL, 4);
|
||||
avs::core::property_node_refer(ea3_ident, ea3_soft, "dest",
|
||||
avs::core::NODE_TYPE_str, EA3_DEST, 2);
|
||||
avs::core::property_node_refer(ea3_ident, ea3_soft, "spec",
|
||||
avs::core::NODE_TYPE_str, EA3_SPEC, 2);
|
||||
avs::core::property_node_refer(ea3_ident, ea3_soft, "rev",
|
||||
avs::core::NODE_TYPE_str, EA3_REV, 2);
|
||||
avs::core::property_node_refer(ea3_ident, ea3_soft, "ext",
|
||||
avs::core::NODE_TYPE_str, EA3_EXT, 11);
|
||||
|
||||
// clean up
|
||||
avs::core::config_destroy(ea3_ident);
|
||||
} else {
|
||||
log_fatal("avs-ea3", "node not found in '{}': /ea3/soft", ea3_config_name);
|
||||
}
|
||||
|
||||
// set account id (`EA3_PCBID` is valid if and only if `/ea3/id` is present)
|
||||
if (ea3_id != nullptr && ea3_id_account == nullptr) {
|
||||
const char *id = strcmp(EA3_MODEL, "M32") == 0 ? EA3_PCBID : "012018008135";
|
||||
|
||||
strncpy(EA3_ACCOUNTID, id, sizeof(EA3_ACCOUNTID));
|
||||
EA3_ACCOUNTID[20] = '\0';
|
||||
|
||||
avs::core::property_node_create(ea3_config, nullptr,
|
||||
avs::core::NODE_TYPE_str, "/ea3/id/accountid", EA3_ACCOUNTID);
|
||||
}
|
||||
|
||||
// replace ext code with release_code from bootstrap.xml if it is a newer date
|
||||
if (fileutils::file_exists(BOOTSTRAP_PATH.c_str())) {
|
||||
|
||||
// read config
|
||||
auto bootstrap = avs::core::config_read(BOOTSTRAP_PATH.c_str(), 0, true);
|
||||
if (bootstrap == nullptr) {
|
||||
|
||||
// bootstrap.xml may be encrypted
|
||||
log_warning("avs-ea3", "'{}' could not be read as property list", BOOTSTRAP_PATH);
|
||||
|
||||
} else {
|
||||
|
||||
// get release code
|
||||
char release_code[11] { 0 };
|
||||
avs::core::property_node_refer(bootstrap, nullptr, "/config/release_code",
|
||||
avs::core::NODE_TYPE_str, release_code, 11);
|
||||
|
||||
// compare dates
|
||||
if (atoi(release_code) > atoi(EA3_EXT)) {
|
||||
log_info("avs-ea3", "overwriting ext {} with {} from {}", EA3_EXT,
|
||||
release_code, BOOTSTRAP_PATH);
|
||||
strncpy(EA3_EXT, release_code, 11);
|
||||
}
|
||||
|
||||
// clean up
|
||||
avs::core::config_destroy(bootstrap);
|
||||
}
|
||||
}
|
||||
|
||||
// custom PCBID
|
||||
if (!PCBID_CUSTOM.empty()) {
|
||||
|
||||
// copy ID
|
||||
strncpy(EA3_PCBID, PCBID_CUSTOM.c_str(), sizeof(EA3_PCBID));
|
||||
EA3_PCBID[20] = '\0';
|
||||
|
||||
// set nodes
|
||||
avs::core::property_search_remove_safe(ea3_config, nullptr, "/ea3/id/pcbid");
|
||||
avs::core::property_node_create(ea3_config, nullptr,
|
||||
avs::core::NODE_TYPE_str, "/ea3/id/pcbid", &EA3_PCBID);
|
||||
|
||||
if (ACCOUNTID_CUSTOM.empty() && strcmp(EA3_MODEL, "M32") == 0) {
|
||||
ACCOUNTID_CUSTOM = PCBID_CUSTOM;
|
||||
}
|
||||
}
|
||||
|
||||
// custom SOFTID
|
||||
if (!SOFTID_CUSTOM.empty()) {
|
||||
|
||||
// copy ID
|
||||
strncpy(EA3_SOFTID, SOFTID_CUSTOM.c_str(), sizeof(EA3_SOFTID));
|
||||
EA3_SOFTID[20] = '\0';
|
||||
|
||||
// set nodes
|
||||
avs::core::property_search_remove_safe(ea3_config, nullptr, "/ea3/id/softid");
|
||||
avs::core::property_node_create(ea3_config, nullptr,
|
||||
avs::core::NODE_TYPE_str, "/ea3/id/softid", &EA3_SOFTID);
|
||||
}
|
||||
|
||||
// custom ACCOUNTID
|
||||
if (!ACCOUNTID_CUSTOM.empty()) {
|
||||
|
||||
// copy ID
|
||||
strncpy(EA3_ACCOUNTID, ACCOUNTID_CUSTOM.c_str(), sizeof(EA3_ACCOUNTID));
|
||||
EA3_ACCOUNTID[20] = '\0';
|
||||
|
||||
// set nodes
|
||||
avs::core::property_search_remove_safe(ea3_config, nullptr, "/ea3/id/accountid");
|
||||
avs::core::property_node_create(ea3_config, nullptr,
|
||||
avs::core::NODE_TYPE_str, "/ea3/id/accountid", &EA3_ACCOUNTID);
|
||||
}
|
||||
|
||||
// check if PCBID is defined
|
||||
if (avs::core::property_search(ea3_config, nullptr, "/ea3/id/pcbid") == nullptr) {
|
||||
log_fatal("avs-ea3", "node not found: /ea3/id/pcbid (try using -p to specify PCBID)");
|
||||
} else if (strlen(EA3_PCBID) == 0) {
|
||||
log_fatal("avs-ea3", "no PCBID set (try using -p to specify PCBID)");
|
||||
}
|
||||
|
||||
// remember IDs
|
||||
char pcbid_buffer[256] { 0 };
|
||||
char accountid_buffer[256] { 0 };
|
||||
avs::core::property_node_refer(ea3_config, nullptr, "/ea3/id/pcbid",
|
||||
avs::core::NODE_TYPE_str, pcbid_buffer, sizeof(pcbid_buffer));
|
||||
avs::core::property_node_refer(ea3_config, nullptr, "/ea3/id/accountid",
|
||||
avs::core::NODE_TYPE_str, accountid_buffer, sizeof(accountid_buffer));
|
||||
EA3_BOOT_PCBID = std::string(pcbid_buffer);
|
||||
EA3_BOOT_ACCOUNTID = std::string(accountid_buffer);
|
||||
|
||||
// build security code
|
||||
std::ostringstream security_code;
|
||||
security_code << "G";
|
||||
if (strcmp(EA3_MODEL, "KK9") == 0) {
|
||||
// Q (Spec F) is FullHD cabinet, E is OLD cabinet.
|
||||
security_code << (strcmp(EA3_SPEC, "F") == 0 ? "Q" : "E");
|
||||
} else if (strcmp(EA3_MODEL, "NCG") == 0) {
|
||||
// we have Q or E as choice again, see prop/code-config.xml
|
||||
security_code << "Q";
|
||||
} else if (strcmp(EA3_MODEL, "KBI") == 0) {
|
||||
// seems to be required to be set to E
|
||||
security_code << "E";
|
||||
} else if (strcmp(EA3_MODEL, "KCK") == 0 || strcmp(EA3_MODEL, "NCK") == 0) {
|
||||
// unsure if it really makes a difference
|
||||
security_code << "E";
|
||||
} else if (strcmp(EA3_MODEL, "LA9") == 0) {
|
||||
// GQ---J(spec)- in bootstrap.xml
|
||||
security_code << "Q";
|
||||
} else {
|
||||
security_code << "*";
|
||||
}
|
||||
security_code << EA3_MODEL;
|
||||
security_code << EA3_DEST;
|
||||
security_code << EA3_SPEC;
|
||||
security_code << EA3_REV;
|
||||
std::string security_code_str = security_code.str();
|
||||
log_info("avs-ea3", "security code: {}", security_code_str);
|
||||
|
||||
// pre game init soft ID code
|
||||
std::ostringstream soft_id_code_pre_init;
|
||||
soft_id_code_pre_init << EA3_MODEL << ":";
|
||||
soft_id_code_pre_init << EA3_DEST << ":";
|
||||
soft_id_code_pre_init << EA3_SPEC << ":";
|
||||
soft_id_code_pre_init << EA3_REV << ":";
|
||||
soft_id_code_pre_init << EA3_EXT;
|
||||
std::string soft_id_code_pre_init_str = soft_id_code_pre_init.str();
|
||||
|
||||
// set env variables
|
||||
avs::core::avs_std_setenv("/env/boot/build", VERSION_STRING);
|
||||
avs::core::avs_std_setenv("/env/boot/version", "SPICETOOLS");
|
||||
avs::core::avs_std_setenv("/env/boot/tag", "SPICETOOLS");
|
||||
avs::core::avs_std_setenv("/env/profile/security_code", security_code_str.c_str());
|
||||
avs::core::avs_std_setenv("/env/profile/secplug_b_security_code", security_code_str.c_str());
|
||||
avs::core::avs_std_setenv("/env/profile/system_id", EA3_PCBID);
|
||||
avs::core::avs_std_setenv("/env/profile/hardware_id", EA3_HARDID);
|
||||
avs::core::avs_std_setenv("/env/profile/license_id", EA3_SOFTID);
|
||||
avs::core::avs_std_setenv("/env/profile/software_id", EA3_SOFTID);
|
||||
avs::core::avs_std_setenv("/env/profile/account_id", EA3_ACCOUNTID);
|
||||
avs::core::avs_std_setenv("/env/profile/soft_id_code", soft_id_code_pre_init_str.c_str());
|
||||
|
||||
// build game init code
|
||||
std::ostringstream init_code;
|
||||
init_code << EA3_MODEL;
|
||||
init_code << EA3_DEST;
|
||||
init_code << EA3_SPEC;
|
||||
init_code << EA3_REV;
|
||||
init_code << EA3_EXT;
|
||||
std::string init_code_str = init_code.str();
|
||||
|
||||
// save game info
|
||||
memcpy(avs::game::MODEL, EA3_MODEL, 4);
|
||||
memcpy(avs::game::DEST, EA3_DEST, 2);
|
||||
memcpy(avs::game::SPEC, EA3_SPEC, 2);
|
||||
memcpy(avs::game::EXT, EA3_EXT, 11);
|
||||
|
||||
// hook AVS functions
|
||||
hooks::avs::init();
|
||||
|
||||
// update pcb_type in app-config
|
||||
if (PCB_TYPE >= 0) {
|
||||
if (strcmp(EA3_MODEL, "K39") == 0 || strcmp(EA3_MODEL, "L39") == 0) {
|
||||
avs::core::property_search_remove_safe(app_config, nullptr, "/param/pcb_type_e");
|
||||
avs::core::property_node_create(app_config, nullptr,
|
||||
avs::core::NODE_TYPE_u8, "/param/pcb_type_e", PCB_TYPE);
|
||||
} else {
|
||||
avs::core::property_search_remove_safe(app_config, nullptr, "/param/pcb_type");
|
||||
avs::core::property_node_create(app_config, nullptr,
|
||||
avs::core::NODE_TYPE_u8, "/param/pcb_type", PCB_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
auto app_param = avs::core::property_search_safe(app_config, nullptr, "/param");
|
||||
|
||||
// call the game init
|
||||
log_info("avs-ea3", "calling entry init");
|
||||
if (!avs::game::entry_init(init_code_str.data(), app_param)) {
|
||||
log_fatal("avs-ea3", "entry init failed :(");
|
||||
}
|
||||
|
||||
// accommodate changes to soft id code
|
||||
//
|
||||
// TODO(felix): test this with other games, feature gating at the moment
|
||||
// for proper reporting of Omnimix and other song packs
|
||||
if (_stricmp(EA3_MODEL, "LDJ") == 0 ||
|
||||
_stricmp(EA3_MODEL, "L44") == 0 ||
|
||||
_stricmp(EA3_MODEL, "M39") == 0 ||
|
||||
_stricmp(EA3_MODEL, "KFC") == 0)
|
||||
{
|
||||
//memcpy(EA3_MODEL, init_code_str.c_str(), 3);
|
||||
//EA3_DEST[0] = init_code_str[3];
|
||||
//EA3_SPEC[0] = init_code_str[4];
|
||||
EA3_REV[0] = init_code_str[5];
|
||||
//memcpy(EA3_EXT, init_code_str.c_str() + 6, 10);
|
||||
}
|
||||
|
||||
// remove nodes
|
||||
avs::core::property_search_remove_safe(ea3_config, nullptr, "/ea3/soft/model");
|
||||
avs::core::property_search_remove_safe(ea3_config, nullptr, "/ea3/soft/dest");
|
||||
avs::core::property_search_remove_safe(ea3_config, nullptr, "/ea3/soft/spec");
|
||||
avs::core::property_search_remove_safe(ea3_config, nullptr, "/ea3/soft/rev");
|
||||
avs::core::property_search_remove_safe(ea3_config, nullptr, "/ea3/soft/ext");
|
||||
|
||||
// create nodes
|
||||
avs::core::property_node_create(ea3_config, nullptr,
|
||||
avs::core::NODE_TYPE_str, "/ea3/soft/model", EA3_MODEL);
|
||||
avs::core::property_node_create(ea3_config, nullptr,
|
||||
avs::core::NODE_TYPE_str, "/ea3/soft/dest", EA3_DEST);
|
||||
avs::core::property_node_create(ea3_config, nullptr,
|
||||
avs::core::NODE_TYPE_str, "/ea3/soft/spec", EA3_SPEC);
|
||||
avs::core::property_node_create(ea3_config, nullptr,
|
||||
avs::core::NODE_TYPE_str, "/ea3/soft/rev", EA3_REV);
|
||||
avs::core::property_node_create(ea3_config, nullptr,
|
||||
avs::core::NODE_TYPE_str, "/ea3/soft/ext", EA3_EXT);
|
||||
|
||||
// create soft ID code
|
||||
std::ostringstream soft_id_code;
|
||||
soft_id_code << EA3_MODEL << ":";
|
||||
soft_id_code << EA3_DEST << ":";
|
||||
soft_id_code << EA3_SPEC << ":";
|
||||
soft_id_code << EA3_REV << ":";
|
||||
soft_id_code << EA3_EXT;
|
||||
std::string soft_id_code_str = soft_id_code.str();
|
||||
log_info("avs-ea3", "soft id code: {}", soft_id_code_str);
|
||||
|
||||
// set soft ID code
|
||||
avs::core::avs_std_setenv("/env/profile/soft_id_code", soft_id_code_str.c_str());
|
||||
|
||||
// save new rev
|
||||
memcpy(avs::game::REV, EA3_REV, 2);
|
||||
|
||||
// http11
|
||||
if (HTTP11 >= 0) {
|
||||
avs::core::property_search_remove_safe(ea3_config, ea3_network, "http11");
|
||||
avs::core::property_node_create(ea3_config, ea3_network,
|
||||
avs::core::NODE_TYPE_bool, "http11", HTTP11);
|
||||
}
|
||||
|
||||
// url slash
|
||||
if (URL_SLASH >= 0) {
|
||||
avs::core::property_search_remove_safe(ea3_config, ea3_network, "url_slash");
|
||||
avs::core::property_node_create(ea3_config, ea3_network,
|
||||
avs::core::NODE_TYPE_bool, "url_slash", URL_SLASH);
|
||||
}
|
||||
|
||||
// custom service url
|
||||
if (!URL_CUSTOM.empty()) {
|
||||
avs::core::property_search_remove_safe(ea3_config, ea3_network, "services");
|
||||
avs::core::property_node_create(ea3_config, ea3_network,
|
||||
avs::core::NODE_TYPE_str, "services", URL_CUSTOM.c_str());
|
||||
}
|
||||
|
||||
// server - replace URL on the fly
|
||||
if (easrv_port != 0u) {
|
||||
std::ostringstream url;
|
||||
url << "http://localhost:" << easrv_port << "/";
|
||||
std::string url_str = url.str();
|
||||
|
||||
avs::core::property_search_remove_safe(ea3_config, ea3_network, "services");
|
||||
avs::core::property_node_create(ea3_config, ea3_network,
|
||||
avs::core::NODE_TYPE_str, "services", url_str.c_str());
|
||||
}
|
||||
|
||||
// remember URL
|
||||
char url_buffer[512] {};
|
||||
avs::core::property_node_refer(ea3_config, nullptr, "/ea3/network/services",
|
||||
avs::core::NODE_TYPE_str, url_buffer, sizeof(url_buffer));
|
||||
EA3_BOOT_URL = std::string(url_buffer);
|
||||
|
||||
// ssl initialization
|
||||
if (string_begins_with(url_buffer, "https")) {
|
||||
|
||||
// load ssl module
|
||||
HMODULE kws = libutils::try_library("kws.dll");
|
||||
if (kws != nullptr) {
|
||||
|
||||
// get functions
|
||||
ssl_protocol_init = libutils::try_proc<ssl_protocol_init_t>(kws, "ssl_protocol_init");
|
||||
ssl_protocol_fini = libutils::try_proc<ssl_protocol_fini_t>(kws, "ssl_protocol_fini");
|
||||
|
||||
// initialize
|
||||
if (ssl_protocol_init != nullptr) {
|
||||
log_info("avs-ea3", "initializing SSL protocol handler");
|
||||
ssl_protocol_init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// smartea logic: check if services are dead
|
||||
if (easrv_smart && !smartea::check_url(EA3_BOOT_URL)) {
|
||||
log_info("avs-ea3", "starting smartea local server on port 8080");
|
||||
|
||||
// start server
|
||||
easrv_start(8080, easrv_maint, 4, 8);
|
||||
|
||||
// fix URL
|
||||
EA3_BOOT_URL = "http://localhost:8080";
|
||||
avs::core::property_search_remove_safe(ea3_config, ea3_network, "services");
|
||||
avs::core::property_node_create(ea3_config, ea3_network,
|
||||
avs::core::NODE_TYPE_str, "services", EA3_BOOT_URL.c_str());
|
||||
|
||||
// fix URL slash
|
||||
URL_SLASH = 1;
|
||||
avs::core::property_search_remove_safe(ea3_config, ea3_network, "url_slash");
|
||||
avs::core::property_node_create(ea3_config, ea3_network,
|
||||
avs::core::NODE_TYPE_bool, "url_slash", &URL_SLASH);
|
||||
}
|
||||
|
||||
// boot EA3
|
||||
logger::PCBIDFilter filter;
|
||||
log_info("avs-ea3", "calling ea3 boot");
|
||||
avs_ea3_boot_startup(ea3);
|
||||
|
||||
// clean up
|
||||
avs::core::config_destroy(app_config);
|
||||
avs::core::config_destroy(ea3_config);
|
||||
|
||||
// print avs mountpoints
|
||||
// it does not exist in VERY old legacy AVS versions (like 2.10.2)
|
||||
if (avs::core::avs_fs_dump_mountpoint) {
|
||||
avs::core::avs_fs_dump_mountpoint();
|
||||
}
|
||||
|
||||
// success
|
||||
log_info("avs-ea3", "boot done");
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
|
||||
// SSL shutdown
|
||||
if (ssl_protocol_fini != nullptr) {
|
||||
log_info("avs-ea3", "unregistering SSL protocol handler");
|
||||
ssl_protocol_fini();
|
||||
}
|
||||
|
||||
// EA3 shutdown
|
||||
log_info("avs-ea3", "shutdown");
|
||||
avs_ea3_shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
54
avs/ea3.h
Normal file
54
avs/ea3.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace avs {
|
||||
|
||||
/*
|
||||
* helpers
|
||||
*/
|
||||
namespace ea3 {
|
||||
|
||||
// import mapping
|
||||
struct avs_ea3_import {
|
||||
const char *version;
|
||||
const char *boot;
|
||||
const char *shutdown;
|
||||
};
|
||||
|
||||
// settings
|
||||
extern std::string CFG_PATH;
|
||||
extern std::string APP_PATH;
|
||||
extern std::string BOOTSTRAP_PATH;
|
||||
extern std::string PCBID_CUSTOM;
|
||||
extern std::string SOFTID_CUSTOM;
|
||||
extern std::string URL_CUSTOM;
|
||||
extern int HTTP11;
|
||||
extern int URL_SLASH;
|
||||
extern int PCB_TYPE;
|
||||
|
||||
// handle
|
||||
extern std::string VERSION_STR;
|
||||
extern HINSTANCE DLL_INSTANCE;
|
||||
extern std::string DLL_NAME;
|
||||
extern std::string EA3_BOOT_URL;
|
||||
extern std::string EA3_BOOT_PCBID;
|
||||
|
||||
// functions
|
||||
void load_dll();
|
||||
void boot(unsigned short easrv_port, bool easrv_maint, bool easrv_smart);
|
||||
void shutdown();
|
||||
}
|
||||
|
||||
/*
|
||||
* library functions
|
||||
*/
|
||||
|
||||
typedef int (*AVS_EA3_BOOT_STARTUP_T)(void *);
|
||||
extern AVS_EA3_BOOT_STARTUP_T avs_ea3_boot_startup;
|
||||
|
||||
typedef void (*AVS_EA3_SHUTDOWN_T)(void);
|
||||
extern AVS_EA3_SHUTDOWN_T avs_ea3_shutdown;
|
||||
}
|
||||
127
avs/game.cpp
Normal file
127
avs/game.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
#include "game.h"
|
||||
|
||||
#include "launcher/launcher.h"
|
||||
#include "util/fileutils.h"
|
||||
#include "util/libutils.h"
|
||||
#include "util/logging.h"
|
||||
|
||||
namespace avs {
|
||||
|
||||
namespace game {
|
||||
|
||||
// function names
|
||||
const char ENTRY_INIT_NAME[] = "dll_entry_init";
|
||||
const char ENTRY_MAIN_NAME[] = "dll_entry_main";
|
||||
|
||||
// functions
|
||||
typedef bool (*ENTRY_INIT_T)(char *, void *);
|
||||
typedef void (*ENTRY_MAIN_T)(void);
|
||||
ENTRY_INIT_T dll_entry_init;
|
||||
ENTRY_MAIN_T dll_entry_main;
|
||||
|
||||
// properties
|
||||
char MODEL[4] = {'0', '0', '0', '\x00'};
|
||||
char DEST[2] = {'0', '\x00'};
|
||||
char SPEC[2] = {'0', '\x00'};
|
||||
char REV[2] = {'0', '\x00'};
|
||||
char EXT[11] = {'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '\x00'};
|
||||
|
||||
// handle
|
||||
HINSTANCE DLL_INSTANCE;
|
||||
std::string DLL_NAME;
|
||||
|
||||
bool is_model(const char *model) {
|
||||
return _stricmp(MODEL, model) == 0;
|
||||
}
|
||||
|
||||
bool is_model(const char *model, const char *ext) {
|
||||
return is_model(model) && is_ext(ext);
|
||||
}
|
||||
|
||||
bool is_model(const std::initializer_list<const char *> model_list) {
|
||||
for (auto &model : model_list) {
|
||||
if (is_model(model)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_ext(const char *ext) {
|
||||
return _stricmp(EXT, ext) == 0;
|
||||
}
|
||||
|
||||
bool is_ext(int datecode_min, int datecode_max) {
|
||||
|
||||
// range check
|
||||
long datecode = strtol(EXT, NULL, 10);
|
||||
return datecode_min <= datecode && datecode <= datecode_max;
|
||||
}
|
||||
|
||||
std::string get_identifier() {
|
||||
return fmt::format("{}:{}:{}:{}:{}",
|
||||
avs::game::MODEL,
|
||||
avs::game::DEST,
|
||||
avs::game::SPEC,
|
||||
avs::game::REV,
|
||||
avs::game::EXT);
|
||||
}
|
||||
|
||||
void load_dll() {
|
||||
log_info("avs-game", "loading DLL '{}'", DLL_NAME);
|
||||
|
||||
// load game instance
|
||||
const auto dll_path = MODULE_PATH / DLL_NAME;
|
||||
const auto dll_path_s = dll_path.string();
|
||||
log_info("avs-game", "DLL path: {}", dll_path_s.c_str());
|
||||
|
||||
if (MAX_PATH <= (dll_path_s.length() + 64)) {
|
||||
log_warning(
|
||||
"avs-game",
|
||||
"PATH TOO LONG WARNING\n\n\n"
|
||||
"-------------------------------------------------------------------\n"
|
||||
"WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n"
|
||||
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
||||
"'{}' has a length of {}\n"
|
||||
"Most of these games will behave unexpectedly when the path is too long,\n"
|
||||
"often resulting in random crashes. Move the game contents to a directory\n"
|
||||
"with shorter path.\n"
|
||||
"-------------------------------------------------------------------\n\n\n",
|
||||
dll_path_s, dll_path_s.length());
|
||||
}
|
||||
if (fileutils::verify_header_pe(dll_path)) {
|
||||
DLL_INSTANCE = libutils::load_library(dll_path);
|
||||
}
|
||||
|
||||
// load entry points
|
||||
dll_entry_init = (ENTRY_INIT_T) libutils::get_proc(DLL_INSTANCE, ENTRY_INIT_NAME);
|
||||
dll_entry_main = (ENTRY_MAIN_T) libutils::get_proc(DLL_INSTANCE, ENTRY_MAIN_NAME);
|
||||
log_info("avs-game", "loaded successfully ({})", fmt::ptr(DLL_INSTANCE));
|
||||
}
|
||||
|
||||
bool entry_init(char *sid_code, void *app_param) {
|
||||
auto current_entry_init = (ENTRY_INIT_T) libutils::get_proc(DLL_INSTANCE, ENTRY_INIT_NAME);
|
||||
|
||||
if (dll_entry_init != current_entry_init) {
|
||||
log_info("avs-game", "dll_entry_init is hooked");
|
||||
|
||||
dll_entry_init = current_entry_init;
|
||||
}
|
||||
|
||||
return dll_entry_init(sid_code, app_param);
|
||||
}
|
||||
|
||||
void entry_main() {
|
||||
auto current_entry_main = (ENTRY_MAIN_T) libutils::get_proc(DLL_INSTANCE, ENTRY_MAIN_NAME);
|
||||
|
||||
if (dll_entry_main != current_entry_main) {
|
||||
log_info("avs-game", "dll_entry_main is hooked");
|
||||
|
||||
dll_entry_main = current_entry_main;
|
||||
}
|
||||
|
||||
dll_entry_main();
|
||||
}
|
||||
}
|
||||
}
|
||||
44
avs/game.h
Normal file
44
avs/game.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace avs {
|
||||
|
||||
/*
|
||||
* helpers
|
||||
*/
|
||||
namespace game {
|
||||
|
||||
// properties
|
||||
extern char MODEL[4];
|
||||
extern char DEST[2];
|
||||
extern char SPEC[2];
|
||||
extern char REV[2];
|
||||
extern char EXT[11];
|
||||
|
||||
// handle
|
||||
extern HINSTANCE DLL_INSTANCE;
|
||||
extern std::string DLL_NAME;
|
||||
|
||||
// helpers
|
||||
bool is_model(const char *model);
|
||||
bool is_model(const char *model, const char *ext);
|
||||
bool is_model(const std::initializer_list<const char *> model_list);
|
||||
bool is_ext(const char *ext);
|
||||
bool is_ext(int datecode_min, int datecode_max);
|
||||
std::string get_identifier();
|
||||
|
||||
// functions
|
||||
void load_dll();
|
||||
|
||||
/*
|
||||
* library functions
|
||||
*/
|
||||
|
||||
bool entry_init(char *sid_code, void *app_param);
|
||||
void entry_main();
|
||||
}
|
||||
}
|
||||
1363
avs/ssl.cpp
Normal file
1363
avs/ssl.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user