From edd7cca0c565c16125804f353efb0f9edb0ba5ad Mon Sep 17 00:00:00 2001 From: Keith Bourdon <33245078+celerizer@users.noreply.github.com> Date: Tue, 16 Dec 2025 19:52:26 -0600 Subject: [PATCH 01/57] init --- cl_action.c | 8 +- cl_action.h | 12 - cl_memory.h | 9 - cl_search_new.c | 583 ++++++++++++++++++++++++++++++++++++ cl_search_new.h | 170 +++++++++++ cl_test.c | 35 ++- cl_types.h | 16 + classicslive-integration.mk | 2 +- 8 files changed, 797 insertions(+), 38 deletions(-) create mode 100644 cl_search_new.c create mode 100644 cl_search_new.h diff --git a/cl_action.c b/cl_action.c index 6488696..1dd6384 100644 --- a/cl_action.c +++ b/cl_action.c @@ -205,13 +205,13 @@ static bool cl_act_compare(cl_action_t *action) switch (action->arguments[4].intval) { - case CL_CMPTYPE_IFEQUAL: + case CL_COMPARE_EQUAL: return cl_ctr_equal(&left, &right); - case CL_CMPTYPE_IFGREATER: + case CL_COMPARE_GREATER: return cl_ctr_greater(&left, &right); - case CL_CMPTYPE_IFLESS: + case CL_COMPARE_LESS: return cl_ctr_lesser(&left, &right); - case CL_CMPTYPE_IFNEQUAL: + case CL_COMPARE_NOT_EQUAL: return cl_ctr_not_equal(&left, &right); default: return cl_free_action(action); diff --git a/cl_action.h b/cl_action.h index 910682c..142970e 100644 --- a/cl_action.h +++ b/cl_action.h @@ -80,18 +80,6 @@ typedef struct bool (*function)(cl_action_t*); } cl_acttype_t; -typedef enum -{ - CL_CMPTYPE_INVALID = 0, - - CL_CMPTYPE_IFEQUAL, - CL_CMPTYPE_IFGREATER, - CL_CMPTYPE_IFLESS, - CL_CMPTYPE_IFNEQUAL, - - CL_CMPTYPE_SIZE -} cl_compare_type; - bool cl_free_action(cl_action_t *action); /* Assign the correct function pointer for the type of action */ diff --git a/cl_memory.h b/cl_memory.h index 47cea63..b0f2f1f 100644 --- a/cl_memory.h +++ b/cl_memory.h @@ -20,15 +20,6 @@ typedef enum CL_SRCTYPE_SIZE } cl_src_t; -#define CLE_CMPTYPE_EQUAL 1 -#define CLE_CMPTYPE_GREATER 2 -#define CLE_CMPTYPE_LESS 3 -#define CLE_CMPTYPE_NOT_EQUAL 4 -#define CLE_CMPTYPE_INCREASED 5 -#define CLE_CMPTYPE_DECREASED 6 -#define CLE_CMPTYPE_ABOVE 7 -#define CLE_CMPTYPE_BELOW 8 - #include "cl_config.h" #include "cl_counter.h" #include "cl_types.h" diff --git a/cl_search_new.c b/cl_search_new.c new file mode 100644 index 0000000..ddb4f02 --- /dev/null +++ b/cl_search_new.c @@ -0,0 +1,583 @@ +#include "cl_search_new.h" + +#include "cl_config.h" +#include "cl_memory.h" + +#if CL_HOST_PLATFORM == CL_PLATFORM_LINUX + #include +#elif CL_HOST_PLATFORM == CL_PLATFORM_WINDOWS + #include +#endif + +#include + +#if CL_EXTERNAL_MEMORY +/** + * The amount of data to retrieve from the external process at a time when + * processing a search. + */ +#define CL_SEARCH_BUCKET_SIZE CL_MB(128) +#endif + +/** + * The granularity of data to keep in memory as search results. + * The total allocation per chunk is twice this size, as the validity bitmap + * is stored alongside the data itself. + * 128KB was decided upon as 256KB is a common L2 cache size. + * @todo Make configurable? + */ +#define CL_SEARCH_CHUNK_SIZE CL_KB(128) + +/** + * Allocate a chunk of page-aligned memory. + * @param size The number of bytes to allocate + * @return A pointer to the bytes, or NULL + */ +static void *cl_mmap(size_t size) +{ +#if CL_HOST_PLATFORM == CL_PLATFORM_LINUX + void *p = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + if (p == CL_ADDRESS_INVALID) + return NULL; + else + return p; +#elif CL_HOST_PLATFORM == CL_PLATFORM_WINDOWS + return VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); +#else + return malloc(size); +#endif +} + +/** + * Free a chunk of page-aligned memory. + * @param memory The pointer to free + * @param size The number of bytes to deallocate + */ +static void cl_munmap(void *memory, size_t size) +{ +#if CL_HOST_PLATFORM == CL_PLATFORM_LINUX + munmap(memory, size); +#elif CL_HOST_PLATFORM == CL_PLATFORM_WINDOWS + CL_UNUSED(size); + VirtualFree(memory, 0, MEM_RELEASE); +#else + CL_UNUSED(size); + free(memory); +#endif +} + +/** @todo is it faster to split comparison and match totaling into two or not? */ + +#define CL_PASTE2(a, b) a##b +#define CL_PASTE3(a, b, c) a##b##c + +#define CL_SEARCH_CMP_IMMEDIATE_TEMPLATE(a, b, c, d) \ +static unsigned CL_PASTE3(cl_search_cmp_imm_, b, _##d)( \ + void *chunk_data, \ + const void *chunk_data_end, \ + unsigned char *chunk_validity, \ + const void *target) \ +{ \ + unsigned matches = 0; \ + unsigned char match; \ + a *chunk_data_cast = (a*)chunk_data; \ + const a *chunk_data_end_cast = (const a*)chunk_data_end; \ + const a right = ((cl_search_target_t*)target)->b; \ + while (chunk_data_cast < chunk_data_end_cast) \ + { \ + match = *chunk_data_cast c right; \ + *chunk_validity = match; \ + matches += match; \ + chunk_data_cast++; \ + chunk_validity++; \ + } \ + return matches; \ +} + +#define CL_SEARCH_CMP_PREVIOUS_TEMPLATE(a, b, c, d) \ +static unsigned CL_PASTE3(cl_search_cmp_prv_, b, _##d)( \ + void *chunk_data, \ + const void *chunk_data_end, \ + unsigned char *chunk_validity, \ + const void *chunk_data_prev) \ +{ \ + unsigned matches = 0; \ + unsigned char match; \ + a *chunk_data_cast = (a*)chunk_data; \ + const a *chunk_data_end_cast = (const a*)chunk_data_end; \ + const a *chunk_data_prev_cast = (const a*)chunk_data_prev; \ + while (chunk_data_cast < chunk_data_end_cast) \ + { \ + match = *chunk_data_cast c *chunk_data_prev_cast; \ + *chunk_validity = match; \ + matches += match; \ + chunk_data_cast++; \ + chunk_validity++; \ + chunk_data_prev_cast++; \ + } \ + return matches; \ +} + +#define CL_SEARCH_CMP_IMMEDIATE_UNROLL(a, b) \ + CL_SEARCH_CMP_IMMEDIATE_TEMPLATE(a, b, ==, equ) \ + CL_SEARCH_CMP_PREVIOUS_TEMPLATE(a, b, ==, equ) \ + CL_SEARCH_CMP_IMMEDIATE_TEMPLATE(a, b, <, les) \ + CL_SEARCH_CMP_PREVIOUS_TEMPLATE(a, b, <, les) \ + CL_SEARCH_CMP_IMMEDIATE_TEMPLATE(a, b, >, gtr) \ + CL_SEARCH_CMP_PREVIOUS_TEMPLATE(a, b, >, gtr) \ + CL_SEARCH_CMP_IMMEDIATE_TEMPLATE(a, b, !=, neq) \ + CL_SEARCH_CMP_PREVIOUS_TEMPLATE(a, b, !=, neq) \ + +CL_SEARCH_CMP_IMMEDIATE_UNROLL(unsigned char, u8) +CL_SEARCH_CMP_IMMEDIATE_UNROLL(signed char, s8) +CL_SEARCH_CMP_IMMEDIATE_UNROLL(unsigned short, u16) +CL_SEARCH_CMP_IMMEDIATE_UNROLL(signed short, s16) +CL_SEARCH_CMP_IMMEDIATE_UNROLL(unsigned int, u32) +CL_SEARCH_CMP_IMMEDIATE_UNROLL(signed int, s32) +CL_SEARCH_CMP_IMMEDIATE_UNROLL(signed long, s64) +CL_SEARCH_CMP_IMMEDIATE_UNROLL(float, fp) +CL_SEARCH_CMP_IMMEDIATE_UNROLL(double, dfp) + +typedef unsigned (*cl_search_compare_func_t)(void*,const void*,unsigned char*,const void*); + +static cl_search_compare_func_t cl_search_comparison_function(cl_search_parameters_t params) +{ + switch (params.value_type) + { + case CL_MEMTYPE_UINT8: + switch (params.compare_type) + { + case CL_COMPARE_EQUAL: + return params.compare_to_previous ? cl_search_cmp_prv_u8_equ : cl_search_cmp_imm_u8_equ; + case CL_COMPARE_GREATER: + return params.compare_to_previous ? cl_search_cmp_prv_u8_gtr : cl_search_cmp_imm_u8_gtr; + case CL_COMPARE_LESS: + return params.compare_to_previous ? cl_search_cmp_prv_u8_les : cl_search_cmp_imm_u8_les; + case CL_COMPARE_NOT_EQUAL: + return params.compare_to_previous ? cl_search_cmp_prv_u8_neq : cl_search_cmp_imm_u8_neq; + default: + return NULL; + } + case CL_MEMTYPE_INT8: + switch (params.compare_type) + { + case CL_COMPARE_EQUAL: + return params.compare_to_previous ? cl_search_cmp_prv_s8_equ : cl_search_cmp_imm_s8_equ; + case CL_COMPARE_GREATER: + return params.compare_to_previous ? cl_search_cmp_prv_s8_gtr : cl_search_cmp_imm_s8_gtr; + case CL_COMPARE_LESS: + return params.compare_to_previous ? cl_search_cmp_prv_s8_les : cl_search_cmp_imm_s8_les; + case CL_COMPARE_NOT_EQUAL: + return params.compare_to_previous ? cl_search_cmp_prv_s8_neq : cl_search_cmp_imm_s8_neq; + default: + return NULL; + } + case CL_MEMTYPE_UINT16: + switch (params.compare_type) + { + case CL_COMPARE_EQUAL: + return params.compare_to_previous ? cl_search_cmp_prv_u16_equ : cl_search_cmp_imm_u16_equ; + case CL_COMPARE_GREATER: + return params.compare_to_previous ? cl_search_cmp_prv_u16_gtr : cl_search_cmp_imm_u16_gtr; + case CL_COMPARE_LESS: + return params.compare_to_previous ? cl_search_cmp_prv_u16_les : cl_search_cmp_imm_u16_les; + case CL_COMPARE_NOT_EQUAL: + return params.compare_to_previous ? cl_search_cmp_prv_u16_neq : cl_search_cmp_imm_u16_neq; + default: + return NULL; + } + case CL_MEMTYPE_INT16: + switch (params.compare_type) + { + case CL_COMPARE_EQUAL: + return params.compare_to_previous ? cl_search_cmp_prv_s16_equ : cl_search_cmp_imm_s16_equ; + case CL_COMPARE_GREATER: + return params.compare_to_previous ? cl_search_cmp_prv_s16_gtr : cl_search_cmp_imm_s16_gtr; + case CL_COMPARE_LESS: + return params.compare_to_previous ? cl_search_cmp_prv_s16_les : cl_search_cmp_imm_s16_les; + case CL_COMPARE_NOT_EQUAL: + return params.compare_to_previous ? cl_search_cmp_prv_s16_neq : cl_search_cmp_imm_s16_neq; + default: + return NULL; + } + case CL_MEMTYPE_UINT32: + switch (params.compare_type) + { + case CL_COMPARE_EQUAL: + return params.compare_to_previous ? cl_search_cmp_prv_u32_equ : cl_search_cmp_imm_u32_equ; + case CL_COMPARE_GREATER: + return params.compare_to_previous ? cl_search_cmp_prv_u32_gtr : cl_search_cmp_imm_u32_gtr; + case CL_COMPARE_LESS: + return params.compare_to_previous ? cl_search_cmp_prv_u32_les : cl_search_cmp_imm_u32_les; + case CL_COMPARE_NOT_EQUAL: + return params.compare_to_previous ? cl_search_cmp_prv_u32_neq : cl_search_cmp_imm_u32_neq; + default: + return NULL; + } + case CL_MEMTYPE_INT32: + switch (params.compare_type) + { + case CL_COMPARE_EQUAL: + return params.compare_to_previous ? cl_search_cmp_prv_s32_equ : cl_search_cmp_imm_s32_equ; + case CL_COMPARE_GREATER: + return params.compare_to_previous ? cl_search_cmp_prv_s32_gtr : cl_search_cmp_imm_s32_gtr; + case CL_COMPARE_LESS: + return params.compare_to_previous ? cl_search_cmp_prv_s32_les : cl_search_cmp_imm_s32_les; + case CL_COMPARE_NOT_EQUAL: + return params.compare_to_previous ? cl_search_cmp_prv_s32_neq : cl_search_cmp_imm_s32_neq; + default: + return NULL; + } + case CL_MEMTYPE_INT64: + switch (params.compare_type) + { + case CL_COMPARE_EQUAL: + return params.compare_to_previous ? cl_search_cmp_prv_s64_equ : cl_search_cmp_imm_s64_equ; + case CL_COMPARE_GREATER: + return params.compare_to_previous ? cl_search_cmp_prv_s64_gtr : cl_search_cmp_imm_s64_gtr; + case CL_COMPARE_LESS: + return params.compare_to_previous ? cl_search_cmp_prv_s64_les : cl_search_cmp_imm_s64_les; + case CL_COMPARE_NOT_EQUAL: + return params.compare_to_previous ? cl_search_cmp_prv_s64_neq : cl_search_cmp_imm_s64_neq; + default: + return NULL; + } + case CL_MEMTYPE_DOUBLE: + switch (params.compare_type) + { + case CL_COMPARE_EQUAL: + return params.compare_to_previous ? cl_search_cmp_prv_dfp_equ : cl_search_cmp_imm_dfp_equ; + case CL_COMPARE_GREATER: + return params.compare_to_previous ? cl_search_cmp_prv_dfp_gtr : cl_search_cmp_imm_dfp_gtr; + case CL_COMPARE_LESS: + return params.compare_to_previous ? cl_search_cmp_prv_dfp_les : cl_search_cmp_imm_dfp_les; + case CL_COMPARE_NOT_EQUAL: + return params.compare_to_previous ? cl_search_cmp_prv_dfp_neq : cl_search_cmp_imm_dfp_neq; + default: + return NULL; + } + case CL_MEMTYPE_FLOAT: + switch (params.compare_type) + { + case CL_COMPARE_EQUAL: + return params.compare_to_previous ? cl_search_cmp_prv_fp_equ : cl_search_cmp_imm_fp_equ; + case CL_COMPARE_GREATER: + return params.compare_to_previous ? cl_search_cmp_prv_fp_gtr : cl_search_cmp_imm_fp_gtr; + case CL_COMPARE_LESS: + return params.compare_to_previous ? cl_search_cmp_prv_fp_les : cl_search_cmp_imm_fp_les; + case CL_COMPARE_NOT_EQUAL: + return params.compare_to_previous ? cl_search_cmp_prv_fp_neq : cl_search_cmp_imm_fp_neq; + default: + return NULL; + } + case CL_MEMTYPE_NOT_SET: + case CL_MEMTYPE_SIZE: + /* No default because we want a warning if we add new types */ + return NULL; + } + + return NULL; +} + +/** + * Runs a comparison function on the values in a search page. + * @param page + * @todo the function should be found in search_step + */ +static cl_error cl_search_step_page(cl_search_page_t *page, const cl_search_parameters_t params, + const void *prev_buffer) +{ + cl_search_compare_func_t comparison_function = cl_search_comparison_function(params); + const void *end = (((unsigned char*)page->chunk) + page->size); + + if (!comparison_function) + return CL_ERR_PARAMETER_INVALID; + page->matches = comparison_function(page->chunk, end, + page->validity, + params.compare_to_previous ? prev_buffer : ¶ms.target); + + return CL_OK; +} + +static cl_error cl_search_profile_memory(cl_search_t *search) +{ + cl_addr_t usage = 0; + unsigned i; + + for (i = 0; i < search->page_region_count; i++) + { + cl_search_page_t *page = search->page_regions->first_page; + + while (page) + { + /* Count the chunks */ + usage += page->size; + usage += page->size / search->params.value_size; + usage += sizeof(cl_search_page_t); + page = page->next; + } + usage += sizeof(cl_search_page_region_t); + } + usage += sizeof(cl_search_t); + search->memory_usage = usage; + + return CL_OK; +} + +cl_error cl_search_change_compare_type(cl_search_t *search, + cl_compare_type compare_type) +{ + if (!search) + return CL_ERR_PARAMETER_NULL; + else if (compare_type == CL_COMPARE_INVALID || + compare_type >= CL_COMPARE_SIZE) + return CL_ERR_PARAMETER_INVALID; + else + { + search->params.compare_type = compare_type; + + return CL_OK; + } +} + +cl_error cl_search_change_value_type(cl_search_t *search, cl_value_type type) +{ + if (!search) + return CL_ERR_PARAMETER_NULL; + else if (type == CL_MEMTYPE_NOT_SET || type >= CL_MEMTYPE_SIZE) + return CL_ERR_PARAMETER_INVALID; + else + { + search->params.value_type = type; + search->params.value_size = cl_sizeof_memtype(type); + + return CL_OK; + } +} + +cl_error cl_search_change_target(cl_search_t *search, const void *value) +{ + if (!search) + return CL_ERR_PARAMETER_NULL; + else if (!value) + search->params.compare_to_previous = 1; + else + { + cl_search_target_t target; + + memset(&target, 0, sizeof(cl_search_target_t)); + switch (search->params.value_size) + { + case 1: + memcpy(&target.u8, value, 1); + break; + case 2: + memcpy(&target.u16, value, 2); + break; + case 4: + memcpy(&target.u32, value, 4); + break; + case 8: + memcpy(&target.u64, value, 8); + break; + default: + return CL_ERR_PARAMETER_INVALID; + } + search->params.target = target; + search->params.compare_to_previous = 0; + } + + return CL_OK; +} + +static cl_error cl_search_free_page(cl_search_page_t *page) +{ + if (page) + { + cl_munmap(page->chunk, page->size * 2); + free(page); + + return CL_OK; + } + + return CL_ERR_PARAMETER_NULL; +} + +cl_error cl_search_free(cl_search_t *search) +{ + unsigned i; + + if (!search) + return CL_ERR_PARAMETER_NULL; + + for (i = 0; i < search->page_region_count; i++) + { + cl_search_page_region_t *page_region = &search->page_regions[i]; + cl_search_page_t *page = page_region->first_page; + cl_search_page_t *next_page = NULL; + + while (page) + { + next_page = page->next; + cl_search_free_page(page); + page = next_page; + } + } + + free(search->page_regions); + memset(search, 0, sizeof(cl_search_t)); + + return CL_OK; +} + +cl_error cl_search_init(cl_search_t *search) +{ + unsigned i; + + if (!search || !memory.regions) + return CL_ERR_PARAMETER_NULL; + else if (memory.region_count == 0) + return CL_ERR_PARAMETER_INVALID; + + /* Zero-init the search */ + memset(search, 0, sizeof(cl_search_t)); + + /* Allocate and init page regions */ + search->page_regions = (cl_search_page_region_t*)calloc( + memory.region_count, sizeof(cl_search_page_region_t)); + search->page_region_count = memory.region_count; + for (i = 0; i < memory.region_count; i++) + { + cl_search_page_region_t *page_region = &search->page_regions[i]; + + page_region->page_count = 0; + page_region->region = &memory.regions[i]; + } + + return cl_search_profile_memory(search); +} + +/** + * Performs the first search step, which is responsible for allocating the + * initial round of chunks. + * @param search A pointer to the search to perform a step on + */ +static cl_error cl_search_step_first(cl_search_t *search) +{ + unsigned i; + + for (i = 0; i < search->page_region_count; i++) + { + cl_search_page_region_t *page_region = &search->page_regions[i]; + cl_search_page_t *page = NULL; + cl_search_page_t *prev_page = NULL; + cl_addr_t processed = 0; + + while (processed < page_region->region->size) + { + unsigned size = CL_SEARCH_CHUNK_SIZE; + + /* Allocate small single or final chunk when it can't divide evenly */ + if (processed + CL_SEARCH_CHUNK_SIZE > page_region->region->size) + size -= CL_SEARCH_CHUNK_SIZE - processed; + + if (!page) + { + page = (cl_search_page_t*)calloc(1, sizeof(cl_search_page_t)); + page->chunk = cl_mmap(size * 2); + page->validity = (void*)((unsigned char*)page->chunk + size); + } + + /* Do the search here */ + cl_search_step_page(page, search->params, NULL); + if (page->matches == 0) + { + /* This page had no matches, so we will reuse it for the next one */ + page->region = page_region->region; + page->start = page_region->region->base_guest + processed; + page->size = size; + memset(page->validity, 1, size / search->params.value_size); + } + else + { + if (!prev_page) + /* This is the first page in this page region */ + page_region->first_page = page; + else + /* This is another page in this page region's linked list */ + prev_page->next = page; + + /* Count up the matches */ + page_region->matches += page->matches; + search->total_matches += page->matches; + + /* The next page will be allocated */ + page = NULL; + } + + processed += size; + } + + /* If the final page had no matches, delete it */ + if (page->matches == 0) + cl_search_free_page(page); + } + search->steps = 1; + + return cl_search_profile_memory(search); +} + +cl_error cl_search_step(cl_search_t *search) +{ + if (!search) + return CL_ERR_PARAMETER_NULL; + else if (search->steps == 0) + return cl_search_step_first(search); + else + { + cl_addr_t total_matches = 0; + unsigned i; + + for (i = 0; i < search->page_region_count; i++) + { + cl_search_page_region_t *page_region = &search->page_regions[i]; + cl_search_page_t *page = page_region->first_page; + cl_search_page_t *prev_page = NULL; + cl_search_page_t *next_page = NULL; + cl_addr_t page_region_matches = 0; + + while (page) + { + cl_error error = cl_search_step_page(page, search->params, NULL); + + if (error != CL_OK) + return error; + else if (page->matches == 0) + { + /* Remove this page from the linked list */ + if (prev_page) + prev_page->next = page->next; + else + page_region->first_page = page->next; + + next_page = page->next; + cl_search_free_page(page); + page = next_page; + } + else + { + /* Keep this page in the linked list */ + prev_page = page; + page = page->next; + page_region_matches += page->matches; + } + } + total_matches += page_region_matches; + } + search->total_matches = total_matches; + search->steps++; + + return cl_search_profile_memory(search); + } +} diff --git a/cl_search_new.h b/cl_search_new.h new file mode 100644 index 0000000..270a365 --- /dev/null +++ b/cl_search_new.h @@ -0,0 +1,170 @@ +#ifndef CL_SEARCH_H +#define CL_SEARCH_H + +#include "cl_types.h" + +typedef struct cl_search_page_t cl_search_page_t; + +struct cl_search_page_t +{ + /* Number of matches found in this page */ + cl_addr_t matches; + + /* A buffer containing the memory chunk data and validity bitmap */ + void *chunk; + + /* A pointer to the position of the validity bitmap within the chunk */ + void *validity; + + /* The starting address of the memory chunk */ + cl_addr_t start; + + /* The first address of the memory chunk that resulted in a match */ + cl_addr_t first; + + /* The last address of the memory chunk that resulted in a match */ + cl_addr_t end; + + /** + * The size, in bytes, of the memory chunks. Should typically be + * `CL_SEARCH_CHUNK_SIZE` except if the target region has memory smaller + * than that or if it's the last chunk in a region that can't be divided + * equally. + */ + cl_addr_t size; + + /* Next page in the linked list */ + cl_search_page_t *next; + + /* The memory region this page is within */ + const cl_memory_region_t *region; +}; + +/* A wrapper for search pages to group them by memory region */ +typedef struct +{ + /* The memory region these pages fall under */ + const cl_memory_region_t *region; + + /* The first page in the linked list */ + cl_search_page_t *first_page; + + /* The number of pages in this page region */ + unsigned page_count; + + unsigned matches; +} cl_search_page_region_t; + +typedef union +{ + unsigned char u8; + signed char s8; + unsigned short u16; + signed short s16; + unsigned int u32; + signed int s32; + unsigned long u64; + signed long s64; + float fp; + double dfp; +} cl_search_target_t; + +typedef struct +{ + /* The type of value being searched for */ + cl_value_type value_type; + + /** + * The size, in bytes, of the value type. + * Should only ever be 1, 2, 4, or 8. + */ + unsigned value_size; + + /* The comparison method to use */ + cl_compare_type compare_type; + + /* The target value to compare against */ + cl_search_target_t target; + + /** + * A pointer to the target value to compare against. This offsets to the + * correct position of the target union. + */ + const void *target_ptr; + + /* Whether to compare to the previous value instead of a target */ + unsigned compare_to_previous; +} cl_search_parameters_t; + +/** + * The main structure representing an ongoing memory search. + * Upon creating a search, call `cl_search_init` to initialize it. + * To free the search, call `cl_search_free`. + */ +typedef struct +{ + /** + * The parameters used for this search. Edit this by using + * `cl_search_change_params`. + */ + cl_search_parameters_t params; + + cl_search_page_region_t *page_regions; + unsigned page_region_count; + + /* The number of times `cl_search_step` has been called with this search */ + unsigned steps; + + /* The total number of pages allocated for this search */ + unsigned total_page_count; + + /* The total number of matches found in the search */ + unsigned total_matches; + + /* The total memory usage of the search, in bytes */ + cl_addr_t memory_usage; +} cl_search_t; + +/** + * Changes the comparison type used in the search. + * @param search A pointer to the search to modify + * @param compare_type The new comparison type to use + */ +cl_error cl_search_change_compare_type(cl_search_t *search, + cl_compare_type compare_type); + +/** + * Changes the value type used in the search. This cannot be used once the + * search has begun (i.e. after calling `cl_search_step`). + * @param search A pointer to the search to modify + * @param type The new value type to use + */ +cl_error cl_search_change_value_type(cl_search_t *search, cl_value_type type); + +/** + * Changes the target value used in the search. + * @param search A pointer to the search to modify + * @param value A pointer to the new target value to use, or NULL to compare + * against the previous value instead + */ +cl_error cl_search_change_target(cl_search_t *search, const void *value); + +cl_error cl_search_init(cl_search_t *search); + +/** + * Filters the values to only those that match the given `params`. The total + * number of matches will then be available in `total_matches`. + * @param search A pointer to the search to perform a step on + */ +cl_error cl_search_step(cl_search_t *search); + +/** + * Retrieves the value at a given address from the search backup memory. + * @param dst A pointer to a type matching the search's `type` + * @param search The search to retrieve the value from + * @param address The virtual address of the value to retrieve + */ +cl_error cl_search_backup_value(void *dst, const cl_search_t *search, + cl_addr_t address); + +#endif diff --git a/cl_test.c b/cl_test.c index 316d116..08c1ae2 100644 --- a/cl_test.c +++ b/cl_test.c @@ -3,7 +3,7 @@ #include "cl_main.h" #include "cl_memory.h" #include "cl_network.h" -#include "cl_search.h" +#include "cl_search_new.h" #include #include @@ -442,22 +442,33 @@ static cl_error cl_test(void) printf("Big-endian virtual memory read/write test passed (got 0x%02x)!\n", byte); /* Initialize a search */ - printf("Initializing memory search...\n"); - memset(&search, 0, sizeof(search)); - search.params.value_type = CL_MEMTYPE_UINT32; - search.params.size = 4; - search.params.compare_type = CLE_CMPTYPE_EQUAL; - word = 0; + printf("Initializing memory search..."); cl_search_init(&search); - cl_search_step(&search, &word); + printf("change cmp..."); + cl_search_change_compare_type(&search, CL_COMPARE_EQUAL); + printf("change val..."); + cl_search_change_value_type(&search, CL_MEMTYPE_UINT32); + printf("set target..."); + word = 0; + cl_search_change_target(&search, &word); + printf("done.\n"); + printf("Compare to 0...\n"); + cl_search_step(&search); + word = 1; + cl_search_change_target(&search, &word); + printf("Compare to 1...\n"); cl_write_memory(NULL, 0x20000000, sizeof(word), &word); - cl_search_step(&search, &word); + cl_search_step(&search); + word = 2; + cl_search_change_target(&search, &word); + printf("Compare to 2...\n"); cl_write_memory(NULL, 0x20000000, sizeof(word), &word); - cl_search_step(&search, &word); - printf("Memory search found %lu matches.\n", search.matches); - if (search.matches != 1) + cl_search_step(&search); + + printf("Memory search found %lu matches.\n", search.total_matches); + if (search.total_matches != 1) { printf("Memory search test failed!\n"); return CL_ERR_CLIENT_RUNTIME; diff --git a/cl_types.h b/cl_types.h index 5f19269..946dc31 100644 --- a/cl_types.h +++ b/cl_types.h @@ -31,6 +31,22 @@ typedef enum CL_ERR_SIZE } cl_error; +typedef enum +{ + CL_COMPARE_INVALID = 0, + + CL_COMPARE_EQUAL, + CL_COMPARE_GREATER, + CL_COMPARE_LESS, + CL_COMPARE_NOT_EQUAL, + CL_COMPARE_INCREASED, + CL_COMPARE_DECREASED, + CL_COMPARE_ABOVE, + CL_COMPARE_BELOW, + + CL_COMPARE_SIZE +} cl_compare_type; + /** * A -1 value to represent invalid addresses in memory regions, as 0 for NULL * may be a valid address on some emulated systems. diff --git a/classicslive-integration.mk b/classicslive-integration.mk index b542ada..ff6c7b4 100644 --- a/classicslive-integration.mk +++ b/classicslive-integration.mk @@ -14,7 +14,7 @@ CLASSICS_LIVE_SOURCES_CLASSICSLIVE = \ $(CLASSICS_LIVE_DIR)/cl_memory.c \ $(CLASSICS_LIVE_DIR)/cl_network.c \ $(CLASSICS_LIVE_DIR)/cl_script.c \ - $(CLASSICS_LIVE_DIR)/cl_search.c \ + $(CLASSICS_LIVE_DIR)/cl_search_new.c \ $(CLASSICS_LIVE_DIR)/3rdparty/jsonsax/jsonsax.c \ $(CLASSICS_LIVE_DIR)/3rdparty/jsonsax/jsonsax_full.c \ From 107f44bc27f90d59ad44173fb6c12b2a32329c2b Mon Sep 17 00:00:00 2001 From: Keith Bourdon <33245078+celerizer@users.noreply.github.com> Date: Tue, 16 Dec 2025 19:57:40 -0600 Subject: [PATCH 02/57] standardize types for match count --- cl_search_new.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cl_search_new.h b/cl_search_new.h index 270a365..aabdf54 100644 --- a/cl_search_new.h +++ b/cl_search_new.h @@ -52,7 +52,8 @@ typedef struct /* The number of pages in this page region */ unsigned page_count; - unsigned matches; + /* The total number of matches in this page region */ + cl_addr_t matches; } cl_search_page_region_t; typedef union @@ -119,7 +120,7 @@ typedef struct unsigned total_page_count; /* The total number of matches found in the search */ - unsigned total_matches; + cl_addr_t total_matches; /* The total memory usage of the search, in bytes */ cl_addr_t memory_usage; From cf41f818951663df0739bd86682a073c194fbac1 Mon Sep 17 00:00:00 2001 From: Keith Bourdon <33245078+celerizer@users.noreply.github.com> Date: Tue, 16 Dec 2025 21:29:16 -0600 Subject: [PATCH 03/57] bugfixes, it works now --- cl_search_new.c | 50 +++++++++++++++++++++++++++----------- cl_test.c | 64 ++++++++++++++++++++++++++++++++++++------------- 2 files changed, 84 insertions(+), 30 deletions(-) diff --git a/cl_search_new.c b/cl_search_new.c index ddb4f02..4452b4e 100644 --- a/cl_search_new.c +++ b/cl_search_new.c @@ -86,9 +86,12 @@ static unsigned CL_PASTE3(cl_search_cmp_imm_, b, _##d)( \ const a right = ((cl_search_target_t*)target)->b; \ while (chunk_data_cast < chunk_data_end_cast) \ { \ - match = *chunk_data_cast c right; \ - *chunk_validity = match; \ - matches += match; \ + if (*chunk_validity) \ + { \ + match = *chunk_data_cast c right; \ + *chunk_validity = match; \ + matches += match; \ + } \ chunk_data_cast++; \ chunk_validity++; \ } \ @@ -307,13 +310,12 @@ static cl_error cl_search_profile_memory(cl_search_t *search) for (i = 0; i < search->page_region_count; i++) { - cl_search_page_t *page = search->page_regions->first_page; + cl_search_page_t *page = search->page_regions[i].first_page; while (page) { /* Count the chunks */ - usage += page->size; - usage += page->size / search->params.value_size; + usage += page->size * 2; usage += sizeof(cl_search_page_t); page = page->next; } @@ -486,18 +488,20 @@ static cl_error cl_search_step_first(cl_search_t *search) { page = (cl_search_page_t*)calloc(1, sizeof(cl_search_page_t)); page->chunk = cl_mmap(size * 2); - page->validity = (void*)((unsigned char*)page->chunk + size); + page->validity = (void*)((unsigned char*)page->chunk + CL_SEARCH_CHUNK_SIZE); } + + page->region = page_region->region; + page->start = page_region->region->base_guest + processed; + page->size = size; + cl_read_memory(page->chunk, page->region, page->start - page->region->base_guest, size); + memset(page->validity, 1, size / search->params.value_size); /* Do the search here */ cl_search_step_page(page, search->params, NULL); if (page->matches == 0) { /* This page had no matches, so we will reuse it for the next one */ - page->region = page_region->region; - page->start = page_region->region->base_guest + processed; - page->size = size; - memset(page->validity, 1, size / search->params.value_size); } else { @@ -507,11 +511,16 @@ static cl_error cl_search_step_first(cl_search_t *search) else /* This is another page in this page region's linked list */ prev_page->next = page; + prev_page = page; /* Count up the matches */ page_region->matches += page->matches; search->total_matches += page->matches; + /* Count up the pages */ + page_region->page_count++; + search->total_page_count++; + /* The next page will be allocated */ page = NULL; } @@ -520,7 +529,7 @@ static cl_error cl_search_step_first(cl_search_t *search) } /* If the final page had no matches, delete it */ - if (page->matches == 0) + if (page && page->matches == 0) cl_search_free_page(page); } search->steps = 1; @@ -549,7 +558,11 @@ cl_error cl_search_step(cl_search_t *search) while (page) { - cl_error error = cl_search_step_page(page, search->params, NULL); + cl_error error; + + cl_read_memory(page->chunk, page->region, + page->start - page->region->base_guest, page->size); + error = cl_search_step_page(page, search->params, NULL); if (error != CL_OK) return error; @@ -563,16 +576,25 @@ cl_error cl_search_step(cl_search_t *search) next_page = page->next; cl_search_free_page(page); + page_region->page_count--; + search->total_page_count--; page = next_page; } else { /* Keep this page in the linked list */ + if (!prev_page) + page_region->first_page = page; prev_page = page; - page = page->next; page_region_matches += page->matches; + page = page->next; } } + if (prev_page) + prev_page->next = NULL; + else + page_region->first_page = NULL; + page_region->matches = page_region_matches; total_matches += page_region_matches; } search->total_matches = total_matches; diff --git a/cl_test.c b/cl_test.c index 08c1ae2..999d39a 100644 --- a/cl_test.c +++ b/cl_test.c @@ -8,6 +8,7 @@ #include #include #include +#include #define CL_TEST_DATA_SIZE 128 #define CL_TEST_REGION_COUNT 4 @@ -354,7 +355,7 @@ cl_error cl_test_console_init(void) /* Fill with nonsense */ for (i = 0; i < CL_TEST_REGION_COUNT; i++) for (j = 0; j < cl_test_system.regions[i].size; j++) - ((unsigned char*)cl_test_system.regions[i].base_host)[j] = (j & 0xFF); + ((unsigned char*)cl_test_system.regions[i].base_host)[j] = (j % 4); /* Setup fake game to be identified */ cl_test_system.identifier.type = CL_GAMEIDENTIFIER_FILE_HASH; @@ -385,6 +386,8 @@ cl_error cl_test_console_free(void) static cl_error cl_test(void) { cl_search_t search; + clock_t start, end; + double cpu_time_used; int error; unsigned int word; unsigned char byte; @@ -447,27 +450,54 @@ static cl_error cl_test(void) printf("change cmp..."); cl_search_change_compare_type(&search, CL_COMPARE_EQUAL); printf("change val..."); - cl_search_change_value_type(&search, CL_MEMTYPE_UINT32); - printf("set target..."); - word = 0; - cl_search_change_target(&search, &word); + cl_search_change_value_type(&search, CL_MEMTYPE_UINT8); printf("done.\n"); - printf("Compare to 0...\n"); + + printf("Compare to 0..."); + byte = 0; + memset(cl_test_system.regions[1].base_host, byte, 16); + cl_search_change_target(&search, &byte); + start = clock(); cl_search_step(&search); - - word = 1; - cl_search_change_target(&search, &word); - printf("Compare to 1...\n"); - cl_write_memory(NULL, 0x20000000, sizeof(word), &word); + end = clock(); + cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC; + printf("%lu matches found. %u pages. %lu memory usage. Time: %.6f s\n", + search.total_matches, search.total_page_count, search.memory_usage, cpu_time_used); + + printf("Compare to 1..."); + byte = 1; + memset(cl_test_system.regions[1].base_host, byte, cl_test_system.regions[1].size); + memset(cl_test_system.regions[2].base_host, byte, cl_test_system.regions[2].size); + cl_search_change_target(&search, &byte); + start = clock(); cl_search_step(&search); + end = clock(); + cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC; + printf("%lu matches found. %u pages. %lu memory usage. Time: %.6f s\n", + search.total_matches, search.total_page_count, search.memory_usage, cpu_time_used); - word = 2; - cl_search_change_target(&search, &word); - printf("Compare to 2...\n"); - cl_write_memory(NULL, 0x20000000, sizeof(word), &word); + printf("Compare to 2..."); + byte = 2; + memset(cl_test_system.regions[1].base_host, byte, 1); + cl_search_change_target(&search, &byte); + start = clock(); cl_search_step(&search); + end = clock(); + cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC; + printf("%lu matches found. %u pages. %lu memory usage. Time: %.6f s\n", + search.total_matches, search.total_page_count, search.memory_usage, cpu_time_used); + + printf("Compare to 3..."); + byte = 3; + memset(cl_test_system.regions[1].base_host, byte, 16); + cl_search_change_target(&search, &byte); + start = clock(); + cl_search_step(&search); + end = clock(); + cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC; + printf("%lu matches found. %u pages. %lu memory usage. Time: %.6f s\n", + search.total_matches, search.total_page_count, search.memory_usage, cpu_time_used); - printf("Memory search found %lu matches.\n", search.total_matches); if (search.total_matches != 1) { printf("Memory search test failed!\n"); @@ -475,6 +505,8 @@ static cl_error cl_test(void) } else printf("Memory search test passed!\n"); + + printf("Freeing search...\n"); cl_search_free(&search); /* Run a few frames */ From 3611bde369d26060c9f2f875c5f6c3d4ccd70758 Mon Sep 17 00:00:00 2001 From: Keith Bourdon <33245078+celerizer@users.noreply.github.com> Date: Tue, 16 Dec 2025 22:00:58 -0600 Subject: [PATCH 04/57] add search backup value --- cl_search_new.c | 43 +++++++++++++++++++++++++++++++++++++++++-- cl_search_new.h | 4 ++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/cl_search_new.c b/cl_search_new.c index 4452b4e..6367483 100644 --- a/cl_search_new.c +++ b/cl_search_new.c @@ -23,10 +23,10 @@ * The granularity of data to keep in memory as search results. * The total allocation per chunk is twice this size, as the validity bitmap * is stored alongside the data itself. - * 128KB was decided upon as 256KB is a common L2 cache size. + * This value was decided on by guessing to see which was most performant. :B * @todo Make configurable? */ -#define CL_SEARCH_CHUNK_SIZE CL_KB(128) +#define CL_SEARCH_CHUNK_SIZE CL_MB(4) /** * Allocate a chunk of page-aligned memory. @@ -603,3 +603,42 @@ cl_error cl_search_step(cl_search_t *search) return cl_search_profile_memory(search); } } + +cl_error cl_search_backup_value(void *dst, const cl_search_t *search, + cl_addr_t address) +{ + cl_search_page_region_t *page_region; + cl_search_page_t *page; + unsigned i; + +#if 0 /* this is already too slow */ + if (!search || !dst) + return CL_ERR_PARAMETER_NULL; +#endif + + for (i = 0; i < search->page_region_count; i++) + { + page_region = &search->page_regions[i]; + + /* Is it in this region? */ + if (address < page_region->region->base_guest || + address >= page_region->region->base_guest + page_region->region->size) + continue; + + page = page_region->first_page; + + while (page) + { + /* Is it in this page? */ + if (address >= page->start && address < page->start + page->size) + { + cl_addr_t offset = address - page->start; + memcpy(dst, (unsigned char*)page->chunk + offset, search->params.value_size); + return CL_OK; + } + page = page->next; + } + } + + return CL_ERR_PARAMETER_INVALID; +} diff --git a/cl_search_new.h b/cl_search_new.h index aabdf54..94c3d88 100644 --- a/cl_search_new.h +++ b/cl_search_new.h @@ -150,6 +150,10 @@ cl_error cl_search_change_value_type(cl_search_t *search, cl_value_type type); */ cl_error cl_search_change_target(cl_search_t *search, const void *value); +/** + * Initializes a memory search structure. + * @param search A pointer to the search to initialize + */ cl_error cl_search_init(cl_search_t *search); /** From c115d6b359eee1b316097171a99df783b42053c8 Mon Sep 17 00:00:00 2001 From: celerizer Date: Tue, 16 Dec 2025 22:10:01 -0600 Subject: [PATCH 05/57] get more performance by not branching --- cl_search_new.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/cl_search_new.c b/cl_search_new.c index 6367483..84e9149 100644 --- a/cl_search_new.c +++ b/cl_search_new.c @@ -86,12 +86,9 @@ static unsigned CL_PASTE3(cl_search_cmp_imm_, b, _##d)( \ const a right = ((cl_search_target_t*)target)->b; \ while (chunk_data_cast < chunk_data_end_cast) \ { \ - if (*chunk_validity) \ - { \ - match = *chunk_data_cast c right; \ - *chunk_validity = match; \ - matches += match; \ - } \ + match = (*chunk_data_cast c right) & *chunk_validity; \ + *chunk_validity = match; \ + matches += match; \ chunk_data_cast++; \ chunk_validity++; \ } \ From 7d9a65de6758cd14fe7e0d2e44be63451ad41543 Mon Sep 17 00:00:00 2001 From: celerizer Date: Tue, 16 Dec 2025 22:53:32 -0600 Subject: [PATCH 06/57] misc warning cleanup --- 3rdparty/jsonsax/jsonsax.c | 402 +++++++++++++++++++------------------ cl_script.c | 6 +- cl_search_new.c | 12 +- cl_test.c | 6 +- cl_types.h | 2 + 5 files changed, 222 insertions(+), 206 deletions(-) diff --git a/3rdparty/jsonsax/jsonsax.c b/3rdparty/jsonsax/jsonsax.c index 17d956c..888ec26 100644 --- a/3rdparty/jsonsax/jsonsax.c +++ b/3rdparty/jsonsax/jsonsax.c @@ -28,269 +28,283 @@ #include "jsonsax.h" #ifdef JSONSAX_ERRORS -const char* jsonsax_errors[] = -{ - "Ok", - "Interrupted", - "Missing key", - "Unterminated key", - "Missing value", - "Unterminated object", - "Unterminated array", - "Unterminated string", - "Invalid value" -}; +const char *jsonsax_errors[] = + { + "Ok", + "Interrupted", + "Missing key", + "Unterminated key", + "Missing value", + "Unterminated object", + "Unterminated array", + "Unterminated string", + "Invalid value"}; #endif typedef struct { - const jsonsax_handlers_t* handlers; + const jsonsax_handlers_t *handlers; - const char* json; - void* ud; - jmp_buf env; -} -state_t; + const char *json; + void *ud; + jmp_buf env; +} state_t; -static INLINE void skip_spaces( state_t* state ) +static INLINE void skip_spaces(state_t *state) { - while ( isspace( (unsigned char)*state->json ) ) + while (isspace((unsigned char)*state->json)) state->json++; } -static INLINE void skip_digits( state_t* state ) +static INLINE void skip_digits(state_t *state) { - while ( isdigit( (unsigned char)*state->json ) ) + while (isdigit((unsigned char)*state->json)) state->json++; } -#define HANDLE_0( event ) \ - do { \ - if ( state->handlers->event && state->handlers->event( state->ud ) ) \ - longjmp( state->env, JSONSAX_INTERRUPTED ); \ - } while ( 0 ) - -#define HANDLE_1( event, arg1 ) \ - do { \ - if ( state->handlers->event && state->handlers->event( state->ud, arg1 ) ) \ - longjmp( state->env, JSONSAX_INTERRUPTED ); \ - } while ( 0 ) - -#define HANDLE_2( event, arg1, arg2 ) \ - do { \ - if ( state->handlers->event && state->handlers->event( state->ud, arg1, arg2 ) ) \ - longjmp( state->env, JSONSAX_INTERRUPTED ); \ - } while ( 0 ) - -static void jsonx_parse_value(state_t* state); - -static void jsonx_parse_object( state_t* state ) +#define HANDLE_0(event) \ + do \ + { \ + if (state->handlers->event && state->handlers->event(state->ud)) \ + longjmp(state->env, JSONSAX_INTERRUPTED); \ + } while (0) + +#define HANDLE_1(event, arg1) \ + do \ + { \ + if (state->handlers->event && state->handlers->event(state->ud, arg1)) \ + longjmp(state->env, JSONSAX_INTERRUPTED); \ + } while (0) + +#define HANDLE_2(event, arg1, arg2) \ + do \ + { \ + if (state->handlers->event && state->handlers->event(state->ud, arg1, arg2)) \ + longjmp(state->env, JSONSAX_INTERRUPTED); \ + } while (0) + +static void jsonx_parse_value(state_t *state); + +static void jsonx_parse_object(state_t *state) { - state->json++; /* we're sure the current character is a '{' */ - skip_spaces( state ); - HANDLE_0( start_object ); + state->json++; /* we're sure the current character is a '{' */ + skip_spaces(state); + HANDLE_0(start_object); - while ( *state->json != '}' ) - { - const char *name = NULL; - if ( *state->json != '"' ) - longjmp( state->env, JSONSAX_MISSING_KEY ); + while (*state->json != '}') + { + const char *name = NULL; + ptrdiff_t diff; + if (*state->json != '"') + longjmp(state->env, JSONSAX_MISSING_KEY); - name = ++state->json; + name = ++state->json; - for ( ;; ) - { - const char* quote = strchr( state->json, '"' ); + for (;;) + { + const char *quote = strchr(state->json, '"'); - if ( !quote ) - longjmp( state->env, JSONSAX_UNTERMINATED_KEY ); + if (!quote) + longjmp(state->env, JSONSAX_UNTERMINATED_KEY); - state->json = quote + 1; + state->json = quote + 1; - if ( quote[ -1 ] != '\\' ) - break; - } + if (quote[-1] != '\\') + break; + } - HANDLE_2( key, name, state->json - name - 1 ); - skip_spaces( state ); + diff = state->json - name - 1; + if (diff < 0) + longjmp(state->env, JSONSAX_UNTERMINATED_KEY); - if ( *state->json != ':' ) - longjmp( state->env, JSONSAX_MISSING_VALUE ); + HANDLE_2(key, name, (size_t)diff); + skip_spaces(state); - state->json++; - skip_spaces( state ); - jsonx_parse_value( state ); - skip_spaces( state ); + if (*state->json != ':') + longjmp(state->env, JSONSAX_MISSING_VALUE); - if ( *state->json != ',' ) - break; + state->json++; + skip_spaces(state); + jsonx_parse_value(state); + skip_spaces(state); - state->json++; - skip_spaces( state ); - } + if (*state->json != ',') + break; - if ( *state->json != '}' ) - longjmp( state->env, JSONSAX_UNTERMINATED_OBJECT ); + state->json++; + skip_spaces(state); + } - state->json++; - HANDLE_0( end_object ); + if (*state->json != '}') + longjmp(state->env, JSONSAX_UNTERMINATED_OBJECT); + + state->json++; + HANDLE_0(end_object); } -static void jsonx_parse_array(state_t* state) +static void jsonx_parse_array(state_t *state) { - unsigned int ndx = 0; + unsigned int ndx = 0; - state->json++; /* we're sure the current character is a '[' */ - skip_spaces( state ); - HANDLE_0( start_array ); + state->json++; /* we're sure the current character is a '[' */ + skip_spaces(state); + HANDLE_0(start_array); - while ( *state->json != ']' ) - { - HANDLE_1( array_index, ndx++ ); - jsonx_parse_value( state ); - skip_spaces( state ); + while (*state->json != ']') + { + HANDLE_1(array_index, ndx++); + jsonx_parse_value(state); + skip_spaces(state); - if ( *state->json != ',' ) - break; + if (*state->json != ',') + break; - state->json++; - skip_spaces( state ); - } + state->json++; + skip_spaces(state); + } - if ( *state->json != ']' ) - longjmp( state->env, JSONSAX_UNTERMINATED_ARRAY ); + if (*state->json != ']') + longjmp(state->env, JSONSAX_UNTERMINATED_ARRAY); - state->json++; - HANDLE_0( end_array ); + state->json++; + HANDLE_0(end_array); } -static void jsonx_parse_string(state_t* state) +static void jsonx_parse_string(state_t *state) { - const char* string = ++state->json; + ptrdiff_t diff; + const char *string = ++state->json; - for ( ;; ) + for (;;) { - const char* quote = strchr( state->json, '"' ); + const char *quote = strchr(state->json, '"'); - if ( !quote ) - longjmp( state->env, JSONSAX_UNTERMINATED_STRING ); + if (!quote) + longjmp(state->env, JSONSAX_UNTERMINATED_STRING); state->json = quote + 1; - if ( quote[ -1 ] != '\\' ) + if (quote[-1] != '\\') break; } - HANDLE_2( string, string, state->json - string - 1 ); + diff = state->json - string - 1; + if (diff < 0) + longjmp(state->env, JSONSAX_UNTERMINATED_STRING); + HANDLE_2(string, string, (size_t)diff); } -static void jsonx_parse_boolean(state_t* state) +static void jsonx_parse_boolean(state_t *state) { - if ( !strncmp( state->json, "true", 4 ) ) - { - state->json += 4; - HANDLE_1( boolean, 1 ); - } - else if ( !strncmp( state->json, "false", 5 ) ) - { - state->json += 5; - HANDLE_1( boolean, 0 ); - } - else - longjmp( state->env, JSONSAX_INVALID_VALUE ); + if (!strncmp(state->json, "true", 4)) + { + state->json += 4; + HANDLE_1(boolean, 1); + } + else if (!strncmp(state->json, "false", 5)) + { + state->json += 5; + HANDLE_1(boolean, 0); + } + else + longjmp(state->env, JSONSAX_INVALID_VALUE); } -static void jsonx_parse_null(state_t* state) +static void jsonx_parse_null(state_t *state) { - if ( !strncmp( state->json + 1, "ull", 3 ) ) /* we're sure the current character is a 'n' */ - { - state->json += 4; - HANDLE_0( null ); - } - else - longjmp( state->env, JSONSAX_INVALID_VALUE ); + if (!strncmp(state->json + 1, "ull", 3)) /* we're sure the current character is a 'n' */ + { + state->json += 4; + HANDLE_0(null); + } + else + longjmp(state->env, JSONSAX_INVALID_VALUE); } -static void jsonx_parse_number(state_t* state) +static void jsonx_parse_number(state_t *state) { - const char* number = state->json; + ptrdiff_t diff; + const char *number = state->json; - if ( *state->json == '-' ) - state->json++; + if (*state->json == '-') + state->json++; - if ( !isdigit( (unsigned char)*state->json ) ) - longjmp( state->env, JSONSAX_INVALID_VALUE ); + if (!isdigit((unsigned char)*state->json)) + longjmp(state->env, JSONSAX_INVALID_VALUE); - skip_digits( state ); + skip_digits(state); - if ( *state->json == '.' ) - { - state->json++; + if (*state->json == '.') + { + state->json++; - if ( !isdigit( (unsigned char)*state->json ) ) - longjmp( state->env, JSONSAX_INVALID_VALUE ); + if (!isdigit((unsigned char)*state->json)) + longjmp(state->env, JSONSAX_INVALID_VALUE); - skip_digits( state ); - } + skip_digits(state); + } - if ( *state->json == 'e' || *state->json == 'E' ) - { - state->json++; + if (*state->json == 'e' || *state->json == 'E') + { + state->json++; - if ( *state->json == '-' || *state->json == '+' ) - state->json++; + if (*state->json == '-' || *state->json == '+') + state->json++; - if ( !isdigit( (unsigned char)*state->json ) ) - longjmp( state->env, JSONSAX_INVALID_VALUE ); + if (!isdigit((unsigned char)*state->json)) + longjmp(state->env, JSONSAX_INVALID_VALUE); - skip_digits( state ); - } + skip_digits(state); + } - HANDLE_2( number, number, state->json - number ); + diff = state->json - number; + if (diff < 0) + longjmp(state->env, JSONSAX_INVALID_VALUE); + HANDLE_2(number, number, (size_t)diff); } -static void jsonx_parse_value(state_t* state) +static void jsonx_parse_value(state_t *state) { - skip_spaces( state ); - - switch ( *state->json ) - { - case '{': - jsonx_parse_object(state); - break; - case '[': - jsonx_parse_array( state ); - break; - case '"': - jsonx_parse_string( state ); - break; - case 't': - case 'f': - jsonx_parse_boolean( state ); - break; - case 'n': - jsonx_parse_null( state ); - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '-': - jsonx_parse_number( state ); - break; - - default: - longjmp( state->env, JSONSAX_INVALID_VALUE ); - } + skip_spaces(state); + + switch (*state->json) + { + case '{': + jsonx_parse_object(state); + break; + case '[': + jsonx_parse_array(state); + break; + case '"': + jsonx_parse_string(state); + break; + case 't': + case 'f': + jsonx_parse_boolean(state); + break; + case 'n': + jsonx_parse_null(state); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + jsonx_parse_number(state); + break; + + default: + longjmp(state->env, JSONSAX_INVALID_VALUE); + } } -int jsonsax_parse( const char* json, const jsonsax_handlers_t* handlers, void* userdata ) +int jsonsax_parse(const char *json, const jsonsax_handlers_t *handlers, void *userdata) { state_t state; int res; @@ -299,15 +313,15 @@ int jsonsax_parse( const char* json, const jsonsax_handlers_t* handlers, void* u state.handlers = handlers; state.ud = userdata; - if ( ( res = setjmp( state.env ) ) == 0 ) + if ((res = setjmp(state.env)) == 0) { - if ( handlers->start_document ) - handlers->start_document( userdata ); + if (handlers->start_document) + handlers->start_document(userdata); jsonx_parse_value(&state); - if ( handlers->end_document ) - handlers->end_document( userdata ); + if (handlers->end_document) + handlers->end_document(userdata); res = JSONSAX_OK; } diff --git a/cl_script.c b/cl_script.c index 765d902..60360ff 100644 --- a/cl_script.c +++ b/cl_script.c @@ -7,7 +7,7 @@ cl_script_t script; -void cl_page_free(cl_page_t *page) +static void cl_page_free(cl_page_t *page) { unsigned i; @@ -31,7 +31,7 @@ void cl_script_free(void) script.page_count = 0; } -bool cl_init_page(const char **pos, cl_page_t *page) +static bool cl_init_page(const char **pos, cl_page_t *page) { cl_action_t *action = NULL; cl_action_t *prev_action = NULL; @@ -145,7 +145,7 @@ static unsigned cl_process_if_statements(cl_page_t *page, unsigned pos) return i; } -bool cl_process_actions(cl_page_t *page) +static bool cl_process_actions(cl_page_t *page) { bool success = true; unsigned i = 0; diff --git a/cl_search_new.c b/cl_search_new.c index 84e9149..65336c0 100644 --- a/cl_search_new.c +++ b/cl_search_new.c @@ -51,19 +51,19 @@ static void *cl_mmap(size_t size) /** * Free a chunk of page-aligned memory. - * @param memory The pointer to free + * @param p The pointer to free * @param size The number of bytes to deallocate */ -static void cl_munmap(void *memory, size_t size) +static void cl_munmap(void *p, size_t size) { #if CL_HOST_PLATFORM == CL_PLATFORM_LINUX - munmap(memory, size); + munmap(p, size); #elif CL_HOST_PLATFORM == CL_PLATFORM_WINDOWS CL_UNUSED(size); - VirtualFree(memory, 0, MEM_RELEASE); + VirtualFree(p, 0, MEM_RELEASE); #else CL_UNUSED(size); - free(memory); + free(p); #endif } @@ -109,7 +109,7 @@ static unsigned CL_PASTE3(cl_search_cmp_prv_, b, _##d)( \ const a *chunk_data_prev_cast = (const a*)chunk_data_prev; \ while (chunk_data_cast < chunk_data_end_cast) \ { \ - match = *chunk_data_cast c *chunk_data_prev_cast; \ + match = (*chunk_data_cast c *chunk_data_prev_cast) & *chunk_validity; \ *chunk_validity = match; \ matches += match; \ chunk_data_cast++; \ diff --git a/cl_test.c b/cl_test.c index 999d39a..968277d 100644 --- a/cl_test.c +++ b/cl_test.c @@ -248,7 +248,7 @@ static cl_error cl_test_external_read(void *dest, cl_addr_t address, #endif } -cl_error cl_test_external_write(const void *src, cl_addr_t address, +static cl_error cl_test_external_write(const void *src, cl_addr_t address, unsigned size, unsigned *written) { snprintf(cl_test_msg, sizeof(cl_test_msg), @@ -310,7 +310,7 @@ static const cl_abi_t cl_test_abi = } }; -cl_error cl_test_console_init(void) +static cl_error cl_test_console_init(void) { static const unsigned region_size = CL_MB(16); unsigned i, j; @@ -370,7 +370,7 @@ cl_error cl_test_console_init(void) return CL_OK; } -cl_error cl_test_console_free(void) +static cl_error cl_test_console_free(void) { unsigned i; diff --git a/cl_types.h b/cl_types.h index 946dc31..2ef92d7 100644 --- a/cl_types.h +++ b/cl_types.h @@ -1,6 +1,8 @@ #ifndef CL_TYPES_H #define CL_TYPES_H +#include "cl_config.h" + #include #include #include From fbd4f52ba2a5b52f476909e0e7b7587c99d9f35f Mon Sep 17 00:00:00 2001 From: Keith Bourdon <33245078+celerizer@users.noreply.github.com> Date: Wed, 17 Dec 2025 06:05:25 -0600 Subject: [PATCH 07/57] use less memory in bitmap for val_size > 1 --- cl_search_new.c | 15 ++++++++------- cl_test.c | 33 ++++++++++++++++++--------------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/cl_search_new.c b/cl_search_new.c index 65336c0..bba2f0f 100644 --- a/cl_search_new.c +++ b/cl_search_new.c @@ -312,7 +312,7 @@ static cl_error cl_search_profile_memory(cl_search_t *search) while (page) { /* Count the chunks */ - usage += page->size * 2; + usage += page->size + page->size / search->params.value_size; usage += sizeof(cl_search_page_t); page = page->next; } @@ -390,11 +390,12 @@ cl_error cl_search_change_target(cl_search_t *search, const void *value) return CL_OK; } -static cl_error cl_search_free_page(cl_search_page_t *page) +static cl_error cl_search_free_page(const cl_search_t *search, + cl_search_page_t *page) { if (page) { - cl_munmap(page->chunk, page->size * 2); + cl_munmap(page->chunk, page->size + page->size / search->params.value_size); free(page); return CL_OK; @@ -419,7 +420,7 @@ cl_error cl_search_free(cl_search_t *search) while (page) { next_page = page->next; - cl_search_free_page(page); + cl_search_free_page(search, page); page = next_page; } } @@ -484,7 +485,7 @@ static cl_error cl_search_step_first(cl_search_t *search) if (!page) { page = (cl_search_page_t*)calloc(1, sizeof(cl_search_page_t)); - page->chunk = cl_mmap(size * 2); + page->chunk = cl_mmap(size + size / search->params.value_size); page->validity = (void*)((unsigned char*)page->chunk + CL_SEARCH_CHUNK_SIZE); } @@ -527,7 +528,7 @@ static cl_error cl_search_step_first(cl_search_t *search) /* If the final page had no matches, delete it */ if (page && page->matches == 0) - cl_search_free_page(page); + cl_search_free_page(search, page); } search->steps = 1; @@ -572,7 +573,7 @@ cl_error cl_search_step(cl_search_t *search) page_region->first_page = page->next; next_page = page->next; - cl_search_free_page(page); + cl_search_free_page(search, page); page_region->page_count--; search->total_page_count--; page = next_page; diff --git a/cl_test.c b/cl_test.c index 968277d..15974aa 100644 --- a/cl_test.c +++ b/cl_test.c @@ -355,7 +355,7 @@ static cl_error cl_test_console_init(void) /* Fill with nonsense */ for (i = 0; i < CL_TEST_REGION_COUNT; i++) for (j = 0; j < cl_test_system.regions[i].size; j++) - ((unsigned char*)cl_test_system.regions[i].base_host)[j] = (j % 4); + ((unsigned char*)cl_test_system.regions[i].base_host)[j] = ((j & 0x0C) >> 2); /* Setup fake game to be identified */ cl_test_system.identifier.type = CL_GAMEIDENTIFIER_FILE_HASH; @@ -450,13 +450,13 @@ static cl_error cl_test(void) printf("change cmp..."); cl_search_change_compare_type(&search, CL_COMPARE_EQUAL); printf("change val..."); - cl_search_change_value_type(&search, CL_MEMTYPE_UINT8); + cl_search_change_value_type(&search, CL_MEMTYPE_UINT32); printf("done.\n"); printf("Compare to 0..."); - byte = 0; - memset(cl_test_system.regions[1].base_host, byte, 16); - cl_search_change_target(&search, &byte); + word = 0; + memset(cl_test_system.regions[1].base_host, word, 16); + cl_search_change_target(&search, &word); start = clock(); cl_search_step(&search); end = clock(); @@ -465,10 +465,12 @@ static cl_error cl_test(void) search.total_matches, search.total_page_count, search.memory_usage, cpu_time_used); printf("Compare to 1..."); - byte = 1; - memset(cl_test_system.regions[1].base_host, byte, cl_test_system.regions[1].size); - memset(cl_test_system.regions[2].base_host, byte, cl_test_system.regions[2].size); - cl_search_change_target(&search, &byte); + word = 1; + for (i = 0; i < cl_test_system.regions[1].size; i += 4) + ((unsigned*)cl_test_system.regions[1].base_host)[i / 4] = word; + for (i = 0; i < cl_test_system.regions[2].size; i += 4) + ((unsigned*)cl_test_system.regions[2].base_host)[i / 4] = word; + cl_search_change_target(&search, &word); start = clock(); cl_search_step(&search); end = clock(); @@ -477,9 +479,9 @@ static cl_error cl_test(void) search.total_matches, search.total_page_count, search.memory_usage, cpu_time_used); printf("Compare to 2..."); - byte = 2; - memset(cl_test_system.regions[1].base_host, byte, 1); - cl_search_change_target(&search, &byte); + word = 2; + ((unsigned*)cl_test_system.regions[1].base_host)[0] = word; + cl_search_change_target(&search, &word); start = clock(); cl_search_step(&search); end = clock(); @@ -488,9 +490,10 @@ static cl_error cl_test(void) search.total_matches, search.total_page_count, search.memory_usage, cpu_time_used); printf("Compare to 3..."); - byte = 3; - memset(cl_test_system.regions[1].base_host, byte, 16); - cl_search_change_target(&search, &byte); + word = 3; + for (i = 0; i < 16; i += 4) + ((unsigned*)cl_test_system.regions[1].base_host)[i / 4] = word; + cl_search_change_target(&search, &word); start = clock(); cl_search_step(&search); end = clock(); From 25752be2edf9c21cbc8e23ab30b23b83c2b95db6 Mon Sep 17 00:00:00 2001 From: Keith Bourdon <33245078+celerizer@users.noreply.github.com> Date: Wed, 17 Dec 2025 06:07:50 -0600 Subject: [PATCH 08/57] probably a bug if chunk < default chunk size --- cl_search_new.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cl_search_new.c b/cl_search_new.c index bba2f0f..ffe1861 100644 --- a/cl_search_new.c +++ b/cl_search_new.c @@ -486,7 +486,7 @@ static cl_error cl_search_step_first(cl_search_t *search) { page = (cl_search_page_t*)calloc(1, sizeof(cl_search_page_t)); page->chunk = cl_mmap(size + size / search->params.value_size); - page->validity = (void*)((unsigned char*)page->chunk + CL_SEARCH_CHUNK_SIZE); + page->validity = (void*)((unsigned char*)page->chunk + size); } page->region = page_region->region; From 5e594aef8053c9f23845d6b204e034e8cd688147 Mon Sep 17 00:00:00 2001 From: Keith Bourdon <33245078+celerizer@users.noreply.github.com> Date: Wed, 17 Dec 2025 06:18:40 -0600 Subject: [PATCH 09/57] initial support for external process read bucket --- cl_search_new.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/cl_search_new.c b/cl_search_new.c index ffe1861..ea11e85 100644 --- a/cl_search_new.c +++ b/cl_search_new.c @@ -543,9 +543,20 @@ cl_error cl_search_step(cl_search_t *search) return cl_search_step_first(search); else { +#if CL_EXTERNAL_MEMORY + void *bucket = NULL; + cl_addr_t bucket_offset = 0; + cl_addr_t bucket_processed = 0; +#endif cl_addr_t total_matches = 0; unsigned i; +#if CL_EXTERNAL_MEMORY + bucket = cl_mmap(CL_SEARCH_BUCKET_SIZE); + if (!bucket) + return CL_ERR_CLIENT_RUNTIME; +#endif + for (i = 0; i < search->page_region_count; i++) { cl_search_page_region_t *page_region = &search->page_regions[i]; @@ -554,6 +565,12 @@ cl_error cl_search_step(cl_search_t *search) cl_search_page_t *next_page = NULL; cl_addr_t page_region_matches = 0; +#if CL_EXTERNAL_MEMORY + cl_read_memory(bucket, page_region->region, bucket_offset, + page_region->region->size < CL_SEARCH_BUCKET_SIZE ? + page_region->region->size : CL_SEARCH_BUCKET_SIZE); +#endif + while (page) { cl_error error; @@ -587,6 +604,19 @@ cl_error cl_search_step(cl_search_t *search) page_region_matches += page->matches; page = page->next; } + +#if CL_EXTERNAL_MEMORY + /* Move the bucket forward */ + bucket_processed += page->size; + if (bucket_processed >= CL_SEARCH_BUCKET_SIZE) + { + bucket_offset += CL_SEARCH_BUCKET_SIZE; + bucket_processed = 0; + cl_read_memory(bucket, page_region->region, bucket_offset, + page_region->region->size - bucket_processed < CL_SEARCH_BUCKET_SIZE ? + page_region->region->size - bucket_offset : CL_SEARCH_BUCKET_SIZE); + } +#endif } if (prev_page) prev_page->next = NULL; @@ -597,6 +627,9 @@ cl_error cl_search_step(cl_search_t *search) } search->total_matches = total_matches; search->steps++; +#if CL_EXTERNAL_MEMORY + cl_munmap(bucket, CL_SEARCH_BUCKET_SIZE); +#endif return cl_search_profile_memory(search); } From c3801be305947a2d06faec3f469718060a4c8a72 Mon Sep 17 00:00:00 2001 From: Keith Bourdon <33245078+celerizer@users.noreply.github.com> Date: Wed, 17 Dec 2025 15:11:27 -0600 Subject: [PATCH 10/57] style, only get funcptr once per search --- cl_search_new.c | 40 ++++++++++++++++++++++++++-------------- cl_search_new.h | 3 ++- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/cl_search_new.c b/cl_search_new.c index ea11e85..48bea59 100644 --- a/cl_search_new.c +++ b/cl_search_new.c @@ -67,8 +67,6 @@ static void cl_munmap(void *p, size_t size) #endif } -/** @todo is it faster to split comparison and match totaling into two or not? */ - #define CL_PASTE2(a, b) a##b #define CL_PASTE3(a, b, c) a##b##c @@ -283,23 +281,25 @@ static cl_search_compare_func_t cl_search_comparison_function(cl_search_paramete /** * Runs a comparison function on the values in a search page. * @param page - * @todo the function should be found in search_step */ -static cl_error cl_search_step_page(cl_search_page_t *page, const cl_search_parameters_t params, +static cl_error cl_search_step_page(cl_search_page_t *page, + const cl_search_parameters_t params, cl_search_compare_func_t function, const void *prev_buffer) { - cl_search_compare_func_t comparison_function = cl_search_comparison_function(params); const void *end = (((unsigned char*)page->chunk) + page->size); - if (!comparison_function) + if (!function) return CL_ERR_PARAMETER_INVALID; - page->matches = comparison_function(page->chunk, end, - page->validity, + page->matches = function(page->chunk, end, page->validity, params.compare_to_previous ? prev_buffer : ¶ms.target); return CL_OK; } +/** + * Steps through the linked list to count up the total memory usage of a + * search, storing the result in `search->memory_usage` as bytes. + */ static cl_error cl_search_profile_memory(cl_search_t *search) { cl_addr_t usage = 0; @@ -410,8 +410,7 @@ cl_error cl_search_free(cl_search_t *search) if (!search) return CL_ERR_PARAMETER_NULL; - - for (i = 0; i < search->page_region_count; i++) + else for (i = 0; i < search->page_region_count; i++) { cl_search_page_region_t *page_region = &search->page_regions[i]; cl_search_page_t *page = page_region->first_page; @@ -424,7 +423,6 @@ cl_error cl_search_free(cl_search_t *search) page = next_page; } } - free(search->page_regions); memset(search, 0, sizeof(cl_search_t)); @@ -465,9 +463,12 @@ cl_error cl_search_init(cl_search_t *search) */ static cl_error cl_search_step_first(cl_search_t *search) { + cl_search_compare_func_t function = cl_search_comparison_function(search->params); unsigned i; - for (i = 0; i < search->page_region_count; i++) + if (!function) + return CL_ERR_PARAMETER_INVALID; + else for (i = 0; i < search->page_region_count; i++) { cl_search_page_region_t *page_region = &search->page_regions[i]; cl_search_page_t *page = NULL; @@ -496,7 +497,7 @@ static cl_error cl_search_step_first(cl_search_t *search) memset(page->validity, 1, size / search->params.value_size); /* Do the search here */ - cl_search_step_page(page, search->params, NULL); + cl_search_step_page(page, search->params, function, NULL); if (page->matches == 0) { /* This page had no matches, so we will reuse it for the next one */ @@ -548,9 +549,14 @@ cl_error cl_search_step(cl_search_t *search) cl_addr_t bucket_offset = 0; cl_addr_t bucket_processed = 0; #endif + cl_search_compare_func_t function; cl_addr_t total_matches = 0; unsigned i; + function = cl_search_comparison_function(search->params); + if (!function) + return CL_ERR_PARAMETER_INVALID; + #if CL_EXTERNAL_MEMORY bucket = cl_mmap(CL_SEARCH_BUCKET_SIZE); if (!bucket) @@ -575,9 +581,15 @@ cl_error cl_search_step(cl_search_t *search) { cl_error error; +#if CL_EXTERNAL_MEMORY + memcpy(page->chunk, + (unsigned char*)bucket + bucket_processed, + page->size); +#else cl_read_memory(page->chunk, page->region, page->start - page->region->base_guest, page->size); - error = cl_search_step_page(page, search->params, NULL); +#endif + error = cl_search_step_page(page, search->params, function, NULL); if (error != CL_OK) return error; diff --git a/cl_search_new.h b/cl_search_new.h index 94c3d88..6c477cf 100644 --- a/cl_search_new.h +++ b/cl_search_new.h @@ -26,10 +26,11 @@ struct cl_search_page_t cl_addr_t end; /** - * The size, in bytes, of the memory chunks. Should typically be + * The size, in bytes, of the data in the memory chunk. Should typically be * `CL_SEARCH_CHUNK_SIZE` except if the target region has memory smaller * than that or if it's the last chunk in a region that can't be divided * equally. + * The chunk size should be `size + size / search->params.value_size`. */ cl_addr_t size; From 35a41f881ce5c2ebf53bdd6c45047bd1cddd8dfb Mon Sep 17 00:00:00 2001 From: Keith Bourdon <33245078+celerizer@users.noreply.github.com> Date: Wed, 17 Dec 2025 20:37:00 -0600 Subject: [PATCH 11/57] remove the old search --- cl_search.c | 370 ++++------------------------------------------------ cl_search.h | 43 ------ 2 files changed, 25 insertions(+), 388 deletions(-) diff --git a/cl_search.c b/cl_search.c index f83e0a6..ef9d24d 100644 --- a/cl_search.c +++ b/cl_search.c @@ -7,197 +7,19 @@ #include #include -cl_searchbank_t* cl_searchbank_from_address(cl_search_t *search, - cl_addr_t address) -{ - if (!search) - return NULL; - else - { - cl_searchbank_t *sbank; - uint8_t i; - - for (i = 0; i < search->searchbank_count; i++) - { - sbank = &search->searchbanks[i]; - if (sbank->region->base_guest <= address && - sbank->region->base_guest + sbank->region->size > address) - return sbank; - } - - return NULL; - } -} - -#if CL_EXTERNAL_MEMORY -cl_error cl_search_deep_copy(cl_search_t *search) -{ - unsigned i; - - if (!search) - return CL_ERR_PARAMETER_NULL; - else for (i = 0; i < search->searchbank_count; i++) - { - cl_searchbank_t *sbank = &search->searchbanks[i]; - - if (!sbank->region->base_host) - continue; - else - cl_abi_external_read(sbank->region->base_host + sbank->first_valid, - sbank->region->base_guest + sbank->first_valid, - sbank->last_valid - sbank->first_valid + search->params.size, - NULL - ); - } - - return CL_OK; -} -#endif - -bool cl_search_free(cl_search_t *search) -{ - if (!search) - return false; - else - { - uint8_t i; - - for (i = 0; i < search->searchbank_count; i++) - { - free(search->searchbanks[i].backup); - free(search->searchbanks[i].valid); -#if CL_EXTERNAL_MEMORY - free(search->searchbanks[i].region->base_host); -#endif - } - free(search->searchbanks); - - return true; - } -} - -bool cl_search_init(cl_search_t *search) -{ - if (!memory.region_count) - return false; - else - { - uint8_t i; - - cl_log("Initializing a new search...\n"); - search->matches = 0; - search->searchbank_count = memory.region_count; - search->searchbanks = (cl_searchbank_t*)calloc(search->searchbank_count, sizeof(cl_searchbank_t)); - - search->params.compare_type = CLE_CMPTYPE_EQUAL; - search->params.size = 1; - search->params.value_type = CL_MEMTYPE_UINT8; - - for (i = 0; i < search->searchbank_count; i++) - { - cl_searchbank_t *sbank = &search->searchbanks[i]; - - sbank->any_valid = true; - sbank->region = &memory.regions[i]; -#if CL_EXTERNAL_MEMORY - sbank->region->base_host = malloc(memory.regions[i].size); -#endif - sbank->backup = (uint8_t*)malloc(memory.regions[i].size); - sbank->valid = (uint8_t*)malloc(memory.regions[i].size); - } - cl_search_reset(search); - } - - return true; -} - -bool cl_read_search(uint32_t *value, cl_search_t *search, cl_searchbank_t *sbank, cl_addr_t address) -{ - if (!sbank) - { - if (memory.region_count == 0) - return false; - else if (memory.region_count == 1) - { - sbank = &search->searchbanks[0]; - address -= sbank->region->base_guest; - } - else - { - unsigned i; - - for (i = 0; i < memory.region_count; i++) - { - if (address >= memory.regions[i].base_guest && - address < memory.regions[i].base_guest + memory.regions[i].size) - { - sbank = &search->searchbanks[i]; - address -= sbank->region->base_guest; - } - } - } - } - if (sbank->backup) - return cl_read(value, sbank->backup, address, search->params.size, sbank->region->endianness); - - return false; -} - -bool cl_search_remove(cl_search_t *search, cl_addr_t address) -{ - cl_searchbank_t *sbank = cl_searchbank_from_address(search, address); - - if (!sbank || sbank->valid[address - sbank->region->base_guest] == 0) - return false; - else - { - sbank->valid[address - sbank->region->base_guest] = 0; - search->matches--; - - return true; - } -} - -bool cl_search_reset(cl_search_t *search) -{ - if (!search) - return false; - else - { - cl_searchbank_t *sbank; - uint8_t i; - -#if CL_EXTERNAL_MEMORY - cl_search_deep_copy(search); -#endif - for (i = 0; i < search->searchbank_count; i++) - { - sbank = &search->searchbanks[i]; - memcpy(sbank->backup, sbank->region->base_host, sbank->region->size); - memset(sbank->valid, 1, sbank->region->size); - sbank->any_valid = true; - sbank->first_valid = 0; - sbank->last_valid = sbank->region->size - 1; - } - search->matches = 0; - - return true; - } -} - bool compare_to_nothing(uint32_t previous, uint32_t current, uint8_t type) { switch (type) { - case CLE_CMPTYPE_EQUAL: + case CL_COMPARE_EQUAL: return previous == current; - case CLE_CMPTYPE_LESS: - case CLE_CMPTYPE_DECREASED: + case CL_COMPARE_LESS: + case CL_COMPARE_DECREASED: return previous > current; - case CLE_CMPTYPE_GREATER: - case CLE_CMPTYPE_INCREASED: + case CL_COMPARE_GREATER: + case CL_COMPARE_INCREASED: return previous < current; - case CLE_CMPTYPE_NOT_EQUAL: + case CL_COMPARE_NOT_EQUAL: return previous != current; } @@ -214,15 +36,15 @@ bool compare_to_nothing_float(uint32_t previous, uint32_t current, uint8_t type) switch (type) { - case CLE_CMPTYPE_EQUAL: + case CL_COMPARE_EQUAL: return (uint32_t)fprevious == (uint32_t)fcurrent; - case CLE_CMPTYPE_LESS: - case CLE_CMPTYPE_DECREASED: + case CL_COMPARE_LESS: + case CL_COMPARE_DECREASED: return (uint32_t)fprevious > (uint32_t)fcurrent; - case CLE_CMPTYPE_GREATER: - case CLE_CMPTYPE_INCREASED: + case CL_COMPARE_GREATER: + case CL_COMPARE_INCREASED: return (uint32_t)fprevious < (uint32_t)fcurrent; - case CLE_CMPTYPE_NOT_EQUAL: + case CL_COMPARE_NOT_EQUAL: return (uint32_t)fprevious != (uint32_t)fcurrent; } @@ -233,17 +55,17 @@ bool compare_to_value(uint32_t previous, uint32_t current, uint8_t type, uint32_ { switch (type) { - case CLE_CMPTYPE_EQUAL: + case CL_COMPARE_EQUAL: return current == value; - case CLE_CMPTYPE_GREATER: + case CL_COMPARE_GREATER: return current > value; - case CLE_CMPTYPE_LESS: + case CL_COMPARE_LESS: return current < value; - case CLE_CMPTYPE_NOT_EQUAL: + case CL_COMPARE_NOT_EQUAL: return current != value; - case CLE_CMPTYPE_INCREASED: + case CL_COMPARE_INCREASED: return current == previous + value; - case CLE_CMPTYPE_DECREASED: + case CL_COMPARE_DECREASED: return current + value == previous; } @@ -269,23 +91,23 @@ bool compare_to_value_float(uint32_t previous, uint32_t current, uint8_t type, switch (type) { - case CLE_CMPTYPE_EQUAL: + case CL_COMPARE_EQUAL: if (has_decimal_precision) return fcurrent == value; else return floor(fcurrent) == value; - case CLE_CMPTYPE_GREATER: + case CL_COMPARE_GREATER: return fcurrent > value; - case CLE_CMPTYPE_LESS: + case CL_COMPARE_LESS: return fcurrent < value; - case CLE_CMPTYPE_NOT_EQUAL: + case CL_COMPARE_NOT_EQUAL: return fcurrent != value; - case CLE_CMPTYPE_INCREASED: + case CL_COMPARE_INCREASED: if (has_decimal_precision) return fcurrent == fprevious + value; else return floor(fcurrent) == floor(fprevious) + value; - case CLE_CMPTYPE_DECREASED: + case CL_COMPARE_DECREASED: if (has_decimal_precision) return fcurrent + value == fprevious; else @@ -317,148 +139,6 @@ bool resolve_pointerresult(cl_addr_t *final_address, const cl_pointerresult_t *r return true; } -uint32_t cl_search_ascii(cl_search_t *search, const char *needle, uint8_t length) -{ - if (!search || search->searchbank_count == 0) - return 0; - else - { - cl_searchbank_t *sbank; - const char *haystack; - uint32_t matches = 0; - uint8_t i; - uint32_t j; - - for (i = 0; i < search->searchbank_count; i++) - { - uint32_t matches_this_bank = 0; - - sbank = &search->searchbanks[i]; - memset(sbank->valid, 0, sbank->region->size); - haystack = (const char*) sbank->region->base_host; - - for (j = 0; j < sbank->region->size; j++) - { - if (!memcmp(&haystack[j], needle, length)) - { - sbank->valid[j] = true; - matches_this_bank++; - } - } - - if (matches_this_bank == 0) - sbank->any_valid = false; - else - matches += matches_this_bank; - memcpy(sbank->backup, sbank->region->base_host, sbank->region->size); - } - search->matches = matches; - - return matches; - } -} - -uint32_t cl_search_step(cl_search_t *search, void *value) -{ - if (!search || search->searchbank_count == 0) - return 0; - else - { - cl_searchbank_t *sbank; - bool compare_result; - uint32_t left = 0; - uint32_t right = 0; - uint32_t matches = 0; - uint8_t cmp_type = search->params.compare_type; - uint8_t size = search->params.size; - uint8_t val_type = search->params.value_type; - uint8_t i; - cl_addr_t j; - - if (!value) - cl_log("Comparing to nothing..."); - else if (val_type == CL_MEMTYPE_FLOAT) - cl_log("Comparing to %f...", *((float*)value)); - else - cl_log("Comparing to %u...", *((uint32_t*)value)); - -#if CL_EXTERNAL_MEMORY - cl_search_deep_copy(search); -#endif - - for (i = 0; i < search->searchbank_count; i++) - { - cl_addr_t matches_this_bank = 0; - cl_addr_t last_valid = 0; - bool first_found = false; - - sbank = &search->searchbanks[i]; - if (!sbank->any_valid) - continue; - - for (j = sbank->first_valid; j <= sbank->last_valid; j += size) - { - /* This address has been weeded out already */ - if (!sbank->valid[j]) - continue; - - cl_read_search(&left, search, sbank, j); - cl_read_memory_internal(&right, NULL, j + sbank->region->base_guest, size); - - if (!value) - { - if (val_type == CL_MEMTYPE_FLOAT) - compare_result = compare_to_nothing_float(left, right, cmp_type); - else - compare_result = compare_to_nothing(left, right, cmp_type); - } - else - { - if (val_type == CL_MEMTYPE_FLOAT) - compare_result = compare_to_value_float(left, right, cmp_type, *((float*)value)); - else - { - uint32_t* intval = (uint32_t*)value; - - if (size == 1) - *intval &= 0xFF; - else if (size == 2) - *intval &= 0xFFFF; - - compare_result = compare_to_value(left, right, cmp_type, *intval); - } - } - - if (!compare_result) - sbank->valid[j] = 0; - else - { - /* Set our new first valid offset */ - if (!first_found) - { - sbank->first_valid = j; - first_found = true; - } - last_valid = j; - sbank->valid[j] = 1; - matches_this_bank++; - } - } - - if (matches_this_bank == 0) - sbank->any_valid = false; - else - matches += matches_this_bank; - memcpy(sbank->backup, sbank->region->base_host, sbank->region->size); - sbank->last_valid = last_valid; - } - search->matches = matches; - cl_log(" %u matches.\n", matches); - - return matches; - } -} - bool cl_pointersearch_free(cl_pointersearch_t *search) { if (!search) @@ -552,7 +232,7 @@ bool cl_pointersearch_init(cl_pointersearch_t *search, /* Initialize search parameters */ search->passes = 1; search->range = range; - search->params.compare_type = CLE_CMPTYPE_EQUAL; + search->params.compare_type = CL_COMPARE_EQUAL; search->params.size = cl_sizeof_memtype(val_type); search->params.value_type = val_type; diff --git a/cl_search.h b/cl_search.h index e6805aa..3eb4f80 100644 --- a/cl_search.h +++ b/cl_search.h @@ -11,24 +11,6 @@ typedef struct cl_search_params_t cl_value_type value_type; } cl_search_params_t; -typedef struct cl_searchbank_t -{ - cl_memory_region_t *region; - uint8_t *backup; - uint8_t *valid; - bool any_valid; - cl_addr_t first_valid; - cl_addr_t last_valid; -} cl_searchbank_t; - -typedef struct cl_search_t -{ - cl_searchbank_t *searchbanks; - cl_search_params_t params; - unsigned searchbank_count; - cl_addr_t matches; -} cl_search_t; - typedef struct cl_pointerresult_t { cl_addr_t address_initial; @@ -47,31 +29,6 @@ typedef struct cl_pointersearch_t uint32_t result_count; } cl_pointersearch_t; -bool cl_read_search (uint32_t *value, cl_search_t *search, - cl_searchbank_t *bank, cl_addr_t address); - -uint32_t cl_search_ascii (cl_search_t *search, const char *needle, uint8_t length); -bool cl_search_free (cl_search_t *search); -bool cl_search_init (cl_search_t *search); - -/* - Unsets the validity of a specific address. - Returns TRUE if it succeeds. -*/ -bool cl_search_remove(cl_search_t *search, cl_addr_t address); - -/* - Sets the validity of all addresses to true. - Returns TRUE if it succeeds. -*/ -bool cl_search_reset(cl_search_t *search); - -/* - Unsets the validity of all addresses that no longer meet the given conditions. - Returns the number of valid addresses afterwards. -*/ -uint32_t cl_search_step(cl_search_t *search, void *value); - bool cl_pointersearch_free(cl_pointersearch_t *search); bool cl_pointersearch_init(cl_pointersearch_t *search, cl_addr_t address, From 6667612646094f395a12e4a6dd0666598b01c1cc Mon Sep 17 00:00:00 2001 From: Keith Bourdon <33245078+celerizer@users.noreply.github.com> Date: Wed, 17 Dec 2025 20:37:12 -0600 Subject: [PATCH 12/57] expose search free --- cl_search_new.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cl_search_new.h b/cl_search_new.h index 6c477cf..4756423 100644 --- a/cl_search_new.h +++ b/cl_search_new.h @@ -151,6 +151,8 @@ cl_error cl_search_change_value_type(cl_search_t *search, cl_value_type type); */ cl_error cl_search_change_target(cl_search_t *search, const void *value); +cl_error cl_search_free(cl_search_t *search); + /** * Initializes a memory search structure. * @param search A pointer to the search to initialize From 5f338290d0615e11478bf5d3b8f650969b7a1348 Mon Sep 17 00:00:00 2001 From: Keith Bourdon <33245078+celerizer@users.noreply.github.com> Date: Wed, 17 Dec 2025 20:37:37 -0600 Subject: [PATCH 13/57] start the boring thankless job of hooking it up --- classicslive-integration.pri | 2 + editor/cle_action_block_comparison.cpp | 8 +-- editor/cle_result_table.h | 83 ++++++++++++-------------- editor/cle_result_table_normal.cpp | 38 ++++++------ editor/cle_result_table_normal.h | 71 +++++++++++++--------- 5 files changed, 106 insertions(+), 96 deletions(-) diff --git a/classicslive-integration.pri b/classicslive-integration.pri index c70a063..f8705a9 100644 --- a/classicslive-integration.pri +++ b/classicslive-integration.pri @@ -23,6 +23,7 @@ SOURCES += \ $$CL_DIR/cl_network.c \ $$CL_DIR/cl_script.c \ $$CL_DIR/cl_search.c \ + $$CL_DIR/cl_search_new.c \ $$CL_DIR/3rdparty/jsonsax/jsonsax.c \ $$CL_DIR/3rdparty/jsonsax/jsonsax_full.c @@ -39,6 +40,7 @@ HEADERS += \ $$CL_DIR/cl_network.h \ $$CL_DIR/cl_script.h \ $$CL_DIR/cl_search.h \ + $$CL_DIR/cl_search_new.h \ $$CL_DIR/cl_types.h \ $$CL_DIR/3rdparty/jsonsax/jsonsax.h \ $$CL_DIR/3rdparty/jsonsax/jsonsax_full.h diff --git a/editor/cle_action_block_comparison.cpp b/editor/cle_action_block_comparison.cpp index 29d16b3..020eea3 100644 --- a/editor/cle_action_block_comparison.cpp +++ b/editor/cle_action_block_comparison.cpp @@ -26,10 +26,10 @@ CleActionBlockComparison::CleActionBlockComparison(cl_action_t *action, /* Comparison selector */ m_ComparisonType = new QComboBox(this); - m_ComparisonType->addItem("= is equal to", CL_CMPTYPE_IFEQUAL); - m_ComparisonType->addItem("!= is not equal to", CL_CMPTYPE_IFNEQUAL); - m_ComparisonType->addItem("< is less than", CL_CMPTYPE_IFLESS); - m_ComparisonType->addItem("> is greater than", CL_CMPTYPE_IFGREATER); + m_ComparisonType->addItem("= is equal to", CL_COMPARE_EQUAL); + m_ComparisonType->addItem("!= is not equal to", CL_COMPARE_NOT_EQUAL); + m_ComparisonType->addItem("< is less than", CL_COMPARE_LESS); + m_ComparisonType->addItem("> is greater than", CL_COMPARE_GREATER); m_Layout->addWidget(m_ComparisonType); /* Right operand type */ diff --git a/editor/cle_result_table.h b/editor/cle_result_table.h index a5fc219..f104cd9 100644 --- a/editor/cle_result_table.h +++ b/editor/cle_result_table.h @@ -1,90 +1,85 @@ #ifndef CLE_RESULT_TABLE_H #define CLE_RESULT_TABLE_H -#include - #include #include extern "C" { - #include "../cl_memory.h" - #include "../cl_search.h" + #include "../cl_search_new.h" } class CleResultTable : public QWidget { - Q_OBJECT + Q_OBJECT public: - QTableWidget *getTable(); + QTableWidget *table(void); - /* - Return an address representing the last clicked row. + /** + * Return an address representing the last clicked row. */ - virtual cl_addr_t getClickedResultAddress() = 0; + virtual cl_addr_t getClickedResultAddress() = 0; - /* - Return a pointer to the relevant search data. - (Dereference into cl_search_t, cl_pointersearch_t, etc.) + /** + * Return a pointer to the relevant search data. + * (Dereference into cl_search_t, cl_pointersearch_t, etc.) */ - virtual void* getSearchData() = 0; + virtual void *searchData(void) = 0; - virtual bool isInitted() { return false; } + virtual int isInitted(void) { return 0; } /* Recreate all rows to adapt to changes in the search data. (Use when a search is reset, stepped through, etc.) */ - virtual void rebuild() = 0; + virtual cl_error rebuild(void) = 0; - virtual void reset(uint8_t value_type) = 0; + virtual cl_error reset(uint8_t value_type) = 0; - /* - Redraw the currently visible table rows with new information. - Should be called every frame or another small interval. + /** + * Redraw the currently visible table rows with new information. + * Should be called every frame or another small interval. */ - virtual void run() = 0; + virtual cl_error run(void) = 0; - virtual bool step(const QString& text) = 0; + virtual cl_error step(void) = 0; - virtual uint8_t getCompareType() { return 0; } - virtual uint8_t getValueType() { return 0; } + virtual cl_compare_type compareType(void) { return CL_COMPARE_INVALID; } + virtual cl_value_type valueType(void) { return CL_MEMTYPE_NOT_SET; } - virtual void setCompareType(const uint8_t new_type) = 0; - virtual void setValueType(const cl_value_type new_type) = 0; + virtual cl_error setCompareType(const cl_compare_type type) = 0; + virtual cl_error setValueType(const cl_value_type type) = 0; public slots: - virtual void onResultClick(QTableWidgetItem *item) = 0; - virtual void onResultDoubleClick(void) = 0; - virtual void onResultEdited(QTableWidgetItem *item) = 0; - virtual void onResultRightClick(const QPoint&) = 0; - virtual void onResultSelectionChanged(void) = 0; + virtual void onResultClick(QTableWidgetItem *item) = 0; + virtual void onResultDoubleClick(void) = 0; + virtual void onResultEdited(QTableWidgetItem *item) = 0; + virtual void onResultRightClick(const QPoint&) = 0; + virtual void onResultSelectionChanged(void) = 0; protected: - /* - The last row an edit dialog was created on, used to write the entered - value back to the right spot in memory. + /** + * The last row an edit dialog was created on, used to write the entered + * value back to the right spot in memory. */ - int32_t m_CurrentEditedRow; + int m_CurrentEditedRow = -1; + int m_ClickedResult = -1; + QTableWidget *m_Table = nullptr; - int32_t m_ClickedResult; - - QTableWidget *m_Table; - - /* - Set up the table. Should only be called once. + /** + * Set up the table. Should only be called once. */ - void init(); + cl_error init(void); /** * Writes user input from a result entry into emulated memory. * @param address The address to write to. * @param params The params of the search type. * @param string The string the user entered into the result entry. - **/ - void writeMemory(const cl_addr_t address, const cl_search_params_t& params, - const QString& string); + */ + void writeMemory(const cl_addr_t address, const cl_search_parameters_t& params, + const QString& string); }; #endif diff --git a/editor/cle_result_table_normal.cpp b/editor/cle_result_table_normal.cpp index 3fa6a89..4434d1c 100644 --- a/editor/cle_result_table_normal.cpp +++ b/editor/cle_result_table_normal.cpp @@ -7,7 +7,7 @@ extern "C" { - #include "../cl_common.h" + #include "../cl_common.h" } #define COL_ADDRESS 0 @@ -16,30 +16,30 @@ extern "C" CleResultTableNormal::CleResultTableNormal(QWidget *parent) { - CleResultTable::init(); + CleResultTable::init(); - /* Normal-specific table styling */ - m_Table->setColumnCount(3); + /* Normal-specific table styling */ + m_Table->setColumnCount(3); - /* Initialize result table column headers */ - QStringList TableHeader; - TableHeader << tr("Address") << tr("Previous") << tr("Current"); - m_Table->setHorizontalHeaderLabels(TableHeader); + /* Initialize result table column headers */ + QStringList TableHeader; + TableHeader << tr("Address") << tr("Previous") << tr("Current"); + m_Table->setHorizontalHeaderLabels(TableHeader); - /* Qt connections to parent */ - connect(this, SIGNAL(addressChanged(cl_addr_t)), - parent, SLOT(onAddressChanged(cl_addr_t))); - connect(this, SIGNAL(requestAddMemoryNote(cl_memnote_t)), - parent, SLOT(requestAddMemoryNote(cl_memnote_t))); - connect(this, SIGNAL(requestPointerSearch(cl_addr_t)), - parent, SLOT(requestPointerSearch(cl_addr_t))); + /* Qt connections to parent */ + connect(this, SIGNAL(addressChanged(cl_addr_t)), + parent, SLOT(onAddressChanged(cl_addr_t))); + connect(this, SIGNAL(requestAddMemoryNote(cl_memnote_t)), + parent, SLOT(requestAddMemoryNote(cl_memnote_t))); + connect(this, SIGNAL(requestPointerSearch(cl_addr_t)), + parent, SLOT(requestPointerSearch(cl_addr_t))); - cl_search_init(&m_Search); + cl_search_init(&m_Search); } CleResultTableNormal::~CleResultTableNormal() { - cl_search_free(&m_Search); + cl_search_free(&m_Search); } cl_addr_t CleResultTableNormal::getClickedResultAddress() @@ -47,9 +47,9 @@ cl_addr_t CleResultTableNormal::getClickedResultAddress() return m_Table->item(m_Table->currentRow(), COL_ADDRESS)->text().split(" ")[0].toULong(NULL, 16); } -void *CleResultTableNormal::getSearchData() +void *CleResultTableNormal::searchData(void) { - return (void*)(&m_Search); + return &m_Search; } void CleResultTableNormal::onResultClick(QTableWidgetItem *item) //todo diff --git a/editor/cle_result_table_normal.h b/editor/cle_result_table_normal.h index 479ab44..f27225e 100644 --- a/editor/cle_result_table_normal.h +++ b/editor/cle_result_table_normal.h @@ -5,8 +5,8 @@ extern "C" { - #include "../cl_memory.h" - #include "../cl_search.h" + #include "../cl_memory.h" + #include "../cl_search_new.h" } #include "cle_result_table.h" @@ -16,44 +16,57 @@ extern "C" class CleResultTableNormal : public CleResultTable { - Q_OBJECT + Q_OBJECT public: - CleResultTableNormal(QWidget* parent); - ~CleResultTableNormal() override; + CleResultTableNormal(QWidget* parent); + ~CleResultTableNormal() override; - cl_addr_t getClickedResultAddress() override; - void* getSearchData() override; - bool isInitted() override { return true; } - void rebuild() override; - void reset(uint8_t value_type) override; - void run() override; - bool step(const QString& text) override; + cl_addr_t getClickedResultAddress() override; + void *searchData(void) override; + int isInitted(void) override { return true; } + cl_error rebuild(void) override; + cl_error reset(uint8_t value_type) override; + cl_error run(void) override; + cl_error step(void) override; - uint8_t getCompareType() override { return m_Search.params.compare_type; } - uint8_t getValueType() override { return m_Search.params.value_type; } + cl_compare_type compareType(void) override + { + return m_Search.params.compare_type; + } - void setCompareType(const uint8_t new_type) override { m_Search.params.compare_type = new_type; } - void setValueType(const cl_value_type new_type) override { m_Search.params.value_type = new_type; m_Search.params.size = cl_sizeof_memtype(new_type); } + cl_value_type valueType(void) override + { + return m_Search.params.value_type; + } + + cl_error setCompareType(const cl_compare_type type) override + { + return cl_search_change_compare_type(&m_Search, type); + } + + cl_error setValueType(const cl_value_type tyoe) override + { + return cl_search_change_value_type(&m_Search, type); + } public slots: - void onClickResultAddMemoryNote(); - void onClickResultPointerSearch(); - void onClickResultRemove(); - void onResultClick(QTableWidgetItem *item) override; - void onResultDoubleClick(void) override; - void onResultEdited(QTableWidgetItem *item) override; - void onResultRightClick(const QPoint&) override; - void onResultSelectionChanged(void) override; + void onClickResultAddMemoryNote(void); + void onClickResultPointerSearch(void); + void onClickResultRemove(void); + void onResultClick(QTableWidgetItem *item) override; + void onResultDoubleClick(void) override; + void onResultEdited(QTableWidgetItem *item) override; + void onResultRightClick(const QPoint&) override; + void onResultSelectionChanged(void) override; signals: - void addressChanged(cl_addr_t address); - void requestAddMemoryNote(cl_memnote_t note); - void requestPointerSearch(cl_addr_t address); - //void requestRemove(uint32_t index) override; + void addressChanged(cl_addr_t address); + void requestAddMemoryNote(cl_memnote_t note); + void requestPointerSearch(cl_addr_t address); private: - cl_search_t m_Search; + cl_search_t m_Search; }; #endif From b7d975e558be5f1540e7d01defc521b0e2c58e89 Mon Sep 17 00:00:00 2001 From: Keith Bourdon <33245078+celerizer@users.noreply.github.com> Date: Wed, 17 Dec 2025 20:49:15 -0600 Subject: [PATCH 14/57] duuurrrrrrrrr c89fix --- cl_test.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/cl_test.c b/cl_test.c index 15974aa..ee727e2 100644 --- a/cl_test.c +++ b/cl_test.c @@ -208,6 +208,8 @@ static cl_error cl_test_user_data(cl_user_t *user, unsigned index) static cl_error cl_test_external_read(void *dest, cl_addr_t address, unsigned size, unsigned *read) { + unsigned i; + snprintf(cl_test_msg, sizeof(cl_test_msg), "cl_abi_external_read - dest:%p address:0x%08x size:%u read:%p", dest, (unsigned)address, size, (void*)read); @@ -218,7 +220,7 @@ static cl_error cl_test_external_read(void *dest, cl_addr_t address, return CL_ERR_PARAMETER_NULL; /* Find the region that contains this address */ - for (unsigned i = 0; i < CL_TEST_REGION_COUNT; i++) + for (i = 0; i < CL_TEST_REGION_COUNT; i++) { cl_memory_region_t *region = &cl_test_system.regions[i]; @@ -244,6 +246,8 @@ static cl_error cl_test_external_read(void *dest, cl_addr_t address, CL_UNUSED(address); CL_UNUSED(size); CL_UNUSED(read); + CL_UNUSED(i); + return CL_ERR_CLIENT_RUNTIME; #endif } @@ -251,6 +255,8 @@ static cl_error cl_test_external_read(void *dest, cl_addr_t address, static cl_error cl_test_external_write(const void *src, cl_addr_t address, unsigned size, unsigned *written) { + unsigned i; + snprintf(cl_test_msg, sizeof(cl_test_msg), "cl_abi_external_write - src:%p address:0x%08x size:%u written:%p", src, (unsigned)address, size, (void*)written); @@ -260,7 +266,7 @@ static cl_error cl_test_external_write(const void *src, cl_addr_t address, if (!src || !written) return CL_ERR_PARAMETER_NULL; /* Find the region that contains this address */ - for (unsigned i = 0; i < CL_TEST_REGION_COUNT; i++) + for (i = 0; i < CL_TEST_REGION_COUNT; i++) { cl_memory_region_t *region = &cl_test_system.regions[i]; @@ -286,6 +292,8 @@ static cl_error cl_test_external_write(const void *src, cl_addr_t address, CL_UNUSED(address); CL_UNUSED(size); CL_UNUSED(written); + CL_UNUSED(i); + return CL_ERR_CLIENT_RUNTIME; #endif } From 33146068eb503b5ed4f5e4965d3aaf4ceaefc098 Mon Sep 17 00:00:00 2001 From: celerizer Date: Thu, 18 Dec 2025 16:13:21 -0600 Subject: [PATCH 15/57] split read/write funcs into read_buffer/read_value --- cl_abi.c | 43 ++++- cl_abi.h | 34 +++- cl_common.c | 486 +++++++++++++++++++++++++++++++++++++++++------- cl_common.h | 52 +++--- cl_config.h | 85 +++++++-- cl_memory.c | 196 +++++++++++-------- cl_memory.h | 70 +++---- cl_search_new.c | 119 ++++++------ cl_test.c | 143 ++++++-------- 9 files changed, 840 insertions(+), 388 deletions(-) diff --git a/cl_abi.c b/cl_abi.c index 7ed3996..b436a62 100644 --- a/cl_abi.c +++ b/cl_abi.c @@ -19,7 +19,10 @@ cl_error cl_abi_register(const cl_abi_t *abi) !abi->functions.core.user_data) return CL_ERR_PARAMETER_INVALID; #if CL_EXTERNAL_MEMORY - else if (!abi->functions.external.read || !abi->functions.external.write) + else if (!abi->functions.external.read_buffer || + !abi->functions.external.read_value || + !abi->functions.external.write_buffer || + !abi->functions.external.write_value) return CL_ERR_PARAMETER_INVALID; #endif else @@ -91,22 +94,44 @@ cl_error cl_abi_user_data(cl_user_t *user, unsigned index) #if CL_EXTERNAL_MEMORY -cl_error cl_abi_external_read(void *dest, cl_addr_t address, +cl_error cl_abi_external_read_buffer(void *dest, cl_addr_t address, unsigned size, unsigned *read) { - if (cl_g_abi && cl_g_abi->functions.external.read && dest) - return cl_g_abi->functions.external.read(dest, address, size, read); - else +#if CL_SAFETY + if (!dest || !read || !cl_g_abi || !cl_g_abi->functions.external.read_buffer) return CL_ERR_PARAMETER_NULL; +#endif + return cl_g_abi->functions.external.read_buffer(dest, address, size, read); +} + +cl_error cl_abi_external_read_value(void *dest, cl_addr_t address, + cl_value_type type) +{ +#if CL_SAFETY + if (!dest || !cl_g_abi || !cl_g_abi->functions.external.read_value) + return CL_ERR_PARAMETER_NULL; +#endif + return cl_g_abi->functions.external.read_value(dest, address, type); } -cl_error cl_abi_external_write(const void *src, cl_addr_t address, +cl_error cl_abi_external_write_buffer(const void *src, cl_addr_t address, unsigned size, unsigned *written) { - if (cl_g_abi && cl_g_abi->functions.external.write && src) - return cl_g_abi->functions.external.write(src, address, size, written); - else +#if CL_SAFETY + if (!src || !written || !cl_g_abi || !cl_g_abi->functions.external.write_buffer) return CL_ERR_PARAMETER_NULL; +#endif + return cl_g_abi->functions.external.write_buffer(src, address, size, written); +} + +cl_error cl_abi_external_write_value(const void *src, cl_addr_t address, + cl_value_type type) +{ +#if CL_SAFETY + if (!src || !cl_g_abi || !cl_g_abi->functions.external.write_value) + return CL_ERR_PARAMETER_NULL; +#endif + return cl_g_abi->functions.external.write_value(src, address, type); } #endif diff --git a/cl_abi.h b/cl_abi.h index d75d081..8c03826 100644 --- a/cl_abi.h +++ b/cl_abi.h @@ -95,8 +95,11 @@ cl_error cl_abi_user_data(cl_user_t *user, unsigned index); * @param size The number of bytes to copy. * @param read The number of bytes successfully read. */ -cl_error cl_abi_external_read(void *dest, cl_addr_t address, - unsigned size, unsigned *read); +cl_error cl_abi_external_read_buffer(void *dest, cl_addr_t address, + unsigned size, unsigned *read); + +cl_error cl_abi_external_read_value(void *dest, cl_addr_t address, + cl_value_type type); /** * Instructs the frontend to copy data to external memory. @@ -106,8 +109,11 @@ cl_error cl_abi_external_read(void *dest, cl_addr_t address, * @param size The number of bytes to copy. * @param written The number of bytes successfully written. */ -cl_error cl_abi_external_write(const void *src, cl_addr_t address, - unsigned size, unsigned *written); +cl_error cl_abi_external_write_buffer(const void *src, cl_addr_t address, + unsigned size, unsigned *written); + +cl_error cl_abi_external_write_value(const void *src, cl_addr_t address, + cl_value_type type); #endif @@ -145,13 +151,21 @@ typedef struct struct external { - /** @see cl_abi_external_read */ - cl_error (*read)(void *dest, cl_addr_t address, unsigned size, - unsigned *read); + /** @see cl_abi_external_read_buffer */ + cl_error (*read_buffer)(void *dest, cl_addr_t address, unsigned size, + unsigned *read); + + /** @see cl_abi_external_read_value */ + cl_error (*read_value)(void *dest, cl_addr_t address, + cl_value_type type); + + /** @see cl_abi_external_write_buffer */ + cl_error (*write_buffer)(const void *src, cl_addr_t address, + unsigned size, unsigned *written); - /** @see cl_abi_external_write */ - cl_error (*write)(const void *src, cl_addr_t address, unsigned size, - unsigned *written); + /** @see cl_abi_external_write_value */ + cl_error (*write_value)(const void *src, cl_addr_t address, + cl_value_type type); } external; } functions; } cl_abi_t; diff --git a/cl_common.c b/cl_common.c index 54c23ca..862edd5 100644 --- a/cl_common.c +++ b/cl_common.c @@ -1,7 +1,5 @@ #include "cl_common.h" -#include "cl_abi.h" - #include #include #include @@ -10,6 +8,8 @@ #include #endif +#include + #ifdef __GNUC__ __attribute__((__format__ (__printf__, 2, 0))) #endif @@ -41,50 +41,166 @@ void cl_log(const char *format, ...) #endif } -bool cl_read(void *dest, const uint8_t *src, cl_addr_t offset, unsigned size, +cl_error cl_read_8(void *value, const void *src, cl_addr_t offset) +{ +#if CL_SAFETY + if (!src || !value) + return CL_ERR_PARAMETER_NULL; +#endif + *(unsigned char*)value = ((unsigned char*)src)[offset]; + + return CL_OK; +} + +cl_error cl_read_16(void *value, const void *src, cl_addr_t offset, cl_endianness endianness) { - if (src && size > 0) +#if CL_SAFETY + if (!src || !value) + return CL_ERR_PARAMETER_NULL; + else { - memcpy(dest, &src[offset], size); +#endif + uint16_t tmp = *((const uint16_t*)( + (const uint8_t*)src + offset)); - /* Byte swap if necessary */ -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - if (endianness == CL_ENDIAN_LITTLE) +#if CL_HOST_ENDIANNESS == CL_ENDIAN_BIG + if (endianness == CL_ENDIAN_LITTLE) #else - if (endianness == CL_ENDIAN_BIG) + if (endianness == CL_ENDIAN_BIG) #endif - { - switch (size) - { - case 2: -#ifdef _MSC_VER - *((uint16_t*)dest) = _byteswap_ushort(*((uint16_t*)dest)); + { +#if defined(_MSC_VER) + *((uint16_t*)value) = _byteswap_ushort(tmp); +#elif defined(__GNUC__) || defined(__clang__) + *((uint16_t*)value) = __builtin_bswap16(tmp); #else - *((uint16_t*)dest) = __builtin_bswap16(*((uint16_t*)dest)); + tmp = (tmp >> 8) | (tmp << 8); #endif - break; - case 4: -#ifdef _MSC_VER - *((uint32_t*)dest) = _byteswap_ulong(*((uint32_t*)dest)); + } + *((uint16_t*)value) = tmp; + + return CL_OK; +#if CL_SAFETY + } +#endif +} + +cl_error cl_read_32(void *value, const void *src, cl_addr_t offset, + cl_endianness endianness) +{ +#if CL_SAFETY + if (!src || !value) + return CL_ERR_PARAMETER_NULL; + else + { +#endif + uint32_t tmp = *((const uint32_t*)( + (const uint8_t*)src + offset)); + +#if CL_HOST_ENDIANNESS == CL_ENDIAN_BIG + if (endianness == CL_ENDIAN_LITTLE) #else - *((uint32_t*)dest) = __builtin_bswap32(*((uint32_t*)dest)); + if (endianness == CL_ENDIAN_BIG) #endif - break; - case 8: -#ifdef _MSC_VER - *((uint64_t*)dest) = _byteswap_uint64(*((uint64_t*)dest)); + { +#if defined(_MSC_VER) + tmp = _byteswap_ulong(tmp); +#elif defined(__GNUC__) || defined(__clang__) + tmp = __builtin_bswap32(tmp); +#else + tmp = ((tmp & 0x000000FFU) << 24) | + ((tmp & 0x0000FF00U) << 8) | + ((tmp & 0x00FF0000U) >> 8) | + ((tmp & 0xFF000000U) >> 24); +#endif + } + *((uint32_t*)value) = tmp; + + return CL_OK; +#if CL_SAFETY + } +#endif +} + +cl_error cl_read_64(void *value, const void *src, cl_addr_t offset, + cl_endianness endianness) +{ +#if CL_SAFETY + if (!src || !value) + return CL_ERR_PARAMETER_NULL; + else + { +#endif + uint64_t tmp = *((const uint64_t*)( + (const uint8_t*)src + offset)); + +#if CL_HOST_ENDIANNESS == CL_ENDIAN_BIG + if (endianness == CL_ENDIAN_LITTLE) #else - *((uint64_t*)dest) = __builtin_bswap64(*((uint64_t*)dest)); + if (endianness == CL_ENDIAN_BIG) #endif - break; - } - } + { +#if defined(_MSC_VER) + tmp = _byteswap_uint64(tmp); +#elif defined(__GNUC__) || defined(__clang__) + tmp = __builtin_bswap64(tmp); +#else + tmp = ((tmp & 0x00000000000000FFULL) << 56) | + ((tmp & 0x000000000000FF00ULL) << 40) | + ((tmp & 0x0000000000FF0000ULL) << 24) | + ((tmp & 0x00000000FF000000ULL) << 8) | + ((tmp & 0x000000FF00000000ULL) >> 8) | + ((tmp & 0x0000FF0000000000ULL) >> 24) | + ((tmp & 0x00FF000000000000ULL) >> 40) | + ((tmp & 0xFF00000000000000ULL) >> 56); +#endif + } + *((uint64_t*)value) = tmp; - return true; + return CL_OK; +#if CL_SAFETY } +#endif +} - return false; +cl_error cl_read_value(void *value, const void *src, cl_addr_t offset, + cl_value_type type, cl_endianness endianness) +{ + switch (type) + { + case CL_MEMTYPE_INT8: + case CL_MEMTYPE_UINT8: + return cl_read_8(value, src, offset); + case CL_MEMTYPE_INT16: + case CL_MEMTYPE_UINT16: + return cl_read_16(value, src, offset, endianness); + case CL_MEMTYPE_INT32: + case CL_MEMTYPE_UINT32: + case CL_MEMTYPE_FLOAT: + return cl_read_32(value, src, offset, endianness); + case CL_MEMTYPE_INT64: + case CL_MEMTYPE_DOUBLE: + return cl_read_64(value, src, offset, endianness); + case CL_MEMTYPE_NOT_SET: + case CL_MEMTYPE_SIZE: + /* No default because we want warnings here */ + return CL_ERR_PARAMETER_INVALID; + } + + return CL_ERR_PARAMETER_INVALID; +} + +cl_error cl_read_buffer(void *dst, const void *src, cl_addr_t offset, + cl_addr_t size) +{ +#if CL_SAFETY + if (!src || !dst) + return CL_ERR_PARAMETER_NULL; +#endif + memcpy(dst, (const unsigned char*)src + offset, size); + + return CL_OK; } bool cl_strto(const char **pos, void *value, unsigned size, bool is_signed) @@ -128,54 +244,290 @@ bool cl_strto(const char **pos, void *value, unsigned size, bool is_signed) return true; } -bool cl_write(uint8_t *dest, const void *src, cl_addr_t offset, unsigned size, - cl_endianness endianness) +cl_error cl_write_8(const void *value, void *dst, cl_addr_t offset) { - if (dest && src && size > 0) +#if CL_SAFETY + if (!dst || !value) + return CL_ERR_PARAMETER_NULL; +#endif + ((uint8_t*)dst)[offset] = *(const uint8_t*)value; + + return CL_OK; +} + +cl_error cl_write_16(const void *value, void *dst, cl_addr_t offset, + cl_endianness endianness) +{ +#if CL_SAFETY + if (!dst || !value) + return CL_ERR_PARAMETER_NULL; + else { - memcpy(&dest[offset], src, size); +#endif + uint16_t tmp = *(const uint16_t*)value; - /* Byte swap if necessary */ -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - if (endianness == CL_ENDIAN_LITTLE) +#if CL_HOST_ENDIANNESS == CL_ENDIAN_BIG + if (endianness == CL_ENDIAN_LITTLE) #else - if (endianness == CL_ENDIAN_BIG) + if (endianness == CL_ENDIAN_BIG) #endif - { - switch (size) - { - case 2: -#ifdef _MSC_VER - *((uint16_t*)&dest[offset]) = - _byteswap_ushort(*((uint16_t*)&dest[offset])); + { +#if defined(_MSC_VER) + tmp = _byteswap_ushort(tmp); +#elif defined(__GNUC__) || defined(__clang__) + tmp = __builtin_bswap16(tmp); #else - *((uint16_t*)&dest[offset]) = - __builtin_bswap16(*((uint16_t*)&dest[offset])); + tmp = (tmp >> 8) | (tmp << 8); #endif - break; - case 4: -#ifdef _MSC_VER - *((uint32_t*)&dest[offset]) = - _byteswap_ulong(*((uint32_t*)&dest[offset])); + } + + *((uint16_t*)((uint8_t*)dst + offset)) = tmp; + + return CL_OK; +#if CL_SAFETY + } +#endif +} + +cl_error cl_write_32(const void *value, void *dst, cl_addr_t offset, + cl_endianness endianness) +{ +#if CL_SAFETY + if (!dst || !value) + return CL_ERR_PARAMETER_NULL; + else + { +#endif + uint32_t tmp = *(const uint32_t*)value; + +#if CL_HOST_ENDIANNESS == CL_ENDIAN_BIG + if (endianness == CL_ENDIAN_LITTLE) #else - *((uint32_t*)&dest[offset]) = - __builtin_bswap32(*((uint32_t*)&dest[offset])); + if (endianness == CL_ENDIAN_BIG) #endif - break; - case 8: -#ifdef _MSC_VER - *((uint64_t*)&dest[offset]) = - _byteswap_uint64(*((uint64_t*)&dest[offset])); + { +#if defined(_MSC_VER) + tmp = _byteswap_ulong(tmp); +#elif defined(__GNUC__) || defined(__clang__) + tmp = __builtin_bswap32(tmp); #else - *((uint64_t*)&dest[offset]) = - __builtin_bswap64(*((uint64_t*)&dest[offset])); + tmp = ((tmp & 0x000000FFU) << 24) | + ((tmp & 0x0000FF00U) << 8) | + ((tmp & 0x00FF0000U) >> 8) | + ((tmp & 0xFF000000U) >> 24); #endif - break; - } - } + } - return true; + *((uint32_t*)((uint8_t*)dst + offset)) = tmp; + + return CL_OK; +#if CL_SAFETY + } +#endif +} + +cl_error cl_write_64(const void *value, void *dst, cl_addr_t offset, + cl_endianness endianness) +{ +#if CL_SAFETY + if (!dst || !value) + return CL_ERR_PARAMETER_NULL; + else + { +#endif + uint64_t tmp = *(const uint64_t*)value; + +#if CL_HOST_ENDIANNESS == CL_ENDIAN_BIG + if (endianness == CL_ENDIAN_LITTLE) +#else + if (endianness == CL_ENDIAN_BIG) +#endif + { +#if defined(_MSC_VER) + tmp = _byteswap_uint64(tmp); +#elif defined(__GNUC__) || defined(__clang__) + tmp = __builtin_bswap64(tmp); +#else + tmp = ((tmp & 0x00000000000000FFULL) << 56) | + ((tmp & 0x000000000000FF00ULL) << 40) | + ((tmp & 0x0000000000FF0000ULL) << 24) | + ((tmp & 0x00000000FF000000ULL) << 8) | + ((tmp & 0x000000FF00000000ULL) >> 8) | + ((tmp & 0x0000FF0000000000ULL) >> 24) | + ((tmp & 0x00FF000000000000ULL) >> 40) | + ((tmp & 0xFF00000000000000ULL) >> 56); +#endif + } + + *((uint64_t*)((uint8_t*)dst + offset)) = tmp; + + return CL_OK; +#if CL_SAFETY + } +#endif +} + +cl_error cl_write_value(const void *value, void *dst, cl_addr_t offset, + cl_value_type type, cl_endianness endianness) +{ + switch (type) + { + case CL_MEMTYPE_INT8: + case CL_MEMTYPE_UINT8: + return cl_write_8(value, dst, offset); + case CL_MEMTYPE_INT16: + case CL_MEMTYPE_UINT16: + return cl_write_16(value, dst, offset, endianness); + case CL_MEMTYPE_INT32: + case CL_MEMTYPE_UINT32: + case CL_MEMTYPE_FLOAT: + return cl_write_32(value, dst, offset, endianness); + case CL_MEMTYPE_INT64: + case CL_MEMTYPE_DOUBLE: + return cl_write_64(value, dst, offset, endianness); + case CL_MEMTYPE_NOT_SET: + case CL_MEMTYPE_SIZE: + /* No default because we want warnings here */ + return CL_ERR_PARAMETER_INVALID; + } + + return CL_ERR_PARAMETER_INVALID; +} + +cl_error cl_write_buffer(const void *src, void *dst, cl_addr_t offset, + cl_addr_t size) +{ +#if CL_SAFETY + if (!dst || !src) + return CL_ERR_PARAMETER_NULL; +#endif + memcpy((unsigned char*)dst + offset, src, size); + + return CL_OK; +} + +unsigned cl_sizeof_memtype(const cl_value_type type) +{ + switch (type) + { + case CL_MEMTYPE_INT8: + case CL_MEMTYPE_UINT8: + return 1; + case CL_MEMTYPE_INT16: + case CL_MEMTYPE_UINT16: + return 2; + case CL_MEMTYPE_INT32: + case CL_MEMTYPE_UINT32: + case CL_MEMTYPE_FLOAT: + return 4; + case CL_MEMTYPE_INT64: + case CL_MEMTYPE_DOUBLE: + return 8; + default: + /* Should not be reached */ + cl_message(CL_MSG_ERROR, "cl_sizeof_memtype bad value %u", type); + return 0; + } +} + +const char *cl_string_bitness(cl_bitness bitness) +{ + switch (bitness) + { + case CL_BITNESS_32: + return "32-bit"; + case CL_BITNESS_64: + return "64-bit"; + case CL_BITNESS_UNKNOWN: + case CL_BITNESS_SIZE: + return "Invalid bitness"; + } + + return "Undefined bitness"; +} + +const char *cl_string_endianness(cl_endianness endianness) +{ + switch (endianness) + { + case CL_ENDIAN_LITTLE: + return "Little-endian"; + case CL_ENDIAN_BIG: + return "Big-endian"; + case CL_ENDIAN_WORD_FLIP_BL: + return "Word-flip big-little-endian"; + case CL_ENDIAN_WORD_FLIP_LB: + return "Word-flip little-big-endian"; + case CL_ENDIAN_INVALID: + return "Invalid endianness"; + } + + return "Undefined endianness"; +} + +const char *cl_string_platform(cl_platform platform) +{ + switch (platform) + { + case CL_PLATFORM_WINDOWS: + return "Windows"; + case CL_PLATFORM_LINUX: + return "Linux"; + case CL_PLATFORM_MACOS: + return "macOS"; + case CL_PLATFORM_ANDROID: + return "Android"; + case CL_PLATFORM_NINTENDO_64: + return "Nintendo 64"; + case CL_PLATFORM_GAMECUBE: + return "GameCube"; + case CL_PLATFORM_WII: + return "Wii"; + case CL_PLATFORM_WII_U: + return "Wii U"; + case CL_PLATFORM_SWITCH: + return "Switch"; + case CL_PLATFORM_SWITCH_2: + return "Switch 2"; + case CL_PLATFORM_UNKNOWN: + case CL_PLATFORM_SIZE: + return "Invalid platform"; + } + + return "Undefined platform"; +} + +const char *cl_string_error(cl_error error) +{ + switch (error) + { + case CL_OK: + return "No error"; + case CL_ERR_UNKNOWN: + return "Unknown error"; + case CL_ERR_USER_CONFIG: + return "User configuration error"; + case CL_ERR_CLIENT_RUNTIME: + return "Client runtime error"; + case CL_ERR_CLIENT_COMPILE: + return "Client compile error"; + case CL_ERR_SERVER_NOT_FOUND: + return "Server not found"; + case CL_ERR_SERVER_UNAVAILABLE: + return "Server unavailable"; + case CL_ERR_SERVER_INTERNAL: + return "Server internal error"; + case CL_ERR_SERVER_UNEXPECTED_RESPONSE: + return "Server unexpected response"; + case CL_ERR_PARAMETER_INVALID: + return "Invalid parameter"; + case CL_ERR_PARAMETER_NULL: + return "Null parameter"; + case CL_ERR_SESSION_MISMATCH: + return "Session mismatch"; + case CL_ERR_SIZE: + return "Error size limit reached"; } - return false; + return "Invalid error code"; } diff --git a/cl_common.h b/cl_common.h index c84f3c3..917511b 100644 --- a/cl_common.h +++ b/cl_common.h @@ -21,31 +21,41 @@ void cl_message(cl_log_level level, const char *format, ...); */ void cl_log(const char *format, ...); -/** - * Reads data from one location to another, automatically applying transforms - * for size and endianness differences. - * @param dest The destination buffer. - * @param src The source buffer. - * @param offset The location from which to start reading from src. - * @param size The number of bytes to read from src. - * @param endianness The endianness of dest. For example, CL_ENDIAN_LITTLE. - * @return Whether the read succeeded. - */ -bool cl_read(void *dest, const uint8_t *src, cl_addr_t offset, unsigned size, +cl_error cl_read_8(void *value, const void *src, cl_addr_t offset); +cl_error cl_read_16(void *value, const void *src, cl_addr_t offset, + cl_endianness endianness); +cl_error cl_read_32(void *value, const void *src, cl_addr_t offset, + cl_endianness endianness); +cl_error cl_read_64(void *value, const void *src, cl_addr_t offset, + cl_endianness endianness); +cl_error cl_read_value(void *value, const void *src, cl_addr_t offset, + cl_value_type type, cl_endianness endianness); +cl_error cl_read_buffer(void *dst, const void *src, cl_addr_t offset, + cl_addr_t size); + +cl_error cl_write_8(const void *value, void *dst, cl_addr_t offset); +cl_error cl_write_16(const void *value, void *dst, cl_addr_t offset, + cl_endianness endianness); +cl_error cl_write_32(const void *value, void *dst, cl_addr_t offset, + cl_endianness endianness); +cl_error cl_write_64(const void *value, void *dst, cl_addr_t offset, cl_endianness endianness); +cl_error cl_write_value(const void *value, void *dst, cl_addr_t offset, + cl_value_type type, cl_endianness endianness); +cl_error cl_write_buffer(const void *src, void *dst, cl_addr_t offset, + cl_addr_t size); /** - * Writes data from one location to another, automatically applying transforms - * for size and endianness differences. - * @param dest The destination buffer. - * @param src The source buffer. - * @param offset The location from which to start reading from src. - * @param size The number of bytes to read from src. - * @param endianness The endianness of dest. For example, CL_ENDIAN_LITTLE. - * @return Whether the write succeeded. + * Returns the size (in bytes) of a given value type. + * @param type A type of memory value. For example, CL_MEMTYPE_8BIT. + * @return The number of bytes the memory type takes up, or 0 if invalid. */ -bool cl_write(uint8_t *dest, const void *src, cl_addr_t offset, unsigned size, - cl_endianness endianness); +unsigned cl_sizeof_memtype(const cl_value_type type); + +const char *cl_string_bitness(cl_bitness bitness); +const char *cl_string_endianness(cl_endianness endianness); +const char *cl_string_error(cl_error error); +const char *cl_string_platform(cl_platform platform); bool cl_strto(const char **pos, void *value, unsigned size, bool is_signed); diff --git a/cl_config.h b/cl_config.h index 68069df..aaebe36 100644 --- a/cl_config.h +++ b/cl_config.h @@ -1,55 +1,102 @@ #ifndef CL_CONFIG_H #define CL_CONFIG_H -#define CL_PLATFORM_UNKNOWN 0 +typedef enum +{ + CL_PLATFORM_UNKNOWN = 0, + + CL_PLATFORM_WINDOWS, + CL_PLATFORM_LINUX, + CL_PLATFORM_MACOS, + CL_PLATFORM_ANDROID, + + CL_PLATFORM_NINTENDO_64, + CL_PLATFORM_GAMECUBE, + CL_PLATFORM_WII, + CL_PLATFORM_WII_U, + CL_PLATFORM_SWITCH, + CL_PLATFORM_SWITCH_2, -#define CL_PLATFORM_WINDOWS 1 -#define CL_PLATFORM_LINUX 2 -#define CL_PLATFORM_MACOS 3 -#define CL_PLATFORM_ANDROID 4 -#define CL_PLATFORM_WII_U 5 + CL_PLATFORM_SIZE +} cl_platform; -#define CL_PLATFORM_64 1 -#define CL_PLATFORM_32 2 +typedef enum +{ + CL_BITNESS_UNKNOWN = 0, + CL_BITNESS_64, + CL_BITNESS_32, + CL_BITNESS_SIZE +} cl_bitness; + +#define CL_HOST_ENDIAN_LITTLE 1 +#define CL_HOST_ENDIAN_BIG 2 #ifndef CL_HOST_PLATFORM #if defined(WIN32) || defined(_WIN32) #define CL_HOST_PLATFORM CL_PLATFORM_WINDOWS #if defined(WIN64) || defined(_WIN64) - #define CL_HOST_ARCHITECTURE CL_PLATFORM_64 + #define CL_HOST_BITNESS CL_BITNESS_64 #else - #define CL_HOST_ARCHITECTURE CL_PLATFORM_32 + #define CL_HOST_BITNESS CL_BITNESS_32 #endif #elif defined(__linux__) && !defined(__ANDROID__) #define CL_HOST_PLATFORM CL_PLATFORM_LINUX #if defined(__x86_64__) || defined(__ppc64__) || defined(__aarch64__) - #define CL_HOST_ARCHITECTURE CL_PLATFORM_64 + #define CL_HOST_BITNESS CL_BITNESS_64 #else - #define CL_HOST_ARCHITECTURE CL_PLATFORM_32 + #define CL_HOST_BITNESS CL_BITNESS_32 #endif #elif defined(__APPLE__) && defined(__MACH__) #define CL_HOST_PLATFORM CL_PLATFORM_MACOS #if defined(__x86_64__) || defined(__ppc64__) || defined(__aarch64__) - #define CL_HOST_ARCHITECTURE CL_PLATFORM_64 + #define CL_HOST_BITNESS CL_BITNESS_64 #else - #define CL_HOST_ARCHITECTURE CL_PLATFORM_32 + #define CL_HOST_BITNESS CL_BITNESS_32 #endif #elif defined(__ANDROID__) #define CL_HOST_PLATFORM CL_PLATFORM_ANDROID #if defined(__x86_64__) || defined(__aarch64__) - #define CL_HOST_ARCHITECTURE CL_PLATFORM_64 + #define CL_HOST_BITNESS CL_BITNESS_64 #else - #define CL_HOST_ARCHITECTURE CL_PLATFORM_32 + #define CL_HOST_BITNESS CL_BITNESS_32 + #endif + #elif defined(N64) + #define CL_HOST_BITNESS CL_BITNESS_32 + #define CL_HOST_PLATFORM CL_PLATFORM_NINTENDO_64 + #define CL_HOST_ENDIANNESS CL_HOST_ENDIAN_BIG + /** + * PowerPC-based Nintendo consoles + * @todo I think GEKKO is always defined, then WII, then __WIIU__ + */ + #elif defined(GEKKO) + #define CL_HOST_BITNESS CL_BITNESS_32 + #define CL_HOST_ENDIANNESS CL_HOST_ENDIAN_BIG + #if defined(__WIIU__) + #define CL_HOST_PLATFORM CL_PLATFORM_WII_U + #elif defined(WII) + #define CL_HOST_PLATFORM CL_PLATFORM_WII + #else + #define CL_HOST_PLATFORM CL_PLATFORM_GAMECUBE #endif - #elif defined(__WIIU__) - #define CL_HOST_PLATFORM CL_PLATFORM_WII_U - #define CL_HOST_ARCHITECTURE CL_PLATFORM_32 #else #define CL_HOST_PLATFORM CL_PLATFORM_UNKNOWN #define CL_HOST_ARCHITECTURE CL_PLATFORM_UNKNOWN #error "Unrecognized target platform" #endif #endif +#ifndef CL_HOST_BITNESS + #error "Unable to determine host bitness" +#endif +#ifndef CL_HOST_ENDIANNESS + #if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + #define CL_HOST_ENDIANNESS CL_HOST_ENDIAN_BIG + #elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + #define CL_HOST_ENDIANNESS CL_HOST_ENDIAN_LITTLE + #else + #warning "Unable to determine host endianness, assuming little-endian" + #define CL_HOST_ENDIANNESS CL_HOST_ENDIAN_LITTLE + #endif +#endif #ifndef CL_HAVE_EDITOR /** diff --git a/cl_memory.c b/cl_memory.c index fa4bb98..88bdb0f 100644 --- a/cl_memory.c +++ b/cl_memory.c @@ -6,8 +6,6 @@ #include #endif -#include - #if CL_HAVE_EDITOR #include "cl_abi.h" #include @@ -364,61 +362,112 @@ cl_error cl_memory_add_note(const cl_memnote_t *note) return CL_OK; } -unsigned cl_read_memory_internal(void *value, const cl_memory_region_t *bank, - cl_addr_t address, unsigned size) +cl_error cl_read_memory_buffer_internal(void *buffer, + const cl_memory_region_t *bank, cl_addr_t address, cl_addr_t size) { if (!bank) { bank = cl_find_memory_region(address); if (!bank) - return 0; + return CL_ERR_PARAMETER_INVALID; else address -= bank->base_guest; } if (bank->base_host && address < bank->size) - return cl_read(value, bank->base_host, address, size, bank->endianness); + return cl_read_buffer(buffer, bank->base_host, address, size); + + return CL_ERR_PARAMETER_INVALID; +} + +cl_error cl_read_memory_value_internal(void *buffer, + const cl_memory_region_t *bank, cl_addr_t address, cl_value_type type) +{ + if (!bank) + { + bank = cl_find_memory_region(address); + if (!bank) + return CL_ERR_PARAMETER_INVALID; + else + address -= bank->base_guest; + } + if (bank->base_host && address < bank->size) + return cl_read_value(buffer, bank->base_host, address, type, + bank->endianness); + + return CL_ERR_PARAMETER_INVALID; +} + +cl_error cl_write_memory_buffer_internal(const void *value, + const cl_memory_region_t *bank, cl_addr_t address, cl_addr_t size) +{ + if (!bank) + { + bank = cl_find_memory_region(address); + if (!bank) + return CL_ERR_PARAMETER_INVALID; + else + address -= bank->base_guest; + } + if (bank->base_host) + return cl_write_buffer(value, bank->base_host, address, size); - return 0; + return CL_ERR_PARAMETER_INVALID; +} + +cl_error cl_write_memory_value_internal(const void *value, + const cl_memory_region_t *bank, cl_addr_t address, cl_value_type type) +{ + if (!bank) + { + bank = cl_find_memory_region(address); + if (!bank) + return CL_ERR_PARAMETER_INVALID; + else + address -= bank->base_guest; + } + if (bank->base_host) + return cl_write_value(value, bank->base_host, address, type, + bank->endianness); + + return CL_ERR_PARAMETER_INVALID; } #if CL_EXTERNAL_MEMORY -unsigned cl_read_memory_external(void *value, const cl_memory_region_t *bank, - cl_addr_t address, unsigned size) + +cl_error cl_read_memory_buffer_external(void *value, + const cl_memory_region_t *bank, cl_addr_t address, cl_addr_t size) { - unsigned written = 0; + if (bank) + address += bank->base_guest; + return cl_abi_external_read_buffer(value, address, size, NULL); +} +cl_error cl_read_memory_value_external(void *value, + const cl_memory_region_t *bank, cl_addr_t address, cl_value_type type) +{ if (bank) address += bank->base_guest; - cl_abi_external_read(value, address, size, &written); + return cl_abi_external_read_value(value, address, type); +} - return written; +cl_error cl_write_memory_buffer_external(const void *value, + const cl_memory_region_t *bank, cl_addr_t address, cl_addr_t size) +{ + if (bank) + address += bank->base_guest; + return cl_abi_external_write_buffer(value, address, size, NULL); } -#endif -unsigned cl_sizeof_memtype(const cl_value_type type) +cl_error cl_write_memory_value_external(const void *value, + const cl_memory_region_t *bank, cl_addr_t address, cl_value_type type) { - switch (type) - { - case CL_MEMTYPE_INT8: - case CL_MEMTYPE_UINT8: - return 1; - case CL_MEMTYPE_INT16: - case CL_MEMTYPE_UINT16: - return 2; - case CL_MEMTYPE_INT32: - case CL_MEMTYPE_UINT32: - case CL_MEMTYPE_FLOAT: - return 4; - case CL_MEMTYPE_INT64: - case CL_MEMTYPE_DOUBLE: - return 8; - default: - /* Should not be reached */ - cl_message(CL_MSG_ERROR, "cl_sizeof_memtype bad value %u", type); - return 0; - } + if (bank) + address += bank->base_guest; + return cl_abi_external_write_value(value, address, type); } +#endif + /** * Gets the final address referenced by a memory note's chain of pointers, and * reads it into a buffer. @@ -434,14 +483,33 @@ bool cl_memnote_resolve_ptrs(cl_memnote_t *note) for (i = 0; i < note->pointer_passes; i++) { const cl_memory_region_t *region = cl_find_memory_region(final_addr); - + if (!region) return false; - else if (!cl_read_memory(&final_addr, NULL, final_addr, - region->pointer_length)) - return false; + else + { + cl_value_type ptr_type; + + switch (region->pointer_length) + { + case 2: + ptr_type = CL_MEMTYPE_UINT16; + break; + case 4: + ptr_type = CL_MEMTYPE_UINT32; + break; + case 8: + ptr_type = CL_MEMTYPE_INT64; + break; + default: + return false; + } + if (cl_read_memory_value(&final_addr, NULL, final_addr, + ptr_type) != CL_OK) + return false; - final_addr += note->pointer_offsets[i]; + final_addr += note->pointer_offsets[i]; + } } note->address = final_addr; @@ -459,7 +527,7 @@ bool cl_update_memnote(cl_memnote_t *note) /* The "previous" value is the value from the previous frame */ note->previous = note->current; - cl_read_memory(&new_val, NULL, note->address, cl_sizeof_memtype(note->type)); + cl_read_memory_value(&new_val, NULL, note->address, note->type); cl_ctr_store(¬e->current, &new_val, note->type); /* Logic for "last unique" values; the previous value will persist */ @@ -485,54 +553,18 @@ void cl_update_memory(void) } } -unsigned cl_write_memory(cl_memory_region_t *bank, cl_addr_t address, - unsigned size, const void *value) -{ -#if CL_EXTERNAL_MEMORY - unsigned written = 0; - CL_UNUSED(bank); - - cl_abi_external_write(value, address, size, &written); - - return written; -#else - if (!size || !value) - return false; - else if (!bank) - { - bank = cl_find_memory_region(address); - if (!bank) - return false; - else - address -= bank->base_guest; - } - if (bank->base_host) - /* TODO: The address should be masked */ - return cl_write(bank->base_host, value, address, size, bank->endianness); - - return false; -#endif -} - bool cl_write_memnote(cl_memnote_t *note, const cl_counter_t *value) { if (!note || !value) return false; else { - if (cl_memnote_resolve_ptrs(note)) - { - if (cl_ctr_is_float(¬e->current)) - return cl_write_memory(NULL, - note->address, - cl_sizeof_memtype(note->type), - &value->floatval) == cl_sizeof_memtype(note->type); - else - return cl_write_memory(NULL, - note->address, - cl_sizeof_memtype(note->type), - &value->intval) == cl_sizeof_memtype(note->type); - } + if (cl_memnote_resolve_ptrs(note)) + { + return cl_write_memory_value(cl_ctr_is_float(value) ? + (const void *)&value->floatval.fp : (const void *)&value->intval.i64, + NULL, note->address, note->type) == CL_OK; + } } return false; diff --git a/cl_memory.h b/cl_memory.h index b0f2f1f..211fc51 100644 --- a/cl_memory.h +++ b/cl_memory.h @@ -77,65 +77,67 @@ bool cl_get_memnote_value_from_key(cl_counter_t *value, unsigned key, unsigned t /* Populate a memory holder with values returned by the web API */ bool cl_init_memory(const char **pos); -/** - * Reads a value at a virtual memory address into a buffer by using the memory - * bank data pointer. +/** + * Reads a value at a virtual memory address into a buffer by reading internal + * process memory. * In most cases, the cl_read_memory macro should be used instead. * @param value The buffer to be read into. * @param bank A pointer to a specific memory bank, or NULL to have it be * looked up automatically. * @param address The virtual memory address to read from. * @param size The number of bytes to read. - **/ -unsigned cl_read_memory_internal(void *value, const cl_memory_region_t *bank, - cl_addr_t address, unsigned size); + */ +cl_error cl_read_memory_buffer_internal(void *buffer, + const cl_memory_region_t *bank, cl_addr_t address, cl_addr_t size); -#if CL_EXTERNAL_MEMORY -/** - * Reads a value at a virtual memory address into a buffer by reading external +/** + * Reads a value at a virtual memory address into a buffer by reading internal * process memory. * In most cases, the cl_read_memory macro should be used instead. * @param value The buffer to be read into. * @param bank A pointer to a specific memory bank, or NULL to have it be * looked up automatically. * @param address The virtual memory address to read from. - * @param size The number of bytes to read. - **/ -unsigned cl_read_memory_external(void *value, const cl_memory_region_t *bank, - cl_addr_t address, unsigned size); + * @param type The type of value to read. + */ +cl_error cl_read_memory_value_internal(void *buffer, + const cl_memory_region_t *bank, cl_addr_t address, cl_value_type type); + +cl_error cl_write_memory_buffer_internal(const void *buffer, + const cl_memory_region_t *bank, cl_addr_t address, cl_addr_t size); + +cl_error cl_write_memory_value_internal(const void *buffer, + const cl_memory_region_t *bank, cl_addr_t address, cl_value_type type); + +#if CL_EXTERNAL_MEMORY +cl_error cl_read_memory_buffer_external(void *buffer, + const cl_memory_region_t *bank, cl_addr_t address, cl_addr_t size); +cl_error cl_read_memory_value_external(void *buffer, + const cl_memory_region_t *bank, cl_addr_t address, cl_value_type type); +cl_error cl_write_memory_buffer_external(const void *buffer, + const cl_memory_region_t *bank, cl_addr_t address, cl_addr_t size); +cl_error cl_write_memory_value_external(const void *buffer, + const cl_memory_region_t *bank, cl_addr_t address, cl_value_type type); #endif #if CL_EXTERNAL_MEMORY -#define cl_read_memory cl_read_memory_external +#define cl_read_memory_buffer cl_read_memory_buffer_external +#define cl_read_memory_value cl_read_memory_value_external +#define cl_write_memory_buffer cl_write_memory_buffer_external +#define cl_write_memory_value cl_write_memory_value_external #else -#define cl_read_memory cl_read_memory_internal +#define cl_read_memory_buffer cl_read_memory_buffer_internal +#define cl_read_memory_value cl_read_memory_value_internal +#define cl_write_memory_buffer cl_write_memory_buffer_internal +#define cl_write_memory_value cl_write_memory_value_internal #endif -/** - * Returns the size (in bytes) of a given memory type ID. - * @param type A type of memory value. For example, CL_MEMTYPE_8BIT. - * @return The number of bytes the memory type takes up, or 0 if invalid. - **/ -unsigned cl_sizeof_memtype(const cl_value_type type); - /** * Steps through all memory notes and updates their values. Should be called * once per frame. **/ void cl_update_memory(void); -/** - * Writes the given data to a location in emulated virtual memory. - * @param bank A pointer to a specific memory bank, or NULL to have it be - * looked up automatically. - * @param address The virtual address to write to. - * @param size The number of bytes to write. - * @param value A pointer to the source data. - * @return Number of bytes written. - **/ -unsigned cl_write_memory(cl_memory_region_t *bank, cl_addr_t address, - unsigned size, const void *value); - /** * Writes the value referenced by a memory note with a given value. * @param note A pointer to a memory note. diff --git a/cl_search_new.c b/cl_search_new.c index 48bea59..43fd06d 100644 --- a/cl_search_new.c +++ b/cl_search_new.c @@ -12,13 +12,16 @@ #include #if CL_EXTERNAL_MEMORY +#ifndef CL_SEARCH_BUCKET_SIZE /** * The amount of data to retrieve from the external process at a time when * processing a search. */ #define CL_SEARCH_BUCKET_SIZE CL_MB(128) #endif +#endif +#ifndef CL_SEARCH_CHUNK_SIZE /** * The granularity of data to keep in memory as search results. * The total allocation per chunk is twice this size, as the validity bitmap @@ -27,6 +30,7 @@ * @todo Make configurable? */ #define CL_SEARCH_CHUNK_SIZE CL_MB(4) +#endif /** * Allocate a chunk of page-aligned memory. @@ -463,25 +467,45 @@ cl_error cl_search_init(cl_search_t *search) */ static cl_error cl_search_step_first(cl_search_t *search) { +#if CL_EXTERNAL_MEMORY + void *bucket = NULL; + cl_addr_t bucket_offset = 0; + cl_addr_t bucket_processed = 0; + cl_addr_t bucket_size = 0; +#endif cl_search_compare_func_t function = cl_search_comparison_function(search->params); unsigned i; if (!function) return CL_ERR_PARAMETER_INVALID; - else for (i = 0; i < search->page_region_count; i++) + +#if CL_EXTERNAL_MEMORY + bucket = cl_mmap(CL_SEARCH_BUCKET_SIZE); + if (!bucket) + return CL_ERR_CLIENT_RUNTIME; +#endif + + for (i = 0; i < search->page_region_count; i++) { cl_search_page_region_t *page_region = &search->page_regions[i]; cl_search_page_t *page = NULL; cl_search_page_t *prev_page = NULL; cl_addr_t processed = 0; +#if CL_EXTERNAL_MEMORY + bucket_offset = 0; + bucket_processed = 0; + bucket_size = page_region->region->size < CL_SEARCH_BUCKET_SIZE ? + page_region->region->size : CL_SEARCH_BUCKET_SIZE; + cl_read_memory_buffer(bucket, page_region->region, bucket_offset, bucket_size); +#endif + while (processed < page_region->region->size) { unsigned size = CL_SEARCH_CHUNK_SIZE; - /* Allocate small single or final chunk when it can't divide evenly */ if (processed + CL_SEARCH_CHUNK_SIZE > page_region->region->size) - size -= CL_SEARCH_CHUNK_SIZE - processed; + size = (unsigned)(page_region->region->size - processed); if (!page) { @@ -493,46 +517,68 @@ static cl_error cl_search_step_first(cl_search_t *search) page->region = page_region->region; page->start = page_region->region->base_guest + processed; page->size = size; - cl_read_memory(page->chunk, page->region, page->start - page->region->base_guest, size); + +#if CL_EXTERNAL_MEMORY + memcpy(page->chunk, (unsigned char*)bucket + bucket_processed, page->size); +#else + cl_read_memory_buffer(page->chunk, page->region, + page->start - page->region->base_guest, size); +#endif + memset(page->validity, 1, size / search->params.value_size); - - /* Do the search here */ + cl_search_step_page(page, search->params, function, NULL); + if (page->matches == 0) { - /* This page had no matches, so we will reuse it for the next one */ + /* reuse this page for next chunk */ } else { if (!prev_page) - /* This is the first page in this page region */ page_region->first_page = page; else - /* This is another page in this page region's linked list */ prev_page->next = page; - prev_page = page; - /* Count up the matches */ + prev_page = page; page_region->matches += page->matches; search->total_matches += page->matches; - - /* Count up the pages */ page_region->page_count++; search->total_page_count++; - /* The next page will be allocated */ page = NULL; } processed += size; + +#if CL_EXTERNAL_MEMORY + bucket_processed += size; + if (bucket_processed >= bucket_size) + { + bucket_offset += bucket_size; + if (bucket_offset < page_region->region->size) + { + bucket_size = page_region->region->size - bucket_offset; + if (bucket_size > CL_SEARCH_BUCKET_SIZE) + bucket_size = CL_SEARCH_BUCKET_SIZE; + + cl_read_memory_buffer(bucket, page_region->region, bucket_offset, bucket_size); + } + bucket_processed = 0; + } +#endif } - - /* If the final page had no matches, delete it */ + if (page && page->matches == 0) cl_search_free_page(search, page); } + search->steps = 1; +#if CL_EXTERNAL_MEMORY + cl_munmap(bucket, CL_SEARCH_BUCKET_SIZE); +#endif + return cl_search_profile_memory(search); } @@ -544,11 +590,6 @@ cl_error cl_search_step(cl_search_t *search) return cl_search_step_first(search); else { -#if CL_EXTERNAL_MEMORY - void *bucket = NULL; - cl_addr_t bucket_offset = 0; - cl_addr_t bucket_processed = 0; -#endif cl_search_compare_func_t function; cl_addr_t total_matches = 0; unsigned i; @@ -557,12 +598,6 @@ cl_error cl_search_step(cl_search_t *search) if (!function) return CL_ERR_PARAMETER_INVALID; -#if CL_EXTERNAL_MEMORY - bucket = cl_mmap(CL_SEARCH_BUCKET_SIZE); - if (!bucket) - return CL_ERR_CLIENT_RUNTIME; -#endif - for (i = 0; i < search->page_region_count; i++) { cl_search_page_region_t *page_region = &search->page_regions[i]; @@ -571,24 +606,12 @@ cl_error cl_search_step(cl_search_t *search) cl_search_page_t *next_page = NULL; cl_addr_t page_region_matches = 0; -#if CL_EXTERNAL_MEMORY - cl_read_memory(bucket, page_region->region, bucket_offset, - page_region->region->size < CL_SEARCH_BUCKET_SIZE ? - page_region->region->size : CL_SEARCH_BUCKET_SIZE); -#endif - while (page) { cl_error error; -#if CL_EXTERNAL_MEMORY - memcpy(page->chunk, - (unsigned char*)bucket + bucket_processed, - page->size); -#else - cl_read_memory(page->chunk, page->region, + cl_read_memory_buffer(page->chunk, page->region, page->start - page->region->base_guest, page->size); -#endif error = cl_search_step_page(page, search->params, function, NULL); if (error != CL_OK) @@ -616,19 +639,6 @@ cl_error cl_search_step(cl_search_t *search) page_region_matches += page->matches; page = page->next; } - -#if CL_EXTERNAL_MEMORY - /* Move the bucket forward */ - bucket_processed += page->size; - if (bucket_processed >= CL_SEARCH_BUCKET_SIZE) - { - bucket_offset += CL_SEARCH_BUCKET_SIZE; - bucket_processed = 0; - cl_read_memory(bucket, page_region->region, bucket_offset, - page_region->region->size - bucket_processed < CL_SEARCH_BUCKET_SIZE ? - page_region->region->size - bucket_offset : CL_SEARCH_BUCKET_SIZE); - } -#endif } if (prev_page) prev_page->next = NULL; @@ -639,9 +649,6 @@ cl_error cl_search_step(cl_search_t *search) } search->total_matches = total_matches; search->steps++; -#if CL_EXTERNAL_MEMORY - cl_munmap(bucket, CL_SEARCH_BUCKET_SIZE); -#endif return cl_search_profile_memory(search); } diff --git a/cl_test.c b/cl_test.c index ee727e2..3f43106 100644 --- a/cl_test.c +++ b/cl_test.c @@ -12,6 +12,11 @@ #define CL_TEST_DATA_SIZE 128 #define CL_TEST_REGION_COUNT 4 + +#ifndef CL_TEST_REGION_SIZE +#define CL_TEST_REGION_SIZE CL_MB(16) +#endif + typedef struct { cl_memory_region_t regions[CL_TEST_REGION_COUNT]; @@ -205,97 +210,48 @@ static cl_error cl_test_user_data(cl_user_t *user, unsigned index) return CL_OK; } -static cl_error cl_test_external_read(void *dest, cl_addr_t address, +static cl_error cl_test_external_read_buffer(void *dest, cl_addr_t address, unsigned size, unsigned *read) { - unsigned i; - snprintf(cl_test_msg, sizeof(cl_test_msg), "cl_abi_external_read - dest:%p address:0x%08x size:%u read:%p", dest, (unsigned)address, size, (void*)read); cl_test_display_message(CL_MSG_DEBUG, cl_test_msg); -#if CL_EXTERNAL_MEMORY - if (!dest || !read) - return CL_ERR_PARAMETER_NULL; - - /* Find the region that contains this address */ - for (i = 0; i < CL_TEST_REGION_COUNT; i++) - { - cl_memory_region_t *region = &cl_test_system.regions[i]; + return cl_read_memory_buffer_internal(dest, NULL, address, size); +} - if (address >= region->base_guest && - address + size <= region->base_guest + region->size) - { - /* Found the region, perform the read */ - cl_addr_t offset = address - region->base_guest; - - memcpy(dest, - (unsigned char*)region->base_host + offset, - size); - *read = size; - return CL_OK; - } - } +static cl_error cl_test_external_read_value(void *dest, cl_addr_t address, + cl_value_type type) +{ + snprintf(cl_test_msg, sizeof(cl_test_msg), + "cl_abi_external_read_value - dest:%p address:0x%08x type:%u", + dest, (unsigned)address, type); + cl_test_display_message(CL_MSG_DEBUG, cl_test_msg); - /* Address not found */ - *read = 0; - return CL_ERR_PARAMETER_INVALID; -#else - CL_UNUSED(dest); - CL_UNUSED(address); - CL_UNUSED(size); - CL_UNUSED(read); - CL_UNUSED(i); - - return CL_ERR_CLIENT_RUNTIME; -#endif + return cl_read_memory_value_internal(dest, NULL, address, type); } -static cl_error cl_test_external_write(const void *src, cl_addr_t address, +static cl_error cl_test_external_write_buffer(const void *src, cl_addr_t address, unsigned size, unsigned *written) { - unsigned i; - snprintf(cl_test_msg, sizeof(cl_test_msg), "cl_abi_external_write - src:%p address:0x%08x size:%u written:%p", src, (unsigned)address, size, (void*)written); cl_test_display_message(CL_MSG_DEBUG, cl_test_msg); -#if CL_EXTERNAL_MEMORY - if (!src || !written) - return CL_ERR_PARAMETER_NULL; - /* Find the region that contains this address */ - for (i = 0; i < CL_TEST_REGION_COUNT; i++) - { - cl_memory_region_t *region = &cl_test_system.regions[i]; + return cl_write_memory_buffer_internal(src, NULL, address, size); +} - if (address >= region->base_guest && - address + size <= region->base_guest + region->size) - { - /* Found the region, perform the write */ - cl_addr_t offset = address - region->base_guest; - - memcpy((unsigned char*)region->base_host + offset, - src, - size); - *written = size; - return CL_OK; - } - } +static cl_error cl_test_external_write_value(const void *src, cl_addr_t address, + cl_value_type type) +{ + snprintf(cl_test_msg, sizeof(cl_test_msg), + "cl_abi_external_write_value - src:%p address:0x%08x type:%u", + src, (unsigned)address, type); + cl_test_display_message(CL_MSG_DEBUG, cl_test_msg); - /* Address not found */ - *written = 0; - return CL_ERR_PARAMETER_INVALID; -#else - CL_UNUSED(src); - CL_UNUSED(address); - CL_UNUSED(size); - CL_UNUSED(written); - CL_UNUSED(i); - - return CL_ERR_CLIENT_RUNTIME; -#endif + return cl_write_memory_value_internal(src, NULL, address, type); } static const cl_abi_t cl_test_abi = @@ -312,21 +268,22 @@ static const cl_abi_t cl_test_abi = cl_test_user_data }, { - cl_test_external_read, - cl_test_external_write + cl_test_external_read_buffer, + cl_test_external_read_value, + cl_test_external_write_buffer, + cl_test_external_write_value } } }; static cl_error cl_test_console_init(void) { - static const unsigned region_size = CL_MB(16); unsigned i, j; /* Setup fake memory regions */ cl_test_system.regions[0].base_guest = 0x10000000; - cl_test_system.regions[0].size = region_size; - cl_test_system.regions[0].base_host = malloc(region_size); + cl_test_system.regions[0].size = CL_TEST_REGION_SIZE; + cl_test_system.regions[0].base_host = malloc(CL_TEST_REGION_SIZE); cl_test_system.regions[0].endianness = CL_ENDIAN_NATIVE; cl_test_system.regions[0].pointer_length = 4; snprintf(cl_test_system.regions[0].title, @@ -334,8 +291,8 @@ static cl_error cl_test_console_init(void) "Test Region 0"); cl_test_system.regions[1].base_guest = 0x20000000; - cl_test_system.regions[1].size = region_size; - cl_test_system.regions[1].base_host = malloc(region_size); + cl_test_system.regions[1].size = CL_TEST_REGION_SIZE; + cl_test_system.regions[1].base_host = malloc(CL_TEST_REGION_SIZE); cl_test_system.regions[1].endianness = CL_ENDIAN_NATIVE; cl_test_system.regions[1].pointer_length = 4; snprintf(cl_test_system.regions[1].title, @@ -343,8 +300,8 @@ static cl_error cl_test_console_init(void) "Test Region 1"); cl_test_system.regions[2].base_guest = 0x30000000; - cl_test_system.regions[2].size = region_size; - cl_test_system.regions[2].base_host = malloc(region_size); + cl_test_system.regions[2].size = CL_TEST_REGION_SIZE; + cl_test_system.regions[2].base_host = malloc(CL_TEST_REGION_SIZE); cl_test_system.regions[2].endianness = CL_ENDIAN_LITTLE; cl_test_system.regions[2].pointer_length = 4; snprintf(cl_test_system.regions[2].title, @@ -352,8 +309,8 @@ static cl_error cl_test_console_init(void) "Test Region 2 (little-endian)"); cl_test_system.regions[3].base_guest = 0x40000000; - cl_test_system.regions[3].size = region_size; - cl_test_system.regions[3].base_host = malloc(region_size); + cl_test_system.regions[3].size = CL_TEST_REGION_SIZE; + cl_test_system.regions[3].base_host = malloc(CL_TEST_REGION_SIZE); cl_test_system.regions[3].endianness = CL_ENDIAN_BIG; cl_test_system.regions[3].pointer_length = 4; snprintf(cl_test_system.regions[3].title, @@ -400,6 +357,12 @@ static cl_error cl_test(void) unsigned int word; unsigned char byte; unsigned i; + + printf("Starting classicslive-integration tests for target:\n" + "Platform: %s\nBitness: %s\nEndianness: %s\n\n", + cl_string_platform(CL_HOST_PLATFORM), + cl_string_bitness(CL_HOST_BITNESS), + cl_string_endianness(CL_HOST_ENDIANNESS)); /* Perform basic counter function tests */ error = cl_ctr_tests(); @@ -432,8 +395,8 @@ static cl_error cl_test(void) /* Perform some virtual memory tests */ printf("Performing virtual memory tests...\n"); word = 0xDEADBEEF; - cl_write_memory(NULL, 0x30000000, sizeof(word), &word); - cl_read_memory(&byte, NULL, 0x30000000, 1); + cl_write_memory_value(&word, NULL, 0x30000000, CL_MEMTYPE_UINT32); + cl_read_memory_value(&byte, NULL, 0x30000000, CL_MEMTYPE_UINT8); if (byte != 0xEF) { printf("Little-endian virtual memory read/write test failed (got 0x%02x)!\n", byte); @@ -442,8 +405,8 @@ static cl_error cl_test(void) else printf("Little-endian virtual memory read/write test passed (got 0x%02x)!\n", byte); - cl_write_memory(NULL, 0x40000000, sizeof(word), &word); - cl_read_memory(&byte, NULL, 0x40000000, 1); + cl_write_memory_value(&word, NULL, 0x40000000, CL_MEMTYPE_UINT32); + cl_read_memory_value(&byte, NULL, 0x40000000, CL_MEMTYPE_UINT8); if (byte != 0xDE) { printf("Big-endian virtual memory read/write test failed (got 0x%02x)!\n", byte); @@ -523,13 +486,13 @@ static cl_error cl_test(void) /* Run a few frames */ printf("Running simulated frames...\n"); word = 0x20000000; - cl_write_memory(NULL, 0x10000000, sizeof(word), &word); + cl_write_memory_value(&word, NULL, 0x10000000, CL_MEMTYPE_UINT32); for (i = 0; i < 10; i++) { - cl_write_memory(NULL, 0x20000004, sizeof(i), &i); + cl_write_memory_value(&i, NULL, 0x20000004, CL_MEMTYPE_UINT32); cl_run(); - cl_read_memory(&i, NULL, 0x20000004, sizeof(i)); - printf(" - Frame %u completed, memory at 0x20000004 = 0x%08x\n", i, i); + cl_read_memory_value(&word, NULL, 0x20000004, CL_MEMTYPE_UINT32); + printf(" - Frame %u completed, memory at 0x20000004 = 0x%08x\n", i, word); } /* Close and free */ From 5d3e7503fb2d34a7c4d32579159d559e29ede49a Mon Sep 17 00:00:00 2001 From: celerizer Date: Thu, 18 Dec 2025 18:12:46 -0600 Subject: [PATCH 16/57] gruntwork for 32bit and big endian --- Makefile | 5 +- cl_action.c | 6 +- cl_common.c | 31 ++++++--- cl_config.h | 125 ++++++++++++++++++++---------------- cl_identify.c | 8 ++- cl_json.c | 6 +- cl_memory.h | 4 +- cl_network.c | 2 +- cl_test.c | 27 ++------ cl_test.h | 3 + cl_test_main.c | 6 ++ cl_types.h | 13 +++- classicslive-integration.mk | 10 ++- 13 files changed, 145 insertions(+), 101 deletions(-) create mode 100644 cl_test.h create mode 100644 cl_test_main.c diff --git a/Makefile b/Makefile index 3e63293..c4e7842 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ TARGET := cl_test OBJS_CLASSICSLIVE := $(CLASSICS_LIVE_SOURCES_CLASSICSLIVE:.c=.o) OBJS_LIBRETRO := $(CLASSICS_LIVE_SOURCES_LIBRETRO:.c=.o) -OBJS_TEST := $(CLASSICS_LIVE_DIR)/cl_test.o +OBJS_TEST := $(CLASSICS_LIVE_DIR)/cl_test.o $(CLASSICS_LIVE_DIR)/cl_test_main.o OBJS := $(OBJS_CLASSICSLIVE) $(OBJS_LIBRETRO) $(OBJS_TEST) .PHONY: all clean @@ -25,6 +25,9 @@ $(CLASSICS_LIVE_LIBRETRO_DIR)/%.o: $(CLASSICS_LIVE_LIBRETRO_DIR)/%.c $(CLASSICS_LIVE_DIR)/cl_test.o: $(CLASSICS_LIVE_DIR)/cl_test.c $(CC) $(CFLAGS_C89) -c $< -o $@ +$(CLASSICS_LIVE_DIR)/cl_test_main.o: $(CLASSICS_LIVE_DIR)/cl_test_main.c + $(CC) $(CFLAGS_C89) -c $< -o $@ + $(TARGET): $(OBJS) $(CC) $(OBJS) -o $@ $(LDFLAGS) diff --git a/cl_action.c b/cl_action.c index 1dd6384..96b5026 100644 --- a/cl_action.c +++ b/cl_action.c @@ -47,7 +47,7 @@ static cl_error cl_print_counter_values(char *buffer, unsigned len) snprintf(counter_buffer, sizeof(counter_buffer), "&c%u=%f", i, counter->floatval.fp); else - snprintf(counter_buffer, sizeof(counter_buffer), "&c%u=%lu", + snprintf(counter_buffer, sizeof(counter_buffer), "&c%u=%llu", i, counter->intval.raw); /* Check destination buffer can hold it */ @@ -152,7 +152,7 @@ static bool cl_act_post_achievement(cl_action_t *action) #if !CL_HAVE_EDITOR char data[CL_POST_DATA_SIZE]; - snprintf(data, CL_POST_DATA_SIZE, "ach_id=%lu", ach_id.intval.raw); + snprintf(data, CL_POST_DATA_SIZE, "ach_id=%llu", ach_id.intval.raw); cl_network_post_clint(CL_END_CLINT_ACHIEVEMENT, data, NULL, NULL); /* Clear this action so we don't re-submit the achievement */ @@ -186,7 +186,7 @@ static bool cl_act_post_leaderboard(cl_action_t *action) action->arguments[1].uintval); char data[CL_POST_DATA_SIZE]; - snprintf(data, CL_POST_DATA_SIZE, "ldb_id=%lu", ldb_id.intval.raw); + snprintf(data, CL_POST_DATA_SIZE, "ldb_id=%llu", ldb_id.intval.raw); if (cl_print_counter_values(data, sizeof(data)) != CL_OK) cl_message(CL_MSG_ERROR, "Unable to allocate leaderboard data."); else diff --git a/cl_common.c b/cl_common.c index 862edd5..8c576c0 100644 --- a/cl_common.c +++ b/cl_common.c @@ -1,5 +1,9 @@ #include "cl_common.h" +#if CL_SHOW_ERRORS || CL_LOGGING +#include "cl_abi.h" +#endif + #include #include #include @@ -33,11 +37,16 @@ __attribute__((__format__ (__printf__, 1, 0))) void cl_log(const char *format, ...) { #if CL_LOGGING - va_list argv; + if (!format) + return; + else + { + va_list argv; - va_start(argv, format); - vprintf(format, argv); - va_end(argv); + va_start(argv, format); + vprintf(format, argv); + va_end(argv); + } #endif } @@ -64,7 +73,7 @@ cl_error cl_read_16(void *value, const void *src, cl_addr_t offset, uint16_t tmp = *((const uint16_t*)( (const uint8_t*)src + offset)); -#if CL_HOST_ENDIANNESS == CL_ENDIAN_BIG +#if CL_HOST_ENDIANNESS == _CL_ENDIANNESS_BIG if (endianness == CL_ENDIAN_LITTLE) #else if (endianness == CL_ENDIAN_BIG) @@ -98,12 +107,13 @@ cl_error cl_read_32(void *value, const void *src, cl_addr_t offset, uint32_t tmp = *((const uint32_t*)( (const uint8_t*)src + offset)); -#if CL_HOST_ENDIANNESS == CL_ENDIAN_BIG +#if CL_HOST_ENDIANNESS == _CL_ENDIANNESS_BIG if (endianness == CL_ENDIAN_LITTLE) #else if (endianness == CL_ENDIAN_BIG) #endif { + printf("Swapping endian\n"); #if defined(_MSC_VER) tmp = _byteswap_ulong(tmp); #elif defined(__GNUC__) || defined(__clang__) @@ -135,7 +145,7 @@ cl_error cl_read_64(void *value, const void *src, cl_addr_t offset, uint64_t tmp = *((const uint64_t*)( (const uint8_t*)src + offset)); -#if CL_HOST_ENDIANNESS == CL_ENDIAN_BIG +#if CL_HOST_ENDIANNESS == _CL_ENDIANNESS_BIG if (endianness == CL_ENDIAN_LITTLE) #else if (endianness == CL_ENDIAN_BIG) @@ -266,7 +276,7 @@ cl_error cl_write_16(const void *value, void *dst, cl_addr_t offset, #endif uint16_t tmp = *(const uint16_t*)value; -#if CL_HOST_ENDIANNESS == CL_ENDIAN_BIG +#if CL_HOST_ENDIANNESS == _CL_ENDIANNESS_BIG if (endianness == CL_ENDIAN_LITTLE) #else if (endianness == CL_ENDIAN_BIG) @@ -300,12 +310,13 @@ cl_error cl_write_32(const void *value, void *dst, cl_addr_t offset, #endif uint32_t tmp = *(const uint32_t*)value; -#if CL_HOST_ENDIANNESS == CL_ENDIAN_BIG +#if CL_HOST_ENDIANNESS == _CL_ENDIANNESS_BIG if (endianness == CL_ENDIAN_LITTLE) #else if (endianness == CL_ENDIAN_BIG) #endif { + printf("Swapping endian\n"); #if defined(_MSC_VER) tmp = _byteswap_ulong(tmp); #elif defined(__GNUC__) || defined(__clang__) @@ -337,7 +348,7 @@ cl_error cl_write_64(const void *value, void *dst, cl_addr_t offset, #endif uint64_t tmp = *(const uint64_t*)value; -#if CL_HOST_ENDIANNESS == CL_ENDIAN_BIG +#if CL_HOST_ENDIANNESS == _CL_ENDIANNESS_BIG if (endianness == CL_ENDIAN_LITTLE) #else if (endianness == CL_ENDIAN_BIG) diff --git a/cl_config.h b/cl_config.h index aaebe36..0f6f061 100644 --- a/cl_config.h +++ b/cl_config.h @@ -1,100 +1,115 @@ #ifndef CL_CONFIG_H #define CL_CONFIG_H +#define _CL_PLATFORM_UNKNOWN 0 +#define _CL_PLATFORM_WINDOWS 1 +#define _CL_PLATFORM_LINUX 2 +#define _CL_PLATFORM_MACOS 3 +#define _CL_PLATFORM_ANDROID 4 +#define _CL_PLATFORM_NINTENDO_64 5 +#define _CL_PLATFORM_GAMECUBE 6 +#define _CL_PLATFORM_WII 7 +#define _CL_PLATFORM_WII_U 8 +#define _CL_PLATFORM_SWITCH 9 +#define _CL_PLATFORM_SWITCH_2 10 + typedef enum { - CL_PLATFORM_UNKNOWN = 0, - - CL_PLATFORM_WINDOWS, - CL_PLATFORM_LINUX, - CL_PLATFORM_MACOS, - CL_PLATFORM_ANDROID, - - CL_PLATFORM_NINTENDO_64, - CL_PLATFORM_GAMECUBE, - CL_PLATFORM_WII, - CL_PLATFORM_WII_U, - CL_PLATFORM_SWITCH, - CL_PLATFORM_SWITCH_2, + CL_PLATFORM_UNKNOWN = _CL_PLATFORM_UNKNOWN, + + CL_PLATFORM_WINDOWS = _CL_PLATFORM_WINDOWS, + CL_PLATFORM_LINUX = _CL_PLATFORM_LINUX, + CL_PLATFORM_MACOS = _CL_PLATFORM_MACOS, + CL_PLATFORM_ANDROID = _CL_PLATFORM_ANDROID, + CL_PLATFORM_NINTENDO_64 = _CL_PLATFORM_NINTENDO_64, + CL_PLATFORM_GAMECUBE = _CL_PLATFORM_GAMECUBE, + CL_PLATFORM_WII = _CL_PLATFORM_WII, + CL_PLATFORM_WII_U = _CL_PLATFORM_WII_U, + CL_PLATFORM_SWITCH = _CL_PLATFORM_SWITCH, + CL_PLATFORM_SWITCH_2 = _CL_PLATFORM_SWITCH_2, CL_PLATFORM_SIZE } cl_platform; +#define _CL_BITNESS_UNKNOWN 0 +#define _CL_BITNESS_64 1 +#define _CL_BITNESS_32 2 + typedef enum { - CL_BITNESS_UNKNOWN = 0, - CL_BITNESS_64, - CL_BITNESS_32, + CL_BITNESS_UNKNOWN = _CL_BITNESS_UNKNOWN, + CL_BITNESS_64 = _CL_BITNESS_64, + CL_BITNESS_32 = _CL_BITNESS_32, CL_BITNESS_SIZE } cl_bitness; -#define CL_HOST_ENDIAN_LITTLE 1 -#define CL_HOST_ENDIAN_BIG 2 +#define _CL_ENDIANNESS_LITTLE 1 +#define _CL_ENDIANNESS_BIG 2 #ifndef CL_HOST_PLATFORM - #if defined(WIN32) || defined(_WIN32) - #define CL_HOST_PLATFORM CL_PLATFORM_WINDOWS + #if defined(N64) || defined(__N64__) || defined(_N64) + #define CL_HOST_PLATFORM _CL_PLATFORM_NINTENDO_64 + #elif defined(GEKKO) + #if defined(WIIU) + #define CL_HOST_PLATFORM _CL_PLATFORM_WII_U + #elif defined(WII) + #define CL_HOST_PLATFORM _CL_PLATFORM_WII + #else + #define CL_HOST_PLATFORM _CL_PLATFORM_GAMECUBE + #endif + #elif defined(WIN32) || defined(_WIN32) + #define CL_HOST_PLATFORM _CL_PLATFORM_WINDOWS #if defined(WIN64) || defined(_WIN64) - #define CL_HOST_BITNESS CL_BITNESS_64 + #define CL_HOST_BITNESS _CL_BITNESS_64 #else - #define CL_HOST_BITNESS CL_BITNESS_32 + #define CL_HOST_BITNESS _CL_BITNESS_32 #endif #elif defined(__linux__) && !defined(__ANDROID__) - #define CL_HOST_PLATFORM CL_PLATFORM_LINUX + #define CL_HOST_PLATFORM _CL_PLATFORM_LINUX #if defined(__x86_64__) || defined(__ppc64__) || defined(__aarch64__) - #define CL_HOST_BITNESS CL_BITNESS_64 + #define CL_HOST_BITNESS _CL_BITNESS_64 #else - #define CL_HOST_BITNESS CL_BITNESS_32 + #define CL_HOST_BITNESS _CL_BITNESS_32 #endif #elif defined(__APPLE__) && defined(__MACH__) - #define CL_HOST_PLATFORM CL_PLATFORM_MACOS + #define CL_HOST_PLATFORM _CL_PLATFORM_MACOS #if defined(__x86_64__) || defined(__ppc64__) || defined(__aarch64__) - #define CL_HOST_BITNESS CL_BITNESS_64 + #define CL_HOST_BITNESS _CL_BITNESS_64 #else - #define CL_HOST_BITNESS CL_BITNESS_32 + #define CL_HOST_BITNESS _CL_BITNESS_32 #endif #elif defined(__ANDROID__) - #define CL_HOST_PLATFORM CL_PLATFORM_ANDROID + #define CL_HOST_PLATFORM _CL_PLATFORM_ANDROID #if defined(__x86_64__) || defined(__aarch64__) - #define CL_HOST_BITNESS CL_BITNESS_64 + #define CL_HOST_BITNESS _CL_BITNESS_64 #else - #define CL_HOST_BITNESS CL_BITNESS_32 - #endif - #elif defined(N64) - #define CL_HOST_BITNESS CL_BITNESS_32 - #define CL_HOST_PLATFORM CL_PLATFORM_NINTENDO_64 - #define CL_HOST_ENDIANNESS CL_HOST_ENDIAN_BIG - /** - * PowerPC-based Nintendo consoles - * @todo I think GEKKO is always defined, then WII, then __WIIU__ - */ - #elif defined(GEKKO) - #define CL_HOST_BITNESS CL_BITNESS_32 - #define CL_HOST_ENDIANNESS CL_HOST_ENDIAN_BIG - #if defined(__WIIU__) - #define CL_HOST_PLATFORM CL_PLATFORM_WII_U - #elif defined(WII) - #define CL_HOST_PLATFORM CL_PLATFORM_WII - #else - #define CL_HOST_PLATFORM CL_PLATFORM_GAMECUBE + #define CL_HOST_BITNESS _CL_BITNESS_32 #endif #else - #define CL_HOST_PLATFORM CL_PLATFORM_UNKNOWN - #define CL_HOST_ARCHITECTURE CL_PLATFORM_UNKNOWN - #error "Unrecognized target platform" + #error "Unable to determine host platform" #endif #endif + +#if CL_HOST_PLATFORM == _CL_PLATFORM_NINTENDO_64 || \ + CL_HOST_PLATFORM == _CL_PLATFORM_GAMECUBE || \ + CL_HOST_PLATFORM == _CL_PLATFORM_WII || \ + CL_HOST_PLATFORM == _CL_PLATFORM_WII_U + #define CL_HOST_BITNESS _CL_BITNESS_32 + #define CL_HOST_ENDIANNESS _CL_ENDIANNESS_BIG +#endif + #ifndef CL_HOST_BITNESS #error "Unable to determine host bitness" #endif + #ifndef CL_HOST_ENDIANNESS #if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) - #define CL_HOST_ENDIANNESS CL_HOST_ENDIAN_BIG + #define CL_HOST_ENDIANNESS _CL_ENDIANNESS_BIG #elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) - #define CL_HOST_ENDIANNESS CL_HOST_ENDIAN_LITTLE + #define CL_HOST_ENDIANNESS _CL_ENDIANNESS_LITTLE #else #warning "Unable to determine host endianness, assuming little-endian" - #define CL_HOST_ENDIANNESS CL_HOST_ENDIAN_LITTLE + #define CL_HOST_ENDIANNESS _CL_ENDIANNESS_LITTLE #endif #endif diff --git a/cl_identify.c b/cl_identify.c index 2ca7fc7..062f2d1 100644 --- a/cl_identify.c +++ b/cl_identify.c @@ -5,10 +5,15 @@ #include +#if CL_HOST_PLATFORM == CL_PLATFORM_LINUX || \ + CL_HOST_PLATFORM == CL_PLATFORM_MACOS || \ + CL_HOST_PLATFORM == CL_PLATFORM_ANDROID #include +#else +#include +#endif #include -#include #include #if CL_HAVE_FILESYSTEM @@ -16,6 +21,7 @@ #include #include #include +#include #endif typedef struct cl_md5_ctx_t diff --git a/cl_json.c b/cl_json.c index 0272f9d..9b9b611 100644 --- a/cl_json.c +++ b/cl_json.c @@ -378,8 +378,10 @@ static void unescape(char *s) src++; for (i = 0; i < 2 && isxdigit((unsigned char)*src); i++, src++) { - val = val * 16 + (isdigit(*src) ? *src - '0' : - (tolower(*src) - 'a' + 10)); + val = val * 16 + + (isdigit((unsigned char)*src) + ? (unsigned char)*src - '0' + : (tolower((unsigned char)*src) - 'a' + 10)); } *dst++ = (char)val; src--; diff --git a/cl_memory.h b/cl_memory.h index 211fc51..14e5ad8 100644 --- a/cl_memory.h +++ b/cl_memory.h @@ -62,7 +62,7 @@ bool cl_init_membanks_libretro(const struct retro_memory_descriptor **descs, * @param flag The memory note flag to check. For example, CL_MEMFLAG_RICH. **/ bool cl_get_memnote_flag(cl_memnote_t *note, uint8_t flag); -bool cl_get_memnote_flag_from_key(uint32_t key, uint8_t flag); +bool cl_get_memnote_flag_from_key(unsigned key, uint8_t flag); /** * Copies the current value of a memory note into a buffer. @@ -154,7 +154,7 @@ bool cl_write_memnote_from_key(unsigned key, const cl_counter_t *value); * @return A pointer to the appropriate memory note, or NULL if one with the * given key does not exist. **/ -cl_memnote_t* cl_find_memnote(uint32_t key); +cl_memnote_t* cl_find_memnote(unsigned key); /** * Adds a new memory note to the global memory context. diff --git a/cl_network.c b/cl_network.c index 505fd47..3c832ce 100644 --- a/cl_network.c +++ b/cl_network.c @@ -40,7 +40,7 @@ static char *cl_build_generic_post_data(void) written = snprintf(temp, sizeof(temp), "&m%u=%f", note->key, value.floatval.fp); else - written = snprintf(temp, sizeof(temp), "&m%u=%li", + written = snprintf(temp, sizeof(temp), "&m%u=%lli", note->key, value.intval.i64); /* Grow buffer if needed */ diff --git a/cl_test.c b/cl_test.c index 3f43106..bf955d2 100644 --- a/cl_test.c +++ b/cl_test.c @@ -204,7 +204,7 @@ static cl_error cl_test_user_data(cl_user_t *user, unsigned index) return CL_ERR_PARAMETER_INVALID; snprintf(user->username, sizeof(user->username), "clint"); snprintf(user->password, sizeof(user->password), "coffeecoffeefrog123"); - snprintf(user->token, sizeof(user->token), ""); + user->token[0] = '\0'; snprintf(user->language, sizeof(user->language), "en_US"); return CL_OK; @@ -348,7 +348,7 @@ static cl_error cl_test_console_free(void) return CL_OK; } -static cl_error cl_test(void) +cl_error cl_test(void) { cl_search_t search; clock_t start, end; @@ -432,7 +432,7 @@ static cl_error cl_test(void) cl_search_step(&search); end = clock(); cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC; - printf("%lu matches found. %u pages. %lu memory usage. Time: %.6f s\n", + printf(CL_SIZEF " matches found. %u pages. " CL_SIZEF " memory usage. Time: %.6f s\n", search.total_matches, search.total_page_count, search.memory_usage, cpu_time_used); printf("Compare to 1..."); @@ -446,7 +446,7 @@ static cl_error cl_test(void) cl_search_step(&search); end = clock(); cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC; - printf("%lu matches found. %u pages. %lu memory usage. Time: %.6f s\n", + printf(CL_SIZEF " matches found. %u pages. " CL_SIZEF " memory usage. Time: %.6f s\n", search.total_matches, search.total_page_count, search.memory_usage, cpu_time_used); printf("Compare to 2..."); @@ -457,7 +457,7 @@ static cl_error cl_test(void) cl_search_step(&search); end = clock(); cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC; - printf("%lu matches found. %u pages. %lu memory usage. Time: %.6f s\n", + printf(CL_SIZEF " matches found. %u pages. " CL_SIZEF " memory usage. Time: %.6f s\n", search.total_matches, search.total_page_count, search.memory_usage, cpu_time_used); printf("Compare to 3..."); @@ -469,7 +469,7 @@ static cl_error cl_test(void) cl_search_step(&search); end = clock(); cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC; - printf("%lu matches found. %u pages. %lu memory usage. Time: %.6f s\n", + printf(CL_SIZEF " matches found. %u pages. " CL_SIZEF " memory usage. Time: %.6f s\n", search.total_matches, search.total_page_count, search.memory_usage, cpu_time_used); if (search.total_matches != 1) @@ -510,18 +510,3 @@ static cl_error cl_test(void) return CL_OK; } - -int main(void) -{ - unsigned i; - - for (i = 0; i < 10; i++) - { - printf("=== Running test iteration %u ===\n", i + 1); - if (cl_test() != CL_OK) - break; - printf("\n"); - } - - return CL_OK; -} diff --git a/cl_test.h b/cl_test.h new file mode 100644 index 0000000..f01abe0 --- /dev/null +++ b/cl_test.h @@ -0,0 +1,3 @@ +#include "cl_types.h" + +cl_error cl_test(void); diff --git a/cl_test_main.c b/cl_test_main.c new file mode 100644 index 0000000..8ed8960 --- /dev/null +++ b/cl_test_main.c @@ -0,0 +1,6 @@ +#include "cl_test.h" + +int main(void) +{ + return cl_test(); +} diff --git a/cl_types.h b/cl_types.h index 2ef92d7..b66289c 100644 --- a/cl_types.h +++ b/cl_types.h @@ -116,10 +116,10 @@ typedef enum /* 89ABCDEF01234567 */ CL_ENDIAN_WORD_FLIP_LB, -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - CL_ENDIAN_NATIVE = CL_ENDIAN_BIG, +#if CL_HOST_ENDIANNESS == _CL_ENDIANNESS_BIG + CL_ENDIAN_NATIVE = _CL_ENDIANNESS_BIG, #else - CL_ENDIAN_NATIVE = CL_ENDIAN_LITTLE, + CL_ENDIAN_NATIVE = _CL_ENDIANNESS_LITTLE, #endif CL_ENDIAN_SIZE @@ -366,6 +366,13 @@ typedef struct /** A virtual address for the emulated system. */ typedef uintptr_t cl_addr_t; +#if CL_HOST_BITNESS == _CL_BITNESS_32 + #define CL_ADDRF "%08X" + #define CL_SIZEF "%u" +#else + #define CL_ADDRF "%016lX" + #define CL_SIZEF "%lu" +#endif typedef struct cl_counter_t { diff --git a/classicslive-integration.mk b/classicslive-integration.mk index ff6c7b4..7bacd4f 100644 --- a/classicslive-integration.mk +++ b/classicslive-integration.mk @@ -1,6 +1,6 @@ # Paths CLASSICS_LIVE_DIR ?= $(PWD) -CLASSICS_LIVE_LIBRETRO_DIR ?= $(PWD)/../libretro-common +CLASSICS_LIVE_LIBRETRO_DIR ?= $(CLASSICS_LIVE_DIR)/../libretro-common CLASSICS_LIVE_SOURCES_CLASSICSLIVE = \ $(CLASSICS_LIVE_DIR)/cl_abi.c \ @@ -31,8 +31,14 @@ CLASSICS_LIVE_SOURCES_LIBRETRO = \ $(CLASSICS_LIVE_LIBRETRO_DIR)/streams/memory_stream.c \ $(CLASSICS_LIVE_LIBRETRO_DIR)/string/stdstring.c \ $(CLASSICS_LIVE_LIBRETRO_DIR)/time/rtime.c \ - $(CLASSICS_LIVE_LIBRETRO_DIR)/utils/md5.c \ + $(CLASSICS_LIVE_LIBRETRO_DIR)/utils/md5.c + +# VFS is sometimes needed, sometimes not, and sometimes broken. Define this +# variable if it causes issues. +ifndef CL_OMIT_VFS +CLASSICS_LIVE_SOURCES_LIBRETRO += \ $(CLASSICS_LIVE_LIBRETRO_DIR)/vfs/vfs_implementation.c +endif ifeq ($(CL_HAVE_FILESYSTEM),1) CLASSICS_LIVE_SOURCES_LIBRETRO += \ From 0604613963148b52b17cadcb4751a8afcd68395e Mon Sep 17 00:00:00 2001 From: celerizer Date: Thu, 18 Dec 2025 19:38:07 -0600 Subject: [PATCH 17/57] baka gaijin --- cl_common.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/cl_common.c b/cl_common.c index 8c576c0..937e2d5 100644 --- a/cl_common.c +++ b/cl_common.c @@ -113,7 +113,6 @@ cl_error cl_read_32(void *value, const void *src, cl_addr_t offset, if (endianness == CL_ENDIAN_BIG) #endif { - printf("Swapping endian\n"); #if defined(_MSC_VER) tmp = _byteswap_ulong(tmp); #elif defined(__GNUC__) || defined(__clang__) @@ -316,7 +315,6 @@ cl_error cl_write_32(const void *value, void *dst, cl_addr_t offset, if (endianness == CL_ENDIAN_BIG) #endif { - printf("Swapping endian\n"); #if defined(_MSC_VER) tmp = _byteswap_ulong(tmp); #elif defined(__GNUC__) || defined(__clang__) From 62dd581f9c4a1f547598f7479d0a69d6f0770a02 Mon Sep 17 00:00:00 2001 From: celerizer Date: Thu, 18 Dec 2025 21:11:45 -0600 Subject: [PATCH 18/57] adjust fake cl-server responses --- cl_test.c | 30 ++++++++++++++++++++++++++---- cl_test_main.c | 12 +++++++++++- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/cl_test.c b/cl_test.c index bf955d2..cfcedf5 100644 --- a/cl_test.c +++ b/cl_test.c @@ -114,7 +114,7 @@ static cl_error cl_test_network_post(const char *url, char *data, response.data = "{" "\"success\":true," - "\"session_id\":\"#0000000000000000000000000000000\"" + "\"session_id\":\"#000000000000000000000000000000\"" "}"; } else if (strstr(url, CL_CLINT_URL CL_END_CLINT_START)) @@ -130,17 +130,33 @@ static cl_error cl_test_network_post(const char *url, char *data, "]," "\"achievements\":" "[" - "{\"achievement_id\":1,\"name\":\"High Five\",\"description\":\"" - "Increment a value to equal 5.\"}" + "{\"id\":1,\"title\":\"High Five\",\"description\":\"" + "Increment a value to equal 5.\"}," + "{\"id\":2,\"title\":\"Not Happening\",\"description\":\"" + "You will never achieve this.\"}" "]," "\"leaderboards\":" "[" - "{\"leaderboard_id\":1,\"name\":\"High Scores\",\"description\":\"" + "{\"leaderboard_id\":1,\"title\":\"High Scores\",\"description\":\"" "Top scores for the game.\"}" "]," "\"script\":\"1 2 0 15 5 1 1 0 5 1 1 18 2 0 1\"" "}"; } + else if (strstr(url, CL_CLINT_URL CL_END_CLINT_ACHIEVEMENT)) + { + response.data = + "{" + "\"success\":true" + "}"; + } + else if (strstr(url, CL_CLINT_URL CL_END_CLINT_CLOSE)) + { + response.data = + "{" + "\"success\":true" + "}"; + } else { response.data = NULL; @@ -392,6 +408,12 @@ cl_error cl_test(void) if (error != CL_OK) return error; + for (i = 0; i < session.achievement_count; i++) + printf("Achievement %u: %s - %s\n", + session.achievements[i].id, + session.achievements[i].title, + session.achievements[i].description); + /* Perform some virtual memory tests */ printf("Performing virtual memory tests...\n"); word = 0xDEADBEEF; diff --git a/cl_test_main.c b/cl_test_main.c index 8ed8960..b2ad0a8 100644 --- a/cl_test_main.c +++ b/cl_test_main.c @@ -2,5 +2,15 @@ int main(void) { - return cl_test(); + cl_error error; + unsigned i; + + for (i = 0; i < 5; i++) + { + error = cl_test(); + if (error != CL_OK) + return error; + } + + return CL_OK; } From e12c88d5bd53e4bea1bf9a5e2d93a41b04c8aa59 Mon Sep 17 00:00:00 2001 From: celerizer Date: Thu, 18 Dec 2025 21:44:23 -0600 Subject: [PATCH 19/57] not needed here --- cl_identify.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/cl_identify.c b/cl_identify.c index 062f2d1..02ac7c8 100644 --- a/cl_identify.c +++ b/cl_identify.c @@ -9,8 +9,6 @@ CL_HOST_PLATFORM == CL_PLATFORM_MACOS || \ CL_HOST_PLATFORM == CL_PLATFORM_ANDROID #include -#else -#include #endif #include From 7d1ce3833d511ecb23b619b670d10c633a6ebc25 Mon Sep 17 00:00:00 2001 From: celerizer Date: Thu, 18 Dec 2025 23:18:05 -0600 Subject: [PATCH 20/57] just adjusting what the tests print --- cl_test.c | 50 +++++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/cl_test.c b/cl_test.c index cfcedf5..84ff34f 100644 --- a/cl_test.c +++ b/cl_test.c @@ -115,7 +115,7 @@ static cl_error cl_test_network_post(const char *url, char *data, "{" "\"success\":true," "\"session_id\":\"#000000000000000000000000000000\"" - "}"; + "}\n"; } else if (strstr(url, CL_CLINT_URL CL_END_CLINT_START)) { @@ -141,21 +141,21 @@ static cl_error cl_test_network_post(const char *url, char *data, "Top scores for the game.\"}" "]," "\"script\":\"1 2 0 15 5 1 1 0 5 1 1 18 2 0 1\"" - "}"; + "}\n"; } else if (strstr(url, CL_CLINT_URL CL_END_CLINT_ACHIEVEMENT)) { response.data = "{" "\"success\":true" - "}"; + "}\n"; } else if (strstr(url, CL_CLINT_URL CL_END_CLINT_CLOSE)) { response.data = "{" "\"success\":true" - "}"; + "}\n"; } else { @@ -380,7 +380,8 @@ cl_error cl_test(void) cl_string_bitness(CL_HOST_BITNESS), cl_string_endianness(CL_HOST_ENDIANNESS)); - /* Perform basic counter function tests */ + printf("============================================================\n"); + printf("Performing basic counter function tests...\n"); error = cl_ctr_tests(); if (!error) printf("Counter tests passed!\n"); @@ -390,19 +391,19 @@ cl_error cl_test(void) return error; } - /* Register the test ABI */ + printf("============================================================\n"); printf("Registering test ABI...\n"); error = cl_abi_register(&cl_test_abi); if (error != CL_OK) return error; - /* Initialize the test console */ + printf("============================================================\n"); printf("Initializing test console...\n"); error = cl_test_console_init(); if (error != CL_OK) return error; - /* Perform login flow tests */ + printf("============================================================\n"); printf("Performing login flow tests...\n"); error = cl_login_and_start(cl_test_system.identifier); if (error != CL_OK) @@ -413,31 +414,35 @@ cl_error cl_test(void) session.achievements[i].id, session.achievements[i].title, session.achievements[i].description); + for (i = 0; i < session.leaderboard_count; i++) + printf("Leaderboard %u: %s - %s\n", + session.leaderboards[i].id, + session.leaderboards[i].title, + session.leaderboards[i].description); - /* Perform some virtual memory tests */ + printf("============================================================\n"); printf("Performing virtual memory tests...\n"); - word = 0xDEADBEEF; + word = 0x0D15EA5E; cl_write_memory_value(&word, NULL, 0x30000000, CL_MEMTYPE_UINT32); cl_read_memory_value(&byte, NULL, 0x30000000, CL_MEMTYPE_UINT8); - if (byte != 0xEF) + if (byte != 0x5E) { - printf("Little-endian virtual memory read/write test failed (got 0x%02x)!\n", byte); + printf("Little-endian virtual memory read/write test failed (got 0x%02X)!\n", byte); return CL_ERR_CLIENT_RUNTIME; } else - printf("Little-endian virtual memory read/write test passed (got 0x%02x)!\n", byte); - + printf("Little-endian virtual memory read/write test passed (got 0x%02X)!\n", byte); cl_write_memory_value(&word, NULL, 0x40000000, CL_MEMTYPE_UINT32); cl_read_memory_value(&byte, NULL, 0x40000000, CL_MEMTYPE_UINT8); - if (byte != 0xDE) + if (byte != 0x0D) { - printf("Big-endian virtual memory read/write test failed (got 0x%02x)!\n", byte); + printf("Big-endian virtual memory read/write test failed (got 0x%02X)!\n", byte); return CL_ERR_CLIENT_RUNTIME; } else - printf("Big-endian virtual memory read/write test passed (got 0x%02x)!\n", byte); + printf("Big-endian virtual memory read/write test passed (got 0x%02X)!\n", byte); - /* Initialize a search */ + printf("============================================================\n"); printf("Initializing memory search..."); cl_search_init(&search); printf("change cmp..."); @@ -501,12 +506,12 @@ cl_error cl_test(void) } else printf("Memory search test passed!\n"); - printf("Freeing search...\n"); cl_search_free(&search); - /* Run a few frames */ + printf("============================================================\n"); printf("Running simulated frames...\n"); + printf("Achievement should unlock between 4 and 5...\n"); word = 0x20000000; cl_write_memory_value(&word, NULL, 0x10000000, CL_MEMTYPE_UINT32); for (i = 0; i < 10; i++) @@ -517,18 +522,17 @@ cl_error cl_test(void) printf(" - Frame %u completed, memory at 0x20000004 = 0x%08x\n", i, word); } - /* Close and free */ + printf("============================================================\n"); printf("Freeing test session...\n"); error = cl_free(); if (error != CL_OK) return error; - printf("Freeing test console...\n"); error = cl_test_console_free(); if (error != CL_OK) return error; - printf("All tests completed successfully!\n"); + printf("\nd(. _ . )b All tests completed successfully!\n"); return CL_OK; } From dcddea8c889c100c3f056c759b8305987e10f657 Mon Sep 17 00:00:00 2001 From: Keith Bourdon <33245078+celerizer@users.noreply.github.com> Date: Sat, 20 Dec 2025 09:39:12 -0600 Subject: [PATCH 21/57] make an opaque handle for search target --- cl_search_new.c | 116 ++++++++++++++++++++++++++++++++++++++++++------ cl_search_new.h | 16 +++---- 2 files changed, 109 insertions(+), 23 deletions(-) diff --git a/cl_search_new.c b/cl_search_new.c index 43fd06d..a0ced08 100644 --- a/cl_search_new.c +++ b/cl_search_new.c @@ -9,6 +9,7 @@ #include #endif +#include #include #if CL_EXTERNAL_MEMORY @@ -32,6 +33,21 @@ #define CL_SEARCH_CHUNK_SIZE CL_MB(4) #endif +typedef union +{ + uint8_t u8; + int8_t s8; + uint16_t u16; + int16_t s16; + uint32_t u32; + int32_t s32; + int64_t s64; + float fp; + double dfp; +} cl_search_target_impl_t; + +#define CL_TARGET(target) ((cl_search_target_impl_t *)&(target)) + /** * Allocate a chunk of page-aligned memory. * @param size The number of bytes to allocate @@ -85,7 +101,7 @@ static unsigned CL_PASTE3(cl_search_cmp_imm_, b, _##d)( \ unsigned char match; \ a *chunk_data_cast = (a*)chunk_data; \ const a *chunk_data_end_cast = (const a*)chunk_data_end; \ - const a right = ((cl_search_target_t*)target)->b; \ + const a right = ((cl_search_target_impl_t *)(target))->b; \ while (chunk_data_cast < chunk_data_end_cast) \ { \ match = (*chunk_data_cast c right) & *chunk_validity; \ @@ -131,13 +147,13 @@ static unsigned CL_PASTE3(cl_search_cmp_prv_, b, _##d)( \ CL_SEARCH_CMP_IMMEDIATE_TEMPLATE(a, b, !=, neq) \ CL_SEARCH_CMP_PREVIOUS_TEMPLATE(a, b, !=, neq) \ -CL_SEARCH_CMP_IMMEDIATE_UNROLL(unsigned char, u8) -CL_SEARCH_CMP_IMMEDIATE_UNROLL(signed char, s8) -CL_SEARCH_CMP_IMMEDIATE_UNROLL(unsigned short, u16) -CL_SEARCH_CMP_IMMEDIATE_UNROLL(signed short, s16) -CL_SEARCH_CMP_IMMEDIATE_UNROLL(unsigned int, u32) -CL_SEARCH_CMP_IMMEDIATE_UNROLL(signed int, s32) -CL_SEARCH_CMP_IMMEDIATE_UNROLL(signed long, s64) +CL_SEARCH_CMP_IMMEDIATE_UNROLL(uint8_t, u8) +CL_SEARCH_CMP_IMMEDIATE_UNROLL(int8_t, s8) +CL_SEARCH_CMP_IMMEDIATE_UNROLL(uint16_t, u16) +CL_SEARCH_CMP_IMMEDIATE_UNROLL(int16_t, s16) +CL_SEARCH_CMP_IMMEDIATE_UNROLL(uint32_t, u32) +CL_SEARCH_CMP_IMMEDIATE_UNROLL(int32_t, s32) +CL_SEARCH_CMP_IMMEDIATE_UNROLL(int64_t, s64) CL_SEARCH_CMP_IMMEDIATE_UNROLL(float, fp) CL_SEARCH_CMP_IMMEDIATE_UNROLL(double, dfp) @@ -344,6 +360,70 @@ cl_error cl_search_change_compare_type(cl_search_t *search, } } +/** + * Return the canonical target value of a search. + * @param search A pointer to the search to get the target from + * @param out_target A pointer to store the target value into + */ +static cl_error cl_search_get_target(const cl_search_t *search, int64_t *out) +{ + if (!search || !out) + return CL_ERR_PARAMETER_NULL; + else + { + cl_search_target_impl_t *target = CL_TARGET(search->params.target); + + switch (search->params.value_size) + { + case 1: + *out = target->s8; + return CL_OK; + case 2: + *out = target->s16; + return CL_OK; + case 4: + *out = target->s32; + return CL_OK; + case 8: + *out = target->s64; + return CL_OK; + default: + return CL_ERR_PARAMETER_INVALID; + } + } +} + +static cl_error cl_search_set_target(cl_search_t *search, int64_t value) +{ + if (!search) + return CL_ERR_PARAMETER_NULL; + else + { + cl_search_target_impl_t *target = CL_TARGET(search->params.target); + + target->s64 = 0; + switch (search->params.value_size) + { + case 1: + target->s8 = (int8_t)value; + break; + case 2: + target->s16 = (int16_t)value; + break; + case 4: + target->s32 = (int32_t)value; + break; + case 8: + target->s64 = (int64_t)value; + break; + default: + return CL_ERR_PARAMETER_INVALID; + } + + return CL_OK; + } +} + cl_error cl_search_change_value_type(cl_search_t *search, cl_value_type type) { if (!search) @@ -352,8 +432,12 @@ cl_error cl_search_change_value_type(cl_search_t *search, cl_value_type type) return CL_ERR_PARAMETER_INVALID; else { + int64_t target_value = 0; + + cl_search_get_target(search, &target_value); search->params.value_type = type; search->params.value_size = cl_sizeof_memtype(type); + cl_search_set_target(search, target_value); return CL_OK; } @@ -368,21 +452,22 @@ cl_error cl_search_change_target(cl_search_t *search, const void *value) else { cl_search_target_t target; + cl_search_target_impl_t *target_impl = CL_TARGET(target); - memset(&target, 0, sizeof(cl_search_target_t)); + target_impl->s64 = 0; switch (search->params.value_size) { case 1: - memcpy(&target.u8, value, 1); + target_impl->s8 = *(const int8_t*)value; break; case 2: - memcpy(&target.u16, value, 2); + target_impl->s16 = *(const int16_t*)value; break; case 4: - memcpy(&target.u32, value, 4); + target_impl->s32 = *(const int32_t*)value; break; case 8: - memcpy(&target.u64, value, 8); + target_impl->s64 = *(const int64_t*)value; break; default: return CL_ERR_PARAMETER_INVALID; @@ -441,6 +526,11 @@ cl_error cl_search_init(cl_search_t *search) return CL_ERR_PARAMETER_NULL; else if (memory.region_count == 0) return CL_ERR_PARAMETER_INVALID; + else if (sizeof(cl_search_target_impl_t) != sizeof(cl_search_target_t)) + { + cl_message(CL_MSG_ERROR, "Compile: search target impl size mismatch"); + return CL_ERR_CLIENT_COMPILE; + } /* Zero-init the search */ memset(search, 0, sizeof(cl_search_t)); diff --git a/cl_search_new.h b/cl_search_new.h index 4756423..e8c2c6a 100644 --- a/cl_search_new.h +++ b/cl_search_new.h @@ -57,18 +57,14 @@ typedef struct cl_addr_t matches; } cl_search_page_region_t; +/** + * An opaque handle representing a target value for searches. + * The actual implementation is available in `cl_search.c`. + */ typedef union { - unsigned char u8; - signed char s8; - unsigned short u16; - signed short s16; - unsigned int u32; - signed int s32; - unsigned long u64; - signed long s64; - float fp; - double dfp; + unsigned char raw[8]; + double _align; } cl_search_target_t; typedef struct From e25c9a129aa20ebc331656ff69528f548cd36448 Mon Sep 17 00:00:00 2001 From: celerizer Date: Sat, 20 Dec 2025 13:34:29 -0600 Subject: [PATCH 22/57] simplify --- cl_search_new.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/cl_search_new.c b/cl_search_new.c index a0ced08..7781cbc 100644 --- a/cl_search_new.c +++ b/cl_search_new.c @@ -619,11 +619,8 @@ static cl_error cl_search_step_first(cl_search_t *search) cl_search_step_page(page, search->params, function, NULL); - if (page->matches == 0) - { - /* reuse this page for next chunk */ - } - else + /* If there were no matches, reuse the allocated page */ + if (page->matches > 0) { if (!prev_page) page_region->first_page = page; From 8a5ddbde7bb2c0b72c67909de3ddf72f2e91cfa7 Mon Sep 17 00:00:00 2001 From: celerizer Date: Sat, 20 Dec 2025 21:51:39 -0600 Subject: [PATCH 23/57] poop --- cl_common.c | 21 ++ cl_common.h | 6 + cl_config.h | 21 ++ cl_memory.h | 13 - cl_search.c | 17 +- cl_search.h | 16 +- cl_search_new.c | 102 +++++-- cl_search_new.h | 19 +- cl_types.h | 14 + editor/cle_action_block.cpp | 5 + editor/cle_action_block_bookend.cpp | 5 + editor/cle_action_block_comparison.cpp | 5 + editor/cle_action_block_ctrbinary.cpp | 6 +- editor/cle_common.cpp | 140 ++++----- editor/cle_common.h | 8 +- editor/cle_hex_view.cpp | 71 ++--- editor/cle_memory_inspector.cpp | 253 ++++++++--------- editor/cle_memory_inspector.h | 2 +- editor/cle_result_table.cpp | 80 +++--- editor/cle_result_table.h | 12 +- editor/cle_result_table_normal.cpp | 377 +++++++++++++------------ editor/cle_result_table_normal.h | 4 +- editor/cle_result_table_pointer.cpp | 48 ++-- editor/cle_result_table_pointer.h | 72 +++-- 24 files changed, 727 insertions(+), 590 deletions(-) diff --git a/cl_common.c b/cl_common.c index 937e2d5..4993675 100644 --- a/cl_common.c +++ b/cl_common.c @@ -50,6 +50,27 @@ void cl_log(const char *format, ...) #endif } +cl_value_type cl_pointer_type(const unsigned size) +{ + switch (size) + { + case 1: + return CL_MEMTYPE_UINT8; + case 2: + return CL_MEMTYPE_UINT16; + case 3: + case 4: + return CL_MEMTYPE_UINT32; + case 5: + case 6: + case 7: + case 8: + return CL_MEMTYPE_INT64; + } + + return CL_MEMTYPE_NOT_SET; +} + cl_error cl_read_8(void *value, const void *src, cl_addr_t offset) { #if CL_SAFETY diff --git a/cl_common.h b/cl_common.h index 917511b..8606002 100644 --- a/cl_common.h +++ b/cl_common.h @@ -21,6 +21,12 @@ void cl_message(cl_log_level level, const char *format, ...); */ void cl_log(const char *format, ...); +/** + * Returns the value type that represents a pointer of a given size. + * @param size Pointer size, in bytes + */ +cl_value_type cl_pointer_type(const unsigned size); + cl_error cl_read_8(void *value, const void *src, cl_addr_t offset); cl_error cl_read_16(void *value, const void *src, cl_addr_t offset, cl_endianness endianness); diff --git a/cl_config.h b/cl_config.h index 0f6f061..c3f7a58 100644 --- a/cl_config.h +++ b/cl_config.h @@ -154,6 +154,27 @@ typedef enum #define CL_LIBRETRO false #endif +#if CL_EXTERNAL_MEMORY +#ifndef CL_SEARCH_BUCKET_SIZE +/** + * The amount of data to retrieve from the external process at a time when + * processing a search. + */ +#define CL_SEARCH_BUCKET_SIZE CL_MB(128) +#endif +#endif + +#ifndef CL_SEARCH_CHUNK_SIZE +/** + * The granularity of data to keep in memory as search results. + * The total allocation per chunk is twice this size, as the validity bitmap + * is stored alongside the data itself. + * This value was decided on by guessing to see which was most performant. :B + * @todo Make configurable? + */ +#define CL_SEARCH_CHUNK_SIZE CL_MB(4) +#endif + #ifndef CL_URL_HOSTNAME /** * The full hostname for the CL website. diff --git a/cl_memory.h b/cl_memory.h index 14e5ad8..3099ab6 100644 --- a/cl_memory.h +++ b/cl_memory.h @@ -7,19 +7,6 @@ as well as on timed intervals to retrieve a play status string. */ #define CL_MEMFLAG_RICH 0 -typedef enum -{ - CL_SRCTYPE_IMMEDIATE_INT = 0, - CL_SRCTYPE_CURRENT_RAM, - CL_SRCTYPE_PREVIOUS_RAM, - CL_SRCTYPE_LAST_UNIQUE_RAM, - CL_SRCTYPE_ROM, - CL_SRCTYPE_COUNTER, - CL_SRCTYPE_IMMEDIATE_FLOAT, - - CL_SRCTYPE_SIZE -} cl_src_t; - #include "cl_config.h" #include "cl_counter.h" #include "cl_types.h" diff --git a/cl_search.c b/cl_search.c index ef9d24d..9355b2b 100644 --- a/cl_search.c +++ b/cl_search.c @@ -126,10 +126,11 @@ bool resolve_pointerresult(cl_addr_t *final_address, const cl_pointerresult_t *r for (i = 0; i < passes; i++) { const cl_memory_region_t *region = cl_find_memory_region(address); + cl_value_type ptr_type = cl_pointer_type(region->pointer_length); if (!region) return false; - else if (!cl_read_memory(&address, NULL, address, region->pointer_length)) + else if (!cl_read_memory_value(&address, NULL, address, ptr_type)) return false; else address += result->offsets[i]; @@ -176,7 +177,8 @@ bool add_pass(cl_pointersearch_t* search, uint32_t range, uint32_t max_results) for (k = 0; k < region->size; k += region->pointer_length) { - cl_read_memory_internal(&value, region, k, region->pointer_length); + cl_value_type ptr_type = cl_pointer_type(region->pointer_length); + cl_read_memory_value_internal(&value, region, k, ptr_type); if (value <= target && value >= target - range) { @@ -223,7 +225,7 @@ bool cl_pointersearch_init(cl_pointersearch_t *search, uint32_t i, j; /* Is the address we're looking for valid? */ - if (!cl_read_memory(&prev_value, NULL, address, cl_sizeof_memtype(val_type))) + if (!cl_read_memory_value(&prev_value, NULL, address, val_type)) { cl_log("Address %08X is invalid for a pointer search.\n", address); return false; @@ -251,12 +253,13 @@ bool cl_pointersearch_init(cl_pointersearch_t *search, #if CL_EXTERNAL_MEMORY region->base_host = malloc(region->size); - cl_read_memory_external(region->base_host, NULL, region->base_guest, region->size); + cl_read_memory_buffer_external(region->base_host, NULL, region->base_guest, region->size); #endif for (j = 0; j < region->size; j += region->pointer_length) { - cl_read_memory_internal(&value, region, j, region->pointer_length); + cl_value_type ptr_type = cl_pointer_type(region->pointer_length); + cl_read_memory_value_internal(&value, region, j, ptr_type); if (value <= address && value >= address - range) { @@ -322,7 +325,7 @@ uint32_t cl_pointersearch_step(cl_pointersearch_t *search, void *value) if (!resolve_pointerresult(&address, result, search->passes)) continue; - else if (!cl_read_memory(&final_value, NULL, address, search->params.size)) + else if (!cl_read_memory_value(&final_value, NULL, address, search->params.value_type)) continue; else { @@ -375,7 +378,7 @@ void cl_pointersearch_update(cl_pointersearch_t *search) if (!resolve_pointerresult(&result->address_final, result, search->passes)) continue; else - cl_read_memory(&result->value_current, NULL, result->address_final, search->params.size); + cl_read_memory_value(&result->value_current, NULL, result->address_final, search->params.value_type); } } } diff --git a/cl_search.h b/cl_search.h index 3eb4f80..a13b452 100644 --- a/cl_search.h +++ b/cl_search.h @@ -6,18 +6,18 @@ typedef struct cl_search_params_t { - uint8_t compare_type; - uint8_t size; - cl_value_type value_type; + cl_compare_type compare_type; + unsigned size; + cl_value_type value_type; } cl_search_params_t; typedef struct cl_pointerresult_t { - cl_addr_t address_initial; - cl_addr_t address_final; - uint32_t value_current; - uint32_t value_previous; - uint32_t offsets[CL_POINTER_MAX_PASSES]; + cl_addr_t address_initial; + cl_addr_t address_final; + uint32_t value_current; + uint32_t value_previous; + uint32_t offsets[CL_POINTER_MAX_PASSES]; } cl_pointerresult_t; typedef struct cl_pointersearch_t diff --git a/cl_search_new.c b/cl_search_new.c index 7781cbc..5adca7b 100644 --- a/cl_search_new.c +++ b/cl_search_new.c @@ -12,27 +12,6 @@ #include #include -#if CL_EXTERNAL_MEMORY -#ifndef CL_SEARCH_BUCKET_SIZE -/** - * The amount of data to retrieve from the external process at a time when - * processing a search. - */ -#define CL_SEARCH_BUCKET_SIZE CL_MB(128) -#endif -#endif - -#ifndef CL_SEARCH_CHUNK_SIZE -/** - * The granularity of data to keep in memory as search results. - * The total allocation per chunk is twice this size, as the validity bitmap - * is stored alongside the data itself. - * This value was decided on by guessing to see which was most performant. :B - * @todo Make configurable? - */ -#define CL_SEARCH_CHUNK_SIZE CL_MB(4) -#endif - typedef union { uint8_t u8; @@ -564,6 +543,7 @@ static cl_error cl_search_step_first(cl_search_t *search) cl_addr_t bucket_size = 0; #endif cl_search_compare_func_t function = cl_search_comparison_function(search->params); + int64_t print_target = 0; unsigned i; if (!function) @@ -575,6 +555,9 @@ static cl_error cl_search_step_first(cl_search_t *search) return CL_ERR_CLIENT_RUNTIME; #endif + cl_search_get_target(search, &print_target); + cl_log("Performing initial search step with %li...", print_target); + for (i = 0; i < search->page_region_count; i++) { cl_search_page_region_t *page_region = &search->page_regions[i]; @@ -665,6 +648,10 @@ static cl_error cl_search_step_first(cl_search_t *search) #if CL_EXTERNAL_MEMORY cl_munmap(bucket, CL_SEARCH_BUCKET_SIZE); #endif + cl_search_profile_memory(search); + + cl_log("%u matches, %u bytes memory usage.\n", + search->total_matches, search->memory_usage); return cl_search_profile_memory(search); } @@ -679,12 +666,16 @@ cl_error cl_search_step(cl_search_t *search) { cl_search_compare_func_t function; cl_addr_t total_matches = 0; + int64_t print_target = 0; unsigned i; function = cl_search_comparison_function(search->params); if (!function) return CL_ERR_PARAMETER_INVALID; + cl_search_get_target(search, &print_target); + cl_log("Performing search step %u with %li...", search->steps, print_target); + for (i = 0; i < search->page_region_count; i++) { cl_search_page_region_t *page_region = &search->page_regions[i]; @@ -736,8 +727,73 @@ cl_error cl_search_step(cl_search_t *search) } search->total_matches = total_matches; search->steps++; + cl_search_profile_memory(search); + + cl_log("%u matches, %u bytes memory usage.\n", total_matches, search->memory_usage); + + return CL_OK; + } +} + +cl_error cl_search_remove(cl_search_t *search, cl_addr_t address) +{ + cl_search_page_region_t *page_region; + cl_search_page_t *page; + unsigned i; + + if (!search) + return CL_ERR_PARAMETER_NULL; + + for (i = 0; i < search->page_region_count; i++) + { + page_region = &search->page_regions[i]; - return cl_search_profile_memory(search); + /* Is it in this region? */ + if (address < page_region->region->base_guest || + address >= page_region->region->base_guest + page_region->region->size) + continue; + + page = page_region->first_page; + + while (page) + { + /* Is it in this page? */ + if (address >= page->start && address < page->start + page->size) + { + cl_addr_t offset = address - page->start; + unsigned char *target = &page->validity[offset / search->params.value_size]; + + if (*target) + { + page->validity[offset / search->params.value_size] = 0; + page->matches--; + if (page->matches == 0) + cl_search_free_page(search, page); + + return CL_OK; + } + } + page = page->next; + } + } + + return CL_ERR_PARAMETER_INVALID; +} + +cl_error cl_search_reset(cl_search_t *search) +{ + if (!search) + return CL_ERR_PARAMETER_NULL; + else + { + cl_search_parameters_t params = search->params; + cl_error error = cl_search_free(search); + + if (error) + return error; + search->params = params; + + return CL_OK; } } @@ -748,7 +804,7 @@ cl_error cl_search_backup_value(void *dst, const cl_search_t *search, cl_search_page_t *page; unsigned i; -#if 0 /* this is already too slow */ +#if CL_SAFETY if (!search || !dst) return CL_ERR_PARAMETER_NULL; #endif diff --git a/cl_search_new.h b/cl_search_new.h index e8c2c6a..f53e5cd 100644 --- a/cl_search_new.h +++ b/cl_search_new.h @@ -1,5 +1,5 @@ -#ifndef CL_SEARCH_H -#define CL_SEARCH_H +#ifndef CL_SEARCH_NEW_H +#define CL_SEARCH_NEW_H #include "cl_types.h" @@ -14,7 +14,7 @@ struct cl_search_page_t void *chunk; /* A pointer to the position of the validity bitmap within the chunk */ - void *validity; + unsigned char *validity; /* The starting address of the memory chunk */ cl_addr_t start; @@ -155,6 +155,19 @@ cl_error cl_search_free(cl_search_t *search); */ cl_error cl_search_init(cl_search_t *search); +/** + * Remove one address from the search, freeing any memory if possible. + * @param search A pointer to the search + * @param address The address to invalidate + */ +cl_error cl_search_remove(cl_search_t *search, cl_addr_t address); + +/** + * Resets a search, freeing the data but retaining the parameters. + * @param search A pointer to the search to reset + */ +cl_error cl_search_reset(cl_search_t *search); + /** * Filters the values to only those that match the given `params`. The total * number of matches will then be available in `total_matches`. diff --git a/cl_types.h b/cl_types.h index b66289c..019db86 100644 --- a/cl_types.h +++ b/cl_types.h @@ -49,6 +49,20 @@ typedef enum CL_COMPARE_SIZE } cl_compare_type; +/** @todo make immediate 1 */ +typedef enum +{ + CL_SRCTYPE_IMMEDIATE_INT = 0, + CL_SRCTYPE_CURRENT_RAM, + CL_SRCTYPE_PREVIOUS_RAM, + CL_SRCTYPE_LAST_UNIQUE_RAM, + CL_SRCTYPE_ROM, + CL_SRCTYPE_COUNTER, + CL_SRCTYPE_IMMEDIATE_FLOAT, + + CL_SRCTYPE_SIZE +} cl_src_t; + /** * A -1 value to represent invalid addresses in memory regions, as 0 for NULL * may be a valid address on some emulated systems. diff --git a/editor/cle_action_block.cpp b/editor/cle_action_block.cpp index 9034a13..e60febf 100644 --- a/editor/cle_action_block.cpp +++ b/editor/cle_action_block.cpp @@ -7,6 +7,11 @@ #include "cle_action_block.h" +extern "C" +{ + #include "../cl_common.h" +} + CleActionBlock::CleActionBlock(cl_action_t *action, QWidget *parent = nullptr) : QWidget(parent) { diff --git a/editor/cle_action_block_bookend.cpp b/editor/cle_action_block_bookend.cpp index 5036ad0..46b9edf 100644 --- a/editor/cle_action_block_bookend.cpp +++ b/editor/cle_action_block_bookend.cpp @@ -1,5 +1,10 @@ #include "cle_action_block_bookend.h" +extern "C" +{ + #include "../cl_common.h" +} + #include CleActionBlockBookend::CleActionBlockBookend(bool is_end, diff --git a/editor/cle_action_block_comparison.cpp b/editor/cle_action_block_comparison.cpp index 020eea3..1550b76 100644 --- a/editor/cle_action_block_comparison.cpp +++ b/editor/cle_action_block_comparison.cpp @@ -1,5 +1,10 @@ #include "cle_action_block_comparison.h" +extern "C" +{ + #include "../cl_memory.h" +} + CleActionBlockComparison::CleActionBlockComparison(cl_action_t *action, QWidget* parent = nullptr) : CleActionBlock(action, parent) { diff --git a/editor/cle_action_block_ctrbinary.cpp b/editor/cle_action_block_ctrbinary.cpp index f2bab00..64d69f1 100644 --- a/editor/cle_action_block_ctrbinary.cpp +++ b/editor/cle_action_block_ctrbinary.cpp @@ -1,10 +1,10 @@ +#include "cle_action_block_ctrbinary.h" + extern "C" { - #include "../cl_script.h" + #include "../cl_memory.h" } -#include "cle_action_block_ctrbinary.h" - CleActionBlockCtrBinary::CleActionBlockCtrBinary(cl_action_t *action, QWidget* parent = nullptr) : CleActionBlock(action, parent) { diff --git a/editor/cle_common.cpp b/editor/cle_common.cpp index 57022e3..38e6f88 100644 --- a/editor/cle_common.cpp +++ b/editor/cle_common.cpp @@ -1,82 +1,82 @@ #include "cle_common.h" -uint32_t stringToValue(QString string, bool *ok) +int64_t stringToValue(QString string, bool *ok) { - if (string.isEmpty()) - return 0; - else - { - uint8_t base = 0; - bool negative = false; - char prefix = string.at(0).toLatin1(); + if (string.isEmpty()) + return 0; + else + { + uint8_t base = 0; + bool negative = false; + char prefix = string.at(0).toLatin1(); - /* Pop one more if entered value is negative */ - if (prefix == '-') - { - negative = true; - string.remove(0, 1); - prefix = string.at(0).toLatin1(); - } + /* Pop one more if entered value is negative */ + if (prefix == '-') + { + negative = true; + string.remove(0, 1); + prefix = string.at(0).toLatin1(); + } - /* Return interpretation of entered number */ - switch (tolower(prefix)) - { - case 'b': - /* Binary */ - base = 2; - break; - case 'o': - /* Octal */ - base = 8; - break; - case 'd': - /* Decimal */ - base = 10; - break; - case 'h': - case 'x': - /* Hexidecimal */ - base = 16; - } + /* Return interpretation of entered number */ + switch (tolower(prefix)) + { + case 'b': + /* Binary */ + base = 2; + break; + case 'o': + /* Octal */ + base = 8; + break; + case 'd': + /* Decimal */ + base = 10; + break; + case 'h': + case 'x': + /* Hexidecimal */ + base = 16; + } - if (base) - string.remove(0, 1); - else - base = 10; // TODO: Config option for default base? + if (base) + string.remove(0, 1); + else + base = 10; // TODO: Config option for default base? - return negative ? 0 - (uint32_t)string.toInt(ok, base) : - string.toUInt(ok, base); - } + return negative ? 0 - (int64_t)string.toInt(ok, base) : + string.toUInt(ok, base); + } } -void valueToString(char *string, uint8_t length, uint32_t value, - uint8_t memtype) +void valueToString(char *string, unsigned length, int64_t value, + cl_value_type memtype) { - switch (memtype) - { - case CL_MEMTYPE_INT8: - snprintf(string, length, "%02X (%i)", value, value); - break; - case CL_MEMTYPE_UINT8: - snprintf(string, length, "%02X (%u)", value, value); - break; - case CL_MEMTYPE_INT16: - snprintf(string, length, "%04X (%i)", value, value); - break; - case CL_MEMTYPE_UINT16: - snprintf(string, length, "%04X (%u)", value, value); - break; - case CL_MEMTYPE_INT32: - snprintf(string, length, "%08X (%i)", value, value); - break; - case CL_MEMTYPE_UINT32: - snprintf(string, length, "%08X (%u)", value, value); - break; - case CL_MEMTYPE_FLOAT: - snprintf(string, length, "%08X (%f)", value, *((float*)(&value))); - break; - default: - snprintf(string, length, "%08X", value); + switch (memtype) + { + case CL_MEMTYPE_INT8: + snprintf(string, length, "%02lX (%li)", value, value); + break; + case CL_MEMTYPE_UINT8: + snprintf(string, length, "%02lX (%lu)", value, value); + break; + case CL_MEMTYPE_INT16: + snprintf(string, length, "%04lX (%li)", value, value); + break; + case CL_MEMTYPE_UINT16: + snprintf(string, length, "%04lX (%lu)", value, value); break; - } + case CL_MEMTYPE_INT32: + snprintf(string, length, "%08lX (%li)", value, value); + break; + case CL_MEMTYPE_UINT32: + snprintf(string, length, "%08lX (%lu)", value, value); + break; + case CL_MEMTYPE_FLOAT: + snprintf(string, length, "%08lX (%f)", value, *((float*)(&value))); + break; + default: + snprintf(string, length, "%08lX", value); + break; + } } diff --git a/editor/cle_common.h b/editor/cle_common.h index 47cc38a..41d29c5 100644 --- a/editor/cle_common.h +++ b/editor/cle_common.h @@ -3,16 +3,16 @@ extern "C" { - #include "../cl_memory.h" + #include "../cl_types.h" } #include -uint32_t stringToValue(QString string, bool *ok); +int64_t stringToValue(QString string, bool *ok); /* Output an appropriately formatted C-string representing a memory value. */ -void valueToString(char *string, uint8_t length, uint32_t value, - uint8_t memtype); +void valueToString(char *string, unsigned length, int64_t value, + cl_value_type memtype); typedef struct { diff --git a/editor/cle_hex_view.cpp b/editor/cle_hex_view.cpp index 2198940..f4f7f6b 100644 --- a/editor/cle_hex_view.cpp +++ b/editor/cle_hex_view.cpp @@ -202,38 +202,41 @@ void CleHexWidget::onClickPointerSearch() void CleHexWidget::onRightClick(cl_addr_t address, QPoint& pos) { - if (address < m_Position || pos.isNull()) + if (address < m_Position || pos.isNull()) + return; + else + { + QMenu menu; + QAction *action_add = menu.addAction(tr("&Add memory note...")); + QAction *action_ptr = menu.addAction(tr("Search for &pointers")); + QAction *action_goto; + const cl_memory_region_t *region; + cl_addr_t goto_address; + cl_value_type ptr_type; + + setCursorOffset(address); + connect(action_add, SIGNAL(triggered()), this, + SLOT(onClickAddMemoryNote())); + connect(action_ptr, SIGNAL(triggered()), this, + SLOT(onClickPointerSearch())); + + /* Allow following a pointer if it is valid */ + region = cl_find_memory_region(address); + if (!region) return; - else - { - QMenu menu; - QAction *action_add = menu.addAction(tr("&Add memory note...")); - QAction *action_ptr = menu.addAction(tr("Search for &pointers")); - QAction *action_goto; - const cl_memory_region_t *region; - cl_addr_t goto_address; - - setCursorOffset(address); - connect(action_add, SIGNAL(triggered()), this, - SLOT(onClickAddMemoryNote())); - connect(action_ptr, SIGNAL(triggered()), this, - SLOT(onClickPointerSearch())); - - /* Allow following a pointer if it is valid */ - region = cl_find_memory_region(address); - if (!region) - return; - else if (cl_read_memory(&goto_address, nullptr, address, region->pointer_length) && - cl_find_memory_region(goto_address)) - { - m_CursorOffset = goto_address; - action_goto = menu.addAction(tr("&Goto this address")); - connect(action_goto, SIGNAL(triggered()), this, - SLOT(onClickGoto())); - } - menu.exec(mapToGlobal(pos)); - } + ptr_type = cl_pointer_type(region->pointer_length); + if (cl_read_memory_value(&goto_address, nullptr, address, ptr_type) && + cl_find_memory_region(goto_address)) + { + m_CursorOffset = goto_address; + action_goto = menu.addAction(tr("&Goto this address")); + connect(action_goto, SIGNAL(triggered()), this, + SLOT(onClickGoto())); + } + + menu.exec(mapToGlobal(pos)); + } } void CleHexWidget::paintEvent(QPaintEvent *event) @@ -290,12 +293,16 @@ void CleHexWidget::repaintAscii(char new_char, uint8_t index) void CleHexWidget::repaintRect(const void *buffer, uint8_t index) { - uint64_t val = 0; + int64_t val = 0; /* Update the hex value drawn over the given rect */ if (buffer) { - cl_read(&val, reinterpret_cast(buffer), index * m_Size, m_Size, m_UseByteSwap ? CL_ENDIAN_BIG : CL_ENDIAN_LITTLE); + cl_read_value(&val, + reinterpret_cast(buffer), + index * m_Size, + cl_pointer_type(m_Size), + m_UseByteSwap ? CL_ENDIAN_BIG : CL_ENDIAN_LITTLE); switch (m_Size) { diff --git a/editor/cle_memory_inspector.cpp b/editor/cle_memory_inspector.cpp index 49c0b72..3fddd59 100644 --- a/editor/cle_memory_inspector.cpp +++ b/editor/cle_memory_inspector.cpp @@ -42,14 +42,14 @@ CleMemoryInspector::CleMemoryInspector() /* Initialize dropdown boxes */ m_CompareDropdown = new QComboBox(); - m_CompareDropdown->addItem(tr("are equal to..."), CLE_CMPTYPE_EQUAL); - m_CompareDropdown->addItem(tr("are greater than..."), CLE_CMPTYPE_GREATER); - m_CompareDropdown->addItem(tr("are less than..."), CLE_CMPTYPE_LESS); - m_CompareDropdown->addItem(tr("are not equal to..."), CLE_CMPTYPE_NOT_EQUAL); - m_CompareDropdown->addItem(tr("have increased by..."), CLE_CMPTYPE_INCREASED); - m_CompareDropdown->addItem(tr("have decreased by..."), CLE_CMPTYPE_DECREASED); - m_CompareDropdown->addItem(tr("are above address..."), CLE_CMPTYPE_ABOVE); - m_CompareDropdown->addItem(tr("are below address..."), CLE_CMPTYPE_BELOW); + m_CompareDropdown->addItem(tr("are equal to..."), CL_COMPARE_EQUAL); + m_CompareDropdown->addItem(tr("are greater than..."), CL_COMPARE_GREATER); + m_CompareDropdown->addItem(tr("are less than..."), CL_COMPARE_LESS); + m_CompareDropdown->addItem(tr("are not equal to..."), CL_COMPARE_NOT_EQUAL); + m_CompareDropdown->addItem(tr("have increased by..."), CL_COMPARE_INCREASED); + m_CompareDropdown->addItem(tr("have decreased by..."), CL_COMPARE_DECREASED); + m_CompareDropdown->addItem(tr("are above address..."), CL_COMPARE_ABOVE); + m_CompareDropdown->addItem(tr("are below address..."), CL_COMPARE_BELOW); connect(m_CompareDropdown, SIGNAL(activated(int)), this, SLOT(onChangeCompareType())); @@ -111,7 +111,7 @@ CleMemoryInspector::CleMemoryInspector() m_CurrentSearch = m_Searches[0]; m_TableStack = new QStackedWidget(this); - m_TableStack->addWidget(m_CurrentSearch->getTable()); + m_TableStack->addWidget(m_CurrentSearch->table()); rebuildLayout(); setWindowTitle(tr("Live Editor")); @@ -125,9 +125,10 @@ CleMemoryInspector::CleMemoryInspector() onChangeCompareType(); } -uint8_t CleMemoryInspector::getCurrentCompareType(void) +cl_compare_type CleMemoryInspector::getCurrentCompareType(void) { - return m_CompareDropdown->itemData(m_CompareDropdown->currentIndex()).toUInt(); + return static_cast(m_CompareDropdown->itemData( + m_CompareDropdown->currentIndex()).toUInt()); } cl_value_type CleMemoryInspector::getCurrentSizeType(void) @@ -157,26 +158,26 @@ void CleMemoryInspector::onAddressChanged(cl_addr_t address) } } -void CleMemoryInspector::onChangeCompareType() +void CleMemoryInspector::onChangeCompareType(void) { - switch (getCurrentCompareType()) - { - case CLE_CMPTYPE_EQUAL: - case CLE_CMPTYPE_GREATER: - case CLE_CMPTYPE_LESS: - case CLE_CMPTYPE_NOT_EQUAL: - m_TextEntry->setPlaceholderText(tr("previous value")); - break; - case CLE_CMPTYPE_INCREASED: - case CLE_CMPTYPE_DECREASED: - m_TextEntry->setPlaceholderText(tr("any amount")); - break; - case CLE_CMPTYPE_ABOVE: - case CLE_CMPTYPE_BELOW: - default: - m_TextEntry->setPlaceholderText(""); - } - m_CurrentSearch->setCompareType(getCurrentCompareType()); + switch (getCurrentCompareType()) + { + case CL_COMPARE_EQUAL: + case CL_COMPARE_GREATER: + case CL_COMPARE_LESS: + case CL_COMPARE_NOT_EQUAL: + m_TextEntry->setPlaceholderText(tr("previous value")); + break; + case CL_COMPARE_INCREASED: + case CL_COMPARE_DECREASED: + m_TextEntry->setPlaceholderText(tr("any amount")); + break; + case CL_COMPARE_ABOVE: + case CL_COMPARE_BELOW: + default: + m_TextEntry->setPlaceholderText(""); + } + m_CurrentSearch->setCompareType(getCurrentCompareType()); } void CleMemoryInspector::onChangeScrollbar(int value) @@ -186,125 +187,125 @@ void CleMemoryInspector::onChangeScrollbar(int value) void CleMemoryInspector::onChangeSizeType() { - m_CurrentSearch->setValueType(getCurrentSizeType()); - m_HexWidget->setSize(cl_sizeof_memtype(getCurrentSizeType())); + m_CurrentSearch->setValueType(getCurrentSizeType()); + m_HexWidget->setSize(cl_sizeof_memtype(getCurrentSizeType())); } -void CleMemoryInspector::onChangeTab() +void CleMemoryInspector::onChangeTab(void) { - uint8_t new_tab = m_Tabs->currentIndex(); - - /* Was the "new tab" icon clicked? */ - if (new_tab >= m_TabCount) - { - /* Setup this tab to be a new search, add a "+" button */ - m_Tabs->setTabText(new_tab, tr("New Search")); - m_Tabs->addTab("+"); - m_TabCount++; - m_Searches[new_tab] = new CleResultTableNormal(this); - m_TableStack->addWidget(m_Searches[new_tab]->getTable()); - } - m_CurrentSearch = m_Searches[new_tab]; - m_CurrentSearch->rebuild(); - m_TableStack->setCurrentIndex(new_tab); - - m_CompareDropdown->setCurrentIndex( - m_CompareDropdown->findData(m_CurrentSearch->getCompareType())); - m_SizeDropdown->setCurrentIndex( - m_SizeDropdown->findData(m_CurrentSearch->getValueType())); - m_HexWidget->setSize(cl_sizeof_memtype(getCurrentSizeType())); + unsigned new_tab = m_Tabs->currentIndex(); + + /* Was the "new tab" icon clicked? */ + if (new_tab >= m_TabCount) + { + /* Setup this tab to be a new search, add a "+" button */ + m_Tabs->setTabText(new_tab, tr("New Search")); + m_Tabs->addTab("+"); + m_TabCount++; + m_Searches[new_tab] = new CleResultTableNormal(this); + m_TableStack->addWidget(m_Searches[new_tab]->table()); + } + m_CurrentSearch = m_Searches[new_tab]; + m_CurrentSearch->rebuild(); + m_TableStack->setCurrentIndex(new_tab); + + m_CompareDropdown->setCurrentIndex( + m_CompareDropdown->findData(m_CurrentSearch->compareType())); + m_SizeDropdown->setCurrentIndex( + m_SizeDropdown->findData(m_CurrentSearch->valueType())); + m_HexWidget->setSize(cl_sizeof_memtype(getCurrentSizeType())); } void CleMemoryInspector::onClickNew() { - if (!memory.region_count) - return; - else - { - m_TableStack->removeWidget(m_Searches[m_Tabs->currentIndex()]->getTable()); - delete m_Searches[m_Tabs->currentIndex()]; - m_Searches[m_Tabs->currentIndex()] = new CleResultTableNormal(this); - m_CurrentSearch = m_Searches[m_Tabs->currentIndex()]; - - m_TableStack->insertWidget(m_Tabs->currentIndex(), m_CurrentSearch->getTable()); - m_TableStack->setCurrentWidget(m_CurrentSearch->getTable()); - m_Tabs->setTabTextColor(m_Tabs->currentIndex(), Qt::white); - - m_CurrentSearch->setCompareType(getCurrentCompareType()); - m_CurrentSearch->setValueType(getCurrentSizeType()); - } + if (!memory.region_count) + return; + else + { + m_TableStack->removeWidget(m_Searches[m_Tabs->currentIndex()]->table()); + delete m_Searches[m_Tabs->currentIndex()]; + m_Searches[m_Tabs->currentIndex()] = new CleResultTableNormal(this); + m_CurrentSearch = m_Searches[m_Tabs->currentIndex()]; + + m_TableStack->insertWidget(m_Tabs->currentIndex(), m_CurrentSearch->table()); + m_TableStack->setCurrentWidget(m_CurrentSearch->table()); + m_Tabs->setTabTextColor(m_Tabs->currentIndex(), Qt::white); + + m_CurrentSearch->setCompareType(getCurrentCompareType()); + m_CurrentSearch->setValueType(getCurrentSizeType()); + } } void CleMemoryInspector::onClickSearch() { - if (!memory.region_count) - return; - else - { - if (!m_CurrentSearch->isInitted()) - onClickNew(); - if (!m_CurrentSearch->step(m_TextEntry->text())) - { - cl_log("Search input failed: %s\n", m_TextEntry->text().toStdString().c_str()); - m_TextEntry->setText(""); - } - } + if (!memory.region_count) + return; + else + { + if (!m_CurrentSearch->isInitted()) + onClickNew(); + if (!m_CurrentSearch->step()) + { + cl_log("Search input failed: %s\n", m_TextEntry->text().toStdString().c_str()); + m_TextEntry->setText(""); + } + } } void CleMemoryInspector::onHexWidgetValueEdited(cl_addr_t address, uint8_t value) { - cl_write_memory(nullptr, address, cl_sizeof_memtype(getCurrentSizeType()), &value); + cl_write_memory_value(&value, NULL, address, CL_MEMTYPE_UINT8); } -void CleMemoryInspector::onClickTabRename() +void CleMemoryInspector::onClickTabRename(void) { - QString text = QInputDialog::getText - ( - this, - tr("Rename"), - tr("Search tab name:") - ); - - if (m_ClickedTab >= 0 && m_ClickedTab < m_TabCount && !text.isEmpty()) - m_Tabs->setTabText(m_ClickedTab, text); + QString text = QInputDialog::getText + ( + this, + tr("Rename"), + tr("Search tab name:") + ); + + if (m_ClickedTab >= 0 && m_ClickedTab < m_TabCount && !text.isEmpty()) + m_Tabs->setTabText(m_ClickedTab, text); } void CleMemoryInspector::onRightClickTabs(const QPoint &pos) { - if (pos.isNull()) + if (pos.isNull()) + return; + else + { + m_ClickedTab = m_Tabs->tabAt(pos); + if (m_ClickedTab < 0 || m_ClickedTab >= m_TabCount) return; - else - { - m_ClickedTab = m_Tabs->tabAt(pos); - if (m_ClickedTab < 0 || m_ClickedTab >= m_TabCount) - return; - else - { - QMenu menu; - QAction *action_rename = menu.addAction(tr("Rename")); + else + { + QMenu menu; + QAction *action_rename = menu.addAction(tr("Rename")); - connect(action_rename, SIGNAL(triggered()), this, - SLOT(onClickTabRename())); + connect(action_rename, SIGNAL(triggered()), this, + SLOT(onClickTabRename())); - menu.exec(m_Tabs->mapToGlobal(pos)); - } - } + menu.exec(m_Tabs->mapToGlobal(pos)); + } + } } void CleMemoryInspector::requestAddMemoryNote(cl_memnote_t note) { - if (!session.game_id) - { - QMessageBox::warning(this, "Live Editor", - tr("The content you are running was not recognized by the server, so " - "you cannot submit memory notes.") - ); - } - else - { - m_MemoryNoteSubmit = new CleMemoryNoteSubmit(note); - m_MemoryNoteSubmit->show(); - } + if (!session.game_id) + { + QMessageBox::warning(this, "Live Editor", + tr("The content you are running was not recognized by the server, so " + "you cannot submit memory notes.") + ); + } + else + { + m_MemoryNoteSubmit = new CleMemoryNoteSubmit(note); + m_MemoryNoteSubmit->show(); + } } void CleMemoryInspector::requestAddMemoryNote(cl_addr_t address) @@ -325,7 +326,7 @@ void CleMemoryInspector::requestPointerSearch(cl_addr_t address) ClePointerSearchDialog dlg(this); if (dlg.exec() != QDialog::Accepted) - return; // user canceled + return; m_Searches[m_TabCount] = new CleResultTablePointer( this, @@ -337,7 +338,7 @@ void CleMemoryInspector::requestPointerSearch(cl_addr_t address) ); m_TabCount++; - m_TableStack->addWidget(m_Searches[m_TabCount-1]->getTable()); + m_TableStack->addWidget(m_Searches[m_TabCount-1]->table()); m_Tabs->setCurrentIndex(m_TabCount - 1); m_Tabs->setTabText(m_Tabs->currentIndex(), tr("Pointers")); m_Tabs->setTabTextColor(m_Tabs->currentIndex(), QColor(200, 180, 255)); @@ -347,8 +348,8 @@ void CleMemoryInspector::requestPointerSearch(cl_addr_t address) void CleMemoryInspector::run() { - m_CurrentSearch->run(); - cl_read_memory(m_BufferCurrent, nullptr, m_AddressOffset + m_CurrentMembank->base_guest, 256); - m_HexWidget->refresh(m_BufferCurrent, m_BufferPrevious); - memcpy(m_BufferPrevious, m_BufferCurrent, 256); + m_CurrentSearch->run(); + cl_read_memory_buffer(m_BufferCurrent, nullptr, m_AddressOffset + m_CurrentMembank->base_guest, 256); + m_HexWidget->refresh(m_BufferCurrent, m_BufferPrevious); + memcpy(m_BufferPrevious, m_BufferCurrent, 256); } diff --git a/editor/cle_memory_inspector.h b/editor/cle_memory_inspector.h index eb03888..22a8c5b 100644 --- a/editor/cle_memory_inspector.h +++ b/editor/cle_memory_inspector.h @@ -64,7 +64,7 @@ public slots: QTabBar *m_Tabs; QTimer *m_UpdateTimer; - uint8_t getCurrentCompareType(void); + cl_compare_type getCurrentCompareType(void); cl_value_type getCurrentSizeType(void); void rebuildLayout(void); diff --git a/editor/cle_result_table.cpp b/editor/cle_result_table.cpp index dad6438..fbf5425 100644 --- a/editor/cle_result_table.cpp +++ b/editor/cle_result_table.cpp @@ -5,59 +5,47 @@ extern "C" { - #include "../cl_common.h" + #include "../cl_common.h" } -QTableWidget* CleResultTable::getTable() +QTableWidget* CleResultTable::table(void) { - return m_Table; + return m_Table; } -void CleResultTable::init() +cl_error CleResultTable::init(void) { - /* Initialize basic table properties and style */ - m_Table = new QTableWidget(); - m_Table->setRowCount(0); - m_Table->setContextMenuPolicy(Qt::CustomContextMenu); - m_Table->setAlternatingRowColors(true); - m_Table->setShowGrid(false); - m_Table->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::Stretch); - m_Table->verticalHeader()->setVisible(false); - m_Table->verticalHeader()->setDefaultSectionSize(16); - - /* Setup Qt slots */ - connect(m_Table, SIGNAL(itemClicked(QTableWidgetItem*)), - this, SLOT(onResultClick(QTableWidgetItem*))); - connect(m_Table, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), - this, SLOT(onResultDoubleClick())); - connect(m_Table, SIGNAL(itemChanged(QTableWidgetItem*)), - this, SLOT(onResultEdited(QTableWidgetItem*))); - connect(m_Table, SIGNAL(customContextMenuRequested(const QPoint&)), - this, SLOT(onResultRightClick(const QPoint&))); - connect(m_Table, SIGNAL(itemSelectionChanged()), - this, SLOT(onResultSelectionChanged())); - - m_ClickedResult = -1; - m_CurrentEditedRow = -1; + /* Initialize basic table properties and style */ + m_Table = new QTableWidget(); + m_Table->setRowCount(0); + m_Table->setContextMenuPolicy(Qt::CustomContextMenu); + m_Table->setAlternatingRowColors(true); + m_Table->setShowGrid(false); + m_Table->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::Stretch); + m_Table->verticalHeader()->setVisible(false); + m_Table->verticalHeader()->setDefaultSectionSize(16); + + /* Setup Qt slots */ + connect(m_Table, SIGNAL(itemClicked(QTableWidgetItem*)), + this, SLOT(onResultClick(QTableWidgetItem*))); + connect(m_Table, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), + this, SLOT(onResultDoubleClick())); + connect(m_Table, SIGNAL(itemChanged(QTableWidgetItem*)), + this, SLOT(onResultEdited(QTableWidgetItem*))); + connect(m_Table, SIGNAL(customContextMenuRequested(const QPoint&)), + this, SLOT(onResultRightClick(const QPoint&))); + connect(m_Table, SIGNAL(itemSelectionChanged()), + this, SLOT(onResultSelectionChanged())); + + m_ClickedResult = -1; + m_CurrentEditedRow = -1; + + return CL_OK; } -void CleResultTable::writeMemory(const cl_addr_t address, - const cl_search_params_t& params, const QString& string) +cl_error CleResultTable::writeMemory(const cl_addr_t address, + const cl_search_parameters_t& params, const QString& string) { - void *value; - bool ok; - - if (params.value_type == CL_MEMTYPE_FLOAT) - value = new float(string.toFloat(&ok)); - else if (params.value_type == CL_MEMTYPE_DOUBLE) - value = new double(string.toDouble(&ok)); - else - value = new uint64_t(stringToValue(string, &ok)); - - if (ok) - { - cl_write_memory(NULL, address, params.size, value); - cl_log("Wrote %s to 0x%08X.\n", string.toStdString().c_str(), address); - } - free(value); +/** @todo */ + return CL_OK; } diff --git a/editor/cle_result_table.h b/editor/cle_result_table.h index f104cd9..0cda7af 100644 --- a/editor/cle_result_table.h +++ b/editor/cle_result_table.h @@ -19,7 +19,7 @@ class CleResultTable : public QWidget /** * Return an address representing the last clicked row. */ - virtual cl_addr_t getClickedResultAddress() = 0; + virtual cl_addr_t getClickedResultAddress(void) = 0; /** * Return a pointer to the relevant search data. @@ -29,13 +29,13 @@ class CleResultTable : public QWidget virtual int isInitted(void) { return 0; } - /* - Recreate all rows to adapt to changes in the search data. - (Use when a search is reset, stepped through, etc.) + /** + * Recreate all rows to adapt to changes in the search data. + * (Use when a search is reset, stepped through, etc.) */ virtual cl_error rebuild(void) = 0; - virtual cl_error reset(uint8_t value_type) = 0; + virtual cl_error reset(void) = 0; /** * Redraw the currently visible table rows with new information. @@ -78,7 +78,7 @@ public slots: * @param params The params of the search type. * @param string The string the user entered into the result entry. */ - void writeMemory(const cl_addr_t address, const cl_search_parameters_t& params, + cl_error writeMemory(const cl_addr_t address, const cl_search_parameters_t& params, const QString& string); }; diff --git a/editor/cle_result_table_normal.cpp b/editor/cle_result_table_normal.cpp index 4434d1c..e79c7b4 100644 --- a/editor/cle_result_table_normal.cpp +++ b/editor/cle_result_table_normal.cpp @@ -37,14 +37,14 @@ CleResultTableNormal::CleResultTableNormal(QWidget *parent) cl_search_init(&m_Search); } -CleResultTableNormal::~CleResultTableNormal() +CleResultTableNormal::~CleResultTableNormal(void) { cl_search_free(&m_Search); } -cl_addr_t CleResultTableNormal::getClickedResultAddress() +cl_addr_t CleResultTableNormal::getClickedResultAddress(void) { - return m_Table->item(m_Table->currentRow(), COL_ADDRESS)->text().split(" ")[0].toULong(NULL, 16); + return m_Table->item(m_Table->currentRow(), COL_ADDRESS)->text().split(" ")[0].toULong(NULL, 16); } void *CleResultTableNormal::searchData(void) @@ -54,229 +54,246 @@ void *CleResultTableNormal::searchData(void) void CleResultTableNormal::onResultClick(QTableWidgetItem *item) //todo { - emit addressChanged(getClickedResultAddress() & ~0xF); + CL_UNUSED(item); + emit addressChanged(getClickedResultAddress() & ~0xF); } -void CleResultTableNormal::onResultDoubleClick() +void CleResultTableNormal::onResultDoubleClick(void) { - if (m_Table->currentColumn() == COL_CURRENT_VALUE) - { - uint32_t i; - - /* We gray out the other entries because they won't update while - we're editing. */ - for (i = 0; i < m_Table->rowCount(); i++) - m_Table->item(i, COL_CURRENT_VALUE)->setTextColor(Qt::gray); - m_CurrentEditedRow = m_Table->currentRow(); - } + if (m_Table->currentColumn() == COL_CURRENT_VALUE) + { + int i; + + /* We gray out the other entries because they won't update while + we're editing. */ + for (i = 0; i < m_Table->rowCount(); i++) + m_Table->item(i, COL_CURRENT_VALUE)->setForeground(Qt::gray); + m_CurrentEditedRow = m_Table->currentRow(); + } } void CleResultTableNormal::onResultEdited(QTableWidgetItem *result) { - if (result->row() == m_CurrentEditedRow && result->column() == COL_CURRENT_VALUE) - { - if (result->isSelected()) - writeMemory(getClickedResultAddress(), m_Search.params, result->text()); - m_CurrentEditedRow = -1; - } + if (result->row() == m_CurrentEditedRow && result->column() == COL_CURRENT_VALUE) + { + if (result->isSelected()) + writeMemory(getClickedResultAddress(), m_Search.params, result->text()); + m_CurrentEditedRow = -1; + } } -void CleResultTableNormal::onClickResultAddMemoryNote() +void CleResultTableNormal::onClickResultAddMemoryNote(void) { - cl_memnote_t note; + cl_memnote_t note; - note.address_initial = getClickedResultAddress(); - note.type = m_Search.params.value_type; - note.pointer_passes = 0; + memset(¬e, 0, sizeof(note)); + note.address_initial = getClickedResultAddress(); + note.type = m_Search.params.value_type; + note.pointer_passes = 0; - emit requestAddMemoryNote(note); + emit requestAddMemoryNote(note); } -void CleResultTableNormal::onClickResultPointerSearch() +void CleResultTableNormal::onClickResultPointerSearch(void) { - emit requestPointerSearch(getClickedResultAddress()); + emit requestPointerSearch(getClickedResultAddress()); } -void CleResultTableNormal::onClickResultRemove() +void CleResultTableNormal::onClickResultRemove(void) { - if (cl_search_remove(&m_Search, getClickedResultAddress())) - rebuild(); + if (cl_search_remove(&m_Search, getClickedResultAddress()) == CL_OK) + rebuild(); } void CleResultTableNormal::onResultRightClick(const QPoint& pos) { - if (pos.isNull()) + if (pos.isNull()) + return; + else + { + m_ClickedResult = m_Table->rowAt(pos.y()); + if (m_ClickedResult < 0 || m_ClickedResult >= m_Table->rowCount()) return; - else - { - m_ClickedResult = m_Table->rowAt(pos.y()); - if (m_ClickedResult < 0 || m_ClickedResult >= m_Table->rowCount()) - return; - else - { - QMenu menu; - QAction *action_add = menu.addAction(tr("&Add memory note...")); - QAction *action_ptr = menu.addAction(tr("Search for &pointers...")); - QAction *action_remove = menu.addAction(tr("&Remove")); - - connect(action_add, SIGNAL(triggered()), this, - SLOT(onClickResultAddMemoryNote())); - connect(action_ptr, SIGNAL(triggered()), this, - SLOT(onClickResultPointerSearch())); - connect(action_remove, SIGNAL(triggered()), this, - SLOT(onClickResultRemove())); - - menu.exec(m_Table->mapToGlobal(pos)); - } - } + else + { + QMenu menu; + QAction *action_add = menu.addAction(tr("&Add memory note...")); + QAction *action_ptr = menu.addAction(tr("Search for &pointers...")); + QAction *action_remove = menu.addAction(tr("&Remove")); + + connect(action_add, SIGNAL(triggered()), this, + SLOT(onClickResultAddMemoryNote())); + connect(action_ptr, SIGNAL(triggered()), this, + SLOT(onClickResultPointerSearch())); + connect(action_remove, SIGNAL(triggered()), this, + SLOT(onClickResultRemove())); + + menu.exec(m_Table->mapToGlobal(pos)); + } + } } -void CleResultTableNormal::onResultSelectionChanged() +void CleResultTableNormal::onResultSelectionChanged(void) { - m_CurrentEditedRow = -1; + m_CurrentEditedRow = -1; } -void CleResultTableNormal::rebuild() +cl_error CleResultTableNormal::rebuild(void) { - char temp_string[32]; - uint8_t size, val_type; - uint32_t current_row, matches, temp_value, i, j; - - /* (De)allocate rows */ - matches = m_Search.matches; - if (matches > CLE_SEARCH_MAX_ROWS) - matches = CLE_SEARCH_MAX_ROWS; - else if (matches == 0) - { - m_Table->setRowCount(0); - return; - } - - current_row = 0; - size = m_Search.params.size; - val_type = m_Search.params.value_type; + char temp_string[32]; + int64_t temp_value = 0; + unsigned val_size = m_Search.params.value_size; + cl_value_type val_type = m_Search.params.value_type; + unsigned current_row = 0; + unsigned matches = m_Search.total_matches; + unsigned char *chunk_buffer; + + if (matches == 0) + { + m_Table->setRowCount(0); + return CL_OK; + } + if (matches > CLE_SEARCH_MAX_ROWS) + matches = CLE_SEARCH_MAX_ROWS; + + m_Table->setRowCount(matches); + chunk_buffer = reinterpret_cast(malloc(CL_SEARCH_CHUNK_SIZE)); + + for (unsigned i = 0; i < m_Search.page_region_count; i++) + { + cl_search_page_t* page; + + /* Skip entire region if no matches */ + if (m_Search.page_regions[i].matches == 0) + continue; + page = m_Search.page_regions[i].first_page; + while (page) + { + unsigned char *data = (unsigned char*)page->chunk; + unsigned char *valid = (unsigned char*)page->validity; + + /* Skip entire page if no matches */ + if (page->matches == 0) + { + page = page->next; + continue; + } - for (i = 0; i < memory.region_count; i++) - { - if (!m_Search.searchbanks[i].any_valid) - continue; + /* This page has matches, so copy a chunk from live memory for current values */ + cl_read_memory_buffer(chunk_buffer, page->region, 0, page->size); - for (j = 0; j < memory.regions[i].size; j += size) + for (cl_addr_t offset = 0; offset < page->size; offset += val_size) { - /* This value was filtered out */ - if (!m_Search.searchbanks[i].valid[j]) - continue; - - /* This value is still valid; add a new row */ - m_Table->insertRow(current_row); - - /* Address */ - snprintf(temp_string, 256, "%08X", j + memory.regions[i].base_guest); - m_Table->setItem(current_row, 0, new QTableWidgetItem(QString(temp_string))); - /* Previous value */ - cl_read_search(&temp_value, &m_Search, &m_Search.searchbanks[i], j); - valueToString(temp_string, sizeof(temp_string), temp_value, val_type); - m_Table->setItem(current_row, 1, new QTableWidgetItem(QString(temp_string))); - /* Current value */ - cl_read_memory(&temp_value, /*&memory.banks[i]*/nullptr, j + memory.regions[i].base_guest, size); - valueToString(temp_string, sizeof(temp_string), temp_value, val_type); - m_Table->setItem(current_row, 2, new QTableWidgetItem(QString(temp_string))); - current_row++; - - /* No need to continue */ - if (current_row == matches) - { - m_Table->setRowCount(matches); - return; - } + /* Skip value if not a match */ + if (!valid[offset / val_size]) + continue; + + /* Create a new row */ + m_Table->insertRow(current_row); + + /* Address */ + snprintf(temp_string, sizeof(temp_string), "%08X", (unsigned)(page->start + offset)); + m_Table->setItem(current_row, 0, new QTableWidgetItem(QString(temp_string))); + + /* Previous value (from chunk) */ + memcpy(&temp_value, data + offset, val_size); + valueToString(temp_string, sizeof(temp_string), temp_value, val_type); + m_Table->setItem(current_row, 1, new QTableWidgetItem(QString(temp_string))); + + /* Current value (from live memory) */ + cl_read_value(&temp_value, chunk_buffer, offset, val_type, page->region->endianness); + valueToString(temp_string, sizeof(temp_string), temp_value, val_type); + m_Table->setItem(current_row, 2, new QTableWidgetItem(QString(temp_string))); + + current_row++; + if (current_row == matches) + { + m_Table->setRowCount(matches); + free(chunk_buffer); + return CL_OK; + } } - } + page = page->next; + } + } + m_Table->setRowCount(matches); + free(chunk_buffer); + + return CL_ERR_CLIENT_RUNTIME; } -void CleResultTableNormal::reset(uint8_t value_type) +cl_error CleResultTableNormal::reset(void) { - cl_search_reset(&m_Search); - m_Table->setRowCount(0); + cl_search_reset(&m_Search); + m_Table->setRowCount(0); + + return CL_OK; } -void CleResultTableNormal::run() +cl_error CleResultTableNormal::run(void) { - QTableWidgetItem *item; - char temp_string[32]; - uint8_t size, val_type; - uint32_t address, curr_value = 0, prev_value = 0, i, j; - - size = m_Search.params.size; - val_type = m_Search.params.value_type; - - for (i = 0; i < m_Table->rowCount(); i++) - { - item = m_Table->item(i, 0); - if (!item) - return; - - /* Don't visually update search results that are out of view */ - if (i < m_Table->verticalScrollBar()->value()) - continue; - else if (i > m_Table->verticalScrollBar()->value() + m_Table->size().height() / 16) - break; - - /* Kind of gross, but should save some memory - Only a few results should be redrawn at any time anyway */ - address = item->text().split(" ")[0].toULong(NULL, 16); - - if (!cl_read_memory(&curr_value, NULL, address, size) || - !cl_read_search(&prev_value, &m_Search, NULL, address)) - break; - - /* Update previous value column */ - item = m_Table->item(i, COL_PREVIOUS_VALUE); + QTableWidgetItem *item; + char temp_string[32]; + cl_value_type val_type = m_Search.params.value_type; + cl_addr_t address = 0; + int64_t curr_value = 0, prev_value = 0; + int i; + + for (i = 0; i < m_Table->rowCount(); i++) + { + item = m_Table->item(i, 0); + if (!item) + continue; + + /* Only update rows that are visible */ + if (i < m_Table->verticalScrollBar()->value()) + continue; + if (i > m_Table->verticalScrollBar()->value() + m_Table->height() / 16) + break; + + /* Parse the address from the first column */ + address = item->text().split(" ")[0].toULong(NULL, 16); + + /* Get the two values */ + if (cl_read_memory_value(&curr_value, nullptr, address, val_type) != CL_OK || + cl_search_backup_value(&prev_value, &m_Search, address) != CL_OK) + continue; + + /* Update previous value column */ + item = m_Table->item(i, COL_PREVIOUS_VALUE); + if (item) + { valueToString(temp_string, sizeof(temp_string), prev_value, val_type); item->setText(temp_string); + } - /* Update current value column */ - if (m_CurrentEditedRow < 0) + /* Update current value column */ + if (m_CurrentEditedRow < 0) + { + item = m_Table->item(i, COL_CURRENT_VALUE); + if (item) { - item = m_Table->item(i, COL_CURRENT_VALUE); + valueToString(temp_string, sizeof(temp_string), curr_value, val_type); + item->setText(temp_string); - valueToString(temp_string, sizeof(temp_string), curr_value, val_type); - item->setText(temp_string); - - /* Display changed values in red */ - item->setTextColor(prev_value != curr_value ? Qt::red : Qt::white); + /* Highlight changed values in red */ + item->setForeground(prev_value != curr_value ? Qt::red : Qt::white); } - } + } + } + + return CL_OK; } -bool CleResultTableNormal::step(const QString& text) +cl_error CleResultTableNormal::step(void) { - void *compare_value; - bool no_input = text.isEmpty(); - bool ok = true; - - if (m_Search.params.value_type == CL_MEMTYPE_FLOAT) - compare_value = new float(text.toFloat(&ok)); - else - compare_value = new uint32_t(stringToValue(text, &ok)); - - /* Run the C code for doing the actual search */ - if (ok || no_input) - cl_search_step - ( - &m_Search, - no_input ? NULL : compare_value - ); - else if (text.front() == '"' && text.back() == '"') - cl_search_ascii - ( - &m_Search, - text.mid(1, text.length() - 2).toStdString().c_str(), - text.length() - 2 - ); - else - return false; - free(compare_value); - rebuild(); - - return true; + cl_error err = cl_search_step(&m_Search); + + if (err) + return err; + else + { + rebuild(); + return CL_OK; + } } diff --git a/editor/cle_result_table_normal.h b/editor/cle_result_table_normal.h index f27225e..652c1f7 100644 --- a/editor/cle_result_table_normal.h +++ b/editor/cle_result_table_normal.h @@ -26,7 +26,7 @@ class CleResultTableNormal : public CleResultTable void *searchData(void) override; int isInitted(void) override { return true; } cl_error rebuild(void) override; - cl_error reset(uint8_t value_type) override; + cl_error reset(void) override; cl_error run(void) override; cl_error step(void) override; @@ -45,7 +45,7 @@ class CleResultTableNormal : public CleResultTable return cl_search_change_compare_type(&m_Search, type); } - cl_error setValueType(const cl_value_type tyoe) override + cl_error setValueType(const cl_value_type type) override { return cl_search_change_value_type(&m_Search, type); } diff --git a/editor/cle_result_table_pointer.cpp b/editor/cle_result_table_pointer.cpp index b9e3f6c..7126aee 100644 --- a/editor/cle_result_table_pointer.cpp +++ b/editor/cle_result_table_pointer.cpp @@ -4,6 +4,8 @@ #include "cle_result_table_pointer.h" #include "cle_common.h" +/** @todo everything here was dummied in anticipation of a pointersearch redo */ + CleResultTablePointer::CleResultTablePointer(QWidget *parent, uint32_t address, uint8_t size, uint8_t passes, uint32_t range, uint32_t max_results) { @@ -52,9 +54,9 @@ cl_addr_t CleResultTablePointer::getClickedResultAddress() return m_Search.results[m_Table->currentRow()].address_final; } -void* CleResultTablePointer::getSearchData() +void *CleResultTablePointer::searchData(void) { - return (void*)(&m_Search); + return &m_Search; } void CleResultTablePointer::onClickResultAddMemoryNote() @@ -121,6 +123,7 @@ void CleResultTablePointer::onResultDoubleClick() void CleResultTablePointer::onResultEdited(QTableWidgetItem *item) { +#if 0 if (item->row() == m_CurrentEditedRow && item->column() == m_ColValueCurr) { if (item->isSelected()) @@ -130,10 +133,13 @@ void CleResultTablePointer::onResultEdited(QTableWidgetItem *item) } m_CurrentEditedRow = -1; } +#endif } -void CleResultTablePointer::rebuild() +cl_error CleResultTablePointer::rebuild(void) { + return CL_OK; +#if 0 char temp_string[32]; uint8_t size; uint32_t current_row, temp_value, i, j; @@ -161,15 +167,17 @@ void CleResultTablePointer::rebuild() valueToString(temp_string, sizeof(temp_string), m_Search.results[i].value_current, size); m_Table->setItem(i, m_ColValueCurr, new QTableWidgetItem(QString(temp_string))); } +#endif } -void CleResultTablePointer::reset(uint8_t value_type) +cl_error CleResultTablePointer::reset(void) { - cl_pointersearch_free(&m_Search); + return CL_OK; } -void CleResultTablePointer::run() +cl_error CleResultTablePointer::run(void) { +#if 0 QTableWidgetItem *item; char temp_string[32]; uint8_t val_type; @@ -213,31 +221,13 @@ void CleResultTablePointer::run() item->setTextColor(value_prev != value_curr ? Qt::red : Qt::white); } } +#endif } -bool CleResultTablePointer::step(const QString& text) +cl_error CleResultTablePointer::step(void) { - void *compare_value; - bool no_input = text.isEmpty(); - bool ok = true; - - if (m_Search.params.value_type == CL_MEMTYPE_FLOAT) - compare_value = new float(text.toFloat(&ok)); - else - compare_value = new uint32_t(stringToValue(text, &ok)); - - /* Run the C code for doing the actual search */ - if (ok || no_input) - cl_pointersearch_step - ( - &m_Search, - no_input ? NULL : compare_value - ); - else - return false; - - free(compare_value); - rebuild(); + cl_pointersearch_step(&m_Search, NULL); + rebuild(); - return true; + return CL_OK; } diff --git a/editor/cle_result_table_pointer.h b/editor/cle_result_table_pointer.h index 1e37863..f38208a 100644 --- a/editor/cle_result_table_pointer.h +++ b/editor/cle_result_table_pointer.h @@ -3,54 +3,52 @@ #include "cle_result_table.h" +extern "C" +{ + #include "../cl_search.h" +} + class CleResultTablePointer : public CleResultTable { Q_OBJECT public: - CleResultTablePointer(QWidget *parent, uint32_t address, uint8_t size, - uint8_t passes, uint32_t range, uint32_t max_results); - ~CleResultTablePointer() override; - - cl_addr_t getClickedResultAddress() override; - void* getSearchData() override; - bool isInitted() override { return true; } - void rebuild() override; - void reset(uint8_t value_type) override; - void run() override; - bool step(const QString& text) override; - - uint8_t getCompareType() override { return m_Search.params.compare_type; } - uint8_t getValueType() override { return m_Search.params.value_type; } - - void setCompareType(const uint8_t new_type) override - { - m_Search.params.compare_type = new_type; - } - void setValueType(const cl_value_type new_type) override - { - m_Search.params.value_type = new_type; - m_Search.params.size = cl_sizeof_memtype(new_type); - } + CleResultTablePointer(QWidget *parent, uint32_t address, uint8_t size, + uint8_t passes, uint32_t range, uint32_t max_results); + ~CleResultTablePointer() override; + + cl_addr_t getClickedResultAddress() override; + void *searchData(void) override; + int isInitted(void) override { return true; } + cl_error rebuild() override; + cl_error reset(void) override; + cl_error run(void) override; + cl_error step(void) override; + + cl_compare_type compareType(void) override { return m_Search.params.compare_type; } + cl_value_type valueType(void) override { return CL_MEMTYPE_NOT_SET; } + + cl_error setCompareType(const cl_compare_type type) override {} + cl_error setValueType(const cl_value_type type) override {} public slots: - void onClickResultAddMemoryNote(); - void onResultClick(QTableWidgetItem *item) override; - void onResultDoubleClick(void) override; - void onResultEdited(QTableWidgetItem *item) override; - void onResultRightClick(const QPoint&) override; - void onResultSelectionChanged(void) override {} + void onClickResultAddMemoryNote(); + void onResultClick(QTableWidgetItem *item) override; + void onResultDoubleClick(void) override; + void onResultEdited(QTableWidgetItem *item) override; + void onResultRightClick(const QPoint&) override; + void onResultSelectionChanged(void) override {} signals: - void addressChanged(cl_addr_t address); - void requestAddMemoryNote(cl_memnote_t note); - void requestRemove(uint32_t index); + void addressChanged(cl_addr_t address); + void requestAddMemoryNote(cl_memnote_t note); + void requestRemove(uint32_t index); private: - uint8_t m_ColAddress; - uint8_t m_ColValuePrev; - uint8_t m_ColValueCurr; - cl_pointersearch_t m_Search; + uint8_t m_ColAddress; + uint8_t m_ColValuePrev; + uint8_t m_ColValueCurr; + cl_pointersearch_t m_Search; }; #endif From 35b30980cf5ca465839bc881fcb0796baff3c3a8 Mon Sep 17 00:00:00 2001 From: Keith Bourdon <33245078+celerizer@users.noreply.github.com> Date: Sun, 21 Dec 2025 10:03:45 -0600 Subject: [PATCH 24/57] add settarget to ui --- editor/cle_memory_inspector.cpp | 11 ++++++ editor/cle_memory_inspector.h | 2 ++ editor/cle_result_table.h | 1 + editor/cle_result_table_normal.h | 59 +++++++++++++++++++++++++++++++ editor/cle_result_table_pointer.h | 1 + 5 files changed, 74 insertions(+) diff --git a/editor/cle_memory_inspector.cpp b/editor/cle_memory_inspector.cpp index 3fddd59..0017ce7 100644 --- a/editor/cle_memory_inspector.cpp +++ b/editor/cle_memory_inspector.cpp @@ -63,6 +63,8 @@ CleMemoryInspector::CleMemoryInspector() /* Initialize text entry box for comparison value */ m_TextEntry = new QLineEdit(); + connect(m_TextEntry, SIGNAL(textChanged(const QString&)), + this, SLOT(onTargetChanged())); connect(m_TextEntry, SIGNAL(returnPressed()), m_SearchButton, SIGNAL(clicked())); @@ -292,6 +294,15 @@ void CleMemoryInspector::onRightClickTabs(const QPoint &pos) } } +void CleMemoryInspector::onTargetChanged(const QString& target) +{ + if (!m_CurrentSearch->setTarget(target)) + { + cl_log("Search input failed: %s\n", target.toStdString().c_str()); + m_TextEntry->setText(""); + } +} + void CleMemoryInspector::requestAddMemoryNote(cl_memnote_t note) { if (!session.game_id) diff --git a/editor/cle_memory_inspector.h b/editor/cle_memory_inspector.h index 22a8c5b..d6429dc 100644 --- a/editor/cle_memory_inspector.h +++ b/editor/cle_memory_inspector.h @@ -82,6 +82,8 @@ private slots: void onRightClickTabs(const QPoint &pos); + void onTargetChanged(const QString&); + void requestAddMemoryNote(cl_memnote_t note); void requestAddMemoryNote(cl_addr_t address); void requestPointerSearch(cl_addr_t address); diff --git a/editor/cle_result_table.h b/editor/cle_result_table.h index 0cda7af..db31918 100644 --- a/editor/cle_result_table.h +++ b/editor/cle_result_table.h @@ -49,6 +49,7 @@ class CleResultTable : public QWidget virtual cl_value_type valueType(void) { return CL_MEMTYPE_NOT_SET; } virtual cl_error setCompareType(const cl_compare_type type) = 0; + virtual cl_error setTarget(const QString &target) = 0; virtual cl_error setValueType(const cl_value_type type) = 0; public slots: diff --git a/editor/cle_result_table_normal.h b/editor/cle_result_table_normal.h index 652c1f7..236b774 100644 --- a/editor/cle_result_table_normal.h +++ b/editor/cle_result_table_normal.h @@ -45,6 +45,65 @@ class CleResultTableNormal : public CleResultTable return cl_search_change_compare_type(&m_Search, type); } + cl_error setTarget(const QString& target) override + { + if (target.isEmpty()) + return cl_search_change_target(&m_Search, NULL); + else switch (m_Search.params.value_type) + { + case CL_MEMTYPE_INT8: + { + int8_t val = (int8_t)target.toInt(); + return cl_search_change_target(&m_Search, &val); + } + case CL_MEMTYPE_UINT8: + { + uint8_t val = (uint8_t)target.toUInt(); + return cl_search_change_target(&m_Search, &val); + } + case CL_MEMTYPE_INT16: + { + int16_t val = (int16_t)target.toInt(); + return cl_search_change_target(&m_Search, &val); + } + case CL_MEMTYPE_UINT16: + { + uint16_t val = (uint16_t)target.toUInt(); + return cl_search_change_target(&m_Search, &val); + } + case CL_MEMTYPE_INT32: + { + int32_t val = (int32_t)target.toInt(); + return cl_search_change_target(&m_Search, &val); + } + case CL_MEMTYPE_UINT32: + { + uint32_t val = (uint32_t)target.toUInt(); + return cl_search_change_target(&m_Search, &val); + } + case CL_MEMTYPE_INT64: + { + int64_t val = (int64_t)target.toLongLong(); + return cl_search_change_target(&m_Search, &val); + } + case CL_MEMTYPE_DOUBLE: + { + double val = target.toDouble(); + return cl_search_change_target(&m_Search, &val); + } + case CL_MEMTYPE_FLOAT: + { + float val = target.toFloat(); + return cl_search_change_target(&m_Search, &val); + } + case CL_MEMTYPE_NOT_SET: + case CL_MEMTYPE_SIZE: + break; + } + + return CL_ERR_PARAMETER_INVALID; + } + cl_error setValueType(const cl_value_type type) override { return cl_search_change_value_type(&m_Search, type); diff --git a/editor/cle_result_table_pointer.h b/editor/cle_result_table_pointer.h index f38208a..cc9e52e 100644 --- a/editor/cle_result_table_pointer.h +++ b/editor/cle_result_table_pointer.h @@ -29,6 +29,7 @@ class CleResultTablePointer : public CleResultTable cl_value_type valueType(void) override { return CL_MEMTYPE_NOT_SET; } cl_error setCompareType(const cl_compare_type type) override {} + cl_error setTarget(const QString& target) override {} cl_error setValueType(const cl_value_type type) override {} public slots: From c76bbb60fd3fddcf807543334a6b777cc6e9df4f Mon Sep 17 00:00:00 2001 From: celerizer Date: Mon, 22 Dec 2025 00:33:45 -0600 Subject: [PATCH 25/57] little stuff --- cl_abi.h | 2 ++ cl_config.h | 2 +- cl_identify.h | 2 +- cl_main.c | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/cl_abi.h b/cl_abi.h index 8c03826..7013ad2 100644 --- a/cl_abi.h +++ b/cl_abi.h @@ -38,6 +38,8 @@ cl_error cl_abi_install_memory_regions(cl_memory_region_t **regions, /** * Requests from the frontend the name of the target library or program. + * Make sure the string returned remains valid for the lifetime of the + * program. * This could be the name of a dynamically linked library, an external * process name, or the name of a program classicslive-integration has * been statically compiled into. diff --git a/cl_config.h b/cl_config.h index c3f7a58..f8c59c4 100644 --- a/cl_config.h +++ b/cl_config.h @@ -172,7 +172,7 @@ typedef enum * This value was decided on by guessing to see which was most performant. :B * @todo Make configurable? */ -#define CL_SEARCH_CHUNK_SIZE CL_MB(4) +#define CL_SEARCH_CHUNK_SIZE CL_KB(4) #endif #ifndef CL_URL_HOSTNAME diff --git a/cl_identify.h b/cl_identify.h index 5821ad1..911cbe7 100644 --- a/cl_identify.h +++ b/cl_identify.h @@ -13,7 +13,7 @@ * @param library The name of the core, which can be used to choose more * specific identification methods. * @param callback A function to run after identification is complete. - **/ + */ bool cl_identify(const void *info_data, const unsigned info_size, const char *info_path, const char *library, char *checksum, CL_TASK_CB_T callback); diff --git a/cl_main.c b/cl_main.c index e2c2f9d..b9f401f 100644 --- a/cl_main.c +++ b/cl_main.c @@ -61,8 +61,8 @@ static cl_error cl_init_session(const char* json) { if (!cl_script_init(&iterator)) { - cl_message(CL_MSG_ERROR, "Failed to initialize CL script."); #if !CL_HAVE_EDITOR + cl_message(CL_MSG_ERROR, "Failed to initialize CL script."); return CL_ERR_SERVER_UNEXPECTED_RESPONSE; #endif } From a9602f1fbf42df9bade8d79531fb31668c720629 Mon Sep 17 00:00:00 2001 From: celerizer Date: Mon, 22 Dec 2025 00:34:25 -0600 Subject: [PATCH 26/57] hhokup new options to ui (64/dfp search, target) --- editor/cle_memory_inspector.cpp | 30 +++++++++++++++++++++++------- editor/cle_result_table_normal.cpp | 8 ++++---- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/editor/cle_memory_inspector.cpp b/editor/cle_memory_inspector.cpp index 0017ce7..031dbe7 100644 --- a/editor/cle_memory_inspector.cpp +++ b/editor/cle_memory_inspector.cpp @@ -56,15 +56,17 @@ CleMemoryInspector::CleMemoryInspector() m_SizeDropdown = new QComboBox(); m_SizeDropdown->addItem(tr("1-byte values"), CL_MEMTYPE_UINT8); m_SizeDropdown->addItem(tr("2-byte values"), CL_MEMTYPE_UINT16); - m_SizeDropdown->addItem(tr("4-byte values"), CL_MEMTYPE_INT32); + m_SizeDropdown->addItem(tr("4-byte values"), CL_MEMTYPE_UINT32); m_SizeDropdown->addItem(tr("float values"), CL_MEMTYPE_FLOAT); + m_SizeDropdown->addItem(tr("8-byte values"), CL_MEMTYPE_INT64); + m_SizeDropdown->addItem(tr("double values"), CL_MEMTYPE_DOUBLE); connect(m_SizeDropdown, SIGNAL(activated(int)), this, SLOT(onChangeSizeType())); /* Initialize text entry box for comparison value */ m_TextEntry = new QLineEdit(); - connect(m_TextEntry, SIGNAL(textChanged(const QString&)), - this, SLOT(onTargetChanged())); + connect(m_TextEntry, SIGNAL(textChanged(const QString&)), + this, SLOT(onTargetChanged(const QString&))); connect(m_TextEntry, SIGNAL(returnPressed()), m_SearchButton, SIGNAL(clicked())); @@ -110,6 +112,9 @@ CleMemoryInspector::CleMemoryInspector() memset(m_Searches, 0, sizeof(m_Searches)); m_Searches[0] = new CleResultTableNormal(this); + m_Searches[0]->setCompareType(getCurrentCompareType()); + m_Searches[0]->setTarget(m_TextEntry->text()); + m_Searches[0]->setValueType(getCurrentSizeType()); m_CurrentSearch = m_Searches[0]; m_TableStack = new QStackedWidget(this); @@ -205,6 +210,10 @@ void CleMemoryInspector::onChangeTab(void) m_Tabs->addTab("+"); m_TabCount++; m_Searches[new_tab] = new CleResultTableNormal(this); + m_Searches[new_tab]->setCompareType(getCurrentCompareType()); + m_Searches[new_tab]->setTarget(m_TextEntry->text()); + m_Searches[new_tab]->setValueType(getCurrentSizeType()); + m_SizeDropdown->setDisabled(false); m_TableStack->addWidget(m_Searches[new_tab]->table()); } m_CurrentSearch = m_Searches[new_tab]; @@ -235,6 +244,9 @@ void CleMemoryInspector::onClickNew() m_CurrentSearch->setCompareType(getCurrentCompareType()); m_CurrentSearch->setValueType(getCurrentSizeType()); + m_CurrentSearch->setTarget(m_TextEntry->text()); + + m_SizeDropdown->setDisabled(false); } } @@ -246,11 +258,13 @@ void CleMemoryInspector::onClickSearch() { if (!m_CurrentSearch->isInitted()) onClickNew(); - if (!m_CurrentSearch->step()) + if (m_CurrentSearch->step() != CL_OK) { - cl_log("Search input failed: %s\n", m_TextEntry->text().toStdString().c_str()); + cl_log("Search step failed: %s\n", m_TextEntry->text().toStdString().c_str()); m_TextEntry->setText(""); } + else + m_SizeDropdown->setDisabled(true); } } @@ -296,11 +310,13 @@ void CleMemoryInspector::onRightClickTabs(const QPoint &pos) void CleMemoryInspector::onTargetChanged(const QString& target) { - if (!m_CurrentSearch->setTarget(target)) + if (m_CurrentSearch->setTarget(target) != CL_OK) { cl_log("Search input failed: %s\n", target.toStdString().c_str()); - m_TextEntry->setText(""); + m_TextEntry->setStyleSheet("color: gray;"); } + else + m_TextEntry->setStyleSheet("color: white;"); } void CleMemoryInspector::requestAddMemoryNote(cl_memnote_t note) diff --git a/editor/cle_result_table_normal.cpp b/editor/cle_result_table_normal.cpp index e79c7b4..d5ada69 100644 --- a/editor/cle_result_table_normal.cpp +++ b/editor/cle_result_table_normal.cpp @@ -141,7 +141,7 @@ void CleResultTableNormal::onResultSelectionChanged(void) cl_error CleResultTableNormal::rebuild(void) { char temp_string[32]; - int64_t temp_value = 0; + unsigned char temp_value[8]; unsigned val_size = m_Search.params.value_size; cl_value_type val_type = m_Search.params.value_type; unsigned current_row = 0; @@ -196,7 +196,7 @@ cl_error CleResultTableNormal::rebuild(void) m_Table->setItem(current_row, 0, new QTableWidgetItem(QString(temp_string))); /* Previous value (from chunk) */ - memcpy(&temp_value, data + offset, val_size); + cl_read_value(&temp_value, data, offset, val_type, page->region->endianness); valueToString(temp_string, sizeof(temp_string), temp_value, val_type); m_Table->setItem(current_row, 1, new QTableWidgetItem(QString(temp_string))); @@ -263,7 +263,7 @@ cl_error CleResultTableNormal::run(void) item = m_Table->item(i, COL_PREVIOUS_VALUE); if (item) { - valueToString(temp_string, sizeof(temp_string), prev_value, val_type); + valueToString(temp_string, sizeof(temp_string), &prev_value, val_type); item->setText(temp_string); } @@ -273,7 +273,7 @@ cl_error CleResultTableNormal::run(void) item = m_Table->item(i, COL_CURRENT_VALUE); if (item) { - valueToString(temp_string, sizeof(temp_string), curr_value, val_type); + valueToString(temp_string, sizeof(temp_string), &curr_value, val_type); item->setText(temp_string); /* Highlight changed values in red */ From 4d97550f189ae6c890e89913dc1acb7492541de0 Mon Sep 17 00:00:00 2001 From: celerizer Date: Mon, 22 Dec 2025 00:34:36 -0600 Subject: [PATCH 27/57] redo valuetostring --- editor/cle_common.cpp | 33 ++++++++++++++++++++------------- editor/cle_common.h | 3 +-- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/editor/cle_common.cpp b/editor/cle_common.cpp index 38e6f88..4c8ee80 100644 --- a/editor/cle_common.cpp +++ b/editor/cle_common.cpp @@ -49,34 +49,41 @@ int64_t stringToValue(QString string, bool *ok) } } -void valueToString(char *string, unsigned length, int64_t value, - cl_value_type memtype) +cl_error valueToString(char *string, unsigned length, const void *value, cl_value_type type) { - switch (memtype) + switch (type) { case CL_MEMTYPE_INT8: - snprintf(string, length, "%02lX (%li)", value, value); + snprintf(string, length, "%02X (%i)", *(int8_t*)value, *(int8_t*)value); break; case CL_MEMTYPE_UINT8: - snprintf(string, length, "%02lX (%lu)", value, value); + snprintf(string, length, "%02X (%u)", *(uint8_t*)value, *(uint8_t*)value); break; case CL_MEMTYPE_INT16: - snprintf(string, length, "%04lX (%li)", value, value); + snprintf(string, length, "%04X (%i)", *(int16_t*)value, *(int16_t*)value); break; case CL_MEMTYPE_UINT16: - snprintf(string, length, "%04lX (%lu)", value, value); - break; + snprintf(string, length, "%04X (%u)", *(uint16_t*)value, *(uint16_t*)value); + break; case CL_MEMTYPE_INT32: - snprintf(string, length, "%08lX (%li)", value, value); + snprintf(string, length, "%08X (%i)", *(int32_t*)value, *(int32_t*)value); break; case CL_MEMTYPE_UINT32: - snprintf(string, length, "%08lX (%lu)", value, value); + snprintf(string, length, "%08X (%u)", *(uint32_t*)value, *(uint32_t*)value); + break; + case CL_MEMTYPE_INT64: + snprintf(string, length, "%08lX (%li)", *(int64_t*)value, *(int64_t*)value); break; case CL_MEMTYPE_FLOAT: - snprintf(string, length, "%08lX (%f)", value, *((float*)(&value))); + snprintf(string, length, "%f", *(float*)value); break; - default: - snprintf(string, length, "%08lX", value); + case CL_MEMTYPE_DOUBLE: + snprintf(string, length, "%f", *(double*)value); break; + default: + snprintf(string, length, "???"); + return CL_ERR_PARAMETER_INVALID; } + + return CL_OK; } diff --git a/editor/cle_common.h b/editor/cle_common.h index 41d29c5..3cc7a50 100644 --- a/editor/cle_common.h +++ b/editor/cle_common.h @@ -11,8 +11,7 @@ extern "C" int64_t stringToValue(QString string, bool *ok); /* Output an appropriately formatted C-string representing a memory value. */ -void valueToString(char *string, unsigned length, int64_t value, - cl_value_type memtype); +cl_error valueToString(char *string, unsigned length, const void *value, cl_value_type type); typedef struct { From 843b0d3a7d42751a671ea8226bf8f59086b969da Mon Sep 17 00:00:00 2001 From: celerizer Date: Mon, 22 Dec 2025 00:35:13 -0600 Subject: [PATCH 28/57] add endianness, delta search, other stuff --- cl_search_new.c | 602 ++++++++++++++++++++++++++++++++++++++++++------ cl_search_new.h | 7 +- 2 files changed, 535 insertions(+), 74 deletions(-) diff --git a/cl_search_new.c b/cl_search_new.c index 5adca7b..6d5ab6b 100644 --- a/cl_search_new.c +++ b/cl_search_new.c @@ -3,9 +3,9 @@ #include "cl_config.h" #include "cl_memory.h" -#if CL_HOST_PLATFORM == CL_PLATFORM_LINUX +#if CL_HOST_PLATFORM == _CL_PLATFORM_LINUX && 0 #include -#elif CL_HOST_PLATFORM == CL_PLATFORM_WINDOWS +#elif CL_HOST_PLATFORM == _CL_PLATFORM_WINDOWS && 0 #include #endif @@ -34,14 +34,14 @@ typedef union */ static void *cl_mmap(size_t size) { -#if CL_HOST_PLATFORM == CL_PLATFORM_LINUX +#if CL_HOST_PLATFORM == _CL_PLATFORM_LINUX && 0 void *p = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (p == CL_ADDRESS_INVALID) return NULL; else return p; -#elif CL_HOST_PLATFORM == CL_PLATFORM_WINDOWS +#elif CL_HOST_PLATFORM == _CL_PLATFORM_WINDOWS && 0 return VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); #else return malloc(size); @@ -55,9 +55,9 @@ static void *cl_mmap(size_t size) */ static void cl_munmap(void *p, size_t size) { -#if CL_HOST_PLATFORM == CL_PLATFORM_LINUX +#if CL_HOST_PLATFORM == _CL_PLATFORM_LINUX && 0 munmap(p, size); -#elif CL_HOST_PLATFORM == CL_PLATFORM_WINDOWS +#elif CL_HOST_PLATFORM == _CL_PLATFORM_WINDOWS && 0 CL_UNUSED(size); VirtualFree(p, 0, MEM_RELEASE); #else @@ -68,19 +68,95 @@ static void cl_munmap(void *p, size_t size) #define CL_PASTE2(a, b) a##b #define CL_PASTE3(a, b, c) a##b##c +#define CL_PASTE4(a, b, c, d) a##b##c##d + +#if defined(_MSC_VER) +#include +#define CL_SEARCH_SWAP_s8(a) (a) +#define CL_SEARCH_SWAP_u8(a) (a) +#define CL_SEARCH_SWAP_s16(a) _byteswap_ushort(*(uint16_t*)&(a)) +#define CL_SEARCH_SWAP_u16(a) _byteswap_ushort(*(uint16_t*)&(a)) +#define CL_SEARCH_SWAP_s32(a) _byteswap_ulong(*(uint32_t*)&(a)) +#define CL_SEARCH_SWAP_u32(a) _byteswap_ulong(*(uint32_t*)&(a)) +#define CL_SEARCH_SWAP_s64(a) _byteswap_uint64(*(uint64_t*)&(a)) +#elif defined(__GNUC__) || defined(__clang__) +#define CL_SEARCH_SWAP_s8(a) (a) +#define CL_SEARCH_SWAP_u8(a) (a) +#define CL_SEARCH_SWAP_s16(a) __builtin_bswap16(*(uint16_t*)&(a)) +#define CL_SEARCH_SWAP_u16(a) __builtin_bswap16(*(uint16_t*)&(a)) +#define CL_SEARCH_SWAP_s32(a) __builtin_bswap32(*(uint32_t*)&(a)) +#define CL_SEARCH_SWAP_u32(a) __builtin_bswap32(*(uint32_t*)&(a)) +#define CL_SEARCH_SWAP_s64(a) __builtin_bswap64(*(uint64_t*)&(a)) +#else +#error "Endianness helpers are not supported on this compiler. You should try compiling with CL_HAVE_SEARCH=0." +#endif + +static float cl_bswap_float(float f) +{ + union { uint32_t i; float f; } u; + u.f = f; + u.i = CL_SEARCH_SWAP_u32(u.i); + return u.f; +} +static double cl_bswap_double(double d) +{ + union { uint64_t i; double d; } u; + u.d = d; + u.i = CL_SEARCH_SWAP_s64(u.i); + return u.d; +} + +#define CL_SEARCH_SWAP_fp(a) cl_bswap_float(a) +#define CL_SEARCH_SWAP_dfp(a) cl_bswap_double(a) + +/** + * Kernel builder to compare an immediate to native-endian guest memory. + */ #define CL_SEARCH_CMP_IMMEDIATE_TEMPLATE(a, b, c, d) \ static unsigned CL_PASTE3(cl_search_cmp_imm_, b, _##d)( \ void *chunk_data, \ const void *chunk_data_end, \ unsigned char *chunk_validity, \ + const void *chunk_data_prev, \ const void *target) \ { \ unsigned matches = 0; \ unsigned char match; \ a *chunk_data_cast = (a*)chunk_data; \ const a *chunk_data_end_cast = (const a*)chunk_data_end; \ - const a right = ((cl_search_target_impl_t *)(target))->b; \ + const a right = ((cl_search_target_impl_t*)(target))->b; \ + CL_UNUSED(chunk_data_prev); \ + while (chunk_data_cast < chunk_data_end_cast) \ + { \ + match = (*chunk_data_cast c right) & *chunk_validity; \ + *chunk_validity = match; \ + matches += match; \ + chunk_data_cast++; \ + chunk_validity++; \ + } \ + return matches; \ +} + +/** + * Kernel builder to compare an immediate to opposite-endian guest memory, + * byteswapping the immediate once. This works only for equality/inequality, + * but is faster. + */ +#define CL_SEARCH_CMP_IMMEDIATE_SWAPHOST_TEMPLATE(a, b, c, d) \ +static unsigned CL_PASTE4(cl_search_cmp_imm_, b, _##d, _swaphost)( \ + void *chunk_data, \ + const void *chunk_data_end, \ + unsigned char *chunk_validity, \ + const void *chunk_data_prev, \ + const void *target) \ +{ \ + unsigned matches = 0; \ + unsigned char match; \ + a *chunk_data_cast = (a*)chunk_data; \ + const a *chunk_data_end_cast = (const a*)chunk_data_end; \ + const a right = CL_SEARCH_SWAP_##b(((cl_search_target_impl_t*)(target))->b); \ + CL_UNUSED(chunk_data_prev); \ while (chunk_data_cast < chunk_data_end_cast) \ { \ match = (*chunk_data_cast c right) & *chunk_validity; \ @@ -92,18 +168,54 @@ static unsigned CL_PASTE3(cl_search_cmp_imm_, b, _##d)( \ return matches; \ } +/** + * Kernel builder to compare an immediate to opposite-endian guest memory, + * byteswapping each guest value in sequence. This works for all other forms + * of comparison. + */ +#define CL_SEARCH_CMP_IMMEDIATE_SWAPGUEST_TEMPLATE(a, b, c, d) \ +static unsigned CL_PASTE4(cl_search_cmp_imm_, b, _##d, _swapguest)( \ + void *chunk_data, \ + const void *chunk_data_end, \ + unsigned char *chunk_validity, \ + const void *chunk_data_prev, \ + const void *target) \ +{ \ + unsigned matches = 0; \ + unsigned char match; \ + a *chunk_data_cast = (a*)chunk_data; \ + const a *chunk_data_end_cast = (const a*)chunk_data_end; \ + const a right = ((cl_search_target_impl_t *)(target))->b; \ + CL_UNUSED(chunk_data_prev); \ + while (chunk_data_cast < chunk_data_end_cast) \ + { \ + match = ((a)CL_SEARCH_SWAP_##b(*chunk_data_cast) c (a)right) & *chunk_validity; \ + *chunk_validity = match; \ + matches += match; \ + chunk_data_cast++; \ + chunk_validity++; \ + } \ + return matches; \ +} + +/** + * Kernel builder to compare each value to its value from the previous search + * step, in native-endian. + */ #define CL_SEARCH_CMP_PREVIOUS_TEMPLATE(a, b, c, d) \ static unsigned CL_PASTE3(cl_search_cmp_prv_, b, _##d)( \ void *chunk_data, \ const void *chunk_data_end, \ unsigned char *chunk_validity, \ - const void *chunk_data_prev) \ + const void *chunk_data_prev, \ + const void *target) \ { \ unsigned matches = 0; \ unsigned char match; \ a *chunk_data_cast = (a*)chunk_data; \ const a *chunk_data_end_cast = (const a*)chunk_data_end; \ const a *chunk_data_prev_cast = (const a*)chunk_data_prev; \ + CL_UNUSED(target); \ while (chunk_data_cast < chunk_data_end_cast) \ { \ match = (*chunk_data_cast c *chunk_data_prev_cast) & *chunk_validity; \ @@ -116,7 +228,92 @@ static unsigned CL_PASTE3(cl_search_cmp_prv_, b, _##d)( \ return matches; \ } -#define CL_SEARCH_CMP_IMMEDIATE_UNROLL(a, b) \ +/** + * Kernel builder to compare each value to its value from the previous search + * step, swapping endianness of every value. + */ +#define CL_SEARCH_CMP_PREVIOUS_SWAPBOTH_TEMPLATE(a, b, c, d) \ +static unsigned CL_PASTE4(cl_search_cmp_prv_, b, _##d, _swapboth)( \ + void *chunk_data, \ + const void *chunk_data_end, \ + unsigned char *chunk_validity, \ + const void *chunk_data_prev, \ + const void *target) \ +{ \ + unsigned matches = 0; \ + unsigned char match; \ + a *chunk_data_cast = (a*)chunk_data; \ + const a *chunk_data_end_cast = (const a*)chunk_data_end; \ + const a *chunk_data_prev_cast = (const a*)chunk_data_prev; \ + CL_UNUSED(target); \ + while (chunk_data_cast < chunk_data_end_cast) \ + { \ + match = (CL_SEARCH_SWAP_##b(*chunk_data_cast) c \ + CL_SEARCH_SWAP_##b(*chunk_data_prev_cast)) & *chunk_validity; \ + *chunk_validity = match; \ + matches += match; \ + chunk_data_cast++; \ + chunk_validity++; \ + chunk_data_prev_cast++; \ + } \ + return matches; \ +} + +#define CL_SEARCH_CMP_DELTA_TEMPLATE(a, b, c, d) \ +static unsigned CL_PASTE3(cl_search_cmp_dlt_, b, _##d)( \ + void *chunk_data, \ + const void *chunk_data_end, \ + unsigned char *chunk_validity, \ + const void *chunk_data_prev, \ + const void *target) \ +{ \ + unsigned matches = 0; \ + unsigned char match; \ + a *cur = (a*)chunk_data; \ + const a *end = (const a*)chunk_data_end; \ + const a *prev = (const a*)chunk_data_prev; \ + const a delta = ((const cl_search_target_impl_t*)(target))->b; \ + while (cur < end) \ + { \ + match = ((*cur) c (*prev + delta)) & *chunk_validity; \ + *chunk_validity = match; \ + matches += match; \ + cur++; \ + prev++; \ + chunk_validity++; \ + } \ + return matches; \ +} + +#define CL_SEARCH_CMP_DELTA_SWAPBOTH_TEMPLATE(a, b, c, d) \ +static unsigned CL_PASTE4(cl_search_cmp_dlt_, b, _##d, _swapboth)( \ + void *chunk_data, \ + const void *chunk_data_end, \ + unsigned char *chunk_validity, \ + const void *chunk_data_prev, \ + const void *target) \ +{ \ + unsigned matches = 0; \ + unsigned char match; \ + a *cur = (a*)chunk_data; \ + const a *end = (const a*)chunk_data_end; \ + const a *prev = (const a*)chunk_data_prev; \ + const a delta = ((const cl_search_target_impl_t*)(target))->b; \ + while (cur < end) \ + { \ + match = (((a)CL_SEARCH_SWAP_##b(*cur) c \ + ((a)CL_SEARCH_SWAP_##b(*prev) + delta))) & *chunk_validity; \ + *chunk_validity = match; \ + matches += match; \ + cur++; \ + prev++; \ + chunk_validity++; \ + } \ + return matches; \ +} + +/** Unroll kernels with endianness ignored */ +#define CL_SEARCH_CMP_IMMEDIATE_UNROLL_8BIT(a, b) \ CL_SEARCH_CMP_IMMEDIATE_TEMPLATE(a, b, ==, equ) \ CL_SEARCH_CMP_PREVIOUS_TEMPLATE(a, b, ==, equ) \ CL_SEARCH_CMP_IMMEDIATE_TEMPLATE(a, b, <, les) \ @@ -125,9 +322,39 @@ static unsigned CL_PASTE3(cl_search_cmp_prv_, b, _##d)( \ CL_SEARCH_CMP_PREVIOUS_TEMPLATE(a, b, >, gtr) \ CL_SEARCH_CMP_IMMEDIATE_TEMPLATE(a, b, !=, neq) \ CL_SEARCH_CMP_PREVIOUS_TEMPLATE(a, b, !=, neq) \ + CL_SEARCH_CMP_DELTA_TEMPLATE(a, b, >, inc) \ + CL_SEARCH_CMP_DELTA_TEMPLATE(a, b, <, dec) \ + \ -CL_SEARCH_CMP_IMMEDIATE_UNROLL(uint8_t, u8) -CL_SEARCH_CMP_IMMEDIATE_UNROLL(int8_t, s8) +/** Unroll kernels with endianness accounted for */ +#define CL_SEARCH_CMP_IMMEDIATE_UNROLL(a, b) \ + CL_SEARCH_CMP_IMMEDIATE_TEMPLATE(a, b, ==, equ) \ + CL_SEARCH_CMP_IMMEDIATE_SWAPHOST_TEMPLATE(a, b, ==, equ) \ + CL_SEARCH_CMP_PREVIOUS_TEMPLATE(a, b, ==, equ) \ + \ + CL_SEARCH_CMP_IMMEDIATE_TEMPLATE(a, b, !=, neq) \ + CL_SEARCH_CMP_IMMEDIATE_SWAPHOST_TEMPLATE(a, b, !=, neq) \ + CL_SEARCH_CMP_PREVIOUS_TEMPLATE(a, b, !=, neq) \ + \ + CL_SEARCH_CMP_IMMEDIATE_TEMPLATE(a, b, <, les) \ + CL_SEARCH_CMP_IMMEDIATE_SWAPGUEST_TEMPLATE(a, b, <, les) \ + CL_SEARCH_CMP_PREVIOUS_TEMPLATE(a, b, <, les) \ + CL_SEARCH_CMP_PREVIOUS_SWAPBOTH_TEMPLATE(a, b, <, les) \ + \ + CL_SEARCH_CMP_IMMEDIATE_TEMPLATE(a, b, >, gtr) \ + CL_SEARCH_CMP_IMMEDIATE_SWAPGUEST_TEMPLATE(a, b, >, gtr) \ + CL_SEARCH_CMP_PREVIOUS_TEMPLATE(a, b, >, gtr) \ + CL_SEARCH_CMP_PREVIOUS_SWAPBOTH_TEMPLATE(a, b, >, gtr) \ + \ + CL_SEARCH_CMP_DELTA_TEMPLATE(a, b, >, inc) \ + CL_SEARCH_CMP_DELTA_SWAPBOTH_TEMPLATE(a, b, >, inc) \ + \ + CL_SEARCH_CMP_DELTA_TEMPLATE(a, b, <, dec) \ + CL_SEARCH_CMP_DELTA_SWAPBOTH_TEMPLATE(a, b, <, dec) \ + \ + +CL_SEARCH_CMP_IMMEDIATE_UNROLL_8BIT(uint8_t, u8) +CL_SEARCH_CMP_IMMEDIATE_UNROLL_8BIT(int8_t, s8) CL_SEARCH_CMP_IMMEDIATE_UNROLL(uint16_t, u16) CL_SEARCH_CMP_IMMEDIATE_UNROLL(int16_t, s16) CL_SEARCH_CMP_IMMEDIATE_UNROLL(uint32_t, u32) @@ -136,147 +363,359 @@ CL_SEARCH_CMP_IMMEDIATE_UNROLL(int64_t, s64) CL_SEARCH_CMP_IMMEDIATE_UNROLL(float, fp) CL_SEARCH_CMP_IMMEDIATE_UNROLL(double, dfp) -typedef unsigned (*cl_search_compare_func_t)(void*,const void*,unsigned char*,const void*); +typedef unsigned (*cl_search_compare_func_t)(void*,const void*,unsigned char*,const void*,const void*); -static cl_search_compare_func_t cl_search_comparison_function(cl_search_parameters_t params) +static cl_search_compare_func_t cl_search_comparison_function( + cl_search_parameters_t params, cl_endianness endianness) { + int swap = (endianness != CL_HOST_ENDIANNESS); + switch (params.value_type) { case CL_MEMTYPE_UINT8: switch (params.compare_type) { case CL_COMPARE_EQUAL: - return params.compare_to_previous ? cl_search_cmp_prv_u8_equ : cl_search_cmp_imm_u8_equ; + return params.target_none + ? cl_search_cmp_prv_u8_equ + : cl_search_cmp_imm_u8_equ; case CL_COMPARE_GREATER: - return params.compare_to_previous ? cl_search_cmp_prv_u8_gtr : cl_search_cmp_imm_u8_gtr; + return params.target_none + ? cl_search_cmp_prv_u8_gtr + : cl_search_cmp_imm_u8_gtr; case CL_COMPARE_LESS: - return params.compare_to_previous ? cl_search_cmp_prv_u8_les : cl_search_cmp_imm_u8_les; + return params.target_none + ? cl_search_cmp_prv_u8_les + : cl_search_cmp_imm_u8_les; case CL_COMPARE_NOT_EQUAL: - return params.compare_to_previous ? cl_search_cmp_prv_u8_neq : cl_search_cmp_imm_u8_neq; + return params.target_none + ? cl_search_cmp_prv_u8_neq + : cl_search_cmp_imm_u8_neq; + case CL_COMPARE_INCREASED: + return params.target_none + ? cl_search_cmp_prv_u8_gtr + : cl_search_cmp_dlt_u8_inc; + case CL_COMPARE_DECREASED: + return params.target_none + ? cl_search_cmp_prv_u8_les + : cl_search_cmp_dlt_u8_dec; default: return NULL; } + case CL_MEMTYPE_INT8: switch (params.compare_type) { case CL_COMPARE_EQUAL: - return params.compare_to_previous ? cl_search_cmp_prv_s8_equ : cl_search_cmp_imm_s8_equ; + return params.target_none + ? cl_search_cmp_prv_s8_equ + : cl_search_cmp_imm_s8_equ; case CL_COMPARE_GREATER: - return params.compare_to_previous ? cl_search_cmp_prv_s8_gtr : cl_search_cmp_imm_s8_gtr; + return params.target_none + ? cl_search_cmp_prv_s8_gtr + : cl_search_cmp_imm_s8_gtr; case CL_COMPARE_LESS: - return params.compare_to_previous ? cl_search_cmp_prv_s8_les : cl_search_cmp_imm_s8_les; + return params.target_none + ? cl_search_cmp_prv_s8_les + : cl_search_cmp_imm_s8_les; case CL_COMPARE_NOT_EQUAL: - return params.compare_to_previous ? cl_search_cmp_prv_s8_neq : cl_search_cmp_imm_s8_neq; + return params.target_none + ? cl_search_cmp_prv_s8_neq + : cl_search_cmp_imm_s8_neq; + case CL_COMPARE_INCREASED: + return params.target_none + ? cl_search_cmp_prv_s8_gtr + : cl_search_cmp_dlt_s8_inc; + case CL_COMPARE_DECREASED: + return params.target_none + ? cl_search_cmp_prv_s8_les + : cl_search_cmp_dlt_s8_dec; default: return NULL; } + case CL_MEMTYPE_UINT16: switch (params.compare_type) { case CL_COMPARE_EQUAL: - return params.compare_to_previous ? cl_search_cmp_prv_u16_equ : cl_search_cmp_imm_u16_equ; + return params.target_none + ? cl_search_cmp_prv_u16_equ + : (swap ? cl_search_cmp_imm_u16_equ_swaphost : + cl_search_cmp_imm_u16_equ); case CL_COMPARE_GREATER: - return params.compare_to_previous ? cl_search_cmp_prv_u16_gtr : cl_search_cmp_imm_u16_gtr; + return params.target_none + ? cl_search_cmp_prv_u16_gtr + : (swap ? cl_search_cmp_imm_u16_gtr_swapguest : + cl_search_cmp_imm_u16_gtr); case CL_COMPARE_LESS: - return params.compare_to_previous ? cl_search_cmp_prv_u16_les : cl_search_cmp_imm_u16_les; + return params.target_none + ? cl_search_cmp_prv_u16_les + : (swap ? cl_search_cmp_imm_u16_les_swapguest : + cl_search_cmp_imm_u16_les); case CL_COMPARE_NOT_EQUAL: - return params.compare_to_previous ? cl_search_cmp_prv_u16_neq : cl_search_cmp_imm_u16_neq; + return params.target_none + ? cl_search_cmp_prv_u16_neq + : (swap ? cl_search_cmp_imm_u16_neq_swaphost : + cl_search_cmp_imm_u16_neq); + case CL_COMPARE_INCREASED: + return params.target_none + ? (swap ? cl_search_cmp_prv_u16_gtr_swapboth : + cl_search_cmp_prv_u16_gtr) + : (swap ? cl_search_cmp_dlt_u16_inc_swapboth : + cl_search_cmp_dlt_u16_inc); + case CL_COMPARE_DECREASED: + return params.target_none + ? (swap ? cl_search_cmp_prv_u16_les_swapboth : + cl_search_cmp_prv_u16_les) + : (swap ? cl_search_cmp_dlt_u16_dec_swapboth : + cl_search_cmp_dlt_u16_dec); default: return NULL; } + case CL_MEMTYPE_INT16: switch (params.compare_type) { case CL_COMPARE_EQUAL: - return params.compare_to_previous ? cl_search_cmp_prv_s16_equ : cl_search_cmp_imm_s16_equ; + return params.target_none + ? cl_search_cmp_prv_s16_equ + : (swap ? cl_search_cmp_imm_s16_equ_swaphost : + cl_search_cmp_imm_s16_equ); case CL_COMPARE_GREATER: - return params.compare_to_previous ? cl_search_cmp_prv_s16_gtr : cl_search_cmp_imm_s16_gtr; + return params.target_none + ? cl_search_cmp_prv_s16_gtr + : (swap ? cl_search_cmp_imm_s16_gtr_swapguest : + cl_search_cmp_imm_s16_gtr); case CL_COMPARE_LESS: - return params.compare_to_previous ? cl_search_cmp_prv_s16_les : cl_search_cmp_imm_s16_les; + return params.target_none + ? cl_search_cmp_prv_s16_les + : (swap ? cl_search_cmp_imm_s16_les_swapguest : + cl_search_cmp_imm_s16_les); case CL_COMPARE_NOT_EQUAL: - return params.compare_to_previous ? cl_search_cmp_prv_s16_neq : cl_search_cmp_imm_s16_neq; + return params.target_none + ? cl_search_cmp_prv_s16_neq + : (swap ? cl_search_cmp_imm_s16_neq_swaphost : + cl_search_cmp_imm_s16_neq); + case CL_COMPARE_INCREASED: + return params.target_none + ? (swap ? cl_search_cmp_prv_s16_gtr_swapboth : + cl_search_cmp_prv_s16_gtr) + : (swap ? cl_search_cmp_dlt_s16_inc_swapboth : + cl_search_cmp_dlt_s16_inc); + case CL_COMPARE_DECREASED: + return params.target_none + ? (swap ? cl_search_cmp_prv_s16_les_swapboth : + cl_search_cmp_prv_s16_les) + : (swap ? cl_search_cmp_dlt_s16_dec_swapboth : + cl_search_cmp_dlt_s16_dec); default: return NULL; } + case CL_MEMTYPE_UINT32: switch (params.compare_type) { case CL_COMPARE_EQUAL: - return params.compare_to_previous ? cl_search_cmp_prv_u32_equ : cl_search_cmp_imm_u32_equ; + return params.target_none + ? cl_search_cmp_prv_u32_equ + : (swap ? cl_search_cmp_imm_u32_equ_swaphost : + cl_search_cmp_imm_u32_equ); case CL_COMPARE_GREATER: - return params.compare_to_previous ? cl_search_cmp_prv_u32_gtr : cl_search_cmp_imm_u32_gtr; + return params.target_none + ? cl_search_cmp_prv_u32_gtr + : (swap ? cl_search_cmp_imm_u32_gtr_swapguest : + cl_search_cmp_imm_u32_gtr); case CL_COMPARE_LESS: - return params.compare_to_previous ? cl_search_cmp_prv_u32_les : cl_search_cmp_imm_u32_les; + return params.target_none + ? cl_search_cmp_prv_u32_les + : (swap ? cl_search_cmp_imm_u32_les_swapguest : + cl_search_cmp_imm_u32_les); case CL_COMPARE_NOT_EQUAL: - return params.compare_to_previous ? cl_search_cmp_prv_u32_neq : cl_search_cmp_imm_u32_neq; + return params.target_none + ? cl_search_cmp_prv_u32_neq + : (swap ? cl_search_cmp_imm_u32_neq_swaphost : + cl_search_cmp_imm_u32_neq); + case CL_COMPARE_INCREASED: + return params.target_none + ? (swap ? cl_search_cmp_prv_u32_gtr_swapboth : + cl_search_cmp_prv_u32_gtr) + : (swap ? cl_search_cmp_dlt_u32_inc_swapboth : + cl_search_cmp_dlt_u32_inc); + case CL_COMPARE_DECREASED: + return params.target_none + ? (swap ? cl_search_cmp_prv_u32_les_swapboth : + cl_search_cmp_prv_u32_les) + : (swap ? cl_search_cmp_dlt_u32_dec_swapboth : + cl_search_cmp_dlt_u32_dec); default: return NULL; } + case CL_MEMTYPE_INT32: switch (params.compare_type) { case CL_COMPARE_EQUAL: - return params.compare_to_previous ? cl_search_cmp_prv_s32_equ : cl_search_cmp_imm_s32_equ; + return params.target_none + ? cl_search_cmp_prv_s32_equ + : (swap ? cl_search_cmp_imm_s32_equ_swaphost : + cl_search_cmp_imm_s32_equ); case CL_COMPARE_GREATER: - return params.compare_to_previous ? cl_search_cmp_prv_s32_gtr : cl_search_cmp_imm_s32_gtr; + return params.target_none + ? cl_search_cmp_prv_s32_gtr + : (swap ? cl_search_cmp_imm_s32_gtr_swapguest : + cl_search_cmp_imm_s32_gtr); case CL_COMPARE_LESS: - return params.compare_to_previous ? cl_search_cmp_prv_s32_les : cl_search_cmp_imm_s32_les; + return params.target_none + ? cl_search_cmp_prv_s32_les + : (swap ? cl_search_cmp_imm_s32_les_swapguest : + cl_search_cmp_imm_s32_les); case CL_COMPARE_NOT_EQUAL: - return params.compare_to_previous ? cl_search_cmp_prv_s32_neq : cl_search_cmp_imm_s32_neq; + return params.target_none + ? cl_search_cmp_prv_s32_neq + : (swap ? cl_search_cmp_imm_s32_neq_swaphost : + cl_search_cmp_imm_s32_neq); + case CL_COMPARE_INCREASED: + return params.target_none + ? (swap ? cl_search_cmp_prv_s32_gtr_swapboth : + cl_search_cmp_prv_s32_gtr) + : (swap ? cl_search_cmp_dlt_s32_inc_swapboth : + cl_search_cmp_dlt_s32_inc); + case CL_COMPARE_DECREASED: + return params.target_none + ? (swap ? cl_search_cmp_prv_s32_les_swapboth : + cl_search_cmp_prv_s32_les) + : (swap ? cl_search_cmp_dlt_s32_dec_swapboth : + cl_search_cmp_dlt_s32_dec); default: return NULL; } + case CL_MEMTYPE_INT64: switch (params.compare_type) { case CL_COMPARE_EQUAL: - return params.compare_to_previous ? cl_search_cmp_prv_s64_equ : cl_search_cmp_imm_s64_equ; + return params.target_none + ? cl_search_cmp_prv_s64_equ + : (swap ? cl_search_cmp_imm_s64_equ_swaphost : + cl_search_cmp_imm_s64_equ); case CL_COMPARE_GREATER: - return params.compare_to_previous ? cl_search_cmp_prv_s64_gtr : cl_search_cmp_imm_s64_gtr; + return params.target_none + ? cl_search_cmp_prv_s64_gtr + : (swap ? cl_search_cmp_imm_s64_gtr_swapguest : + cl_search_cmp_imm_s64_gtr); case CL_COMPARE_LESS: - return params.compare_to_previous ? cl_search_cmp_prv_s64_les : cl_search_cmp_imm_s64_les; + return params.target_none + ? cl_search_cmp_prv_s64_les + : (swap ? cl_search_cmp_imm_s64_les_swapguest : + cl_search_cmp_imm_s64_les); case CL_COMPARE_NOT_EQUAL: - return params.compare_to_previous ? cl_search_cmp_prv_s64_neq : cl_search_cmp_imm_s64_neq; + return params.target_none + ? cl_search_cmp_prv_s64_neq + : (swap ? cl_search_cmp_imm_s64_neq_swaphost : + cl_search_cmp_imm_s64_neq); + case CL_COMPARE_INCREASED: + return params.target_none + ? (swap ? cl_search_cmp_prv_s64_gtr_swapboth : + cl_search_cmp_prv_s64_gtr) + : (swap ? cl_search_cmp_dlt_s64_inc_swapboth : + cl_search_cmp_dlt_s64_inc); + case CL_COMPARE_DECREASED: + return params.target_none + ? (swap ? cl_search_cmp_prv_s64_les_swapboth : + cl_search_cmp_prv_s64_les) + : (swap ? cl_search_cmp_dlt_s64_dec_swapboth : + cl_search_cmp_dlt_s64_dec); default: return NULL; } - case CL_MEMTYPE_DOUBLE: + + case CL_MEMTYPE_FLOAT: switch (params.compare_type) { case CL_COMPARE_EQUAL: - return params.compare_to_previous ? cl_search_cmp_prv_dfp_equ : cl_search_cmp_imm_dfp_equ; + return params.target_none + ? cl_search_cmp_prv_fp_equ + : (swap ? cl_search_cmp_imm_fp_equ_swaphost : + cl_search_cmp_imm_fp_equ); case CL_COMPARE_GREATER: - return params.compare_to_previous ? cl_search_cmp_prv_dfp_gtr : cl_search_cmp_imm_dfp_gtr; + return params.target_none + ? cl_search_cmp_prv_fp_gtr + : (swap ? cl_search_cmp_imm_fp_gtr_swapguest : + cl_search_cmp_imm_fp_gtr); case CL_COMPARE_LESS: - return params.compare_to_previous ? cl_search_cmp_prv_dfp_les : cl_search_cmp_imm_dfp_les; + return params.target_none + ? cl_search_cmp_prv_fp_les + : (swap ? cl_search_cmp_imm_fp_les_swapguest : + cl_search_cmp_imm_fp_les); case CL_COMPARE_NOT_EQUAL: - return params.compare_to_previous ? cl_search_cmp_prv_dfp_neq : cl_search_cmp_imm_dfp_neq; + return params.target_none + ? cl_search_cmp_prv_fp_neq + : (swap ? cl_search_cmp_imm_fp_neq_swaphost : + cl_search_cmp_imm_fp_neq); + case CL_COMPARE_INCREASED: + return params.target_none + ? (swap ? cl_search_cmp_prv_fp_gtr_swapboth : + cl_search_cmp_prv_fp_gtr) + : (swap ? cl_search_cmp_dlt_fp_inc_swapboth : + cl_search_cmp_dlt_fp_inc); + case CL_COMPARE_DECREASED: + return params.target_none + ? (swap ? cl_search_cmp_prv_fp_les_swapboth : + cl_search_cmp_prv_fp_les) + : (swap ? cl_search_cmp_dlt_fp_dec_swapboth : + cl_search_cmp_dlt_fp_dec); default: return NULL; } - case CL_MEMTYPE_FLOAT: + + case CL_MEMTYPE_DOUBLE: switch (params.compare_type) { case CL_COMPARE_EQUAL: - return params.compare_to_previous ? cl_search_cmp_prv_fp_equ : cl_search_cmp_imm_fp_equ; + return params.target_none + ? cl_search_cmp_prv_dfp_equ + : (swap ? cl_search_cmp_imm_dfp_equ_swaphost : + cl_search_cmp_imm_dfp_equ); case CL_COMPARE_GREATER: - return params.compare_to_previous ? cl_search_cmp_prv_fp_gtr : cl_search_cmp_imm_fp_gtr; + return params.target_none + ? cl_search_cmp_prv_dfp_gtr + : (swap ? cl_search_cmp_imm_dfp_gtr_swapguest : + cl_search_cmp_imm_dfp_gtr); case CL_COMPARE_LESS: - return params.compare_to_previous ? cl_search_cmp_prv_fp_les : cl_search_cmp_imm_fp_les; + return params.target_none + ? cl_search_cmp_prv_dfp_les + : (swap ? cl_search_cmp_imm_dfp_les_swapguest : + cl_search_cmp_imm_dfp_les); case CL_COMPARE_NOT_EQUAL: - return params.compare_to_previous ? cl_search_cmp_prv_fp_neq : cl_search_cmp_imm_fp_neq; + return params.target_none + ? cl_search_cmp_prv_dfp_neq + : (swap ? cl_search_cmp_imm_dfp_neq_swaphost : + cl_search_cmp_imm_dfp_neq); + case CL_COMPARE_INCREASED: + return params.target_none + ? (swap ? cl_search_cmp_prv_dfp_gtr_swapboth : + cl_search_cmp_prv_dfp_gtr) + : (swap ? cl_search_cmp_dlt_dfp_inc_swapboth : + cl_search_cmp_dlt_dfp_inc); + case CL_COMPARE_DECREASED: + return params.target_none + ? (swap ? cl_search_cmp_prv_dfp_les_swapboth : + cl_search_cmp_prv_dfp_les) + : (swap ? cl_search_cmp_dlt_dfp_dec_swapboth : + cl_search_cmp_dlt_dfp_dec); default: return NULL; } + case CL_MEMTYPE_NOT_SET: case CL_MEMTYPE_SIZE: - /* No default because we want a warning if we add new types */ return NULL; } return NULL; } + /** * Runs a comparison function on the values in a search page. * @param page @@ -289,8 +728,11 @@ static cl_error cl_search_step_page(cl_search_page_t *page, if (!function) return CL_ERR_PARAMETER_INVALID; - page->matches = function(page->chunk, end, page->validity, - params.compare_to_previous ? prev_buffer : ¶ms.target); + page->matches = function(page->chunk, + end, + page->validity, + prev_buffer, + ¶ms.target); return CL_OK; } @@ -427,7 +869,7 @@ cl_error cl_search_change_target(cl_search_t *search, const void *value) if (!search) return CL_ERR_PARAMETER_NULL; else if (!value) - search->params.compare_to_previous = 1; + search->params.target_none = 1; else { cl_search_target_t target; @@ -452,7 +894,7 @@ cl_error cl_search_change_target(cl_search_t *search, const void *value) return CL_ERR_PARAMETER_INVALID; } search->params.target = target; - search->params.compare_to_previous = 0; + search->params.target_none = 0; } return CL_OK; @@ -542,13 +984,11 @@ static cl_error cl_search_step_first(cl_search_t *search) cl_addr_t bucket_processed = 0; cl_addr_t bucket_size = 0; #endif - cl_search_compare_func_t function = cl_search_comparison_function(search->params); + cl_search_compare_func_t function; int64_t print_target = 0; + clock_t start = clock(); unsigned i; - if (!function) - return CL_ERR_PARAMETER_INVALID; - #if CL_EXTERNAL_MEMORY bucket = cl_mmap(CL_SEARCH_BUCKET_SIZE); if (!bucket) @@ -565,6 +1005,10 @@ static cl_error cl_search_step_first(cl_search_t *search) cl_search_page_t *prev_page = NULL; cl_addr_t processed = 0; + function = cl_search_comparison_function(search->params, page_region->region->endianness); + if (!function) + continue; + #if CL_EXTERNAL_MEMORY bucket_offset = 0; bucket_processed = 0; @@ -649,9 +1093,11 @@ static cl_error cl_search_step_first(cl_search_t *search) cl_munmap(bucket, CL_SEARCH_BUCKET_SIZE); #endif cl_search_profile_memory(search); + search->time_taken = ((double)(clock() - start)) / CLOCKS_PER_SEC; - cl_log("%u matches, %u bytes memory usage.\n", - search->total_matches, search->memory_usage); + cl_log("%u matches, %u pages, %u bytes memory usage in %.6f seconds.\n", + search->total_matches, search->total_page_count, + search->memory_usage, search->time_taken); return cl_search_profile_memory(search); } @@ -667,14 +1113,13 @@ cl_error cl_search_step(cl_search_t *search) cl_search_compare_func_t function; cl_addr_t total_matches = 0; int64_t print_target = 0; + clock_t start = clock(); + void *prev_buffer = malloc(CL_SEARCH_CHUNK_SIZE); unsigned i; - function = cl_search_comparison_function(search->params); - if (!function) - return CL_ERR_PARAMETER_INVALID; - cl_search_get_target(search, &print_target); cl_log("Performing search step %u with %li...", search->steps, print_target); + search->time_taken = clock(); for (i = 0; i < search->page_region_count; i++) { @@ -684,16 +1129,21 @@ cl_error cl_search_step(cl_search_t *search) cl_search_page_t *next_page = NULL; cl_addr_t page_region_matches = 0; + function = cl_search_comparison_function(search->params, page_region->region->endianness); + if (!function) + continue; + while (page) { cl_error error; + memcpy(prev_buffer, page->chunk, page->size); cl_read_memory_buffer(page->chunk, page->region, page->start - page->region->base_guest, page->size); - error = cl_search_step_page(page, search->params, function, NULL); + error = cl_search_step_page(page, search->params, function, prev_buffer); if (error != CL_OK) - return error; + goto error; else if (page->matches == 0) { /* Remove this page from the linked list */ @@ -728,10 +1178,18 @@ cl_error cl_search_step(cl_search_t *search) search->total_matches = total_matches; search->steps++; cl_search_profile_memory(search); + search->time_taken = ((double)(clock() - start)) / CLOCKS_PER_SEC; - cl_log("%u matches, %u bytes memory usage.\n", total_matches, search->memory_usage); + cl_log("%u matches, %u pages, %u bytes memory usage in %.6f seconds.\n", + search->total_matches, search->total_page_count, + search->memory_usage, search->time_taken); + free(prev_buffer); return CL_OK; + + error: + free(prev_buffer); + return CL_ERR_CLIENT_RUNTIME; } } @@ -825,9 +1283,9 @@ cl_error cl_search_backup_value(void *dst, const cl_search_t *search, /* Is it in this page? */ if (address >= page->start && address < page->start + page->size) { - cl_addr_t offset = address - page->start; - memcpy(dst, (unsigned char*)page->chunk + offset, search->params.value_size); - return CL_OK; + return cl_read_value(dst, page->chunk, address - page->start, + search->params.value_type, + page->region->endianness); } page = page->next; } diff --git a/cl_search_new.h b/cl_search_new.h index f53e5cd..3d42359 100644 --- a/cl_search_new.h +++ b/cl_search_new.h @@ -90,8 +90,8 @@ typedef struct */ const void *target_ptr; - /* Whether to compare to the previous value instead of a target */ - unsigned compare_to_previous; + /** Whether to use the target value as a value in comparisons */ + unsigned target_none; } cl_search_parameters_t; /** @@ -121,6 +121,9 @@ typedef struct /* The total memory usage of the search, in bytes */ cl_addr_t memory_usage; + + /* The amount of time taken by the last search step, in seconds */ + double time_taken; } cl_search_t; /** From 8650c428c00eec2cd8df0aae186b8c2c06d793d7 Mon Sep 17 00:00:00 2001 From: celerizer Date: Wed, 24 Dec 2025 13:17:24 -0600 Subject: [PATCH 29/57] guh --- cl_common.c | 54 +++++++++++ cl_common.h | 2 + cl_search_new.c | 150 +++++++++++++++++++++-------- cl_search_new.h | 3 + editor/cle_memory_inspector.cpp | 23 +++-- editor/cle_memory_inspector.h | 5 +- editor/cle_result_table.cpp | 73 +++++++++++++- editor/cle_result_table.h | 2 + editor/cle_result_table_normal.cpp | 9 ++ editor/cle_result_table_normal.h | 1 + editor/cle_result_table_pointer.h | 1 + 11 files changed, 270 insertions(+), 53 deletions(-) diff --git a/cl_common.c b/cl_common.c index 4993675..948543a 100644 --- a/cl_common.c +++ b/cl_common.c @@ -476,6 +476,29 @@ const char *cl_string_bitness(cl_bitness bitness) return "Undefined bitness"; } +const char *cl_string_compare_type(cl_compare_type compare_type) +{ + switch (compare_type) + { + case CL_COMPARE_EQUAL: + return "equal to"; + case CL_COMPARE_NOT_EQUAL: + return "not equal to"; + case CL_COMPARE_GREATER: + return "greater than"; + case CL_COMPARE_LESS: + return "less than"; + case CL_COMPARE_INCREASED: + return "increased by"; + case CL_COMPARE_DECREASED: + return "decreased by"; + case CL_COMPARE_SIZE: + return "Invalid compare type"; + } + + return "Undefined compare type"; +} + const char *cl_string_endianness(cl_endianness endianness) { switch (endianness) @@ -561,3 +584,34 @@ const char *cl_string_error(cl_error error) return "Invalid error code"; } + +const char *cl_string_value_type(cl_value_type type) +{ + switch (type) + { + case CL_MEMTYPE_INT8: + return "int8_t"; + case CL_MEMTYPE_UINT8: + return "uint8_t"; + case CL_MEMTYPE_INT16: + return "int16_t"; + case CL_MEMTYPE_UINT16: + return "uint16_t"; + case CL_MEMTYPE_INT32: + return "int32_t"; + case CL_MEMTYPE_UINT32: + return "uint32_t"; + case CL_MEMTYPE_INT64: + return "int64_t"; + case CL_MEMTYPE_DOUBLE: + return "double"; + case CL_MEMTYPE_FLOAT: + return "float"; + case CL_MEMTYPE_NOT_SET: + return "Type not set"; + case CL_MEMTYPE_SIZE: + return "Invalid value type"; + } + + return "Undefined value type"; +} diff --git a/cl_common.h b/cl_common.h index 8606002..944377a 100644 --- a/cl_common.h +++ b/cl_common.h @@ -59,9 +59,11 @@ cl_error cl_write_buffer(const void *src, void *dst, cl_addr_t offset, unsigned cl_sizeof_memtype(const cl_value_type type); const char *cl_string_bitness(cl_bitness bitness); +const char *cl_string_compare_type(cl_compare_type compare_type); const char *cl_string_endianness(cl_endianness endianness); const char *cl_string_error(cl_error error); const char *cl_string_platform(cl_platform platform); +const char *cl_string_value_type(cl_value_type type); bool cl_strto(const char **pos, void *value, unsigned size, bool is_signed); diff --git a/cl_search_new.c b/cl_search_new.c index 6d5ab6b..03f5e92 100644 --- a/cl_search_new.c +++ b/cl_search_new.c @@ -275,7 +275,7 @@ static unsigned CL_PASTE3(cl_search_cmp_dlt_, b, _##d)( \ const a delta = ((const cl_search_target_impl_t*)(target))->b; \ while (cur < end) \ { \ - match = ((*cur) c (*prev + delta)) & *chunk_validity; \ + match = ((*cur) == (*prev c delta)) & *chunk_validity; \ *chunk_validity = match; \ matches += match; \ cur++; \ @@ -301,8 +301,8 @@ static unsigned CL_PASTE4(cl_search_cmp_dlt_, b, _##d, _swapboth)( \ const a delta = ((const cl_search_target_impl_t*)(target))->b; \ while (cur < end) \ { \ - match = (((a)CL_SEARCH_SWAP_##b(*cur) c \ - ((a)CL_SEARCH_SWAP_##b(*prev) + delta))) & *chunk_validity; \ + match = (((a)CL_SEARCH_SWAP_##b(*cur) == \ + ((a)CL_SEARCH_SWAP_##b(*prev) c delta))) & *chunk_validity; \ *chunk_validity = match; \ matches += match; \ cur++; \ @@ -322,8 +322,8 @@ static unsigned CL_PASTE4(cl_search_cmp_dlt_, b, _##d, _swapboth)( \ CL_SEARCH_CMP_PREVIOUS_TEMPLATE(a, b, >, gtr) \ CL_SEARCH_CMP_IMMEDIATE_TEMPLATE(a, b, !=, neq) \ CL_SEARCH_CMP_PREVIOUS_TEMPLATE(a, b, !=, neq) \ - CL_SEARCH_CMP_DELTA_TEMPLATE(a, b, >, inc) \ - CL_SEARCH_CMP_DELTA_TEMPLATE(a, b, <, dec) \ + CL_SEARCH_CMP_DELTA_TEMPLATE(a, b, +, inc) \ + CL_SEARCH_CMP_DELTA_TEMPLATE(a, b, -, dec) \ \ /** Unroll kernels with endianness accounted for */ @@ -346,11 +346,11 @@ static unsigned CL_PASTE4(cl_search_cmp_dlt_, b, _##d, _swapboth)( \ CL_SEARCH_CMP_PREVIOUS_TEMPLATE(a, b, >, gtr) \ CL_SEARCH_CMP_PREVIOUS_SWAPBOTH_TEMPLATE(a, b, >, gtr) \ \ - CL_SEARCH_CMP_DELTA_TEMPLATE(a, b, >, inc) \ - CL_SEARCH_CMP_DELTA_SWAPBOTH_TEMPLATE(a, b, >, inc) \ + CL_SEARCH_CMP_DELTA_TEMPLATE(a, b, +, inc) \ + CL_SEARCH_CMP_DELTA_SWAPBOTH_TEMPLATE(a, b, +, inc) \ \ - CL_SEARCH_CMP_DELTA_TEMPLATE(a, b, <, dec) \ - CL_SEARCH_CMP_DELTA_SWAPBOTH_TEMPLATE(a, b, <, dec) \ + CL_SEARCH_CMP_DELTA_TEMPLATE(a, b, -, dec) \ + CL_SEARCH_CMP_DELTA_SWAPBOTH_TEMPLATE(a, b, -, dec) \ \ CL_SEARCH_CMP_IMMEDIATE_UNROLL_8BIT(uint8_t, u8) @@ -444,12 +444,14 @@ static cl_search_compare_func_t cl_search_comparison_function( cl_search_cmp_imm_u16_equ); case CL_COMPARE_GREATER: return params.target_none - ? cl_search_cmp_prv_u16_gtr + ? (swap ? cl_search_cmp_prv_u16_gtr_swapboth : + cl_search_cmp_prv_u16_gtr) : (swap ? cl_search_cmp_imm_u16_gtr_swapguest : cl_search_cmp_imm_u16_gtr); case CL_COMPARE_LESS: return params.target_none - ? cl_search_cmp_prv_u16_les + ? (swap ? cl_search_cmp_prv_u16_les_swapboth : + cl_search_cmp_prv_u16_les) : (swap ? cl_search_cmp_imm_u16_les_swapguest : cl_search_cmp_imm_u16_les); case CL_COMPARE_NOT_EQUAL: @@ -483,12 +485,14 @@ static cl_search_compare_func_t cl_search_comparison_function( cl_search_cmp_imm_s16_equ); case CL_COMPARE_GREATER: return params.target_none - ? cl_search_cmp_prv_s16_gtr + ? (swap ? cl_search_cmp_prv_s16_gtr_swapboth : + cl_search_cmp_prv_s16_gtr) : (swap ? cl_search_cmp_imm_s16_gtr_swapguest : cl_search_cmp_imm_s16_gtr); case CL_COMPARE_LESS: return params.target_none - ? cl_search_cmp_prv_s16_les + ? (swap ? cl_search_cmp_prv_s16_les_swapboth : + cl_search_cmp_prv_s16_les) : (swap ? cl_search_cmp_imm_s16_les_swapguest : cl_search_cmp_imm_s16_les); case CL_COMPARE_NOT_EQUAL: @@ -522,12 +526,14 @@ static cl_search_compare_func_t cl_search_comparison_function( cl_search_cmp_imm_u32_equ); case CL_COMPARE_GREATER: return params.target_none - ? cl_search_cmp_prv_u32_gtr + ? (swap ? cl_search_cmp_prv_u32_gtr_swapboth : + cl_search_cmp_prv_u32_gtr) : (swap ? cl_search_cmp_imm_u32_gtr_swapguest : cl_search_cmp_imm_u32_gtr); case CL_COMPARE_LESS: return params.target_none - ? cl_search_cmp_prv_u32_les + ? (swap ? cl_search_cmp_prv_u32_les_swapboth : + cl_search_cmp_prv_u32_les) : (swap ? cl_search_cmp_imm_u32_les_swapguest : cl_search_cmp_imm_u32_les); case CL_COMPARE_NOT_EQUAL: @@ -561,12 +567,14 @@ static cl_search_compare_func_t cl_search_comparison_function( cl_search_cmp_imm_s32_equ); case CL_COMPARE_GREATER: return params.target_none - ? cl_search_cmp_prv_s32_gtr + ? (swap ? cl_search_cmp_prv_s32_gtr_swapboth : + cl_search_cmp_prv_s32_gtr) : (swap ? cl_search_cmp_imm_s32_gtr_swapguest : cl_search_cmp_imm_s32_gtr); case CL_COMPARE_LESS: return params.target_none - ? cl_search_cmp_prv_s32_les + ? (swap ? cl_search_cmp_prv_s32_les_swapboth : + cl_search_cmp_prv_s32_les) : (swap ? cl_search_cmp_imm_s32_les_swapguest : cl_search_cmp_imm_s32_les); case CL_COMPARE_NOT_EQUAL: @@ -600,12 +608,14 @@ static cl_search_compare_func_t cl_search_comparison_function( cl_search_cmp_imm_s64_equ); case CL_COMPARE_GREATER: return params.target_none - ? cl_search_cmp_prv_s64_gtr + ? (swap ? cl_search_cmp_prv_s64_gtr_swapboth : + cl_search_cmp_prv_s64_gtr) : (swap ? cl_search_cmp_imm_s64_gtr_swapguest : cl_search_cmp_imm_s64_gtr); case CL_COMPARE_LESS: return params.target_none - ? cl_search_cmp_prv_s64_les + ? (swap ? cl_search_cmp_prv_s64_les_swapboth : + cl_search_cmp_prv_s64_les) : (swap ? cl_search_cmp_imm_s64_les_swapguest : cl_search_cmp_imm_s64_les); case CL_COMPARE_NOT_EQUAL: @@ -639,12 +649,14 @@ static cl_search_compare_func_t cl_search_comparison_function( cl_search_cmp_imm_fp_equ); case CL_COMPARE_GREATER: return params.target_none - ? cl_search_cmp_prv_fp_gtr + ? (swap ? cl_search_cmp_prv_fp_gtr_swapboth : + cl_search_cmp_prv_fp_gtr) : (swap ? cl_search_cmp_imm_fp_gtr_swapguest : cl_search_cmp_imm_fp_gtr); case CL_COMPARE_LESS: return params.target_none - ? cl_search_cmp_prv_fp_les + ? (swap ? cl_search_cmp_prv_fp_les_swapboth : + cl_search_cmp_prv_fp_les) : (swap ? cl_search_cmp_imm_fp_les_swapguest : cl_search_cmp_imm_fp_les); case CL_COMPARE_NOT_EQUAL: @@ -678,12 +690,14 @@ static cl_search_compare_func_t cl_search_comparison_function( cl_search_cmp_imm_dfp_equ); case CL_COMPARE_GREATER: return params.target_none - ? cl_search_cmp_prv_dfp_gtr + ? (swap ? cl_search_cmp_prv_dfp_gtr_swapboth : + cl_search_cmp_prv_dfp_gtr) : (swap ? cl_search_cmp_imm_dfp_gtr_swapguest : cl_search_cmp_imm_dfp_gtr); case CL_COMPARE_LESS: return params.target_none - ? cl_search_cmp_prv_dfp_les + ? (swap ? cl_search_cmp_prv_dfp_les_swapboth : + cl_search_cmp_prv_dfp_les) : (swap ? cl_search_cmp_imm_dfp_les_swapguest : cl_search_cmp_imm_dfp_les); case CL_COMPARE_NOT_EQUAL: @@ -782,11 +796,11 @@ cl_error cl_search_change_compare_type(cl_search_t *search, } /** - * Return the canonical target value of a search. + * Return the canonical integer target value of a search. * @param search A pointer to the search to get the target from * @param out_target A pointer to store the target value into */ -static cl_error cl_search_get_target(const cl_search_t *search, int64_t *out) +static cl_error cl_search_get_target_int(const cl_search_t *search, int64_t *out) { if (!search || !out) return CL_ERR_PARAMETER_NULL; @@ -814,6 +828,33 @@ static cl_error cl_search_get_target(const cl_search_t *search, int64_t *out) } } +/** + * Return the canonical floating-point target value of a search. + * @param search A pointer to the search to get the target from + * @param out_target A pointer to store the target value into + */ +static cl_error cl_search_get_target_float(const cl_search_t *search, double *out) +{ + if (!search || !out) + return CL_ERR_PARAMETER_NULL; + else + { + cl_search_target_impl_t *target = CL_TARGET(search->params.target); + + switch (search->params.value_size) + { + case 4: + *out = target->fp; + return CL_OK; + case 8: + *out = target->dfp; + return CL_OK; + default: + return CL_ERR_PARAMETER_INVALID; + } + } +} + static cl_error cl_search_set_target(cl_search_t *search, int64_t value) { if (!search) @@ -855,7 +896,7 @@ cl_error cl_search_change_value_type(cl_search_t *search, cl_value_type type) { int64_t target_value = 0; - cl_search_get_target(search, &target_value); + cl_search_get_target_int(search, &target_value); search->params.value_type = type; search->params.value_size = cl_sizeof_memtype(type); cl_search_set_target(search, target_value); @@ -971,6 +1012,44 @@ cl_error cl_search_init(cl_search_t *search) return cl_search_profile_memory(search); } +static cl_error cl_search_step_print(const cl_search_t *search) +{ + cl_log("==============================\n"); + cl_log("Search step %u:\n", search->steps); + cl_log("Find all %s %s ", + cl_string_value_type(search->params.value_type), + cl_string_compare_type(search->params.compare_type)); + if (search->params.target_none) + cl_log("%s", (search->params.compare_type == CL_COMPARE_INCREASED || + search->params.compare_type == CL_COMPARE_DECREASED) ? + "by any amount.\n" : "previous value.\n"); + else if (search->params.value_type == CL_MEMTYPE_FLOAT || + search->params.value_type == CL_MEMTYPE_DOUBLE) + { + double target_value = 0.0; + + cl_search_get_target_float(search, &target_value); + cl_log("target value %f.\n", target_value); + } + else + { + int64_t target_value = 0; + + cl_search_get_target_int(search, &target_value); + cl_log("target value %li.\n", target_value); + } + cl_log("------------------------------\n"); + cl_log("Total memory scanned: %.6f MB\n", + ((double)search->memory_scanned) / (1024.0 * 1024.0)); + cl_log("Total matched addresses: %llu\n", (unsigned long long)search->total_matches); + cl_log("Total pages allocated: %llu\n", (unsigned long long)search->total_page_count); + cl_log("Time taken: %.6f seconds\n", search->time_taken); + cl_log("Estimated memory usage: %.6f MB\n", + ((double)search->memory_usage) / (1024.0 * 1024.0)); + + return CL_OK; +} + /** * Performs the first search step, which is responsible for allocating the * initial round of chunks. @@ -985,7 +1064,6 @@ static cl_error cl_search_step_first(cl_search_t *search) cl_addr_t bucket_size = 0; #endif cl_search_compare_func_t function; - int64_t print_target = 0; clock_t start = clock(); unsigned i; @@ -995,9 +1073,6 @@ static cl_error cl_search_step_first(cl_search_t *search) return CL_ERR_CLIENT_RUNTIME; #endif - cl_search_get_target(search, &print_target); - cl_log("Performing initial search step with %li...", print_target); - for (i = 0; i < search->page_region_count; i++) { cl_search_page_region_t *page_region = &search->page_regions[i]; @@ -1085,6 +1160,7 @@ static cl_error cl_search_step_first(cl_search_t *search) if (page && page->matches == 0) cl_search_free_page(search, page); + search->memory_scanned += page_region->region->size; } search->steps = 1; @@ -1095,9 +1171,7 @@ static cl_error cl_search_step_first(cl_search_t *search) cl_search_profile_memory(search); search->time_taken = ((double)(clock() - start)) / CLOCKS_PER_SEC; - cl_log("%u matches, %u pages, %u bytes memory usage in %.6f seconds.\n", - search->total_matches, search->total_page_count, - search->memory_usage, search->time_taken); + cl_search_step_print(search); return cl_search_profile_memory(search); } @@ -1112,14 +1186,12 @@ cl_error cl_search_step(cl_search_t *search) { cl_search_compare_func_t function; cl_addr_t total_matches = 0; - int64_t print_target = 0; clock_t start = clock(); void *prev_buffer = malloc(CL_SEARCH_CHUNK_SIZE); unsigned i; - cl_search_get_target(search, &print_target); - cl_log("Performing search step %u with %li...", search->steps, print_target); search->time_taken = clock(); + search->memory_scanned = 0; for (i = 0; i < search->page_region_count; i++) { @@ -1141,6 +1213,7 @@ cl_error cl_search_step(cl_search_t *search) cl_read_memory_buffer(page->chunk, page->region, page->start - page->region->base_guest, page->size); error = cl_search_step_page(page, search->params, function, prev_buffer); + search->memory_scanned += page->size; if (error != CL_OK) goto error; @@ -1179,10 +1252,7 @@ cl_error cl_search_step(cl_search_t *search) search->steps++; cl_search_profile_memory(search); search->time_taken = ((double)(clock() - start)) / CLOCKS_PER_SEC; - - cl_log("%u matches, %u pages, %u bytes memory usage in %.6f seconds.\n", - search->total_matches, search->total_page_count, - search->memory_usage, search->time_taken); + cl_search_step_print(search); free(prev_buffer); return CL_OK; diff --git a/cl_search_new.h b/cl_search_new.h index 3d42359..e9f2dde 100644 --- a/cl_search_new.h +++ b/cl_search_new.h @@ -122,6 +122,9 @@ typedef struct /* The total memory usage of the search, in bytes */ cl_addr_t memory_usage; + /* The total amount of memory scanned in the last step, in bytes */ + cl_addr_t memory_scanned; + /* The amount of time taken by the last search step, in seconds */ double time_taken; } cl_search_t; diff --git a/editor/cle_memory_inspector.cpp b/editor/cle_memory_inspector.cpp index 031dbe7..a92dfcf 100644 --- a/editor/cle_memory_inspector.cpp +++ b/editor/cle_memory_inspector.cpp @@ -16,15 +16,15 @@ void CleMemoryInspector::rebuildLayout() m_Layout = new QGridLayout(this); /* Initialize window layout */ - m_Layout->addWidget(m_Tabs, 0, 0, 1, 2); + m_Layout->addWidget(m_Tabs, 0, 0, 1, 4); m_Layout->addWidget(m_SizeDropdown, 1, 0); - m_Layout->addWidget(m_NewButton, 1, 1); - m_Layout->addWidget(m_CompareDropdown, 2, 0); - m_Layout->addWidget(m_TextEntry, 2, 1); - m_Layout->addWidget(m_SearchButton, 3, 0, 1, 2); - m_Layout->addWidget(m_TableStack, 4, 0, 2, 2); - m_Layout->addWidget(m_HexWidget, 6, 0, 2, 2); - m_Layout->addWidget(m_Slider, 6, 2, 1, 1); + m_Layout->addWidget(m_CompareDropdown, 1, 1); + m_Layout->addWidget(m_TextEntry, 1, 2); + m_Layout->addWidget(m_SearchButton, 1, 3); + m_Layout->addWidget(m_TableStack, 2, 0, 2, 4); + m_Layout->addWidget(m_HexWidget, 4, 0, 2, 2); + m_Layout->addWidget(m_Slider, 4, 2, 2, 1); + m_Layout->addWidget(m_Status, 6, 0, 1, 4); setLayout(m_Layout); } @@ -105,6 +105,10 @@ CleMemoryInspector::CleMemoryInspector() m_HexWidget->setOffset(memory.regions[0].base_guest); m_HexWidget->setRange(memory.regions[0].base_guest, memory.regions[0].base_guest + memory.regions[0].size + 1); + /* Initialize status footer */ + m_Status = new QLabel(tr("Matches: 0 | Scanned: 0 MB | Scan time: 0.00 s")); + m_Status->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); + /* Initialize timer for updating search rows */ m_UpdateTimer = new QTimer(this); connect(m_UpdateTimer, SIGNAL(timeout()), this, SLOT(run())); @@ -264,7 +268,10 @@ void CleMemoryInspector::onClickSearch() m_TextEntry->setText(""); } else + { m_SizeDropdown->setDisabled(true); + m_Status->setText(m_CurrentSearch->statusString()); + } } } diff --git a/editor/cle_memory_inspector.h b/editor/cle_memory_inspector.h index d6429dc..2e27147 100644 --- a/editor/cle_memory_inspector.h +++ b/editor/cle_memory_inspector.h @@ -58,8 +58,9 @@ public slots: QComboBox *m_SizeDropdown; QLineEdit *m_TextEntry; QPushButton *m_NewButton; - QPushButton *m_SearchButton; - QSlider *m_Slider; + QPushButton *m_SearchButton = nullptr; + QSlider *m_Slider = nullptr; + QLabel *m_Status = nullptr; QStackedWidget *m_TableStack; QTabBar *m_Tabs; QTimer *m_UpdateTimer; diff --git a/editor/cle_result_table.cpp b/editor/cle_result_table.cpp index fbf5425..89949cf 100644 --- a/editor/cle_result_table.cpp +++ b/editor/cle_result_table.cpp @@ -5,7 +5,7 @@ extern "C" { - #include "../cl_common.h" + #include "../cl_memory.h" } QTableWidget* CleResultTable::table(void) @@ -46,6 +46,73 @@ cl_error CleResultTable::init(void) cl_error CleResultTable::writeMemory(const cl_addr_t address, const cl_search_parameters_t& params, const QString& string) { -/** @todo */ - return CL_OK; + bool ok; + int64_t value64 = stringToValue(string, &ok); + + if (!ok) + return CL_ERR_PARAMETER_INVALID; + + switch (params.value_type) + { + case CL_MEMTYPE_UINT8: + { + uint8_t value = static_cast(value64); + cl_write_memory_value(&value, nullptr, address, params.value_type); + } + break; + case CL_MEMTYPE_UINT16: + { + uint16_t value = static_cast(value64); + cl_write_memory_value(&value, nullptr, address, params.value_type); + } + break; + case CL_MEMTYPE_UINT32: + { + uint32_t value = static_cast(value64); + cl_write_memory_value(&value, nullptr, address, params.value_type); + } + break; + case CL_MEMTYPE_INT8: + { + int8_t value = static_cast(value64); + cl_write_memory_value(&value, nullptr, address, params.value_type); + } + break; + case CL_MEMTYPE_INT16: + { + int16_t value = static_cast(value64); + cl_write_memory_value(&value, nullptr, address, params.value_type); + } + break; + case CL_MEMTYPE_INT32: + { + int32_t value = static_cast(value64); + cl_write_memory_value(&value, nullptr, address, params.value_type); + } + break; + case CL_MEMTYPE_INT64: + { + int64_t value = static_cast(value64); + cl_write_memory_value(&value, nullptr, address, params.value_type); + } + break; + case CL_MEMTYPE_FLOAT: + { + float value; + uint32_t temp = static_cast(value64); + memcpy(&value, &temp, sizeof(float)); + cl_write_memory_value(&value, nullptr, address, params.value_type); + } + break; + case CL_MEMTYPE_DOUBLE: + { + double value; + uint64_t temp = static_cast(value64); + memcpy(&value, &temp, sizeof(double)); + cl_write_memory_value(&value, nullptr, address, params.value_type); + } + break; + default: + return CL_ERR_PARAMETER_INVALID; + } } diff --git a/editor/cle_result_table.h b/editor/cle_result_table.h index db31918..27326a8 100644 --- a/editor/cle_result_table.h +++ b/editor/cle_result_table.h @@ -43,6 +43,8 @@ class CleResultTable : public QWidget */ virtual cl_error run(void) = 0; + virtual QString statusString(void) = 0; + virtual cl_error step(void) = 0; virtual cl_compare_type compareType(void) { return CL_COMPARE_INVALID; } diff --git a/editor/cle_result_table_normal.cpp b/editor/cle_result_table_normal.cpp index d5ada69..7ddb264 100644 --- a/editor/cle_result_table_normal.cpp +++ b/editor/cle_result_table_normal.cpp @@ -285,6 +285,15 @@ cl_error CleResultTableNormal::run(void) return CL_OK; } +QString CleResultTableNormal::statusString(void) +{ + return QString("Matches: %1 | Scanned: %2 MB | Usage: %3 MB | Scan time: %4 s") + .arg(m_Search.total_matches) + .arg(m_Search.memory_scanned / (1024.0 * 1024.0), 0, 'f', 6) + .arg(m_Search.memory_usage / (1024.0 * 1024.0), 0, 'f', 6) + .arg(m_Search.time_taken, 0, 'f', 6); +} + cl_error CleResultTableNormal::step(void) { cl_error err = cl_search_step(&m_Search); diff --git a/editor/cle_result_table_normal.h b/editor/cle_result_table_normal.h index 236b774..eceea71 100644 --- a/editor/cle_result_table_normal.h +++ b/editor/cle_result_table_normal.h @@ -28,6 +28,7 @@ class CleResultTableNormal : public CleResultTable cl_error rebuild(void) override; cl_error reset(void) override; cl_error run(void) override; + QString statusString(void) override; cl_error step(void) override; cl_compare_type compareType(void) override diff --git a/editor/cle_result_table_pointer.h b/editor/cle_result_table_pointer.h index cc9e52e..06ffa58 100644 --- a/editor/cle_result_table_pointer.h +++ b/editor/cle_result_table_pointer.h @@ -23,6 +23,7 @@ class CleResultTablePointer : public CleResultTable cl_error rebuild() override; cl_error reset(void) override; cl_error run(void) override; + QString statusString(void) override { return ""; } cl_error step(void) override; cl_compare_type compareType(void) override { return m_Search.params.compare_type; } From 04bbc52bc12c26f82f1994378b2141479d1d86d9 Mon Sep 17 00:00:00 2001 From: celerizer Date: Sat, 27 Dec 2025 13:54:53 -0600 Subject: [PATCH 30/57] fix crash on poking value --- editor/cle_result_table.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/editor/cle_result_table.cpp b/editor/cle_result_table.cpp index 89949cf..25a4fab 100644 --- a/editor/cle_result_table.cpp +++ b/editor/cle_result_table.cpp @@ -115,4 +115,6 @@ cl_error CleResultTable::writeMemory(const cl_addr_t address, default: return CL_ERR_PARAMETER_INVALID; } + + return CL_OK; } From 20a5901b3a5b4fec97268d58a19e40729d4a3fc3 Mon Sep 17 00:00:00 2001 From: celerizer Date: Sat, 27 Dec 2025 14:48:45 -0600 Subject: [PATCH 31/57] pause guest program on search step --- cl_search_new.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cl_search_new.c b/cl_search_new.c index 03f5e92..1876566 100644 --- a/cl_search_new.c +++ b/cl_search_new.c @@ -1,5 +1,6 @@ #include "cl_search_new.h" +#include "cl_abi.h" #include "cl_config.h" #include "cl_memory.h" @@ -1073,6 +1074,7 @@ static cl_error cl_search_step_first(cl_search_t *search) return CL_ERR_CLIENT_RUNTIME; #endif + cl_abi_set_pause(1); for (i = 0; i < search->page_region_count; i++) { cl_search_page_region_t *page_region = &search->page_regions[i]; @@ -1170,6 +1172,7 @@ static cl_error cl_search_step_first(cl_search_t *search) #endif cl_search_profile_memory(search); search->time_taken = ((double)(clock() - start)) / CLOCKS_PER_SEC; + cl_abi_set_pause(0); cl_search_step_print(search); @@ -1205,6 +1208,7 @@ cl_error cl_search_step(cl_search_t *search) if (!function) continue; + cl_abi_set_pause(1); while (page) { cl_error error; @@ -1254,11 +1258,13 @@ cl_error cl_search_step(cl_search_t *search) search->time_taken = ((double)(clock() - start)) / CLOCKS_PER_SEC; cl_search_step_print(search); free(prev_buffer); + cl_abi_set_pause(0); return CL_OK; error: free(prev_buffer); + cl_abi_set_pause(0); return CL_ERR_CLIENT_RUNTIME; } } From de0c507b730bcb118e89c05f3d58060060a501ea Mon Sep 17 00:00:00 2001 From: celerizer Date: Sat, 27 Dec 2025 15:07:48 -0600 Subject: [PATCH 32/57] use mmap for bucket but keep chunks in heap --- cl_search_new.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/cl_search_new.c b/cl_search_new.c index 1876566..9afb856 100644 --- a/cl_search_new.c +++ b/cl_search_new.c @@ -4,9 +4,9 @@ #include "cl_config.h" #include "cl_memory.h" -#if CL_HOST_PLATFORM == _CL_PLATFORM_LINUX && 0 +#if CL_HOST_PLATFORM == _CL_PLATFORM_LINUX #include -#elif CL_HOST_PLATFORM == _CL_PLATFORM_WINDOWS && 0 +#elif CL_HOST_PLATFORM == _CL_PLATFORM_WINDOWS #include #endif @@ -35,14 +35,14 @@ typedef union */ static void *cl_mmap(size_t size) { -#if CL_HOST_PLATFORM == _CL_PLATFORM_LINUX && 0 +#if CL_HOST_PLATFORM == _CL_PLATFORM_LINUX void *p = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (p == CL_ADDRESS_INVALID) return NULL; else return p; -#elif CL_HOST_PLATFORM == _CL_PLATFORM_WINDOWS && 0 +#elif CL_HOST_PLATFORM == _CL_PLATFORM_WINDOWS return VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); #else return malloc(size); @@ -56,9 +56,9 @@ static void *cl_mmap(size_t size) */ static void cl_munmap(void *p, size_t size) { -#if CL_HOST_PLATFORM == _CL_PLATFORM_LINUX && 0 +#if CL_HOST_PLATFORM == _CL_PLATFORM_LINUX munmap(p, size); -#elif CL_HOST_PLATFORM == _CL_PLATFORM_WINDOWS && 0 +#elif CL_HOST_PLATFORM == _CL_PLATFORM_WINDOWS CL_UNUSED(size); VirtualFree(p, 0, MEM_RELEASE); #else @@ -942,12 +942,11 @@ cl_error cl_search_change_target(cl_search_t *search, const void *value) return CL_OK; } -static cl_error cl_search_free_page(const cl_search_t *search, - cl_search_page_t *page) +static cl_error cl_search_free_page(cl_search_page_t *page) { if (page) { - cl_munmap(page->chunk, page->size + page->size / search->params.value_size); + free(page->chunk); free(page); return CL_OK; @@ -1104,7 +1103,7 @@ static cl_error cl_search_step_first(cl_search_t *search) if (!page) { page = (cl_search_page_t*)calloc(1, sizeof(cl_search_page_t)); - page->chunk = cl_mmap(size + size / search->params.value_size); + page->chunk = malloc(size + size / search->params.value_size); page->validity = (void*)((unsigned char*)page->chunk + size); } @@ -1161,7 +1160,7 @@ static cl_error cl_search_step_first(cl_search_t *search) } if (page && page->matches == 0) - cl_search_free_page(search, page); + cl_search_free_page(page); search->memory_scanned += page_region->region->size; } @@ -1230,7 +1229,7 @@ cl_error cl_search_step(cl_search_t *search) page_region->first_page = page->next; next_page = page->next; - cl_search_free_page(search, page); + cl_search_free_page(page); page_region->page_count--; search->total_page_count--; page = next_page; @@ -1301,8 +1300,6 @@ cl_error cl_search_remove(cl_search_t *search, cl_addr_t address) { page->validity[offset / search->params.value_size] = 0; page->matches--; - if (page->matches == 0) - cl_search_free_page(search, page); return CL_OK; } From 4a88a582ee4fd419e6e0cb34c66653936942ba54 Mon Sep 17 00:00:00 2001 From: celerizer Date: Sat, 27 Dec 2025 15:12:38 -0600 Subject: [PATCH 33/57] oops --- cl_search_new.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/cl_search_new.c b/cl_search_new.c index 9afb856..947132e 100644 --- a/cl_search_new.c +++ b/cl_search_new.c @@ -28,6 +28,8 @@ typedef union #define CL_TARGET(target) ((cl_search_target_impl_t *)&(target)) +#if CL_EXTERNAL_MEMORY + /** * Allocate a chunk of page-aligned memory. * @param size The number of bytes to allocate @@ -67,6 +69,8 @@ static void cl_munmap(void *p, size_t size) #endif } +#endif + #define CL_PASTE2(a, b) a##b #define CL_PASTE3(a, b, c) a##b##c #define CL_PASTE4(a, b, c, d) a##b##c##d @@ -970,7 +974,7 @@ cl_error cl_search_free(cl_search_t *search) while (page) { next_page = page->next; - cl_search_free_page(search, page); + cl_search_free_page(page); page = next_page; } } @@ -1041,8 +1045,8 @@ static cl_error cl_search_step_print(const cl_search_t *search) cl_log("------------------------------\n"); cl_log("Total memory scanned: %.6f MB\n", ((double)search->memory_scanned) / (1024.0 * 1024.0)); - cl_log("Total matched addresses: %llu\n", (unsigned long long)search->total_matches); - cl_log("Total pages allocated: %llu\n", (unsigned long long)search->total_page_count); + cl_log("Total matched addresses: %llu\n", search->total_matches); + cl_log("Total pages allocated: %llu\n", search->total_page_count); cl_log("Time taken: %.6f seconds\n", search->time_taken); cl_log("Estimated memory usage: %.6f MB\n", ((double)search->memory_usage) / (1024.0 * 1024.0)); From 844b82a6a8ce11bc4397c861bfe3c498913a5b31 Mon Sep 17 00:00:00 2001 From: celerizer Date: Sun, 4 Jan 2026 22:29:12 -0600 Subject: [PATCH 34/57] inspector design changes --- editor/cle_common.cpp | 14 ++++++ editor/cle_common.h | 2 + editor/cle_memory_inspector.cpp | 74 +++++++++++++++--------------- editor/cle_memory_inspector.h | 28 +++++------ editor/cle_result_table.cpp | 1 + editor/cle_result_table_normal.cpp | 6 +-- 6 files changed, 71 insertions(+), 54 deletions(-) diff --git a/editor/cle_common.cpp b/editor/cle_common.cpp index 4c8ee80..843c4cc 100644 --- a/editor/cle_common.cpp +++ b/editor/cle_common.cpp @@ -1,5 +1,19 @@ #include "cle_common.h" +QString formatBytes(double bytes) +{ + const double kb = 1024.0; + const double mb = kb * 1024.0; + const double gb = mb * 1024.0; + + if (bytes >= gb) + return QString("%1 GB").arg(bytes / gb, 0, 'f', 2); + else if (bytes >= mb) + return QString("%1 MB").arg(bytes / mb, 0, 'f', 2); + else + return QString("%1 KB").arg(bytes / kb, 0, 'f', 2); +} + int64_t stringToValue(QString string, bool *ok) { if (string.isEmpty()) diff --git a/editor/cle_common.h b/editor/cle_common.h index 3cc7a50..7a793bd 100644 --- a/editor/cle_common.h +++ b/editor/cle_common.h @@ -8,6 +8,8 @@ extern "C" #include +QString formatBytes(double bytes); + int64_t stringToValue(QString string, bool *ok); /* Output an appropriately formatted C-string representing a memory value. */ diff --git a/editor/cle_memory_inspector.cpp b/editor/cle_memory_inspector.cpp index a92dfcf..c1d15db 100644 --- a/editor/cle_memory_inspector.cpp +++ b/editor/cle_memory_inspector.cpp @@ -13,19 +13,23 @@ extern "C" void CleMemoryInspector::rebuildLayout() { - m_Layout = new QGridLayout(this); - - /* Initialize window layout */ - m_Layout->addWidget(m_Tabs, 0, 0, 1, 4); - m_Layout->addWidget(m_SizeDropdown, 1, 0); - m_Layout->addWidget(m_CompareDropdown, 1, 1); - m_Layout->addWidget(m_TextEntry, 1, 2); - m_Layout->addWidget(m_SearchButton, 1, 3); - m_Layout->addWidget(m_TableStack, 2, 0, 2, 4); - m_Layout->addWidget(m_HexWidget, 4, 0, 2, 2); - m_Layout->addWidget(m_Slider, 4, 2, 2, 1); - m_Layout->addWidget(m_Status, 6, 0, 1, 4); - setLayout(m_Layout); + if (layout()) + delete layout(); + + m_Layout = new QGridLayout(this); + + /* Initialize window layout */ + m_Layout->addWidget(m_Tabs, 0, 0, 1, 4); + m_Layout->addWidget(m_SizeDropdown, 1, 0, 1, 1); + m_Layout->addWidget(m_CompareDropdown, 1, 1, 1, 1); + m_Layout->addWidget(m_TextEntry, 1, 2, 1, 1); + m_Layout->addWidget(m_SearchButton, 1, 3, 1, 1); + m_Layout->addWidget(m_TableStack, 2, 0, 2, 4); + m_Layout->addWidget(m_HexWidget, 4, 0, 2, 3); + m_Layout->addWidget(m_Slider, 4, 3, 2, 1); + m_Layout->addWidget(m_Status, 6, 0, 1, 3); + m_Layout->addWidget(m_NewButton, 6, 3, 1, 1); + setLayout(m_Layout); } CleMemoryInspector::CleMemoryInspector() @@ -48,8 +52,6 @@ CleMemoryInspector::CleMemoryInspector() m_CompareDropdown->addItem(tr("are not equal to..."), CL_COMPARE_NOT_EQUAL); m_CompareDropdown->addItem(tr("have increased by..."), CL_COMPARE_INCREASED); m_CompareDropdown->addItem(tr("have decreased by..."), CL_COMPARE_DECREASED); - m_CompareDropdown->addItem(tr("are above address..."), CL_COMPARE_ABOVE); - m_CompareDropdown->addItem(tr("are below address..."), CL_COMPARE_BELOW); connect(m_CompareDropdown, SIGNAL(activated(int)), this, SLOT(onChangeCompareType())); @@ -82,12 +84,12 @@ CleMemoryInspector::CleMemoryInspector() this, SLOT(onRightClickTabs(const QPoint&))); /* Initialize scrollbar */ - m_Slider = new QSlider(this); + m_Slider = new QSlider(Qt::Vertical, this); m_Slider->setInvertedAppearance(true); m_Slider->setTickInterval(1024 * 1024); //1MB m_Slider->setTickPosition(QSlider::TicksRight); - connect(m_Slider, SIGNAL(sliderMoved(int)), - this, SLOT(onChangeScrollbar(int))); + connect(m_Slider, SIGNAL(valueChanged(int)), + this, SLOT(onChangeScrollbar(int))); /* Initialize hex value view widget */ m_HexWidget = new CleHexWidget(this, 1); @@ -149,24 +151,24 @@ cl_value_type CleMemoryInspector::getCurrentSizeType(void) void CleMemoryInspector::onAddressChanged(cl_addr_t address) { - cl_memory_region_t *new_bank = cl_find_memory_region(address); + cl_memory_region_t *new_bank = cl_find_memory_region(address); + if (!new_bank) + return; - if (!new_bank) - return; - else - { - if (m_CurrentMembank != new_bank) - { - m_HexWidget->setRange(new_bank->base_guest, new_bank->base_guest + new_bank->size + 1); - m_CurrentMembank = new_bank; - } - m_AddressOffset = address - m_CurrentMembank->base_guest; - m_HexWidget->setOffset(address); - - m_Slider->setMinimum(0); - m_Slider->setMaximum(m_CurrentMembank->size - 256); - m_Slider->setValue(address - m_CurrentMembank->base_guest); - } + if (m_CurrentMembank != new_bank) + { + m_CurrentMembank = new_bank; + m_HexWidget->setRange(new_bank->base_guest, + new_bank->base_guest + new_bank->size + 1); + m_Slider->setMinimum(0); + m_Slider->setMaximum(new_bank->size - 256); + } + + m_AddressOffset = address - m_CurrentMembank->base_guest; + m_HexWidget->setOffset(address); + + if (m_Slider->value() != m_AddressOffset) + m_Slider->setValue(m_AddressOffset); } void CleMemoryInspector::onChangeCompareType(void) @@ -183,8 +185,6 @@ void CleMemoryInspector::onChangeCompareType(void) case CL_COMPARE_DECREASED: m_TextEntry->setPlaceholderText(tr("any amount")); break; - case CL_COMPARE_ABOVE: - case CL_COMPARE_BELOW: default: m_TextEntry->setPlaceholderText(""); } diff --git a/editor/cle_memory_inspector.h b/editor/cle_memory_inspector.h index 2e27147..d19c37d 100644 --- a/editor/cle_memory_inspector.h +++ b/editor/cle_memory_inspector.h @@ -40,30 +40,30 @@ public slots: private: CleResultTable *m_Searches[CLE_MAX_TABS]; - CleResultTable *m_CurrentSearch; + CleResultTable *m_CurrentSearch = nullptr; - CleHexWidget *m_HexWidget; - CleMemoryNoteSubmit *m_MemoryNoteSubmit; + CleHexWidget *m_HexWidget = nullptr; + CleMemoryNoteSubmit *m_MemoryNoteSubmit = nullptr; - cl_memory_region_t *m_CurrentMembank; + cl_memory_region_t *m_CurrentMembank = nullptr; uint32_t m_AddressOffset; - uint8_t *m_BufferPrevious; - uint8_t *m_BufferCurrent; + uint8_t *m_BufferPrevious = nullptr; + uint8_t *m_BufferCurrent = nullptr; int8_t m_ClickedTab; uint8_t m_TabCount; - QComboBox *m_CompareDropdown; - QGridLayout *m_Layout; - QComboBox *m_SizeDropdown; - QLineEdit *m_TextEntry; - QPushButton *m_NewButton; + QComboBox *m_CompareDropdown = nullptr; + QGridLayout *m_Layout = nullptr; + QComboBox *m_SizeDropdown = nullptr; + QLineEdit *m_TextEntry = nullptr; + QPushButton *m_NewButton = nullptr; QPushButton *m_SearchButton = nullptr; QSlider *m_Slider = nullptr; QLabel *m_Status = nullptr; - QStackedWidget *m_TableStack; - QTabBar *m_Tabs; - QTimer *m_UpdateTimer; + QStackedWidget *m_TableStack = nullptr; + QTabBar *m_Tabs = nullptr; + QTimer *m_UpdateTimer = nullptr; cl_compare_type getCurrentCompareType(void); cl_value_type getCurrentSizeType(void); diff --git a/editor/cle_result_table.cpp b/editor/cle_result_table.cpp index 25a4fab..f9a1bb9 100644 --- a/editor/cle_result_table.cpp +++ b/editor/cle_result_table.cpp @@ -43,6 +43,7 @@ cl_error CleResultTable::init(void) return CL_OK; } +/** @todo floating point */ cl_error CleResultTable::writeMemory(const cl_addr_t address, const cl_search_parameters_t& params, const QString& string) { diff --git a/editor/cle_result_table_normal.cpp b/editor/cle_result_table_normal.cpp index 7ddb264..00a4218 100644 --- a/editor/cle_result_table_normal.cpp +++ b/editor/cle_result_table_normal.cpp @@ -287,10 +287,10 @@ cl_error CleResultTableNormal::run(void) QString CleResultTableNormal::statusString(void) { - return QString("Matches: %1 | Scanned: %2 MB | Usage: %3 MB | Scan time: %4 s") + return QString("Matches: %1 | Scanned: %2 | Usage: %3 | Scan time: %4 s") .arg(m_Search.total_matches) - .arg(m_Search.memory_scanned / (1024.0 * 1024.0), 0, 'f', 6) - .arg(m_Search.memory_usage / (1024.0 * 1024.0), 0, 'f', 6) + .arg(formatBytes(m_Search.memory_scanned)) + .arg(formatBytes(m_Search.memory_usage)) .arg(m_Search.time_taken, 0, 'f', 6); } From e9c01187785c1484bcc24a68347c389fad042a02 Mon Sep 17 00:00:00 2001 From: celerizer Date: Sun, 4 Jan 2026 22:30:17 -0600 Subject: [PATCH 35/57] add conditional to use target format for lu, llu --- cl_action.c | 17 ++++++++--------- cl_network.c | 2 +- cl_search_new.c | 4 ++-- cl_types.h | 10 ++++++++++ 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/cl_action.c b/cl_action.c index 96b5026..5e5638c 100644 --- a/cl_action.c +++ b/cl_action.c @@ -47,7 +47,7 @@ static cl_error cl_print_counter_values(char *buffer, unsigned len) snprintf(counter_buffer, sizeof(counter_buffer), "&c%u=%f", i, counter->floatval.fp); else - snprintf(counter_buffer, sizeof(counter_buffer), "&c%u=%llu", + snprintf(counter_buffer, sizeof(counter_buffer), "&c%u=" CL_FU64, i, counter->intval.raw); /* Check destination buffer can hold it */ @@ -149,18 +149,17 @@ static bool cl_act_post_achievement(cl_action_t *action) { cl_counter_t ach_id = cl_get_compare_value(action->arguments[0].uintval, action->arguments[1].uintval); -#if !CL_HAVE_EDITOR +#if CL_HAVE_EDITOR + cl_message(CL_MSG_INFO, "Editor mode: Achievement " CL_FU64 " unlocked.", + ach_id.intval.raw); +#else char data[CL_POST_DATA_SIZE]; - snprintf(data, CL_POST_DATA_SIZE, "ach_id=%llu", ach_id.intval.raw); + snprintf(data, CL_POST_DATA_SIZE, "achievement_id=" CL_FU64, ach_id.intval.raw); cl_network_post_clint(CL_END_CLINT_ACHIEVEMENT, data, NULL, NULL); - +#endif /* Clear this action so we don't re-submit the achievement */ cl_free_action(action); -#else - cl_message(CL_MSG_INFO, "Editor mode: Achievement %lu unlocked.", - ach_id.intval.raw); -#endif return true; } @@ -186,7 +185,7 @@ static bool cl_act_post_leaderboard(cl_action_t *action) action->arguments[1].uintval); char data[CL_POST_DATA_SIZE]; - snprintf(data, CL_POST_DATA_SIZE, "ldb_id=%llu", ldb_id.intval.raw); + snprintf(data, CL_POST_DATA_SIZE, "leaderboard_id=" CL_FU64, ldb_id.intval.raw); if (cl_print_counter_values(data, sizeof(data)) != CL_OK) cl_message(CL_MSG_ERROR, "Unable to allocate leaderboard data."); else diff --git a/cl_network.c b/cl_network.c index 3c832ce..ca301e7 100644 --- a/cl_network.c +++ b/cl_network.c @@ -40,7 +40,7 @@ static char *cl_build_generic_post_data(void) written = snprintf(temp, sizeof(temp), "&m%u=%f", note->key, value.floatval.fp); else - written = snprintf(temp, sizeof(temp), "&m%u=%lli", + written = snprintf(temp, sizeof(temp), "&m%u=" CL_FS64, note->key, value.intval.i64); /* Grow buffer if needed */ diff --git a/cl_search_new.c b/cl_search_new.c index 947132e..0fc3ba5 100644 --- a/cl_search_new.c +++ b/cl_search_new.c @@ -1045,8 +1045,8 @@ static cl_error cl_search_step_print(const cl_search_t *search) cl_log("------------------------------\n"); cl_log("Total memory scanned: %.6f MB\n", ((double)search->memory_scanned) / (1024.0 * 1024.0)); - cl_log("Total matched addresses: %llu\n", search->total_matches); - cl_log("Total pages allocated: %llu\n", search->total_page_count); + cl_log("Total matched addresses: " CL_FU64 "\n", search->total_matches); + cl_log("Total pages allocated: " CL_FU64 "\n", search->total_page_count); cl_log("Time taken: %.6f seconds\n", search->time_taken); cl_log("Estimated memory usage: %.6f MB\n", ((double)search->memory_usage) / (1024.0 * 1024.0)); diff --git a/cl_types.h b/cl_types.h index 019db86..9ff6a46 100644 --- a/cl_types.h +++ b/cl_types.h @@ -549,4 +549,14 @@ typedef struct cl_memory_t #define CL_MB(a) ((cl_addr_t)(a) << 20) #define CL_GB(a) ((cl_addr_t)(a) << 30) +#if CL_HOST_PLATFORM == _CL_PLATFORM_LINUX + #define CL_FS64 "%li" + #define CL_FU64 "%lu" + #define CL_FX64 "%lX" +#else + #define CL_FS64 "%lli" + #define CL_FU64 "%llu" + #define CL_FX64 "%llX" +#endif + #endif From a5499531645bf27a299b802987ba543428f36695 Mon Sep 17 00:00:00 2001 From: celerizer Date: Sun, 4 Jan 2026 22:30:41 -0600 Subject: [PATCH 36/57] misc warnings --- cl_common.c | 1 + cl_identify.c | 8 ++++---- cl_types.h | 2 -- editor/cle_hex_view.cpp | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/cl_common.c b/cl_common.c index 948543a..05cc1dd 100644 --- a/cl_common.c +++ b/cl_common.c @@ -492,6 +492,7 @@ const char *cl_string_compare_type(cl_compare_type compare_type) return "increased by"; case CL_COMPARE_DECREASED: return "decreased by"; + case CL_COMPARE_INVALID: case CL_COMPARE_SIZE: return "Invalid compare type"; } diff --git a/cl_identify.c b/cl_identify.c index 02ac7c8..ce7201a 100644 --- a/cl_identify.c +++ b/cl_identify.c @@ -305,7 +305,7 @@ static bool cl_identify_cue(char *path, char *extension) /* Apply CUE pathname back to binary track */ filename_length = end - beginning - 1; strncpy(final, beginning, filename_length); - strncpy(path_temp, path, CL_MAX_PATH - 1); + strncpy(path_temp, path, sizeof(path_temp) - 1); fill_pathname_resolve_relative(path, path_temp, final, sizeof(path_temp)); /* Would extension lengths other than 3 ever be used? */ @@ -372,9 +372,9 @@ bool cl_identify(const void *info_data, const unsigned info_size, char path[CL_MAX_PATH]; unsigned size = 0; - strncpy(path, info_path, sizeof(path)); - strncpy(extension, path_get_extension(path), sizeof(extension)); - strncpy(extension, string_to_upper(extension), sizeof(extension)); + strncpy(path, info_path, sizeof(path) - 1); + strncpy(extension, path_get_extension(path), sizeof(extension) - 1); + strncpy(extension, string_to_upper(extension), sizeof(extension) - 1); /* Hashing GC or Wii discs uses a background task that waits until the diff --git a/cl_types.h b/cl_types.h index 9ff6a46..b4df967 100644 --- a/cl_types.h +++ b/cl_types.h @@ -43,8 +43,6 @@ typedef enum CL_COMPARE_NOT_EQUAL, CL_COMPARE_INCREASED, CL_COMPARE_DECREASED, - CL_COMPARE_ABOVE, - CL_COMPARE_BELOW, CL_COMPARE_SIZE } cl_compare_type; diff --git a/editor/cle_hex_view.cpp b/editor/cle_hex_view.cpp index f4f7f6b..109dc9e 100644 --- a/editor/cle_hex_view.cpp +++ b/editor/cle_hex_view.cpp @@ -319,7 +319,7 @@ void CleHexWidget::repaintRect(const void *buffer, uint8_t index) snprintf(m_Texts[index], 16, "%016llX", val); break; default: - snprintf(m_Texts[index], 16, "Err", val); + snprintf(m_Texts[index], 16, "Err"); } /* Draw rect */ From 0933db1d570aec75fe2cf48a43610572ec71419f Mon Sep 17 00:00:00 2001 From: celerizer Date: Wed, 7 Jan 2026 22:02:28 -0600 Subject: [PATCH 37/57] why was this size 0... --- cl_main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cl_main.c b/cl_main.c index b9f401f..68af979 100644 --- a/cl_main.c +++ b/cl_main.c @@ -177,13 +177,16 @@ static CL_NETWORK_CB(cl_login_cb) unsigned char success; if (!cl_json_get(&success, response.data, CL_JSON_KEY_SUCCESS, - CL_JSON_TYPE_BOOLEAN, 0)) + CL_JSON_TYPE_BOOLEAN, sizeof(success))) { cl_log("Malformed JSON output on login.\n%s", response.data); return; } else if (!success) + { + session.state = CL_SESSION_NONE; return; + } if (cl_json_get(session.id, response.data, CL_JSON_KEY_SESSION_ID, CL_JSON_TYPE_STRING, sizeof(session.id))) From 57b3bc5cc30b1fc162163c479a73dfaef0c61f44 Mon Sep 17 00:00:00 2001 From: celerizer Date: Wed, 7 Jan 2026 23:20:33 -0600 Subject: [PATCH 38/57] error handling on cl_login route --- cl_main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cl_main.c b/cl_main.c index 68af979..f38844f 100644 --- a/cl_main.c +++ b/cl_main.c @@ -180,6 +180,7 @@ static CL_NETWORK_CB(cl_login_cb) CL_JSON_TYPE_BOOLEAN, sizeof(success))) { cl_log("Malformed JSON output on login.\n%s", response.data); + session.state = CL_SESSION_NONE; return; } else if (!success) @@ -191,6 +192,11 @@ static CL_NETWORK_CB(cl_login_cb) if (cl_json_get(session.id, response.data, CL_JSON_KEY_SESSION_ID, CL_JSON_TYPE_STRING, sizeof(session.id))) session.state = CL_SESSION_LOGGED_IN; + else + { + cl_log("No session ID received on login.\n%s", response.data); + session.state = CL_SESSION_NONE; + } } } From 5b59c71410663a2077b3f16f788d0701bfe345fc Mon Sep 17 00:00:00 2001 From: celerizer Date: Sat, 10 Jan 2026 20:21:34 -0600 Subject: [PATCH 39/57] allow caller to provide a precomputed md5 --- cl_main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cl_main.c b/cl_main.c index f38844f..258a7a2 100644 --- a/cl_main.c +++ b/cl_main.c @@ -283,12 +283,16 @@ cl_error cl_login_and_start(cl_game_identifier_t identifier) error = cl_abi_library_name(&library_name); if (error) return error; + session.identifier = identifier; - if (identifier.type == CL_GAMEIDENTIFIER_FILE_HASH) + + if (identifier.type == CL_GAMEIDENTIFIER_FILE_HASH && + identifier.checksum[0] == '\0') cl_identify(identifier.data, identifier.size, identifier.filename, library_name, session.identifier.checksum, cl_login_and_start_cb_1); - else if (identifier.type == CL_GAMEIDENTIFIER_PRODUCT_CODE) + else if (identifier.type == CL_GAMEIDENTIFIER_PRODUCT_CODE || + identifier.type == CL_GAMEIDENTIFIER_FILE_HASH) cl_login_internal(cl_login_and_start_cb_2); else return CL_ERR_PARAMETER_INVALID; From 72038586464f757c8e783735fb882b54ddc266cb Mon Sep 17 00:00:00 2001 From: celerizer Date: Sat, 10 Jan 2026 20:21:44 -0600 Subject: [PATCH 40/57] silence maybe-unused warning --- 3rdparty/jsonsax/jsonsax_full.c | 1 + 1 file changed, 1 insertion(+) diff --git a/3rdparty/jsonsax/jsonsax_full.c b/3rdparty/jsonsax/jsonsax_full.c index ba4f12f..39c212b 100644 --- a/3rdparty/jsonsax/jsonsax_full.c +++ b/3rdparty/jsonsax/jsonsax_full.c @@ -3127,6 +3127,7 @@ typedef WriteBufferData* WriteBuffer; static void WriteBuffer_Reset(WriteBuffer buffer) { + buffer->bytes[0] = 0; buffer->used = 0; } From 0f14593946e7354307e901ef50083613096bd8cc Mon Sep 17 00:00:00 2001 From: celerizer Date: Sat, 10 Jan 2026 23:14:20 -0600 Subject: [PATCH 41/57] add user login fields to json parser --- cl_json.c | 3 +++ cl_json.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/cl_json.c b/cl_json.c index 9b9b611..ad192af 100644 --- a/cl_json.c +++ b/cl_json.c @@ -74,6 +74,7 @@ static const cl_json_key_map_t cl_json_key_map[] = { CL_JSON_KEY_GAME_ID, "game_id" }, { CL_JSON_KEY_ICON_URL, "icon_url" }, { CL_JSON_KEY_ID, "id" }, + { CL_JSON_KEY_LANGUAGE, "language" }, { CL_JSON_KEY_LEADERBOARDS, "leaderboards" }, { CL_JSON_KEY_MEMORY_NOTE_ID, "memory_note_id" }, { CL_JSON_KEY_MEMORY_NOTES, "memory_notes" }, @@ -85,8 +86,10 @@ static const cl_json_key_map_t cl_json_key_map[] = { CL_JSON_KEY_SESSION_ID, "session_id" }, { CL_JSON_KEY_SUCCESS, "success" }, { CL_JSON_KEY_TITLE, "title" }, + { CL_JSON_KEY_TOKEN_CLINT, "token_clint" }, { CL_JSON_KEY_TYPE, "type" }, { CL_JSON_KEY_UNLOCKED, "unlocked" }, + { CL_JSON_KEY_USERNAME, "username" }, { CL_JSON_KEY_NONE, NULL } }; diff --git a/cl_json.h b/cl_json.h index ad18a86..74e90a5 100644 --- a/cl_json.h +++ b/cl_json.h @@ -14,6 +14,7 @@ typedef enum CL_JSON_KEY_GAME_ID, CL_JSON_KEY_ICON_URL, CL_JSON_KEY_ID, + CL_JSON_KEY_LANGUAGE, CL_JSON_KEY_LEADERBOARDS, CL_JSON_KEY_MEMORY_NOTES, CL_JSON_KEY_MEMORY_NOTE_ID, @@ -25,8 +26,10 @@ typedef enum CL_JSON_KEY_SESSION_ID, CL_JSON_KEY_SUCCESS, CL_JSON_KEY_TITLE, + CL_JSON_KEY_TOKEN_CLINT, CL_JSON_KEY_TYPE, CL_JSON_KEY_UNLOCKED, + CL_JSON_KEY_USERNAME, CL_JSON_KEY_SIZE } cl_json_field; From 19a73b04d5f071dbaff8283c41f68e10ba794b97 Mon Sep 17 00:00:00 2001 From: celerizer Date: Sat, 10 Jan 2026 23:36:26 -0600 Subject: [PATCH 42/57] allow compiler to exclude md5 hashing --- cl_config.h | 17 ++++++++++++----- cl_identify.c | 45 ++++++++++++++++++++++++++++++++------------- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/cl_config.h b/cl_config.h index f8c59c4..b8a3342 100644 --- a/cl_config.h +++ b/cl_config.h @@ -118,7 +118,7 @@ typedef enum * Whether or not the Classics Live Editor is included in this implementation. * The Classics Live Editor requires a C++ compiler and Qt5. */ -#define CL_HAVE_EDITOR false +#define CL_HAVE_EDITOR 0 #endif #ifndef CL_HAVE_FILESYSTEM @@ -126,7 +126,14 @@ typedef enum * Whether or not the filesystem will be accessed in this implementation. * If false, only raw data passed in cl_init can be used for indentification. */ -#define CL_HAVE_FILESYSTEM false +#define CL_HAVE_FILESYSTEM 0 +#endif + +#ifndef CL_HAVE_MD5 +/** + * Whether or not MD5 hashing is available in this implementation. + */ +#define CL_HAVE_MD5 1 #endif #ifndef CL_HAVE_SSL @@ -134,7 +141,7 @@ typedef enum * Whether or not the networking callbacks in this implementation support HTTPS. * This should be assumed true and only changed with caution. */ -#define CL_HAVE_SSL true +#define CL_HAVE_SSL 1 #endif #ifndef CL_EXTERNAL_MEMORY @@ -144,14 +151,14 @@ typedef enum * If true, the frontend needs to supply implementations of cl_fe_memory_read * and cl_fe_memory_write. See cl_frontend.h. */ -#define CL_EXTERNAL_MEMORY false +#define CL_EXTERNAL_MEMORY 0 #endif #ifndef CL_LIBRETRO /** * Whether or not this implementation is a libretro frontend. */ -#define CL_LIBRETRO false +#define CL_LIBRETRO 0 #endif #if CL_EXTERNAL_MEMORY diff --git a/cl_identify.c b/cl_identify.c index ce7201a..a01216a 100644 --- a/cl_identify.c +++ b/cl_identify.c @@ -5,23 +5,32 @@ #include -#if CL_HOST_PLATFORM == CL_PLATFORM_LINUX || \ - CL_HOST_PLATFORM == CL_PLATFORM_MACOS || \ - CL_HOST_PLATFORM == CL_PLATFORM_ANDROID +#if CL_HOST_PLATFORM == _CL_PLATFORM_LINUX || \ + CL_HOST_PLATFORM == _CL_PLATFORM_MACOS || \ + CL_HOST_PLATFORM == _CL_PLATFORM_ANDROID #include #endif +#if CL_HAVE_MD5 #include -#include +#include +#endif #if CL_HAVE_FILESYSTEM -#include -#include -#include #include #include +#include +#include +#include #endif +#define CL_DOLPHIN_SIZE 0x002C +#define CL_ISO9660_SIZE 0x0800 +#define CL_NCCH_SIZE 0x0200 +#define CL_MAX_PATH 4096 + +#if CL_HAVE_MD5 + typedef struct cl_md5_ctx_t { MD5_CTX context; @@ -32,11 +41,6 @@ typedef struct cl_md5_ctx_t char *md5_final; } cl_md5_ctx_t; -#define CL_DOLPHIN_SIZE 0x002C -#define CL_ISO9660_SIZE 0x0800 -#define CL_NCCH_SIZE 0x0200 -#define CL_MAX_PATH 4096 - static void cl_task_md5(struct cl_task_t *task) { if (!task) @@ -81,6 +85,8 @@ static void cl_push_md5_task(void *data, unsigned size, char *checksum, cl_abi_thread(task); } +#endif + #if CL_HAVE_FILESYSTEM /* Hash info loaded into the beginning of GC/Wii memory. (0x00 - 0x2B) @@ -454,7 +460,7 @@ bool cl_identify(const void *info_data, const unsigned info_size, return true; } -#else +#elif CL_HAVE_MD5 bool cl_identify(const void *info_data, const unsigned info_size, const char *info_path, const char *library, char *checksum, CL_TASK_CB_T callback) @@ -476,4 +482,17 @@ bool cl_identify(const void *info_data, const unsigned info_size, return false; } +#else +bool cl_identify(const void *info_data, const unsigned info_size, + const char *info_path, const char *library, char *checksum, + CL_TASK_CB_T callback) +{ + CL_UNUSED(info_data); + CL_UNUSED(info_size); + CL_UNUSED(info_path); + CL_UNUSED(library); + CL_UNUSED(checksum); + CL_UNUSED(callback); + return false; +} #endif From ae36102f378dc736d92c5a8c7381a8f60b8862ed Mon Sep 17 00:00:00 2001 From: celerizer Date: Sun, 11 Jan 2026 11:32:56 -0600 Subject: [PATCH 43/57] add password field --- cl_json.c | 1 + cl_json.h | 1 + 2 files changed, 2 insertions(+) diff --git a/cl_json.c b/cl_json.c index ad192af..a622753 100644 --- a/cl_json.c +++ b/cl_json.c @@ -80,6 +80,7 @@ static const cl_json_key_map_t cl_json_key_map[] = { CL_JSON_KEY_MEMORY_NOTES, "memory_notes" }, { CL_JSON_KEY_OFFSETS, "offsets" }, { CL_JSON_KEY_ORDER, "order" }, + { CL_JSON_KEY_PASSWORD, "password" }, { CL_JSON_KEY_POINTER_SIZE, "pointer_size" }, { CL_JSON_KEY_REASON, "reason" }, { CL_JSON_KEY_SCRIPT, "script" }, diff --git a/cl_json.h b/cl_json.h index 74e90a5..1573009 100644 --- a/cl_json.h +++ b/cl_json.h @@ -20,6 +20,7 @@ typedef enum CL_JSON_KEY_MEMORY_NOTE_ID, CL_JSON_KEY_OFFSETS, CL_JSON_KEY_ORDER, + CL_JSON_KEY_PASSWORD, CL_JSON_KEY_POINTER_SIZE, CL_JSON_KEY_REASON, CL_JSON_KEY_SCRIPT, From 156037bfca482d558ff5dff05b16065fcf3d9482 Mon Sep 17 00:00:00 2001 From: celerizer Date: Wed, 4 Feb 2026 18:26:21 -0600 Subject: [PATCH 44/57] message bounds check in cl_message --- cl_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cl_common.c b/cl_common.c index 05cc1dd..2d76cd3 100644 --- a/cl_common.c +++ b/cl_common.c @@ -24,7 +24,7 @@ void cl_message(cl_log_level level, const char *format, ...) va_list argv; va_start(argv, format); - vsprintf(msg, format, argv); + vsnprintf(msg, sizeof(msg), format, argv); msg[sizeof(msg) - 1] = '\0'; cl_abi_display_message(level, msg); va_end(argv); From 3dd488c0128464cc9a64357d4d31371782556f62 Mon Sep 17 00:00:00 2001 From: celerizer Date: Wed, 4 Feb 2026 18:26:47 -0600 Subject: [PATCH 45/57] fix mistaken u16 swap on be targets --- cl_common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cl_common.c b/cl_common.c index 2d76cd3..aaa23a0 100644 --- a/cl_common.c +++ b/cl_common.c @@ -101,9 +101,9 @@ cl_error cl_read_16(void *value, const void *src, cl_addr_t offset, #endif { #if defined(_MSC_VER) - *((uint16_t*)value) = _byteswap_ushort(tmp); + tmp = _byteswap_ushort(tmp); #elif defined(__GNUC__) || defined(__clang__) - *((uint16_t*)value) = __builtin_bswap16(tmp); + tmp = __builtin_bswap16(tmp); #else tmp = (tmp >> 8) | (tmp << 8); #endif From ca773f9eb0ec1c546f1cebe45dd9e8803c98f9aa Mon Sep 17 00:00:00 2001 From: celerizer Date: Sat, 7 Feb 2026 20:51:57 -0600 Subject: [PATCH 46/57] fix various unsafe buffer accesses --- cl_common.c | 3 +-- cl_identify.c | 3 ++- cl_main.c | 23 ++++++++++++++++------- cl_network.c | 2 +- cl_script.c | 2 +- 5 files changed, 21 insertions(+), 12 deletions(-) diff --git a/cl_common.c b/cl_common.c index aaa23a0..dd0f3c5 100644 --- a/cl_common.c +++ b/cl_common.c @@ -5,6 +5,7 @@ #endif #include +#include #include #include @@ -12,8 +13,6 @@ #include #endif -#include - #ifdef __GNUC__ __attribute__((__format__ (__printf__, 2, 0))) #endif diff --git a/cl_identify.c b/cl_identify.c index a01216a..bc957e7 100644 --- a/cl_identify.c +++ b/cl_identify.c @@ -353,7 +353,8 @@ bool cl_identify_m3u(char *path, char *extension) { str[i] = '\0'; fill_pathname_resolve_relative(path, path, str, CL_MAX_PATH); - strcpy(extension, path_get_extension(path)); + strncpy(extension, path_get_extension(path), sizeof(extension) - 1); + extension[sizeof(extension) - 1] = '\0'; string_to_upper(extension); cl_log("First item in M3U playlist: %s (%s)\n", path, extension); free(str); diff --git a/cl_main.c b/cl_main.c index 258a7a2..e192006 100644 --- a/cl_main.c +++ b/cl_main.c @@ -108,6 +108,7 @@ cl_error cl_start(cl_game_identifier_t identifier) char post_data[CL_POST_DATA_SIZE]; const char *library_name; cl_error error; + unsigned remaining; error = cl_abi_library_name(&library_name); if (error) @@ -128,8 +129,10 @@ cl_error cl_start(cl_game_identifier_t identifier) { if (strlen(identifier.checksum) == 32) { - strcat(post_data, "&md5="); - strcat(post_data, identifier.checksum); + remaining = sizeof(post_data) - strlen(post_data) - 1; + strncat(post_data, "&md5=", remaining); + remaining = sizeof(post_data) - strlen(post_data) - 1; + strncat(post_data, identifier.checksum, remaining); } else { @@ -143,14 +146,18 @@ cl_error cl_start(cl_game_identifier_t identifier) if (strlen(identifier.product) > 0) { - strcat(post_data, "&product="); - strcat(post_data, identifier.product); + remaining = sizeof(post_data) - strlen(post_data) - 1; + strncat(post_data, "&product=", remaining); + remaining = sizeof(post_data) - strlen(post_data) - 1; + strncat(post_data, identifier.product, remaining); success = 1; } if (strlen(identifier.version) > 0) { - strcat(post_data, "&version="); - strcat(post_data, identifier.version); + remaining = sizeof(post_data) - strlen(post_data) - 1; + strncat(post_data, "&version=", remaining); + remaining = sizeof(post_data) - strlen(post_data) - 1; + strncat(post_data, identifier.version, remaining); success = 1; } if (!success) @@ -204,6 +211,7 @@ static cl_error cl_login_internal(cl_network_cb_t callback) { cl_user_t user; char post_data[256]; + unsigned remaining; /* Retrieve user login info */ if (cl_abi_user_data(&user, 0) != CL_OK) @@ -229,7 +237,8 @@ static cl_error cl_login_internal(cl_network_cb_t callback) /* Append editor flag if available */ #if CL_HAVE_EDITOR - strcat(post_data, "&editor=true"); + remaining = sizeof(post_data) - strlen(post_data) - 1; + strncat(post_data, "&editor=true", remaining); #endif session.state = CL_SESSION_LOGGING_IN; diff --git a/cl_network.c b/cl_network.c index ca301e7..7bfe3b6 100644 --- a/cl_network.c +++ b/cl_network.c @@ -53,7 +53,7 @@ static char *cl_build_generic_post_data(void) return NULL; } - strcat(buf, temp); + strncat(buf, temp, bufsize - strlen(buf) - 1); } } } diff --git a/cl_script.c b/cl_script.c index 60360ff..58b8688 100644 --- a/cl_script.c +++ b/cl_script.c @@ -198,7 +198,7 @@ void cl_script_break(bool fatal, const char *format, ...) script.error_fatal = fatal; va_start(args, format); - vsprintf(script.error_msg, format, args); + vsnprintf(script.error_msg, sizeof(script.error_msg), format, args); va_end(args); /* From 9bcaee8bd58b9a67e23939d863abbbe0d7235758 Mon Sep 17 00:00:00 2001 From: celerizer Date: Sun, 8 Feb 2026 11:44:07 -0600 Subject: [PATCH 47/57] replace all bool with cl_error or cl_bool --- cl_action.c | 149 +++++++++--------- cl_action.h | 20 +-- cl_common.c | 8 +- cl_common.h | 2 +- cl_counter.c | 103 ++++++------ cl_counter.h | 157 +++++++++++++++---- cl_identify.c | 65 ++++---- cl_identify.h | 2 +- cl_json.c | 66 ++++---- cl_json.h | 8 +- cl_main.c | 26 +-- cl_memory.c | 105 +++++++------ cl_memory.h | 20 +-- cl_network.c | 12 +- cl_script.c | 103 ++++++------ cl_script.h | 16 +- cl_search.c | 235 ++++++++++++++-------------- cl_search.h | 4 +- cl_types.h | 16 +- editor/cle_memory_note_submit.cpp | 2 +- editor/cle_result_table_pointer.cpp | 5 +- 21 files changed, 630 insertions(+), 494 deletions(-) diff --git a/cl_action.c b/cl_action.c index 5e5638c..3199379 100644 --- a/cl_action.c +++ b/cl_action.c @@ -7,13 +7,13 @@ #include #include -static bool cl_act_no_process(cl_action_t *action) +static cl_error cl_act_no_process(cl_action_t *action) { CL_UNUSED(action); - return false; + return CL_ERR_CLIENT_RUNTIME; } -bool cl_free_action(cl_action_t *action) +cl_error cl_free_action(cl_action_t *action) { action->argument_count = 0; free(action->arguments); @@ -24,7 +24,7 @@ bool cl_free_action(cl_action_t *action) action->prev_action = NULL; action->next_action = NULL; - return false; + return CL_ERR_CLIENT_RUNTIME; } static cl_error cl_print_counter_values(char *buffer, unsigned len) @@ -145,7 +145,7 @@ static cl_counter_t *cl_get_mutable_value(cl_src_t source, int64_t offset) return NULL; } -static bool cl_act_post_achievement(cl_action_t *action) +static cl_error cl_act_post_achievement(cl_action_t *action) { cl_counter_t ach_id = cl_get_compare_value(action->arguments[0].uintval, action->arguments[1].uintval); @@ -161,10 +161,10 @@ static bool cl_act_post_achievement(cl_action_t *action) /* Clear this action so we don't re-submit the achievement */ cl_free_action(action); - return true; + return CL_OK; } -static bool cl_act_post_progress(cl_action_t *action) +static cl_error cl_act_post_progress(cl_action_t *action) { unsigned key = (unsigned)action->arguments[0].uintval; char data[CL_POST_DATA_SIZE]; @@ -175,11 +175,11 @@ static bool cl_act_post_progress(cl_action_t *action) else cl_message(CL_MSG_ERROR, "Unimplemented endpoint progress\n%s", data); - return true; + return CL_OK; } /** @todo Support optional values */ -static bool cl_act_post_leaderboard(cl_action_t *action) +static cl_error cl_act_post_leaderboard(cl_action_t *action) { cl_counter_t ldb_id = cl_get_compare_value(action->arguments[0].uintval, action->arguments[1].uintval); @@ -190,11 +190,11 @@ static bool cl_act_post_leaderboard(cl_action_t *action) cl_message(CL_MSG_ERROR, "Unable to allocate leaderboard data."); else cl_message(CL_MSG_ERROR, "Unimplemented endpoint leaderboard\n%s", data); - - return true; + + return CL_OK; } -static bool cl_act_compare(cl_action_t *action) +static cl_error cl_act_compare(cl_action_t *action) { cl_counter_t left = cl_get_compare_value(action->arguments[0].uintval, action->arguments[1].uintval); cl_counter_t right = cl_get_compare_value(action->arguments[2].uintval, action->arguments[3].uintval); @@ -217,7 +217,7 @@ static bool cl_act_compare(cl_action_t *action) } } -static bool cl_act_changed(cl_action_t *action) +static cl_error cl_act_changed(cl_action_t *action) { cl_counter_t left = cl_get_compare_value(CL_SRCTYPE_CURRENT_RAM, action->arguments[0].uintval); cl_counter_t right = cl_get_compare_value(CL_SRCTYPE_PREVIOUS_RAM, action->arguments[0].uintval); @@ -228,7 +228,7 @@ static bool cl_act_changed(cl_action_t *action) return cl_ctr_not_equal(&left, &right); } -static bool cl_act_bits(cl_action_t *action) +static cl_error cl_act_bits(cl_action_t *action) { cl_counter_t left = cl_get_compare_value(action->arguments[0].uintval, action->arguments[1].uintval); cl_counter_t right = cl_get_compare_value(action->arguments[2].uintval, action->arguments[3].uintval); @@ -237,10 +237,10 @@ static bool cl_act_bits(cl_action_t *action) return cl_free_action(action); /* TODO: Not exactly what we want */ - return (left.intval.raw & right.intval.raw) == right.intval.raw; + return (left.intval.raw & right.intval.raw) == right.intval.raw ? CL_OK : CL_ERR_CLIENT_RUNTIME; } -static bool cl_act_write(cl_action_t *action) +static cl_error cl_act_write(cl_action_t *action) { cl_counter_t left = cl_get_compare_value(action->arguments[0].uintval, action->arguments[1].uintval); cl_counter_t right = cl_get_compare_value(action->arguments[2].uintval, action->arguments[3].uintval); @@ -257,15 +257,15 @@ static bool cl_act_write(cl_action_t *action) { cl_counter_t *ctr = cl_get_mutable_value(CL_SRCTYPE_COUNTER, action->arguments[1].uintval); if (!ctr) - return false; + return CL_ERR_PARAMETER_NULL; else *ctr = right; - return true; + return CL_OK; } default: - cl_script_break(true, "Invalid srctype to write: %u", action->arguments[0].uintval); - return false; + cl_script_break(CL_TRUE, "Invalid srctype to write: %u", action->arguments[0].uintval); + return CL_ERR_PARAMETER_INVALID; } } } @@ -279,7 +279,7 @@ static bool cl_act_write(cl_action_t *action) action->arguments[0].uintval); \ if (!ctr || \ ctr->type == CL_MEMTYPE_NOT_SET) \ - return false; \ + return CL_ERR_PARAMETER_INVALID; \ else /** @@ -294,10 +294,10 @@ static bool cl_act_write(cl_action_t *action) if (!ctr || \ ctr->type == CL_MEMTYPE_NOT_SET || \ src.type == CL_MEMTYPE_NOT_SET) \ - return false; \ + return CL_ERR_PARAMETER_INVALID; \ else -static bool cl_act_bitwise_and(cl_action_t *action) +static cl_error cl_act_bitwise_and(cl_action_t *action) { CL_TEMPLATE_CTR_BINARY { @@ -305,7 +305,7 @@ static bool cl_act_bitwise_and(cl_action_t *action) } } -static bool cl_act_bitwise_complement(cl_action_t *action) +static cl_error cl_act_bitwise_complement(cl_action_t *action) { CL_TEMPLATE_CTR_UNARY { @@ -313,7 +313,7 @@ static bool cl_act_bitwise_complement(cl_action_t *action) } } -static bool cl_act_bitwise_or(cl_action_t *action) +static cl_error cl_act_bitwise_or(cl_action_t *action) { CL_TEMPLATE_CTR_BINARY { @@ -321,7 +321,7 @@ static bool cl_act_bitwise_or(cl_action_t *action) } } -static bool cl_act_bitwise_xor(cl_action_t *action) +static cl_error cl_act_bitwise_xor(cl_action_t *action) { CL_TEMPLATE_CTR_BINARY { @@ -329,16 +329,16 @@ static bool cl_act_bitwise_xor(cl_action_t *action) } } -static bool cl_act_set(cl_action_t *action) +static cl_error cl_act_set(cl_action_t *action) { CL_TEMPLATE_CTR_BINARY { *ctr = src; - return true; + return CL_OK; } } -static bool cl_act_shift_left(cl_action_t *action) +static cl_error cl_act_shift_left(cl_action_t *action) { CL_TEMPLATE_CTR_BINARY { @@ -346,7 +346,7 @@ static bool cl_act_shift_left(cl_action_t *action) } } -static bool cl_act_shift_right(cl_action_t *action) +static cl_error cl_act_shift_right(cl_action_t *action) { CL_TEMPLATE_CTR_BINARY { @@ -354,7 +354,7 @@ static bool cl_act_shift_right(cl_action_t *action) } } -static bool cl_act_multiplication(cl_action_t *action) +static cl_error cl_act_multiplication(cl_action_t *action) { CL_TEMPLATE_CTR_BINARY { @@ -362,7 +362,7 @@ static bool cl_act_multiplication(cl_action_t *action) } } -static bool cl_act_division(cl_action_t *action) +static cl_error cl_act_division(cl_action_t *action) { CL_TEMPLATE_CTR_BINARY { @@ -370,7 +370,7 @@ static bool cl_act_division(cl_action_t *action) } } -static bool cl_act_addition(cl_action_t *action) +static cl_error cl_act_addition(cl_action_t *action) { CL_TEMPLATE_CTR_BINARY { @@ -378,7 +378,7 @@ static bool cl_act_addition(cl_action_t *action) } } -static bool cl_act_modulo(cl_action_t *action) +static cl_error cl_act_modulo(cl_action_t *action) { CL_TEMPLATE_CTR_BINARY { @@ -386,7 +386,7 @@ static bool cl_act_modulo(cl_action_t *action) } } -static bool cl_act_subtraction(cl_action_t *action) +static cl_error cl_act_subtraction(cl_action_t *action) { CL_TEMPLATE_CTR_BINARY { @@ -394,48 +394,48 @@ static bool cl_act_subtraction(cl_action_t *action) } } -static bool cl_act_change_ctr_type(cl_action_t *action) +static cl_error cl_act_change_ctr_type(cl_action_t *action) { cl_counter_t *ctr = cl_get_mutable_value(CL_SRCTYPE_COUNTER, action->arguments[0].uintval); - return ctr ? cl_ctr_change_type(ctr, action->arguments[1].uintval) : false; + return ctr ? cl_ctr_change_type(ctr, action->arguments[1].uintval) : CL_ERR_PARAMETER_NULL; } static const cl_acttype_t action_types[] = { - { CL_ACTTYPE_NO_PROCESS, false, 0, 0, 0, cl_act_no_process }, - { CL_ACTTYPE_COMPARE, true, 5, 5, 0, cl_act_compare }, - { CL_ACTTYPE_CHANGED, true, 1, 1, 0, cl_act_changed }, - { CL_ACTTYPE_BITS, true, 4, 4, 0, cl_act_bits }, + { CL_ACTTYPE_NO_PROCESS, CL_FALSE, 0, 0, 0, cl_act_no_process }, + { CL_ACTTYPE_COMPARE, CL_TRUE, 5, 5, 0, cl_act_compare }, + { CL_ACTTYPE_CHANGED, CL_TRUE, 1, 1, 0, cl_act_changed }, + { CL_ACTTYPE_BITS, CL_TRUE, 4, 4, 0, cl_act_bits }, /* Counter arithmetic */ - { CL_ACTTYPE_ADDITION, false, 3, 3, 0, cl_act_addition }, - { CL_ACTTYPE_SUBTRACTION, false, 3, 3, 0, cl_act_subtraction }, - { CL_ACTTYPE_MULTIPLICATION, false, 3, 3, 0, cl_act_multiplication }, - { CL_ACTTYPE_DIVISION, false, 3, 3, 0, cl_act_division }, - { CL_ACTTYPE_MODULO, false, 3, 3, 0, cl_act_modulo }, - { CL_ACTTYPE_SET, false, 3, 3, 0, cl_act_set }, + { CL_ACTTYPE_ADDITION, CL_FALSE, 3, 3, 0, cl_act_addition }, + { CL_ACTTYPE_SUBTRACTION, CL_FALSE, 3, 3, 0, cl_act_subtraction }, + { CL_ACTTYPE_MULTIPLICATION, CL_FALSE, 3, 3, 0, cl_act_multiplication }, + { CL_ACTTYPE_DIVISION, CL_FALSE, 3, 3, 0, cl_act_division }, + { CL_ACTTYPE_MODULO, CL_FALSE, 3, 3, 0, cl_act_modulo }, + { CL_ACTTYPE_SET, CL_FALSE, 3, 3, 0, cl_act_set }, /* Counter bitwise arithmetic */ - { CL_ACTTYPE_AND, false, 3, 3, 0, cl_act_bitwise_and }, - { CL_ACTTYPE_OR, false, 3, 3, 0, cl_act_bitwise_or }, - { CL_ACTTYPE_XOR, false, 3, 3, 0, cl_act_bitwise_xor }, - { CL_ACTTYPE_COMPLEMENT, false, 1, 1, 0, cl_act_bitwise_complement }, - { CL_ACTTYPE_SHIFT_LEFT, false, 3, 3, 0, cl_act_shift_left }, - { CL_ACTTYPE_SHIFT_RIGHT, false, 3, 3, 0, cl_act_shift_right }, + { CL_ACTTYPE_AND, CL_FALSE, 3, 3, 0, cl_act_bitwise_and }, + { CL_ACTTYPE_OR, CL_FALSE, 3, 3, 0, cl_act_bitwise_or }, + { CL_ACTTYPE_XOR, CL_FALSE, 3, 3, 0, cl_act_bitwise_xor }, + { CL_ACTTYPE_COMPLEMENT, CL_FALSE, 1, 1, 0, cl_act_bitwise_complement }, + { CL_ACTTYPE_SHIFT_LEFT, CL_FALSE, 3, 3, 0, cl_act_shift_left }, + { CL_ACTTYPE_SHIFT_RIGHT, CL_FALSE, 3, 3, 0, cl_act_shift_right }, /* Direct value manipulation */ - { CL_ACTTYPE_WRITE, false, 4, 4, 0, cl_act_write }, - { CL_ACTTYPE_CHANGE_CTR_TYPE, false, 2, 2, 0, cl_act_change_ctr_type }, + { CL_ACTTYPE_WRITE, CL_FALSE, 4, 4, 0, cl_act_write }, + { CL_ACTTYPE_CHANGE_CTR_TYPE, CL_FALSE, 2, 2, 0, cl_act_change_ctr_type }, /* Website API calls */ - { CL_ACTTYPE_POST_ACHIEVEMENT, false, 2, 2, 0, cl_act_post_achievement }, - { CL_ACTTYPE_POST_LEADERBOARD, false, 2, 16, 2, cl_act_post_leaderboard }, - { CL_ACTTYPE_POST_PROGRESS, false, 2, 16, 2, cl_act_post_progress }, + { CL_ACTTYPE_POST_ACHIEVEMENT, CL_FALSE, 2, 2, 0, cl_act_post_achievement }, + { CL_ACTTYPE_POST_LEADERBOARD, CL_FALSE, 2, 16, 2, cl_act_post_leaderboard }, + { CL_ACTTYPE_POST_PROGRESS, CL_FALSE, 2, 16, 2, cl_act_post_progress }, - { 0, false, 0, 0, 0, NULL } + { 0, CL_FALSE, 0, 0, 0, NULL } }; -bool cl_init_action(cl_action_t *action) +cl_error cl_init_action(cl_action_t *action) { const cl_acttype_t *acttype = &action_types[0]; @@ -461,33 +461,40 @@ bool cl_init_action(cl_action_t *action) action->if_type = acttype->if_type; action->function = acttype->function; - return true; + return CL_OK; } action->function = cl_act_no_process; - return false; + return CL_ERR_PARAMETER_INVALID; } else acttype++; } - return false; + return CL_ERR_PARAMETER_INVALID; } -bool cl_process_action(cl_action_t *action) +cl_error cl_process_action(cl_action_t *action) { + cl_error result; + if (!action) - cl_script_break(true, "Attempted to process a NULL action."); + cl_script_break(CL_TRUE, "Attempted to process a NULL action."); else if (!action->function) - cl_script_break(true, "Attempted to process an action with NULL " + cl_script_break(CL_TRUE, "Attempted to process an action with NULL " "implementation (action type %04X).", action->type); else if (action->breakpoint) - cl_script_break(false, "User-defined breakpoint."); - else if (action->function(action)) + cl_script_break(CL_FALSE, "User-defined breakpoint."); + else { - action->executions++; - return true; + result = action->function(action); + if (result == CL_OK) + { + action->executions++; + return CL_OK; + } + return result; } - return false; + return CL_ERR_CLIENT_RUNTIME; } diff --git a/cl_action.h b/cl_action.h index 142970e..886c2f6 100644 --- a/cl_action.h +++ b/cl_action.h @@ -49,13 +49,13 @@ typedef struct cl_action_t cl_arg_t *arguments; unsigned argument_count; unsigned executions; - bool breakpoint; - bool (*function)(struct cl_action_t *action); - bool if_type; + cl_bool breakpoint; + cl_error (*function)(struct cl_action_t *action); + cl_bool if_type; unsigned indentation; cl_action_id type; - /* TODO: Double-link actions together so the editor can easily insert new lines */ + /* TODO: Double-link actions together so the editor can easily insert new lines */ struct cl_action_t *prev_action; struct cl_action_t *next_action; } cl_action_t; @@ -65,7 +65,7 @@ typedef struct cl_action_id id; /* Whether or not to evaluate the action as a conditional */ - bool if_type; + cl_bool if_type; /* The minimum number of arguments allowed for this action type */ unsigned minimum_args; @@ -77,15 +77,15 @@ typedef struct unsigned modulo_after_minimum; /* The function of the action */ - bool (*function)(cl_action_t*); + cl_error (*function)(cl_action_t*); } cl_acttype_t; -bool cl_free_action(cl_action_t *action); +cl_error cl_free_action(cl_action_t *action); /* Assign the correct function pointer for the type of action */ -bool cl_init_action(cl_action_t *action); +cl_error cl_init_action(cl_action_t *action); -/* Run the function and return whether it succeeded. */ -bool cl_process_action(cl_action_t *action); +/* Run the function and return CL_OK if succeeded. */ +cl_error cl_process_action(cl_action_t *action); #endif diff --git a/cl_common.c b/cl_common.c index dd0f3c5..0ddae1d 100644 --- a/cl_common.c +++ b/cl_common.c @@ -232,12 +232,12 @@ cl_error cl_read_buffer(void *dst, const void *src, cl_addr_t offset, return CL_OK; } -bool cl_strto(const char **pos, void *value, unsigned size, bool is_signed) +cl_error cl_strto(const char **pos, void *value, unsigned size, cl_bool is_signed) { char *end = NULL; if (**pos == '\0') - return false; + return CL_ERR_PARAMETER_INVALID; switch (size) { @@ -266,11 +266,11 @@ bool cl_strto(const char **pos, void *value, unsigned size, bool is_signed) *(uint64_t*)value = (uint64_t)strtoull(*pos, &end, CL_RADIX); break; default: - return false; + return CL_ERR_PARAMETER_INVALID; } *pos = end; - return true; + return CL_OK; } cl_error cl_write_8(const void *value, void *dst, cl_addr_t offset) diff --git a/cl_common.h b/cl_common.h index 944377a..621fb1c 100644 --- a/cl_common.h +++ b/cl_common.h @@ -65,6 +65,6 @@ const char *cl_string_error(cl_error error); const char *cl_string_platform(cl_platform platform); const char *cl_string_value_type(cl_value_type type); -bool cl_strto(const char **pos, void *value, unsigned size, bool is_signed); +cl_error cl_strto(const char **pos, void *value, unsigned size, cl_bool is_signed); #endif diff --git a/cl_counter.c b/cl_counter.c index 3bc9c31..eb85455 100644 --- a/cl_counter.c +++ b/cl_counter.c @@ -7,15 +7,16 @@ #define CL_CTR_EPSILON 0.005 -bool cl_ctr_is_float(const cl_counter_t *counter) +cl_bool cl_ctr_is_float(const cl_counter_t *counter) { - if (counter->type == CL_MEMTYPE_DOUBLE || counter->type == CL_MEMTYPE_FLOAT) - return true; + if (counter->type == CL_MEMTYPE_DOUBLE || + counter->type == CL_MEMTYPE_FLOAT) + return CL_TRUE; else - return false; + return CL_FALSE; } -bool cl_ctr_store(cl_counter_t *counter, const void *src, cl_value_type type) +cl_error cl_ctr_store(cl_counter_t *counter, const void *src, cl_value_type type) { switch (type) { @@ -38,75 +39,77 @@ bool cl_ctr_store(cl_counter_t *counter, const void *src, cl_value_type type) case CL_MEMTYPE_DOUBLE: return cl_ctr_store_float(counter, *((const double*)src)); default: - return false; + return CL_ERR_PARAMETER_INVALID; } } /** @todo Make sure the commented lines still work */ -bool cl_ctr_store_int(cl_counter_t *counter, int64_t value) +cl_error cl_ctr_store_int(cl_counter_t *counter, int64_t value) { counter->intval.i64 = value; counter->floatval.fp = (double)value; counter->type = CL_MEMTYPE_INT64; - return true; + return CL_OK; } -bool cl_ctr_store_float(cl_counter_t *counter, double value) +cl_error cl_ctr_store_float(cl_counter_t *counter, double value) { counter->intval.i64 = (int64_t)value; counter->floatval.fp = value; counter->type = CL_MEMTYPE_DOUBLE; - return true; + return CL_OK; } -bool cl_ctr_equal(const cl_counter_t *left, const cl_counter_t *right) +cl_bool cl_ctr_equal(const cl_counter_t *left, const cl_counter_t *right) { - if (cl_ctr_is_float(left) && cl_ctr_is_float(right)) - return fabs(left->floatval.fp - right->floatval.fp) < CL_CTR_EPSILON; + if (cl_ctr_is_float(left) == CL_TRUE && cl_ctr_is_float(right) == CL_TRUE) + return (fabs(left->floatval.fp - right->floatval.fp) < CL_CTR_EPSILON) ? CL_TRUE : CL_FALSE; else - return left->intval.i64 == right->intval.i64; + return (left->intval.i64 == right->intval.i64) ? CL_TRUE : CL_FALSE; } -bool cl_ctr_equal_exact(const cl_counter_t *left, const cl_counter_t *right) +cl_bool cl_ctr_equal_exact(const cl_counter_t *left, const cl_counter_t *right) { return (left->floatval.raw == right->floatval.raw && - left->intval.i64 == right->intval.i64); + left->intval.i64 == right->intval.i64) ? CL_TRUE : CL_FALSE; } -bool cl_ctr_not_equal(const cl_counter_t *left, const cl_counter_t *right) +cl_bool cl_ctr_not_equal(const cl_counter_t *left, const cl_counter_t *right) { - return !cl_ctr_equal(left, right); + return (cl_ctr_equal(left, right) != CL_TRUE) ? CL_TRUE : CL_FALSE; } -bool cl_ctr_lesser(const cl_counter_t *left, const cl_counter_t *right) +cl_bool cl_ctr_lesser(const cl_counter_t *left, const cl_counter_t *right) { - if (cl_ctr_is_float(left) && cl_ctr_is_float(right)) - return left->floatval.fp < right->floatval.fp; + if (cl_ctr_is_float(left) == CL_TRUE && cl_ctr_is_float(right) == CL_TRUE) + return (left->floatval.fp < right->floatval.fp) ? CL_TRUE : CL_FALSE; else - return left->intval.i64 < right->intval.i64; + return (left->intval.i64 < right->intval.i64) ? CL_TRUE : CL_FALSE; } -bool cl_ctr_greater(const cl_counter_t *left, const cl_counter_t *right) +cl_bool cl_ctr_greater(const cl_counter_t *left, const cl_counter_t *right) { - if (cl_ctr_is_float(left) && cl_ctr_is_float(right)) - return left->floatval.fp > right->floatval.fp; + if (cl_ctr_is_float(left) == CL_TRUE && cl_ctr_is_float(right) == CL_TRUE) + return (left->floatval.fp > right->floatval.fp) ? CL_TRUE : CL_FALSE; else - return left->intval.i64 > right->intval.i64; + return (left->intval.i64 > right->intval.i64) ? CL_TRUE : CL_FALSE; } -bool cl_ctr_lesser_or_equal(const cl_counter_t *left, const cl_counter_t *right) +cl_bool cl_ctr_lesser_or_equal(const cl_counter_t *left, const cl_counter_t *right) { - return cl_ctr_lesser(left, right) || cl_ctr_equal(left, right); + return (cl_ctr_lesser(left, right) == CL_TRUE || + cl_ctr_equal(left, right) == CL_TRUE) ? CL_TRUE : CL_FALSE; } -bool cl_ctr_greater_or_equal(const cl_counter_t *left, const cl_counter_t *right) +cl_bool cl_ctr_greater_or_equal(const cl_counter_t *left, const cl_counter_t *right) { - return cl_ctr_greater(left, right) || cl_ctr_equal(left, right); + return (cl_ctr_greater(left, right) == CL_TRUE || + cl_ctr_equal(left, right) == CL_TRUE) ? CL_TRUE : CL_FALSE; } -bool cl_ctr_and(cl_counter_t *counter, const cl_counter_t *value) +cl_error cl_ctr_and(cl_counter_t *counter, const cl_counter_t *value) { uint64_t temp_src; @@ -128,7 +131,7 @@ bool cl_ctr_and(cl_counter_t *counter, const cl_counter_t *value) return cl_ctr_store_int(counter, counter->intval.raw & temp_src); } -bool cl_ctr_or(cl_counter_t *counter, const cl_counter_t *value) +cl_error cl_ctr_or(cl_counter_t *counter, const cl_counter_t *value) { uint64_t temp_src; @@ -150,7 +153,7 @@ bool cl_ctr_or(cl_counter_t *counter, const cl_counter_t *value) return cl_ctr_store_int(counter, counter->intval.raw | temp_src); } -bool cl_ctr_xor(cl_counter_t *counter, const cl_counter_t *value) +cl_error cl_ctr_xor(cl_counter_t *counter, const cl_counter_t *value) { uint64_t temp_src; @@ -172,94 +175,94 @@ bool cl_ctr_xor(cl_counter_t *counter, const cl_counter_t *value) return cl_ctr_store_int(counter, counter->intval.raw ^ temp_src); } -bool cl_ctr_shift_left(cl_counter_t *counter, const cl_counter_t *value) +cl_error cl_ctr_shift_left(cl_counter_t *counter, const cl_counter_t *value) { if (cl_ctr_is_float(counter)) { counter->floatval.raw <<= value->intval.raw; counter->intval.raw = counter->floatval.raw; - return true; + return CL_OK; } else return cl_ctr_store_int(counter, counter->intval.raw << value->intval.raw); } -bool cl_ctr_shift_right(cl_counter_t *counter, const cl_counter_t *value) +cl_error cl_ctr_shift_right(cl_counter_t *counter, const cl_counter_t *value) { if (cl_ctr_is_float(counter)) { counter->floatval.raw >>= value->intval.raw; counter->intval.raw = counter->floatval.raw; - return true; + return CL_OK; } else return cl_ctr_store_int(counter, counter->intval.raw >> value->intval.raw); } -bool cl_ctr_complement(cl_counter_t *counter) +cl_error cl_ctr_complement(cl_counter_t *counter) { return cl_ctr_store_int(counter, ~(cl_ctr_is_float(counter) ? counter->floatval.raw : counter->intval.raw)); } -bool cl_ctr_add(cl_counter_t *left, const cl_counter_t *right) +cl_error cl_ctr_add(cl_counter_t *left, const cl_counter_t *right) { if (cl_ctr_is_float(left) || cl_ctr_is_float(right)) left->type = CL_MEMTYPE_DOUBLE; left->intval.i64 += right->intval.i64; left->floatval.fp += right->floatval.fp; - return true; + return CL_OK; } -bool cl_ctr_subtract(cl_counter_t *left, const cl_counter_t *right) +cl_error cl_ctr_subtract(cl_counter_t *left, const cl_counter_t *right) { if (cl_ctr_is_float(left) || cl_ctr_is_float(right)) left->type = CL_MEMTYPE_DOUBLE; left->intval.i64 -= right->intval.i64; left->floatval.fp -= right->floatval.fp; - return true; + return CL_OK; } -bool cl_ctr_multiply(cl_counter_t *left, const cl_counter_t *right) +cl_error cl_ctr_multiply(cl_counter_t *left, const cl_counter_t *right) { if (cl_ctr_is_float(left) || cl_ctr_is_float(right)) left->type = CL_MEMTYPE_DOUBLE; left->intval.i64 *= right->intval.i64; left->floatval.fp *= right->floatval.fp; - return true; + return CL_OK; } -bool cl_ctr_divide(cl_counter_t *left, const cl_counter_t *right) +cl_error cl_ctr_divide(cl_counter_t *left, const cl_counter_t *right) { if (cl_ctr_is_float(left) || cl_ctr_is_float(right)) left->type = CL_MEMTYPE_DOUBLE; left->intval.i64 /= right->intval.i64; left->floatval.fp /= right->floatval.fp; - return true; + return CL_OK; } -bool cl_ctr_modulo(cl_counter_t *left, const cl_counter_t *right) +cl_error cl_ctr_modulo(cl_counter_t *left, const cl_counter_t *right) { if (cl_ctr_is_float(left) || cl_ctr_is_float(right)) left->type = CL_MEMTYPE_DOUBLE; left->intval.i64 %= right->intval.i64; left->floatval.fp = fmod(left->floatval.fp, right->floatval.fp); - return true; + return CL_OK; } /* TODO */ -bool cl_ctr_change_type(cl_counter_t *counter, cl_value_type type) +cl_error cl_ctr_change_type(cl_counter_t *counter, cl_value_type type) { counter->type = type; - return true; + return CL_OK; } #if CL_TESTS diff --git a/cl_counter.h b/cl_counter.h index 9bd8598..ec41107 100644 --- a/cl_counter.h +++ b/cl_counter.h @@ -3,61 +3,158 @@ #include "cl_common.h" -bool cl_ctr_store(cl_counter_t *counter, const void *src, cl_value_type type); -bool cl_ctr_store_int(cl_counter_t *counter, int64_t value); -bool cl_ctr_store_float(cl_counter_t *counter, double value); +/** + * Stores a value into a counter. The value is taken from the provided source + * pointer, and the type of the value is specified by the type parameter. + */ +cl_error cl_ctr_store(cl_counter_t *counter, const void *src, cl_value_type type); + +/** + * Stores an integer value into a counter. Changes counter type to int. + */ +cl_error cl_ctr_store_int(cl_counter_t *counter, int64_t value); + +/** + * Stores a floating point value into a counter. Changes counter type to float. + */ +cl_error cl_ctr_store_float(cl_counter_t *counter, double value); -bool cl_ctr_equal(const cl_counter_t *left, const cl_counter_t *right); -bool cl_ctr_equal_exact(const cl_counter_t *left, const cl_counter_t *right); -bool cl_ctr_not_equal(const cl_counter_t *left, const cl_counter_t *right); -bool cl_ctr_lesser(const cl_counter_t *left, const cl_counter_t *right); -bool cl_ctr_greater(const cl_counter_t *left, const cl_counter_t *right); -bool cl_ctr_lesser_or_equal(const cl_counter_t *left, const cl_counter_t *right); -bool cl_ctr_greater_or_equal(const cl_counter_t *left, const cl_counter_t *right); +/** + * Compares two counter values for equality. Returns CL_TRUE if the values are + * equal. + */ +cl_bool cl_ctr_equal(const cl_counter_t *left, const cl_counter_t *right); -bool cl_ctr_and(cl_counter_t *counter, const cl_counter_t *value); -bool cl_ctr_or(cl_counter_t *counter, const cl_counter_t *value); -bool cl_ctr_xor(cl_counter_t *counter, const cl_counter_t *value); +/** + * Compares two counter values for exact equality. Returns CL_TRUE if the raw + * bit representations of the values are equal. + */ +cl_bool cl_ctr_equal_exact(const cl_counter_t *left, const cl_counter_t *right); + +/** + * Compares two counter values for inequality. Returns CL_TRUE if the values are + * not equal. + */ +cl_bool cl_ctr_not_equal(const cl_counter_t *left, const cl_counter_t *right); + +/** + * Compares if the left counter value is lesser than the right counter value. + * Returns CL_TRUE if the left value is lesser. + */ +cl_bool cl_ctr_lesser(const cl_counter_t *left, const cl_counter_t *right); + +/** + * Compares if the left counter value is greater than the right counter value. + * Returns CL_TRUE if the left value is greater. + */ +cl_bool cl_ctr_greater(const cl_counter_t *left, const cl_counter_t *right); + +/** + * Compares if the left counter value is lesser than or equal to the right + * counter value. Returns CL_TRUE if the left value is lesser or equal. + */ +cl_bool cl_ctr_lesser_or_equal(const cl_counter_t *left, const cl_counter_t *right); + +/** + * Compares if the left counter value is greater than or equal to the right + * counter value. Returns CL_TRUE if the left value is greater or equal. + */ +cl_bool cl_ctr_greater_or_equal(const cl_counter_t *left, const cl_counter_t *right); + +/** + * Performs a bitwise AND operation on a counter value with another value. Changes + * counter type to int. + * @param counter The target counter value. + * @param value The value to AND with, taken from intval or floatval depending + * on the type of the value. + */ +cl_error cl_ctr_and(cl_counter_t *counter, const cl_counter_t *value); + +/** + * Performs a bitwise OR operation on a counter value with another value. Changes + * counter type to int. + * @param counter The target counter value. + * @param value The value to OR with, taken from intval or floatval depending + * on the type of the value. + */ +cl_error cl_ctr_or(cl_counter_t *counter, const cl_counter_t *value); + +/** + * Performs a bitwise XOR operation on a counter value with another value. Changes + * counter type to int. + * @param counter The target counter value. + * @param value The value to XOR with, taken from intval or floatval depending + * on the type of the value. + */ +cl_error cl_ctr_xor(cl_counter_t *counter, const cl_counter_t *value); /** * Returns whether or not a counter is representing a floating point value. - **/ -bool cl_ctr_is_float(const cl_counter_t *counter); + */ +cl_bool cl_ctr_is_float(const cl_counter_t *counter); /** * Shifts a counter value to the left. Changes counter type to int. * @param counter The target counter value. * @param value The number of bits to shift left, taken from intval. - **/ -bool cl_ctr_shift_left(cl_counter_t *counter, const cl_counter_t *value); + */ +cl_error cl_ctr_shift_left(cl_counter_t *counter, const cl_counter_t *value); /** * Shifts a counter value to the right. Changes counter type to int. * @param counter The target counter value. * @param value The number of bits to shift right, taken from intval. - **/ -bool cl_ctr_shift_right(cl_counter_t *counter, const cl_counter_t *value); + */ +cl_error cl_ctr_shift_right(cl_counter_t *counter, const cl_counter_t *value); /** * Flips every bit in a counter. Changes counter type to int. - **/ -bool cl_ctr_complement(cl_counter_t *counter); + */ +cl_error cl_ctr_complement(cl_counter_t *counter); + +/** + * Adds a value to a counter. Graduates the target counter to float if adding + * a float value. + */ +cl_error cl_ctr_add(cl_counter_t *left, const cl_counter_t *right); /** - * Adds a value to a counter. Graduates the target counter to float if adding a - * float value. - **/ -bool cl_ctr_add(cl_counter_t *left, const cl_counter_t *right); + * Subtracts a value from a counter. Graduates the target counter to float if + * subtracting a float value. + */ +cl_error cl_ctr_subtract(cl_counter_t *left, const cl_counter_t *right); -bool cl_ctr_subtract(cl_counter_t *left, const cl_counter_t *right); -bool cl_ctr_multiply(cl_counter_t *left, const cl_counter_t *right); -bool cl_ctr_divide(cl_counter_t *left, const cl_counter_t *right); -bool cl_ctr_modulo(cl_counter_t *left, const cl_counter_t *right); +/** + * Multiplies a value with a counter. Graduates the target counter to float if + * multiplying by a float value. + */ +cl_error cl_ctr_multiply(cl_counter_t *left, const cl_counter_t *right); -bool cl_ctr_change_type(cl_counter_t *counter, cl_value_type type); +/** + * Divides a counter by a value. Graduates the target counter to float if + * dividing by a float value. + */ +cl_error cl_ctr_divide(cl_counter_t *left, const cl_counter_t *right); + +/** + * Calculates the modulo of a counter by a value. Graduates the target counter + * to float if modulo by a float value. + */ +cl_error cl_ctr_modulo(cl_counter_t *left, const cl_counter_t *right); + +/** + * Changes the type of a counter. + */ +cl_error cl_ctr_change_type(cl_counter_t *counter, cl_value_type type); #if CL_TESTS + +/** + * Runs tests for the counter module. Returns 0 if all tests passed, or an + * error code if any test failed. + */ int cl_ctr_tests(void); + #endif #endif diff --git a/cl_identify.c b/cl_identify.c index bc957e7..a1b90ea 100644 --- a/cl_identify.c +++ b/cl_identify.c @@ -22,6 +22,7 @@ #include #include #include +#include #endif #define CL_DOLPHIN_SIZE 0x002C @@ -37,7 +38,7 @@ typedef struct cl_md5_ctx_t void *data; unsigned size; uint8_t md5_raw[16]; - bool free_on_finish; + cl_bool free_on_finish; char *md5_final; } cl_md5_ctx_t; @@ -67,8 +68,8 @@ static void cl_task_md5(struct cl_task_t *task) } } -static void cl_push_md5_task(void *data, unsigned size, char *checksum, - bool free_on_finish, CL_TASK_CB_T callback) +static void cl_push_md5_task(void *data, unsigned size, char *checksum, + cl_bool free_on_finish, CL_TASK_CB_T callback) { cl_task_t *task = (cl_task_t*)calloc(1, sizeof(cl_task_t)); cl_md5_ctx_t *context = (cl_md5_ctx_t*)calloc(1, sizeof(cl_md5_ctx_t)); @@ -118,7 +119,7 @@ static void cl_task_gcwii(cl_task_t *task) cl_log("(GC/Wii) Game to be identified: %.8s\n", buffer); cl_push_md5_task(buffer, CL_DOLPHIN_SIZE, - ((cl_md5_ctx_t*)task->state)->md5_final, true, task->callback); + ((cl_md5_ctx_t*)task->state)->md5_final, CL_TRUE, task->callback); task->callback = NULL; } } @@ -143,7 +144,7 @@ static void cl_push_gcwii_task(char *checksum, CL_TASK_CB_T callback) cl_abi_thread(task); } -bool cl_read_from_file(const char *path, uint8_t **data, uint32_t *size) +static cl_error cl_read_from_file(const char *path, uint8_t **data, uint32_t *size) { uint8_t *buffer; int64_t read_bytes; @@ -151,7 +152,7 @@ bool cl_read_from_file(const char *path, uint8_t **data, uint32_t *size) intfstream_t *stream = intfstream_open_file(path, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE); - + *size = (unsigned)intfstream_get_size(stream); buffer = (uint8_t*)malloc(*size); read_bytes = (int64_t)intfstream_read(stream, buffer, *size); @@ -161,11 +162,11 @@ bool cl_read_from_file(const char *path, uint8_t **data, uint32_t *size) free(buffer); *data = NULL; - return false; + return CL_ERR_CLIENT_RUNTIME; } *data = buffer; - return true; + return CL_OK; } /** @@ -281,16 +282,16 @@ static uint8_t* cl_identify_chd(const char *path) * Opens a CUE file and determines the path of the first data track. * @param path Path to the CUE, overwritten by path to the first data track. * @param extension The extension of the first data track, in caps. - * @return Whether or not the track data was properly read. + * @return CL_OK if the track data was properly read; error code otherwise. **/ -static bool cl_identify_cue(char *path, char *extension) +static cl_error cl_identify_cue(char *path, char *extension) { const char *beginning; unsigned length; char *str; - if (!cl_read_from_file(path, (uint8_t**)&str, &length)) - return false; + if (cl_read_from_file(path, (uint8_t**)&str, &length) != CL_OK) + return CL_ERR_CLIENT_RUNTIME; beginning = strstr(str, "FILE "); if (beginning) @@ -319,7 +320,7 @@ static bool cl_identify_cue(char *path, char *extension) string_to_upper(extension); cl_log("First data track of cue sheet: %s (%s)\n", path, extension); - return true; + return CL_OK; } else cl_log("Malformed cue sheet (no ending quote on first data track).\n"); @@ -330,22 +331,22 @@ static bool cl_identify_cue(char *path, char *extension) else cl_log("Malformed cue sheet (first data track not found).\n"); - return false; + return CL_ERR_PARAMETER_INVALID; } /** * Opens an M3U playlist and determines the path of the first item. * @param path Path to the M3U, overwritten by path to the first item. * @param extension The extension of the first item, in caps. - * @return Whether or not the first item was properly read. + * @return CL_OK if the first item was properly read; error code otherwise. **/ -bool cl_identify_m3u(char *path, char *extension) +static cl_error cl_identify_m3u(char *path, char *extension) { unsigned length, i; char *str; - if (!cl_read_from_file(path, (uint8_t**)&str, &length)) - return false; + if (cl_read_from_file(path, (uint8_t**)&str, &length) != CL_OK) + return CL_ERR_CLIENT_RUNTIME; for (i = 0; i < length; i++) { @@ -359,18 +360,18 @@ bool cl_identify_m3u(char *path, char *extension) cl_log("First item in M3U playlist: %s (%s)\n", path, extension); free(str); - return true; + return CL_OK; } } cl_log("Malformed M3U.\n"); free(str); - return false; + return CL_ERR_PARAMETER_INVALID; } #endif #if CL_HAVE_FILESYSTEM -bool cl_identify(const void *info_data, const unsigned info_size, +cl_error cl_identify(const void *info_data, const unsigned info_size, const char *info_path, const char *library, char *checksum, CL_TASK_CB_T callback) { @@ -398,7 +399,7 @@ bool cl_identify(const void *info_data, const unsigned info_size, { cl_push_gcwii_task(checksum, callback); - return true; + return CL_OK; } } @@ -454,15 +455,15 @@ bool cl_identify(const void *info_data, const unsigned info_size, Last case: File was unrecognizable and not already in memory. Re-open the file using the path from retro_game_info and hash it. */ - else if (!cl_read_from_file(path, &data, &size)) - return false; + else if (cl_read_from_file(path, &data, &size) != CL_OK) + return CL_ERR_CLIENT_RUNTIME; } - cl_push_md5_task(data, size, checksum, true, callback); + cl_push_md5_task(data, size, checksum, CL_TRUE, callback); - return true; + return CL_OK; } #elif CL_HAVE_MD5 -bool cl_identify(const void *info_data, const unsigned info_size, +cl_error cl_identify(const void *info_data, const unsigned info_size, const char *info_path, const char *library, char *checksum, CL_TASK_CB_T callback) { @@ -475,16 +476,16 @@ bool cl_identify(const void *info_data, const unsigned info_size, if (data) { memcpy(data, info_data, info_size); - cl_push_md5_task(data, info_size, checksum, true, callback); + cl_push_md5_task(data, info_size, checksum, CL_TRUE, callback); - return true; + return CL_OK; } } - return false; + return CL_ERR_CLIENT_RUNTIME; } #else -bool cl_identify(const void *info_data, const unsigned info_size, +cl_error cl_identify(const void *info_data, const unsigned info_size, const char *info_path, const char *library, char *checksum, CL_TASK_CB_T callback) { @@ -494,6 +495,6 @@ bool cl_identify(const void *info_data, const unsigned info_size, CL_UNUSED(library); CL_UNUSED(checksum); CL_UNUSED(callback); - return false; + return CL_ERR_CLIENT_RUNTIME; } #endif diff --git a/cl_identify.h b/cl_identify.h index 911cbe7..392d218 100644 --- a/cl_identify.h +++ b/cl_identify.h @@ -14,7 +14,7 @@ * specific identification methods. * @param callback A function to run after identification is complete. */ -bool cl_identify(const void *info_data, const unsigned info_size, +cl_error cl_identify(const void *info_data, const unsigned info_size, const char *info_path, const char *library, char *checksum, CL_TASK_CB_T callback); diff --git a/cl_json.c b/cl_json.c index a622753..92e3d6e 100644 --- a/cl_json.c +++ b/cl_json.c @@ -30,13 +30,13 @@ typedef struct cl_json_t const char *key; /** Internal; whether the currently processed JSON element is what we want */ - bool is_current; + cl_bool is_current; /** Internal; whether the currently processed JSON element is in an array */ unsigned array_level; /** Internal; whether the currently processed JSON element is an object */ - bool is_object; + cl_bool is_object; /** Whether or not the requested element was copied into the buffer */ cl_json_state state; @@ -159,11 +159,11 @@ static int cl_json_boolean(void *userdata, int istrue) if (ud->is_current) { - ud->is_current = false; + ud->is_current = CL_FALSE; switch (ud->type) { case CL_JSON_TYPE_BOOLEAN: - *((bool*)ud->data) = istrue ? true : false; + *((cl_bool*)ud->data) = istrue ? CL_TRUE : CL_FALSE; ud->state = CL_JSON_STATE_FINISHED; break; default: @@ -189,7 +189,7 @@ static int cl_json_boolean_array(void *userdata, int istrue) switch (ud->field) { case CL_JSON_KEY_UNLOCKED: - ach->unlocked = istrue ? true : false; + ach->unlocked = istrue ? CL_TRUE : CL_FALSE; break; default: break; @@ -212,11 +212,11 @@ static int cl_json_number(void *userdata, const char* number, size_t length) if (ud->is_current) { - ud->is_current = false; + ud->is_current = CL_FALSE; switch (ud->type) { case CL_JSON_TYPE_NUMBER: - ud->state = cl_strto(&number, ud->data, ud->size, false) ? + ud->state = (cl_strto(&number, ud->data, ud->size, CL_FALSE) == CL_OK) ? CL_JSON_STATE_FINISHED : CL_JSON_STATE_ERROR; break; default: @@ -232,10 +232,10 @@ static int cl_json_number_array(void *userdata, const char* number, { cl_json_t *ud = (cl_json_t*)userdata; unsigned value = 0; - bool success = cl_strto(&number, &value, sizeof(value), false); + cl_error error = cl_strto(&number, &value, sizeof(value), CL_FALSE); CL_UNUSED(length); - if (!success) + if (error != CL_OK) return 1; else if (ud->is_current && ud->field) { @@ -325,7 +325,7 @@ static int cl_json_end_array(void *userdata) if (ud->is_current) { ud->state = CL_JSON_STATE_FINISHED; - ud->is_current = false; + ud->is_current = CL_FALSE; } ud->array_level--; @@ -412,17 +412,17 @@ static void cl_json_strcpy(char *dst, size_t dstlen, const char *src, unescape(dst); } -static bool cl_json_parse_offsets(cl_memnote_t *note, const char *string) +static cl_error cl_json_parse_offsets(cl_memnote_t *note, const char *string) { unsigned count = 0; const char *ptr = string; unsigned i; /* Parse number of offsets */ - if (!cl_strto(&ptr, &count, sizeof(count), false)) - return false; + if (cl_strto(&ptr, &count, sizeof(count), CL_FALSE) != CL_OK) + return CL_ERR_PARAMETER_INVALID; else if (count > CL_POINTER_MAX_PASSES) - return false; + return CL_ERR_PARAMETER_INVALID; note->pointer_passes = count; @@ -435,13 +435,13 @@ static bool cl_json_parse_offsets(cl_memnote_t *note, const char *string) while (*ptr == ' ' || *ptr == '\t') ptr++; - if (!cl_strto(&ptr, &value, sizeof(value), false)) - return false; + if (cl_strto(&ptr, &value, sizeof(value), CL_FALSE) != CL_OK) + return CL_ERR_PARAMETER_INVALID; note->pointer_offsets[i] = value; } - return true; + return CL_OK; } static int cl_json_string(void *userdata, const char *string, size_t length) @@ -450,17 +450,17 @@ static int cl_json_string(void *userdata, const char *string, size_t length) if (ud->is_current || ud->field) { - ud->is_current = false; + ud->is_current = CL_FALSE; switch (ud->type) { case CL_JSON_TYPE_BOOLEAN: if (string_is_equal(ud->data, "true")) - *((bool*)ud->data) = true; + *((cl_bool*)ud->data) = CL_TRUE; else - *((bool*)ud->data) = false; + *((cl_bool*)ud->data) = CL_FALSE; break; case CL_JSON_TYPE_NUMBER: - cl_strto(&string, ud->data, ud->size, false); + cl_strto(&string, ud->data, ud->size, CL_FALSE); break; case CL_JSON_TYPE_STRING: cl_json_strcpy(ud->data, ud->size, string, length); @@ -535,7 +535,7 @@ static int cl_json_string_array(void *userdata, const char *string, switch (ud->field) { case CL_JSON_KEY_OFFSETS: - if (!cl_json_parse_offsets(note, string)) + if (cl_json_parse_offsets(note, string) != CL_OK) return 1; break; #if CL_HAVE_EDITOR @@ -562,7 +562,7 @@ static int cl_json_string_array(void *userdata, const char *string, return 0; } -bool cl_json_get(void *data, const char *json, cl_json_field key, +cl_error cl_json_get(void *data, const char *json, cl_json_field key, cl_json_type type, unsigned size) { const jsonsax_handlers_t handlers = @@ -586,7 +586,7 @@ bool cl_json_get(void *data, const char *json, cl_json_field key, value.data = data; value.element_count = 0; value.element_num = 0; - value.is_current = false; + value.is_current = CL_FALSE; value.field = CL_JSON_KEY_NONE; value.state = CL_JSON_STATE_STARTING; value.key = cl_json_key_name(key); @@ -595,12 +595,12 @@ bool cl_json_get(void *data, const char *json, cl_json_field key, if (jsonsax_parse(json, &handlers, (void*)&value) == JSONSAX_OK && value.state == CL_JSON_STATE_FINISHED) - return true; + return CL_OK; else - return false; + return CL_ERR_CLIENT_RUNTIME; } -bool cl_json_get_array(void **data, unsigned *elements, const char *json, +cl_error cl_json_get_array(void **data, unsigned *elements, const char *json, cl_json_field key, cl_json_type type) { /** @@ -644,7 +644,7 @@ bool cl_json_get_array(void **data, unsigned *elements, const char *json, value.element_count = 0; value.element_num = 0; value.field = CL_JSON_KEY_NONE; - value.is_current = false; + value.is_current = CL_FALSE; value.key = cl_json_key_name(key); value.size = 0; value.state = CL_JSON_STATE_STARTING; @@ -653,7 +653,7 @@ bool cl_json_get_array(void **data, unsigned *elements, const char *json, /* Were we able to count the number of elements in the array? */ if (jsonsax_parse(json, &handlers_count, (void*)&value) != JSONSAX_OK || value.element_count == 0) - return false; + return CL_ERR_CLIENT_RUNTIME; /* Allocate memory for the array of given element type */ *elements = value.element_count; @@ -672,7 +672,7 @@ bool cl_json_get_array(void **data, unsigned *elements, const char *json, sizeof(cl_memnote_t)); break; default: - return false; + return CL_ERR_PARAMETER_INVALID; } /* Now, actually extract the values */ @@ -681,7 +681,7 @@ bool cl_json_get_array(void **data, unsigned *elements, const char *json, value.element_count = *elements; value.element_num = 0; value.field = CL_JSON_KEY_NONE; - value.is_current = false; + value.is_current = CL_FALSE; value.key = cl_json_key_name(key); value.size = 0; value.state = CL_JSON_STATE_STARTING; @@ -691,8 +691,8 @@ bool cl_json_get_array(void **data, unsigned *elements, const char *json, value.state != CL_JSON_STATE_FINISHED) { free(*data); - return false; + return CL_ERR_CLIENT_RUNTIME; } else - return true; + return CL_OK; } diff --git a/cl_json.h b/cl_json.h index 1573009..b9ffbe6 100644 --- a/cl_json.h +++ b/cl_json.h @@ -58,9 +58,9 @@ typedef enum * @param key The key of the value to extract. * @param type The type of the value. * @param size The size, in bytes, of the buffer to be written into. - * @return true if the value was successfully extracted; false otherwise. + * @return CL_OK if the value was successfully extracted; error code otherwise. */ -bool cl_json_get(void *data, const char *json, cl_json_field key, +cl_error cl_json_get(void *data, const char *json, cl_json_field key, cl_json_type type, unsigned size); /** @@ -72,9 +72,9 @@ bool cl_json_get(void *data, const char *json, cl_json_field key, * @param json The JSON text to parse. * @param key The key of the array to extract. * @param type The type of elements in the array. - * @return true if the array was successfully extracted; false otherwise. + * @return CL_OK if the array was successfully extracted; error code otherwise. */ -bool cl_json_get_array(void **data, unsigned *elements, const char *json, +cl_error cl_json_get_array(void **data, unsigned *elements, const char *json, cl_json_field key, cl_json_type type); #endif diff --git a/cl_main.c b/cl_main.c index e192006..c689a08 100644 --- a/cl_main.c +++ b/cl_main.c @@ -28,21 +28,21 @@ static cl_error cl_init_session(const char* json) /* Get game info */ if (cl_json_get(&session.game_title, json, CL_JSON_KEY_TITLE, - CL_JSON_TYPE_STRING, sizeof(session.game_title))) + CL_JSON_TYPE_STRING, sizeof(session.game_title)) == CL_OK) cl_message(CL_MSG_INFO, "Game title: %s", session.game_title); if (cl_json_get(&misc, json, CL_JSON_KEY_GAME_ID, - CL_JSON_TYPE_NUMBER, sizeof(misc))) + CL_JSON_TYPE_NUMBER, sizeof(misc)) == CL_OK) session.game_id = misc; /* Get default endianness of memory regions */ if (cl_json_get(&misc, json, CL_JSON_KEY_ENDIANNESS, - CL_JSON_TYPE_NUMBER, sizeof(misc))) + CL_JSON_TYPE_NUMBER, sizeof(misc)) == CL_OK) for (i = 0; i < memory.region_count; i++) memory.regions[i].endianness = misc; /* Get default pointer length of memory regions */ if (cl_json_get(&misc, json, CL_JSON_KEY_POINTER_SIZE, - CL_JSON_TYPE_NUMBER, sizeof(misc))) + CL_JSON_TYPE_NUMBER, sizeof(misc)) == CL_OK) for (i = 0; i < memory.region_count; i++) memory.regions[i].pointer_length = misc; @@ -57,9 +57,9 @@ static cl_error cl_init_session(const char* json) /* Get script */ iterator = &script_str[0]; - if (cl_json_get(script_str, json, CL_JSON_KEY_SCRIPT, CL_JSON_TYPE_STRING, sizeof(script_str))) + if (cl_json_get(script_str, json, CL_JSON_KEY_SCRIPT, CL_JSON_TYPE_STRING, sizeof(script_str)) == CL_OK) { - if (!cl_script_init(&iterator)) + if (cl_script_init(&iterator) != CL_OK) { #if !CL_HAVE_EDITOR cl_message(CL_MSG_ERROR, "Failed to initialize CL script."); @@ -183,8 +183,8 @@ static CL_NETWORK_CB(cl_login_cb) { unsigned char success; - if (!cl_json_get(&success, response.data, CL_JSON_KEY_SUCCESS, - CL_JSON_TYPE_BOOLEAN, sizeof(success))) + if (cl_json_get(&success, response.data, CL_JSON_KEY_SUCCESS, + CL_JSON_TYPE_BOOLEAN, sizeof(success)) != CL_OK) { cl_log("Malformed JSON output on login.\n%s", response.data); session.state = CL_SESSION_NONE; @@ -197,7 +197,7 @@ static CL_NETWORK_CB(cl_login_cb) } if (cl_json_get(session.id, response.data, CL_JSON_KEY_SESSION_ID, - CL_JSON_TYPE_STRING, sizeof(session.id))) + CL_JSON_TYPE_STRING, sizeof(session.id)) == CL_OK) session.state = CL_SESSION_LOGGED_IN; else { @@ -211,7 +211,9 @@ static cl_error cl_login_internal(cl_network_cb_t callback) { cl_user_t user; char post_data[256]; +#if CL_HAVE_EDITOR unsigned remaining; +#endif /* Retrieve user login info */ if (cl_abi_user_data(&user, 0) != CL_OK) @@ -319,10 +321,14 @@ cl_error cl_login_and_start(cl_game_identifier_t identifier) cl_error cl_run(void) { + cl_error error; + if (session.state == CL_SESSION_STARTED) { cl_update_memory(); - cl_script_update(); + error = cl_script_update(); + if (error != CL_OK) + return error; /* Pingback every X seconds to update rich presence */ if (time(0) >= session.last_status_update + CL_PRESENCE_INTERVAL) diff --git a/cl_memory.c b/cl_memory.c index 88bdb0f..b5e8017 100644 --- a/cl_memory.c +++ b/cl_memory.c @@ -74,28 +74,28 @@ void cl_memory_free(void) memory.regions = NULL; } -bool cl_get_memnote_flag(cl_memnote_t *note, uint8_t flag) +cl_error cl_get_memnote_flag(cl_memnote_t *note, uint8_t flag) { if (!note) - return false; + return CL_ERR_PARAMETER_NULL; else - return (note->flags & (1 << flag)) != 0; + return ((note->flags & (1 << flag)) != 0) ? CL_OK : CL_ERR_CLIENT_RUNTIME; } -bool cl_get_memnote_flag_from_key(unsigned key, uint8_t flag) +cl_error cl_get_memnote_flag_from_key(unsigned key, uint8_t flag) { cl_memnote_t *note = cl_find_memnote(key); if (!note) - return false; + return CL_ERR_PARAMETER_NULL; else return cl_get_memnote_flag(note, flag); } -bool cl_get_memnote_value(cl_counter_t *src, cl_memnote_t *note, unsigned type) +cl_error cl_get_memnote_value(cl_counter_t *src, cl_memnote_t *note, unsigned type) { if (!src || !note) - return false; + return CL_ERR_PARAMETER_NULL; else { switch (type) @@ -110,20 +110,20 @@ bool cl_get_memnote_value(cl_counter_t *src, cl_memnote_t *note, unsigned type) *src = note->last_unique; break; default: - return false; + return CL_ERR_PARAMETER_INVALID; } - return true; + return CL_OK; } } -bool cl_get_memnote_value_from_key(cl_counter_t *src, unsigned key, +cl_error cl_get_memnote_value_from_key(cl_counter_t *src, unsigned key, unsigned type) { cl_memnote_t *note = cl_find_memnote(key); if (!note) - return false; + return CL_ERR_PARAMETER_NULL; else return cl_get_memnote_value(src, note, type); } @@ -144,7 +144,7 @@ void cl_sort_memory_regions(cl_memory_region_t *banks, unsigned count) } #if CL_LIBRETRO -bool cl_init_membanks_libretro(const struct retro_memory_descriptor **descs, +cl_error cl_init_membanks_libretro(const struct retro_memory_descriptor **descs, const unsigned num_descs) { const struct retro_memory_descriptor *desc; @@ -199,7 +199,7 @@ bool cl_init_membanks_libretro(const struct retro_memory_descriptor **descs, region->size, region->title); } - return true; + return CL_OK; } #endif @@ -473,9 +473,9 @@ cl_error cl_write_memory_value_external(const void *value, * reads it into a buffer. * @param address The buffer to read the address into. * @param note A pointer to the memory note to have its address resolved. - * @return Whether or not the final address could be inferred from the note. + * @return CL_OK if the final address could be inferred from the note; error code otherwise. **/ -bool cl_memnote_resolve_ptrs(cl_memnote_t *note) +static cl_error cl_memnote_resolve_ptrs(cl_memnote_t *note) { cl_addr_t final_addr = note->address_initial; unsigned i; @@ -483,9 +483,9 @@ bool cl_memnote_resolve_ptrs(cl_memnote_t *note) for (i = 0; i < note->pointer_passes; i++) { const cl_memory_region_t *region = cl_find_memory_region(final_addr); - + if (!region) - return false; + return CL_ERR_PARAMETER_NULL; else { cl_value_type ptr_type; @@ -502,40 +502,45 @@ bool cl_memnote_resolve_ptrs(cl_memnote_t *note) ptr_type = CL_MEMTYPE_INT64; break; default: - return false; + return CL_ERR_PARAMETER_INVALID; } if (cl_read_memory_value(&final_addr, NULL, final_addr, ptr_type) != CL_OK) - return false; + return CL_ERR_CLIENT_RUNTIME; final_addr += note->pointer_offsets[i]; } } note->address = final_addr; - return true; + return CL_OK; } -bool cl_update_memnote(cl_memnote_t *note) +static cl_error cl_update_memnote(cl_memnote_t *note) { - if (!note || !cl_memnote_resolve_ptrs(note)) - return false; - else - { - int64_t new_val = 0; + cl_error error; + int64_t new_val; - /* The "previous" value is the value from the previous frame */ - note->previous = note->current; + if (!note) + return CL_ERR_PARAMETER_NULL; - cl_read_memory_value(&new_val, NULL, note->address, note->type); - cl_ctr_store(¬e->current, &new_val, note->type); + error = cl_memnote_resolve_ptrs(note); + if (error != CL_OK) + return error; - /* Logic for "last unique" values; the previous value will persist */ - if (!cl_ctr_equal_exact(¬e->previous, ¬e->current)) - note->last_unique = note->previous; + new_val = 0; - return true; - } + /* The "previous" value is the value from the previous frame */ + note->previous = note->current; + + cl_read_memory_value(&new_val, NULL, note->address, note->type); + cl_ctr_store(¬e->current, &new_val, note->type); + + /* Logic for "last unique" values; the previous value will persist */ + if (cl_ctr_equal_exact(¬e->previous, ¬e->current) != CL_OK) + note->last_unique = note->previous; + + return CL_OK; } void cl_update_memory(void) @@ -553,26 +558,28 @@ void cl_update_memory(void) } } -bool cl_write_memnote(cl_memnote_t *note, const cl_counter_t *value) +cl_error cl_write_memnote(cl_memnote_t *note, const cl_counter_t *value) { + cl_error error; + if (!note || !value) - return false; - else - { - if (cl_memnote_resolve_ptrs(note)) - { - return cl_write_memory_value(cl_ctr_is_float(value) ? - (const void *)&value->floatval.fp : (const void *)&value->intval.i64, - NULL, note->address, note->type) == CL_OK; - } - } + return CL_ERR_PARAMETER_NULL; + + error = cl_memnote_resolve_ptrs(note); + if (error != CL_OK) + return error; - return false; + return cl_write_memory_value(cl_ctr_is_float(value) == CL_OK ? + (const void *)&value->floatval.fp : (const void *)&value->intval.i64, + NULL, note->address, note->type); } -bool cl_write_memnote_from_key(unsigned key, const cl_counter_t *value) +cl_error cl_write_memnote_from_key(unsigned key, const cl_counter_t *value) { cl_memnote_t *note = cl_find_memnote(key); - return note ? cl_write_memnote(note, value) : false; + if (!note) + return CL_ERR_PARAMETER_NULL; + else + return cl_write_memnote(note, value); } diff --git a/cl_memory.h b/cl_memory.h index 3099ab6..180c893 100644 --- a/cl_memory.h +++ b/cl_memory.h @@ -35,10 +35,10 @@ void cl_free_memnote(cl_memnote_t *note); * informed via environment callback RETRO_ENVIRONMENT_SET_MEMORY_MAPS. * @param descs An array of libretro memory descriptors. * @param num_descs The count of elements in descs. - * @return Whether or not memory banks could be initialized. + * @return CL_OK if memory banks could be initialized; error code otherwise. */ struct retro_memory_descriptor; -bool cl_init_membanks_libretro(const struct retro_memory_descriptor **descs, +cl_error cl_init_membanks_libretro(const struct retro_memory_descriptor **descs, const unsigned num_descs); #endif @@ -48,8 +48,8 @@ bool cl_init_membanks_libretro(const struct retro_memory_descriptor **descs, * @param key A memory note key to be looked up automatically. * @param flag The memory note flag to check. For example, CL_MEMFLAG_RICH. **/ -bool cl_get_memnote_flag(cl_memnote_t *note, uint8_t flag); -bool cl_get_memnote_flag_from_key(unsigned key, uint8_t flag); +cl_error cl_get_memnote_flag(cl_memnote_t *note, uint8_t flag); +cl_error cl_get_memnote_flag_from_key(unsigned key, uint8_t flag); /** * Copies the current value of a memory note into a buffer. @@ -58,11 +58,11 @@ bool cl_get_memnote_flag_from_key(unsigned key, uint8_t flag); * @param key A memory note key to be looked up automatically. * @param type The data type of the buffer. For example, CL_MEMTYPE_32BIT. **/ -bool cl_get_memnote_value(cl_counter_t *value, cl_memnote_t *note, unsigned type); -bool cl_get_memnote_value_from_key(cl_counter_t *value, unsigned key, unsigned type); +cl_error cl_get_memnote_value(cl_counter_t *value, cl_memnote_t *note, unsigned type); +cl_error cl_get_memnote_value_from_key(cl_counter_t *value, unsigned key, unsigned type); /* Populate a memory holder with values returned by the web API */ -bool cl_init_memory(const char **pos); +cl_error cl_init_memory(const char **pos); /** * Reads a value at a virtual memory address into a buffer by reading internal @@ -130,10 +130,10 @@ void cl_update_memory(void); * @param note A pointer to a memory note. * @param key The unique key of a memory note. * @param value A buffer containing the source value. - * @return Whether or not the write succeeded. + * @return CL_OK if the write succeeded; error code otherwise. **/ -bool cl_write_memnote(cl_memnote_t *note, const cl_counter_t *value); -bool cl_write_memnote_from_key(unsigned key, const cl_counter_t *value); +cl_error cl_write_memnote(cl_memnote_t *note, const cl_counter_t *value); +cl_error cl_write_memnote_from_key(unsigned key, const cl_counter_t *value); /** * Looks up a memory note based on its key. diff --git a/cl_network.c b/cl_network.c index 7bfe3b6..a47bb99 100644 --- a/cl_network.c +++ b/cl_network.c @@ -30,9 +30,9 @@ static char *cl_build_generic_post_data(void) { cl_memnote_t *note = &memory.notes[i]; - if (!cl_get_memnote_flag(note, CL_MEMFLAG_RICH)) + if (cl_get_memnote_flag(note, CL_MEMFLAG_RICH) != CL_OK) continue; - if (cl_get_memnote_value(&value, note, CL_SRCTYPE_CURRENT_RAM)) + if (cl_get_memnote_value(&value, note, CL_SRCTYPE_CURRENT_RAM) == CL_OK) { unsigned written, need; @@ -68,7 +68,7 @@ static CL_NETWORK_CB(cl_default_network_cb) } static cl_error cl_network_post_internal(const char *url, const char *endpoint, - const char *post_data, cl_network_cb_t callback, void *userdata, bool force) + const char *post_data, cl_network_cb_t callback, void *userdata, cl_bool force) { char endpoint_url[256]; char final_data[1024]; @@ -120,7 +120,7 @@ void cl_network_post_api(const char *endpoint, const char *post_data, cl_network_cb_t callback, void *userdata) { cl_network_post_internal(CL_API_URL, endpoint, - post_data, callback, userdata, false); + post_data, callback, userdata, CL_FALSE); } #endif @@ -128,12 +128,12 @@ void cl_network_post_clint(const char *endpoint, const char *post_data, cl_network_cb_t callback, void *userdata) { cl_network_post_internal(CL_CLINT_URL, endpoint, - post_data, callback, userdata, false); + post_data, callback, userdata, CL_FALSE); } void cl_network_post_clint_login(const char *post_data, cl_network_cb_t callback) { cl_network_post_internal(CL_CLINT_URL, CL_END_CLINT_LOGIN, - post_data, callback, NULL, true); + post_data, callback, NULL, CL_TRUE); } diff --git a/cl_script.c b/cl_script.c index 58b8688..dac44d7 100644 --- a/cl_script.c +++ b/cl_script.c @@ -31,15 +31,17 @@ void cl_script_free(void) script.page_count = 0; } -static bool cl_init_page(const char **pos, cl_page_t *page) +static cl_error cl_init_page(const char **pos, cl_page_t *page) { cl_action_t *action = NULL; cl_action_t *prev_action = NULL; unsigned i, j; - if (!cl_strto(pos, &page->action_count, sizeof(page->action_count), false)) - return false; + if (cl_strto(pos, &page->action_count, sizeof(page->action_count), CL_FALSE) != CL_OK) + return CL_ERR_PARAMETER_INVALID; page->actions = (cl_action_t*)calloc(page->action_count, sizeof(cl_action_t)); + if (!page->actions) + return CL_ERR_PARAMETER_NULL; cl_log("Actions: %u\n", page->action_count); @@ -47,20 +49,22 @@ static bool cl_init_page(const char **pos, cl_page_t *page) { action = &page->actions[i]; - if (cl_strto(pos, &action->indentation, sizeof(action->indentation), false) && - cl_strto(pos, &action->type, sizeof(action->type), false) && - cl_strto(pos, &action->argument_count, sizeof(action->argument_count), false)) + if (cl_strto(pos, &action->indentation, sizeof(action->indentation), CL_FALSE) == CL_OK && + cl_strto(pos, &action->type, sizeof(action->type), CL_FALSE) == CL_OK && + cl_strto(pos, &action->argument_count, sizeof(action->argument_count), CL_FALSE) == CL_OK) cl_log("%u %u %u", page->actions[i].indentation, page->actions[i].type, page->actions[i].argument_count); - - if (!cl_init_action(action)) - return false; + + if (cl_init_action(action) != CL_OK) + return CL_ERR_CLIENT_RUNTIME; /* Allocate and initialize action arguments */ action->arguments = (cl_arg_t*)calloc(action->argument_count, sizeof(cl_arg_t)); + if (!action->arguments) + return CL_ERR_PARAMETER_NULL; for (j = 0; j < action->argument_count; j++) { - if (!cl_strto(pos, &action->arguments[j], sizeof(cl_arg_t), true)) - return false; + if (cl_strto(pos, &action->arguments[j], sizeof(cl_arg_t), CL_TRUE) != CL_OK) + return CL_ERR_PARAMETER_INVALID; cl_log(" %lld", page->actions[i].arguments[j].uintval); } @@ -81,33 +85,38 @@ static bool cl_init_page(const char **pos, cl_page_t *page) cl_log("End of page.\n"); - return page->actions != 0; + return CL_OK; } -bool cl_script_init(const char **pos) +cl_error cl_script_init(const char **pos) { + cl_error error; + unsigned i; + script.status = CL_SCRIPT_STATUS_INACTIVE; - if (!cl_strto(pos, &script.page_count, sizeof(script.page_count), false)) - return false; - else - { - unsigned i; + if (cl_strto(pos, &script.page_count, sizeof(script.page_count), CL_FALSE) != CL_OK) + return CL_ERR_PARAMETER_INVALID; - script.pages = (cl_page_t*)calloc(script.page_count, sizeof(cl_page_t)); - for (i = 0; i < script.page_count; i++) - if (!cl_init_page(pos, &script.pages[i])) - return false; - script.status = CL_SCRIPT_STATUS_ACTIVE; + script.pages = (cl_page_t*)calloc(script.page_count, sizeof(cl_page_t)); + if (!script.pages) + return CL_ERR_PARAMETER_NULL; - return true; + for (i = 0; i < script.page_count; i++) + { + error = cl_init_page(pos, &script.pages[i]); + if (error != CL_OK) + return error; } + script.status = CL_SCRIPT_STATUS_ACTIVE; + + return CL_OK; } static unsigned cl_process_if_statements(cl_page_t *page, unsigned pos) { unsigned current_indent = page->actions[pos].indentation; - bool evaluation = true; + cl_bool evaluation = CL_TRUE; unsigned i = pos; if (!page || !page->actions || @@ -145,14 +154,15 @@ static unsigned cl_process_if_statements(cl_page_t *page, unsigned pos) return i; } -static bool cl_process_actions(cl_page_t *page) +static cl_error cl_process_actions(cl_page_t *page) { - bool success = true; + cl_error error = CL_OK; unsigned i = 0; if (!page || !page->actions || page->action_count == 0) - return false; - else while (i < page->action_count) + return CL_ERR_PARAMETER_NULL; + + while (i < page->action_count) { script.current_action = &page->actions[i]; @@ -162,35 +172,36 @@ static bool cl_process_actions(cl_page_t *page) i = cl_process_if_statements(page, i); else { - /* TODO: Error handling if a direct command returns false? */ - success &= cl_process_action(&page->actions[i]); + if (cl_process_action(&page->actions[i]) != CL_OK) + error = CL_ERR_CLIENT_RUNTIME; i++; } } - return success; + return error; } -bool cl_script_update(void) +cl_error cl_script_update(void) { - if (script.status != CL_SCRIPT_STATUS_ACTIVE) - return false; - else - { - bool success = true; - unsigned i; + cl_error error = CL_OK; + cl_error page_error; + unsigned i; - for (i = 0; i < script.page_count; i++) - { - script.current_page = &script.pages[i]; - success &= cl_process_actions(script.current_page); - } + if (script.status != CL_SCRIPT_STATUS_ACTIVE) + return CL_ERR_CLIENT_RUNTIME; - return success; + for (i = 0; i < script.page_count; i++) + { + script.current_page = &script.pages[i]; + page_error = cl_process_actions(script.current_page); + if (page_error != CL_OK) + error = page_error; } + + return error; } -void cl_script_break(bool fatal, const char *format, ...) +void cl_script_break(cl_bool fatal, const char *format, ...) { va_list args; diff --git a/cl_script.h b/cl_script.h index f54bff0..ce70419 100644 --- a/cl_script.h +++ b/cl_script.h @@ -39,13 +39,13 @@ typedef struct cl_script_t /* Which page in a script is currently being processed. */ cl_page_t *current_page; - bool evaluation; + cl_bool evaluation; /* The status of the script. For example, CL_SCRIPT_STATUS_ACTIVE. */ cl_script_status status; /* Whether or not the last script break was triggered by a fatal error. */ - bool error_fatal; + cl_bool error_fatal; /* A message describing the cause of the last script break. */ char error_msg[256]; @@ -59,24 +59,24 @@ void cl_script_free(void); /** * Initializes a script from a string representation of one. * @param pos A string iterator positioned at the start of script data. - * @return Whether or not the script was properly read and initialized. + * @return CL_OK on success, or an error code on failure. **/ -bool cl_script_init(const char **pos); +cl_error cl_script_init(const char **pos); /** * Processes all of the actions in a script. Call once per frame, after * cl_memory_update. - * @return Whether or not all actions processed correctly. + * @return CL_OK on success, or an error code on failure. **/ -bool cl_script_update(void); +cl_error cl_script_update(void); /** - * Signals to halt processing of the script and core. Used when debugging + * Signals to halt processing of the script and core. Used when debugging * scripts. * @param fatal Whether or not the break reason included a fatal error. * @param format A format string with arguments, to set a reason for breaking. **/ -void cl_script_break(bool fatal, const char *format, ...); +void cl_script_break(cl_bool fatal, const char *format, ...); extern cl_script_t script; diff --git a/cl_search.c b/cl_search.c index 9355b2b..98e8793 100644 --- a/cl_search.c +++ b/cl_search.c @@ -7,26 +7,26 @@ #include #include -bool compare_to_nothing(uint32_t previous, uint32_t current, uint8_t type) +static cl_error compare_to_nothing(uint32_t previous, uint32_t current, uint8_t type) { switch (type) { case CL_COMPARE_EQUAL: - return previous == current; + return (previous == current) ? CL_OK : CL_ERR_CLIENT_RUNTIME; case CL_COMPARE_LESS: case CL_COMPARE_DECREASED: - return previous > current; + return (previous > current) ? CL_OK : CL_ERR_CLIENT_RUNTIME; case CL_COMPARE_GREATER: case CL_COMPARE_INCREASED: - return previous < current; + return (previous < current) ? CL_OK : CL_ERR_CLIENT_RUNTIME; case CL_COMPARE_NOT_EQUAL: - return previous != current; + return (previous != current) ? CL_OK : CL_ERR_CLIENT_RUNTIME; } - return false; + return CL_ERR_PARAMETER_INVALID; } -bool compare_to_nothing_float(uint32_t previous, uint32_t current, uint8_t type) +static cl_error compare_to_nothing_float(uint32_t previous, uint32_t current, uint8_t type) { float fprevious, fcurrent; @@ -37,46 +37,46 @@ bool compare_to_nothing_float(uint32_t previous, uint32_t current, uint8_t type) switch (type) { case CL_COMPARE_EQUAL: - return (uint32_t)fprevious == (uint32_t)fcurrent; + return ((uint32_t)fprevious == (uint32_t)fcurrent) ? CL_OK : CL_ERR_CLIENT_RUNTIME; case CL_COMPARE_LESS: case CL_COMPARE_DECREASED: - return (uint32_t)fprevious > (uint32_t)fcurrent; + return ((uint32_t)fprevious > (uint32_t)fcurrent) ? CL_OK : CL_ERR_CLIENT_RUNTIME; case CL_COMPARE_GREATER: case CL_COMPARE_INCREASED: - return (uint32_t)fprevious < (uint32_t)fcurrent; + return ((uint32_t)fprevious < (uint32_t)fcurrent) ? CL_OK : CL_ERR_CLIENT_RUNTIME; case CL_COMPARE_NOT_EQUAL: - return (uint32_t)fprevious != (uint32_t)fcurrent; + return ((uint32_t)fprevious != (uint32_t)fcurrent) ? CL_OK : CL_ERR_CLIENT_RUNTIME; } - return false; + return CL_ERR_PARAMETER_INVALID; } -bool compare_to_value(uint32_t previous, uint32_t current, uint8_t type, uint32_t value) +static cl_error compare_to_value(uint32_t previous, uint32_t current, uint8_t type, uint32_t value) { switch (type) { case CL_COMPARE_EQUAL: - return current == value; + return (current == value) ? CL_OK : CL_ERR_CLIENT_RUNTIME; case CL_COMPARE_GREATER: - return current > value; + return (current > value) ? CL_OK : CL_ERR_CLIENT_RUNTIME; case CL_COMPARE_LESS: - return current < value; + return (current < value) ? CL_OK : CL_ERR_CLIENT_RUNTIME; case CL_COMPARE_NOT_EQUAL: - return current != value; + return (current != value) ? CL_OK : CL_ERR_CLIENT_RUNTIME; case CL_COMPARE_INCREASED: - return current == previous + value; + return (current == previous + value) ? CL_OK : CL_ERR_CLIENT_RUNTIME; case CL_COMPARE_DECREASED: - return current + value == previous; + return (current + value == previous) ? CL_OK : CL_ERR_CLIENT_RUNTIME; } - return false; + return CL_ERR_PARAMETER_INVALID; } -bool compare_to_value_float(uint32_t previous, uint32_t current, uint8_t type, +static cl_error compare_to_value_float(uint32_t previous, uint32_t current, uint8_t type, float value) { float fprevious, fcurrent; - bool has_decimal_precision; + cl_bool has_decimal_precision; /* Cast to float */ memcpy(&fprevious, &previous, sizeof(float)); @@ -84,7 +84,7 @@ bool compare_to_value_float(uint32_t previous, uint32_t current, uint8_t type, /* This float is NaN */ if (isnan(fcurrent)) - return false; + return CL_ERR_PARAMETER_INVALID; /* Only check decimal precision on equal ops if the user has specified */ has_decimal_precision = floor(value) != value; @@ -93,31 +93,31 @@ bool compare_to_value_float(uint32_t previous, uint32_t current, uint8_t type, { case CL_COMPARE_EQUAL: if (has_decimal_precision) - return fcurrent == value; + return (fcurrent == value) ? CL_OK : CL_ERR_CLIENT_RUNTIME; else - return floor(fcurrent) == value; + return (floor(fcurrent) == value) ? CL_OK : CL_ERR_CLIENT_RUNTIME; case CL_COMPARE_GREATER: - return fcurrent > value; + return (fcurrent > value) ? CL_OK : CL_ERR_CLIENT_RUNTIME; case CL_COMPARE_LESS: - return fcurrent < value; + return (fcurrent < value) ? CL_OK : CL_ERR_CLIENT_RUNTIME; case CL_COMPARE_NOT_EQUAL: - return fcurrent != value; + return (fcurrent != value) ? CL_OK : CL_ERR_CLIENT_RUNTIME; case CL_COMPARE_INCREASED: if (has_decimal_precision) - return fcurrent == fprevious + value; + return (fcurrent == fprevious + value) ? CL_OK : CL_ERR_CLIENT_RUNTIME; else - return floor(fcurrent) == floor(fprevious) + value; + return (floor(fcurrent) == floor(fprevious) + value) ? CL_OK : CL_ERR_CLIENT_RUNTIME; case CL_COMPARE_DECREASED: if (has_decimal_precision) - return fcurrent + value == fprevious; + return (fcurrent + value == fprevious) ? CL_OK : CL_ERR_CLIENT_RUNTIME; else - return floor(fcurrent) + value == floor(fprevious); + return (floor(fcurrent) + value == floor(fprevious)) ? CL_OK : CL_ERR_CLIENT_RUNTIME; } - return false; + return CL_ERR_PARAMETER_INVALID; } -bool resolve_pointerresult(cl_addr_t *final_address, const cl_pointerresult_t *result, +static cl_error resolve_pointerresult(cl_addr_t *final_address, const cl_pointerresult_t *result, const uint8_t passes) { cl_addr_t address = result->address_initial; @@ -126,32 +126,34 @@ bool resolve_pointerresult(cl_addr_t *final_address, const cl_pointerresult_t *r for (i = 0; i < passes; i++) { const cl_memory_region_t *region = cl_find_memory_region(address); - cl_value_type ptr_type = cl_pointer_type(region->pointer_length); + cl_value_type ptr_type; if (!region) - return false; - else if (!cl_read_memory_value(&address, NULL, address, ptr_type)) - return false; - else - address += result->offsets[i]; + return CL_ERR_PARAMETER_NULL; + + ptr_type = cl_pointer_type(region->pointer_length); + if (cl_read_memory_value(&address, NULL, address, ptr_type) != CL_OK) + return CL_ERR_CLIENT_RUNTIME; + + address += result->offsets[i]; } *final_address = address; - return true; + return CL_OK; } -bool cl_pointersearch_free(cl_pointersearch_t *search) +cl_error cl_pointersearch_free(cl_pointersearch_t *search) { if (!search) - return false; + return CL_ERR_PARAMETER_NULL; else { free(search->results); - return true; + return CL_OK; } } -bool add_pass(cl_pointersearch_t* search, uint32_t range, uint32_t max_results) +static cl_error add_pass(cl_pointersearch_t* search, uint32_t range, uint32_t max_results) { cl_memory_region_t *region; cl_pointerresult_t *result; @@ -208,28 +210,27 @@ bool add_pass(cl_pointersearch_t* search, uint32_t range, uint32_t max_results) search->results = new_results; search->result_count = matches; - return true; + return CL_OK; } -bool cl_pointersearch_init(cl_pointersearch_t *search, +cl_error cl_pointersearch_init(cl_pointersearch_t *search, cl_addr_t address, uint8_t val_type, uint8_t passes, uint32_t range, uint32_t max_results) { + cl_memory_region_t *region; + cl_pointerresult_t *result; + uint32_t matches, prev_value, value; + uint32_t i, j; + if (!search || address == 0 || passes == 0) - return false; - else - { - cl_memory_region_t *region; - cl_pointerresult_t *result; - uint32_t matches, prev_value, value; - uint32_t i, j; + return CL_ERR_PARAMETER_INVALID; - /* Is the address we're looking for valid? */ - if (!cl_read_memory_value(&prev_value, NULL, address, val_type)) - { - cl_log("Address %08X is invalid for a pointer search.\n", address); - return false; - } + /* Is the address we're looking for valid? */ + if (cl_read_memory_value(&prev_value, NULL, address, val_type) != CL_OK) + { + cl_log("Address %08X is invalid for a pointer search.\n", address); + return CL_ERR_PARAMETER_INVALID; + } /* Initialize search parameters */ search->passes = 1; @@ -278,7 +279,7 @@ bool cl_pointersearch_init(cl_pointersearch_t *search, search->result_count = max_results; cl_log("Pointer search for %08X reached maximum result count of %u.\n", address, max_results); - return true; + return CL_OK; } } } @@ -299,86 +300,82 @@ bool cl_pointersearch_init(cl_pointersearch_t *search, cl_log("Pointer search for %08X found %u results.\n", address, matches); - return true; - } + return CL_OK; } uint32_t cl_pointersearch_step(cl_pointersearch_t *search, void *value) { + cl_pointerresult_t *result; + cl_addr_t address; + uint32_t matches, final_value, valid_pointers; + cl_error compare_result; + uint8_t cmp_type; + uint32_t i; + if (!search) - return false; - else + return 0; + + cmp_type = search->params.compare_type; + matches = 0; + valid_pointers = 0; + cl_log("Result count at start: %u\n", search->result_count); + for (i = 0; i < search->result_count; i++) { - cl_pointerresult_t *result; - cl_addr_t address; - uint32_t matches, final_value, valid_pointers; - bool compare_result; - uint8_t cmp_type = search->params.compare_type; - uint32_t i; + result = &search->results[i]; - matches = 0; - valid_pointers = 0; - cl_log("Result count at start: %u\n", search->result_count); - for (i = 0; i < search->result_count; i++) + if (resolve_pointerresult(&address, result, search->passes) != CL_OK) + continue; + else if (cl_read_memory_value(&final_value, NULL, address, search->params.value_type) != CL_OK) + continue; + else { - result = &search->results[i]; + result->value_current = final_value; - if (!resolve_pointerresult(&address, result, search->passes)) - continue; - else if (!cl_read_memory_value(&final_value, NULL, address, search->params.value_type)) - continue; + if (!value) + { + compare_result = search->params.value_type == CL_MEMTYPE_FLOAT ? + compare_to_nothing_float(result->value_previous, result->value_current, cmp_type) : + compare_to_nothing(result->value_previous, result->value_current, cmp_type); + } else { - result->value_current = final_value; - - if (!value) - { - compare_result = search->params.value_type == CL_MEMTYPE_FLOAT ? - compare_to_nothing_float(result->value_previous, result->value_current, cmp_type) : - compare_to_nothing(result->value_previous, result->value_current, cmp_type); - } - else - { - compare_result = search->params.value_type == CL_MEMTYPE_FLOAT ? - compare_to_value_float(result->value_previous, result->value_current, cmp_type, *((float*)value)) : - compare_to_value(result->value_previous, result->value_current, cmp_type, *((uint32_t*)value)); - } + compare_result = search->params.value_type == CL_MEMTYPE_FLOAT ? + compare_to_value_float(result->value_previous, result->value_current, cmp_type, *((float*)value)) : + compare_to_value(result->value_previous, result->value_current, cmp_type, *((uint32_t*)value)); + } - if (compare_result) - { - memcpy(&search->results[matches], result, sizeof(cl_pointerresult_t)); - matches++; - } - result->value_previous = result->value_current; - valid_pointers++; + if (compare_result == CL_OK) + { + memcpy(&search->results[matches], result, sizeof(cl_pointerresult_t)); + matches++; } + result->value_previous = result->value_current; + valid_pointers++; } - /* All of the still valid results are grouped together, the rest of memory can be cleared */ - search->result_count = matches; - search->results = (cl_pointerresult_t*)realloc(search->results, matches * sizeof(cl_pointerresult_t)); - cl_log("Pointer search now has %u matches across %u valid pointers.\n", matches, valid_pointers); - - return matches; } + /* All of the still valid results are grouped together, the rest of memory can be cleared */ + search->result_count = matches; + search->results = (cl_pointerresult_t*)realloc(search->results, matches * sizeof(cl_pointerresult_t)); + cl_log("Pointer search now has %u matches across %u valid pointers.\n", matches, valid_pointers); + + return matches; } void cl_pointersearch_update(cl_pointersearch_t *search) { + cl_pointerresult_t *result; + uint32_t i; + if (!search) return; - else - { - cl_pointerresult_t *result; - uint32_t i; - for (i = 0; i < search->result_count; i++) - { - result = &search->results[i]; + for (i = 0; i < search->result_count; i++) + { + result = &search->results[i]; - if (!resolve_pointerresult(&result->address_final, result, search->passes)) - continue; - else - cl_read_memory_value(&result->value_current, NULL, result->address_final, search->params.value_type); - } + if (resolve_pointerresult(&result->address_final, result, search->passes) != CL_OK) + continue; + else + cl_read_memory_value(&result->value_current, NULL, result->address_final, search->params.value_type); } } diff --git a/cl_search.h b/cl_search.h index a13b452..977cb78 100644 --- a/cl_search.h +++ b/cl_search.h @@ -29,9 +29,9 @@ typedef struct cl_pointersearch_t uint32_t result_count; } cl_pointersearch_t; -bool cl_pointersearch_free(cl_pointersearch_t *search); +cl_error cl_pointersearch_free(cl_pointersearch_t *search); -bool cl_pointersearch_init(cl_pointersearch_t *search, cl_addr_t address, +cl_error cl_pointersearch_init(cl_pointersearch_t *search, cl_addr_t address, uint8_t size, uint8_t passes, uint32_t range, uint32_t max_results); uint32_t cl_pointersearch_step(cl_pointersearch_t *search, void *value); diff --git a/cl_types.h b/cl_types.h index b4df967..d2dba38 100644 --- a/cl_types.h +++ b/cl_types.h @@ -3,13 +3,17 @@ #include "cl_config.h" -#include #include #include #include #define CL_SESSION_ID_LENGTH 32 +typedef unsigned char cl_bool; + +#define CL_TRUE 1 +#define CL_FALSE 0 + typedef enum { CL_OK = 0, @@ -83,7 +87,7 @@ typedef enum */ #define CL_INTEGRATION_VERSION 1 -#define CL_LOGGING true +#define CL_LOGGING CL_TRUE /** * How often, in seconds, to ping back to the server to update current status. @@ -95,14 +99,14 @@ typedef enum */ #define CL_RADIX 10 -#define CL_SHOW_ERRORS true +#define CL_SHOW_ERRORS CL_TRUE /** * Format string to print the contents of a buffer representing an MD5 hash. */ #define CL_SNPRINTF_MD5 "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" -#define CL_TASK_MUTE true +#define CL_TASK_MUTE CL_TRUE /** * Used for unit tests to print a descriptive failure message. @@ -173,7 +177,7 @@ typedef struct char icon_url[64]; unsigned flags; unsigned id; - bool unlocked; + cl_bool unlocked; } cl_achievement_t; typedef struct @@ -526,7 +530,7 @@ typedef struct cl_memnote_t #if CL_HAVE_EDITOR /* Metadata for generated human-readable strings in Live Editor */ cl_memnote_ex_t details; - bool edited; + cl_bool edited; #endif } cl_memnote_t; diff --git a/editor/cle_memory_note_submit.cpp b/editor/cle_memory_note_submit.cpp index f6ebb3d..9b880fc 100644 --- a/editor/cle_memory_note_submit.cpp +++ b/editor/cle_memory_note_submit.cpp @@ -15,7 +15,7 @@ static CL_NETWORK_CB(cle_memory_note_add_cb) unsigned memory_note_id; if (cl_json_get(&memory_note_id, response.data, CL_JSON_KEY_MEMORY_NOTE_ID, - CL_JSON_TYPE_NUMBER, sizeof(memory_note_id))) + CL_JSON_TYPE_NUMBER, sizeof(memory_note_id)) == CL_OK) { cl_memnote_t *note = (cl_memnote_t*)userdata; note->key = memory_note_id; diff --git a/editor/cle_result_table_pointer.cpp b/editor/cle_result_table_pointer.cpp index 7126aee..a776e22 100644 --- a/editor/cle_result_table_pointer.cpp +++ b/editor/cle_result_table_pointer.cpp @@ -40,7 +40,10 @@ CleResultTablePointer::CleResultTablePointer(QWidget *parent, uint32_t address, connect(this, SIGNAL(requestPointerSearch(cl_addr_t)), parent, SLOT(requestPointerSearch(cl_addr_t))); - cl_pointersearch_init(&m_Search, address, size, passes, range, max_results); + if (cl_pointersearch_init(&m_Search, address, size, passes, range, max_results) != CL_OK) + { + cl_log("Failed to initialize pointer search for address %08X\n", address); + } rebuild(); } From 1576bc4e3278cc9c7aa153291180df9d124095d1 Mon Sep 17 00:00:00 2001 From: celerizer Date: Wed, 11 Feb 2026 15:04:35 -0600 Subject: [PATCH 48/57] pointer search - use types from new search --- cl_search.c | 92 +++++++++++++------------ cl_search.h | 101 ++++++++++++++++++++++------ editor/cle_result_table_pointer.cpp | 26 +++---- editor/cle_result_table_pointer.h | 10 +-- 4 files changed, 148 insertions(+), 81 deletions(-) diff --git a/cl_search.c b/cl_search.c index 98e8793..5c43bef 100644 --- a/cl_search.c +++ b/cl_search.c @@ -7,7 +7,7 @@ #include #include -static cl_error compare_to_nothing(uint32_t previous, uint32_t current, uint8_t type) +static cl_error compare_to_nothing(cl_addr_t previous, cl_addr_t current, cl_compare_type type) { switch (type) { @@ -26,7 +26,7 @@ static cl_error compare_to_nothing(uint32_t previous, uint32_t current, uint8_t return CL_ERR_PARAMETER_INVALID; } -static cl_error compare_to_nothing_float(uint32_t previous, uint32_t current, uint8_t type) +static cl_error compare_to_nothing_float(cl_addr_t previous, cl_addr_t current, cl_compare_type type) { float fprevious, fcurrent; @@ -51,7 +51,7 @@ static cl_error compare_to_nothing_float(uint32_t previous, uint32_t current, ui return CL_ERR_PARAMETER_INVALID; } -static cl_error compare_to_value(uint32_t previous, uint32_t current, uint8_t type, uint32_t value) +static cl_error compare_to_value(cl_addr_t previous, cl_addr_t current, cl_compare_type type, cl_addr_t value) { switch (type) { @@ -72,7 +72,7 @@ static cl_error compare_to_value(uint32_t previous, uint32_t current, uint8_t ty return CL_ERR_PARAMETER_INVALID; } -static cl_error compare_to_value_float(uint32_t previous, uint32_t current, uint8_t type, +static cl_error compare_to_value_float(cl_addr_t previous, cl_addr_t current, cl_compare_type type, float value) { float fprevious, fcurrent; @@ -117,8 +117,8 @@ static cl_error compare_to_value_float(uint32_t previous, uint32_t current, uint return CL_ERR_PARAMETER_INVALID; } -static cl_error resolve_pointerresult(cl_addr_t *final_address, const cl_pointerresult_t *result, - const uint8_t passes) +static cl_error resolve_pointerresult(cl_addr_t *final_address, const cl_pointersearch_result_t *result, + const unsigned passes) { cl_addr_t address = result->address_initial; unsigned i; @@ -153,21 +153,21 @@ cl_error cl_pointersearch_free(cl_pointersearch_t *search) } } -static cl_error add_pass(cl_pointersearch_t* search, uint32_t range, uint32_t max_results) +static cl_error add_pass(cl_pointersearch_t* search) { cl_memory_region_t *region; - cl_pointerresult_t *result; - uint32_t matches, target, value; - uint32_t i, j, k, l; + cl_pointersearch_result_t *result; + cl_addr_t matches, target, value; + unsigned i, j, k, l; - cl_pointerresult_t* new_results = (cl_pointerresult_t*)calloc( - max_results, sizeof(cl_pointerresult_t)); + cl_pointersearch_result_t* new_results = (cl_pointersearch_result_t*)calloc( + search->max_results, sizeof(cl_pointersearch_result_t)); matches = 0; search->passes += 1; for (i = 0; i < search->result_count; i++) { - cl_pointerresult_t *next_result = &search->results[i]; + cl_pointersearch_result_t *next_result = &search->results[i]; for (j = 0; j < memory.region_count; j++) { @@ -182,7 +182,7 @@ static cl_error add_pass(cl_pointersearch_t* search, uint32_t range, uint32_t ma cl_value_type ptr_type = cl_pointer_type(region->pointer_length); cl_read_memory_value_internal(&value, region, k, ptr_type); - if (value <= target && value >= target - range) + if (value <= target && value >= target - search->range) { result = &new_results[matches]; @@ -197,9 +197,9 @@ static cl_error add_pass(cl_pointersearch_t* search, uint32_t range, uint32_t ma } /* Back out if we have too many results */ - if (matches == max_results) + if (matches == search->max_results) { - cl_log("Search reached maximum count of %u.\n", max_results); + cl_log("Search reached maximum count of %llu.\n", (unsigned long long)search->max_results); goto end; } } @@ -214,34 +214,35 @@ static cl_error add_pass(cl_pointersearch_t* search, uint32_t range, uint32_t ma } cl_error cl_pointersearch_init(cl_pointersearch_t *search, - cl_addr_t address, uint8_t val_type, uint8_t passes, uint32_t range, - uint32_t max_results) + cl_addr_t address, cl_value_type value_type, unsigned passes, cl_addr_t range, + cl_addr_t max_results) { cl_memory_region_t *region; - cl_pointerresult_t *result; - uint32_t matches, prev_value, value; - uint32_t i, j; + cl_pointersearch_result_t *result; + cl_addr_t matches, prev_value, value; + unsigned i, j; if (!search || address == 0 || passes == 0) return CL_ERR_PARAMETER_INVALID; /* Is the address we're looking for valid? */ - if (cl_read_memory_value(&prev_value, NULL, address, val_type) != CL_OK) + if (cl_read_memory_value(&prev_value, NULL, address, value_type) != CL_OK) { - cl_log("Address %08X is invalid for a pointer search.\n", address); + cl_log("Address %016llX is invalid for a pointer search.\n", (unsigned long long)address); return CL_ERR_PARAMETER_INVALID; } /* Initialize search parameters */ search->passes = 1; search->range = range; + search->max_results = max_results; search->params.compare_type = CL_COMPARE_EQUAL; - search->params.size = cl_sizeof_memtype(val_type); - search->params.value_type = val_type; + search->params.value_size = cl_sizeof_memtype(value_type); + search->params.value_type = value_type; /* We create a temporary array of max size and trim it down after */ - search->results = (cl_pointerresult_t*)calloc( - max_results, sizeof(cl_pointerresult_t)); + search->results = (cl_pointersearch_result_t*)calloc( + max_results, sizeof(cl_pointersearch_result_t)); matches = 0; /* Do a quick scan to see how many results we start with */ @@ -277,7 +278,8 @@ cl_error cl_pointersearch_init(cl_pointersearch_t *search, if (matches == max_results) { search->result_count = max_results; - cl_log("Pointer search for %08X reached maximum result count of %u.\n", address, max_results); + cl_log("Pointer search for %016llX reached maximum result count of %llu.\n", + (unsigned long long)address, (unsigned long long)max_results); return CL_OK; } @@ -287,30 +289,31 @@ cl_error cl_pointersearch_init(cl_pointersearch_t *search, /* We've only done one pass so far. Run any extra passes */ for (i = passes; i > 1; i--) - add_pass(search, range, max_results); + add_pass(search); /* Clear the unneeded memory */ search->result_count = matches; - search->results = (cl_pointerresult_t*)realloc( - search->results, matches * sizeof(cl_pointerresult_t)); + search->results = (cl_pointersearch_result_t*)realloc( + search->results, matches * sizeof(cl_pointersearch_result_t)); #if CL_EXTERNAL_MEMORY free(region->base_host); region->base_host = NULL; #endif - cl_log("Pointer search for %08X found %u results.\n", address, matches); + cl_log("Pointer search for %016llX found %llu results.\n", + (unsigned long long)address, (unsigned long long)matches); return CL_OK; } -uint32_t cl_pointersearch_step(cl_pointersearch_t *search, void *value) +cl_addr_t cl_pointersearch_step(cl_pointersearch_t *search, const void *value) { - cl_pointerresult_t *result; + cl_pointersearch_result_t *result; cl_addr_t address; - uint32_t matches, final_value, valid_pointers; + cl_addr_t matches, final_value, valid_pointers; cl_error compare_result; - uint8_t cmp_type; - uint32_t i; + cl_compare_type cmp_type; + unsigned i; if (!search) return 0; @@ -318,7 +321,7 @@ uint32_t cl_pointersearch_step(cl_pointersearch_t *search, void *value) cmp_type = search->params.compare_type; matches = 0; valid_pointers = 0; - cl_log("Result count at start: %u\n", search->result_count); + cl_log("Result count at start: %llu\n", (unsigned long long)search->result_count); for (i = 0; i < search->result_count; i++) { result = &search->results[i]; @@ -341,12 +344,12 @@ uint32_t cl_pointersearch_step(cl_pointersearch_t *search, void *value) { compare_result = search->params.value_type == CL_MEMTYPE_FLOAT ? compare_to_value_float(result->value_previous, result->value_current, cmp_type, *((float*)value)) : - compare_to_value(result->value_previous, result->value_current, cmp_type, *((uint32_t*)value)); + compare_to_value(result->value_previous, result->value_current, cmp_type, *((cl_addr_t*)value)); } if (compare_result == CL_OK) { - memcpy(&search->results[matches], result, sizeof(cl_pointerresult_t)); + memcpy(&search->results[matches], result, sizeof(cl_pointersearch_result_t)); matches++; } result->value_previous = result->value_current; @@ -355,16 +358,17 @@ uint32_t cl_pointersearch_step(cl_pointersearch_t *search, void *value) } /* All of the still valid results are grouped together, the rest of memory can be cleared */ search->result_count = matches; - search->results = (cl_pointerresult_t*)realloc(search->results, matches * sizeof(cl_pointerresult_t)); - cl_log("Pointer search now has %u matches across %u valid pointers.\n", matches, valid_pointers); + search->results = (cl_pointersearch_result_t*)realloc(search->results, matches * sizeof(cl_pointersearch_result_t)); + cl_log("Pointer search now has %llu matches across %llu valid pointers.\n", + (unsigned long long)matches, (unsigned long long)valid_pointers); return matches; } void cl_pointersearch_update(cl_pointersearch_t *search) { - cl_pointerresult_t *result; - uint32_t i; + cl_pointersearch_result_t *result; + unsigned i; if (!search) return; diff --git a/cl_search.h b/cl_search.h index 977cb78..10b360d 100644 --- a/cl_search.h +++ b/cl_search.h @@ -4,41 +4,102 @@ #include "cl_memory.h" #include "cl_types.h" -typedef struct cl_search_params_t +/** + * Parameters used for pointer searches + */ +typedef struct { - cl_compare_type compare_type; - unsigned size; + /* The type of value being searched for */ cl_value_type value_type; -} cl_search_params_t; -typedef struct cl_pointerresult_t + /* The size, in bytes, of the value type */ + unsigned value_size; + + /* The comparison method to use */ + cl_compare_type compare_type; +} cl_pointersearch_parameters_t; + +/** + * A single pointer search result containing the pointer chain and values. + */ +typedef struct { + /* The initial address where the pointer chain starts */ cl_addr_t address_initial; + + /* The final address after following all pointers */ cl_addr_t address_final; - uint32_t value_current; - uint32_t value_previous; - uint32_t offsets[CL_POINTER_MAX_PASSES]; -} cl_pointerresult_t; -typedef struct cl_pointersearch_t + /* The current value at the final address */ + cl_addr_t value_current; + + /* The previous value at the final address */ + cl_addr_t value_previous; + + /* The offsets applied at each pointer level */ + cl_addr_t offsets[CL_POINTER_MAX_PASSES]; +} cl_pointersearch_result_t; + +/** + * The main pointer search structure. + * Searches for pointer chains that lead to a target address. + */ +typedef struct { - cl_search_params_t params; - uint8_t passes; - uint32_t range; - cl_pointerresult_t *results; - uint32_t result_count; + /* Search parameters */ + cl_pointersearch_parameters_t params; + + /* Number of pointer dereferences in the chain */ + unsigned passes; + + /* Maximum offset range to search for at each level */ + cl_addr_t range; + + /* Array of found pointer chains */ + cl_pointersearch_result_t *results; + + /* Number of results found */ + cl_addr_t result_count; + + /* Maximum number of results to store */ + cl_addr_t max_results; } cl_pointersearch_t; +/** + * Frees memory allocated for a pointer search. + * @param search A pointer to the pointer search to free + * @return CL_OK on success, or an error code on failure + */ cl_error cl_pointersearch_free(cl_pointersearch_t *search); +/** + * Initializes a pointer search to find chains leading to a target address. + * @param search A pointer to the search structure to initialize + * @param address The target address to find pointers to + * @param value_type The type of value at the target address + * @param passes The number of pointer dereferences to search through + * @param range The maximum offset range for each pointer level + * @param max_results The maximum number of results to store + * @return CL_OK on success, or an error code on failure + */ cl_error cl_pointersearch_init(cl_pointersearch_t *search, cl_addr_t address, - uint8_t size, uint8_t passes, uint32_t range, uint32_t max_results); + cl_value_type value_type, unsigned passes, cl_addr_t range, + cl_addr_t max_results); -uint32_t cl_pointersearch_step(cl_pointersearch_t *search, void *value); +/** + * Filters pointer search results based on value comparisons. + * @param search A pointer to the pointer search + * @param value A pointer to the value to compare against, or NULL to compare + * against previous values + * @return The number of matching results + */ +cl_addr_t cl_pointersearch_step(cl_pointersearch_t *search, const void *value); -/* - Updates the "value_current" variable in every result in a pointersearch. -*/ +/** + * Updates the current values for all pointer search results. + * Resolves each pointer chain and reads the current value. + * @param search A pointer to the pointer search to update + */ void cl_pointersearch_update(cl_pointersearch_t *search); #endif diff --git a/editor/cle_result_table_pointer.cpp b/editor/cle_result_table_pointer.cpp index a776e22..9b5cfea 100644 --- a/editor/cle_result_table_pointer.cpp +++ b/editor/cle_result_table_pointer.cpp @@ -6,11 +6,11 @@ /** @todo everything here was dummied in anticipation of a pointersearch redo */ -CleResultTablePointer::CleResultTablePointer(QWidget *parent, uint32_t address, - uint8_t size, uint8_t passes, uint32_t range, uint32_t max_results) +CleResultTablePointer::CleResultTablePointer(QWidget *parent, cl_addr_t address, + cl_value_type value_type, unsigned passes, cl_addr_t range, cl_addr_t max_results) { char offset_str[16]; - uint8_t i; + unsigned i; CleResultTable::init(); @@ -40,9 +40,9 @@ CleResultTablePointer::CleResultTablePointer(QWidget *parent, uint32_t address, connect(this, SIGNAL(requestPointerSearch(cl_addr_t)), parent, SLOT(requestPointerSearch(cl_addr_t))); - if (cl_pointersearch_init(&m_Search, address, size, passes, range, max_results) != CL_OK) + if (cl_pointersearch_init(&m_Search, address, value_type, passes, range, max_results) != CL_OK) { - cl_log("Failed to initialize pointer search for address %08X\n", address); + cl_log("Failed to initialize pointer search for address %016llX\n", (unsigned long long)address); } rebuild(); } @@ -114,7 +114,7 @@ void CleResultTablePointer::onResultDoubleClick() { if (m_Table->currentColumn() == m_ColValueCurr) { - uint32_t i; + unsigned i; /* We gray out the other entries because they won't update while we're editing. */ @@ -144,8 +144,9 @@ cl_error CleResultTablePointer::rebuild(void) return CL_OK; #if 0 char temp_string[32]; - uint8_t size; - uint32_t current_row, temp_value, i, j; + unsigned size; + unsigned current_row, i, j; + cl_addr_t temp_value; size = m_Search.params.value_type; m_Table->setColumnCount(3 + m_Search.passes); @@ -155,12 +156,12 @@ cl_error CleResultTablePointer::rebuild(void) { m_Table->insertRow(i); - snprintf(temp_string, 256, "%08X", m_Search.results[i].address_initial); + snprintf(temp_string, 256, "%016llX", (unsigned long long)m_Search.results[i].address_initial); m_Table->setItem(i, m_ColAddress, new QTableWidgetItem(QString(temp_string))); for (j = 0; j < m_Search.passes; j++) { - snprintf(temp_string, 256, "%02X", m_Search.results[i].offsets[j]); + snprintf(temp_string, 256, "%llX", (unsigned long long)m_Search.results[i].offsets[j]); m_Table->setItem(i, j + 1, new QTableWidgetItem(QString(temp_string))); } @@ -183,8 +184,9 @@ cl_error CleResultTablePointer::run(void) #if 0 QTableWidgetItem *item; char temp_string[32]; - uint8_t val_type; - uint32_t address, value_curr, value_prev, i; + cl_value_type val_type; + cl_addr_t address, value_curr, value_prev; + unsigned i; val_type = m_Search.params.value_type; diff --git a/editor/cle_result_table_pointer.h b/editor/cle_result_table_pointer.h index 06ffa58..60b19ce 100644 --- a/editor/cle_result_table_pointer.h +++ b/editor/cle_result_table_pointer.h @@ -13,8 +13,8 @@ class CleResultTablePointer : public CleResultTable Q_OBJECT public: - CleResultTablePointer(QWidget *parent, uint32_t address, uint8_t size, - uint8_t passes, uint32_t range, uint32_t max_results); + CleResultTablePointer(QWidget *parent, cl_addr_t address, cl_value_type value_type, + unsigned passes, cl_addr_t range, cl_addr_t max_results); ~CleResultTablePointer() override; cl_addr_t getClickedResultAddress() override; @@ -47,9 +47,9 @@ public slots: void requestRemove(uint32_t index); private: - uint8_t m_ColAddress; - uint8_t m_ColValuePrev; - uint8_t m_ColValueCurr; + unsigned m_ColAddress; + unsigned m_ColValuePrev; + unsigned m_ColValueCurr; cl_pointersearch_t m_Search; }; From fc1c1fe7520c2d61f02097e6198691eccf8f9f78 Mon Sep 17 00:00:00 2001 From: celerizer Date: Wed, 11 Feb 2026 15:04:56 -0600 Subject: [PATCH 49/57] only include os mman if using external mem --- cl_search_new.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/cl_search_new.c b/cl_search_new.c index 0fc3ba5..d1aece7 100644 --- a/cl_search_new.c +++ b/cl_search_new.c @@ -4,12 +4,6 @@ #include "cl_config.h" #include "cl_memory.h" -#if CL_HOST_PLATFORM == _CL_PLATFORM_LINUX - #include -#elif CL_HOST_PLATFORM == _CL_PLATFORM_WINDOWS - #include -#endif - #include #include @@ -30,6 +24,12 @@ typedef union #if CL_EXTERNAL_MEMORY +#if CL_HOST_PLATFORM == _CL_PLATFORM_LINUX + #include +#elif CL_HOST_PLATFORM == _CL_PLATFORM_WINDOWS + #include +#endif + /** * Allocate a chunk of page-aligned memory. * @param size The number of bytes to allocate @@ -734,7 +734,6 @@ static cl_search_compare_func_t cl_search_comparison_function( return NULL; } - /** * Runs a comparison function on the values in a search page. * @param page From da95e83eb9091d8f1e04b1f74a8ba159e19c365f Mon Sep 17 00:00:00 2001 From: celerizer Date: Wed, 11 Feb 2026 15:19:31 -0600 Subject: [PATCH 50/57] remove stdint from global namespace --- cl_action.c | 4 ++-- cl_counter.c | 17 +++++++++-------- cl_counter.h | 2 +- cl_memory.c | 11 ++++++----- cl_memory.h | 25 +++++++++++++++++-------- cl_script.h | 4 ++-- cl_types.h | 23 +++++++++++++++-------- 7 files changed, 52 insertions(+), 34 deletions(-) diff --git a/cl_action.c b/cl_action.c index 3199379..d6a5233 100644 --- a/cl_action.c +++ b/cl_action.c @@ -71,7 +71,7 @@ static cl_error cl_print_counter_values(char *buffer, unsigned len) * a memory note or counter index, or a memory address. * @return A mutable counter, or return CL_CTR_INVALID if unavailable. **/ -static cl_counter_t cl_get_compare_value(cl_src_t source, int64_t offset) +static cl_counter_t cl_get_compare_value(cl_src_t source, cl_int64 offset) { cl_counter_t counter; @@ -123,7 +123,7 @@ static cl_counter_t cl_get_compare_value(cl_src_t source, int64_t offset) * @param offset An address or index relevant to the source type. * @return A mutable counter, or NULL if unavailable. **/ -static cl_counter_t *cl_get_mutable_value(cl_src_t source, int64_t offset) +static cl_counter_t *cl_get_mutable_value(cl_src_t source, cl_int64 offset) { switch (source) { diff --git a/cl_counter.c b/cl_counter.c index eb85455..8284c48 100644 --- a/cl_counter.c +++ b/cl_counter.c @@ -3,6 +3,7 @@ #include "cl_memory.h" #include +#include #include #define CL_CTR_EPSILON 0.005 @@ -44,7 +45,7 @@ cl_error cl_ctr_store(cl_counter_t *counter, const void *src, cl_value_type type } /** @todo Make sure the commented lines still work */ -cl_error cl_ctr_store_int(cl_counter_t *counter, int64_t value) +cl_error cl_ctr_store_int(cl_counter_t *counter, cl_int64 value) { counter->intval.i64 = value; counter->floatval.fp = (double)value; @@ -55,7 +56,7 @@ cl_error cl_ctr_store_int(cl_counter_t *counter, int64_t value) cl_error cl_ctr_store_float(cl_counter_t *counter, double value) { - counter->intval.i64 = (int64_t)value; + counter->intval.i64 = (cl_int64)value; counter->floatval.fp = value; counter->type = CL_MEMTYPE_DOUBLE; @@ -111,7 +112,7 @@ cl_bool cl_ctr_greater_or_equal(const cl_counter_t *left, const cl_counter_t *ri cl_error cl_ctr_and(cl_counter_t *counter, const cl_counter_t *value) { - uint64_t temp_src; + cl_uint64 temp_src; if (cl_ctr_is_float(value)) temp_src = value->floatval.raw; @@ -120,7 +121,7 @@ cl_error cl_ctr_and(cl_counter_t *counter, const cl_counter_t *value) if (cl_ctr_is_float(counter)) { - uint64_t temp = counter->floatval.raw & temp_src; + cl_uint64 temp = counter->floatval.raw & temp_src; double temp_fp; memcpy(&temp_fp, &temp, sizeof(temp_fp)); @@ -133,7 +134,7 @@ cl_error cl_ctr_and(cl_counter_t *counter, const cl_counter_t *value) cl_error cl_ctr_or(cl_counter_t *counter, const cl_counter_t *value) { - uint64_t temp_src; + cl_uint64 temp_src; if (cl_ctr_is_float(value)) temp_src = value->floatval.raw; @@ -142,7 +143,7 @@ cl_error cl_ctr_or(cl_counter_t *counter, const cl_counter_t *value) if (cl_ctr_is_float(counter)) { - uint64_t temp = counter->floatval.raw | temp_src; + cl_uint64 temp = counter->floatval.raw | temp_src; double temp_fp; memcpy(&temp_fp, &temp, sizeof(temp_fp)); @@ -155,7 +156,7 @@ cl_error cl_ctr_or(cl_counter_t *counter, const cl_counter_t *value) cl_error cl_ctr_xor(cl_counter_t *counter, const cl_counter_t *value) { - uint64_t temp_src; + cl_uint64 temp_src; if (cl_ctr_is_float(value)) temp_src = value->floatval.raw; @@ -164,7 +165,7 @@ cl_error cl_ctr_xor(cl_counter_t *counter, const cl_counter_t *value) if (cl_ctr_is_float(counter)) { - uint64_t temp = counter->floatval.raw ^ temp_src; + cl_uint64 temp = counter->floatval.raw ^ temp_src; double temp_fp; memcpy(&temp_fp, &temp, sizeof(temp_fp)); diff --git a/cl_counter.h b/cl_counter.h index ec41107..21e354e 100644 --- a/cl_counter.h +++ b/cl_counter.h @@ -12,7 +12,7 @@ cl_error cl_ctr_store(cl_counter_t *counter, const void *src, cl_value_type type /** * Stores an integer value into a counter. Changes counter type to int. */ -cl_error cl_ctr_store_int(cl_counter_t *counter, int64_t value); +cl_error cl_ctr_store_int(cl_counter_t *counter, cl_int64 value); /** * Stores a floating point value into a counter. Changes counter type to float. diff --git a/cl_memory.c b/cl_memory.c index b5e8017..98b613a 100644 --- a/cl_memory.c +++ b/cl_memory.c @@ -74,7 +74,7 @@ void cl_memory_free(void) memory.regions = NULL; } -cl_error cl_get_memnote_flag(cl_memnote_t *note, uint8_t flag) +cl_error cl_get_memnote_flag(cl_memnote_t *note, cl_memnote_flag flag) { if (!note) return CL_ERR_PARAMETER_NULL; @@ -82,7 +82,7 @@ cl_error cl_get_memnote_flag(cl_memnote_t *note, uint8_t flag) return ((note->flags & (1 << flag)) != 0) ? CL_OK : CL_ERR_CLIENT_RUNTIME; } -cl_error cl_get_memnote_flag_from_key(unsigned key, uint8_t flag) +cl_error cl_get_memnote_flag_from_key(unsigned key, cl_memnote_flag flag) { cl_memnote_t *note = cl_find_memnote(key); @@ -92,7 +92,8 @@ cl_error cl_get_memnote_flag_from_key(unsigned key, uint8_t flag) return cl_get_memnote_flag(note, flag); } -cl_error cl_get_memnote_value(cl_counter_t *src, cl_memnote_t *note, unsigned type) +cl_error cl_get_memnote_value(cl_counter_t *src, cl_memnote_t *note, + cl_src_t type) { if (!src || !note) return CL_ERR_PARAMETER_NULL; @@ -118,7 +119,7 @@ cl_error cl_get_memnote_value(cl_counter_t *src, cl_memnote_t *note, unsigned ty } cl_error cl_get_memnote_value_from_key(cl_counter_t *src, unsigned key, - unsigned type) + cl_src_t type) { cl_memnote_t *note = cl_find_memnote(key); @@ -519,7 +520,7 @@ static cl_error cl_memnote_resolve_ptrs(cl_memnote_t *note) static cl_error cl_update_memnote(cl_memnote_t *note) { cl_error error; - int64_t new_val; + cl_int64 new_val; if (!note) return CL_ERR_PARAMETER_NULL; diff --git a/cl_memory.h b/cl_memory.h index 180c893..fe4f2c0 100644 --- a/cl_memory.h +++ b/cl_memory.h @@ -3,9 +3,16 @@ #include "cl_common.h" -/* Memnotes marked with this are submitted to the server on every request, - as well as on timed intervals to retrieve a play status string. */ -#define CL_MEMFLAG_RICH 0 +typedef enum +{ + /** + * Memory notes marked with this are submitted to the server on every + * request, as well as on timed intervals to retrieve a status string. + */ + CL_MEMFLAG_RICH = 0, + + CL_MEMFLAG_SIZE +} cl_memnote_flag; #include "cl_config.h" #include "cl_counter.h" @@ -48,18 +55,20 @@ cl_error cl_init_membanks_libretro(const struct retro_memory_descriptor **descs, * @param key A memory note key to be looked up automatically. * @param flag The memory note flag to check. For example, CL_MEMFLAG_RICH. **/ -cl_error cl_get_memnote_flag(cl_memnote_t *note, uint8_t flag); -cl_error cl_get_memnote_flag_from_key(unsigned key, uint8_t flag); +cl_error cl_get_memnote_flag(cl_memnote_t *note, cl_memnote_flag flag); +cl_error cl_get_memnote_flag_from_key(unsigned key, cl_memnote_flag flag); /** * Copies the current value of a memory note into a buffer. * @param value A buffer for the value to be copied into. Should not be NULL. * @param note A pointer to a memory note. * @param key A memory note key to be looked up automatically. - * @param type The data type of the buffer. For example, CL_MEMTYPE_32BIT. + * @param type The source type of the buffer. For example, CL_SRC_CURRENT_RAM. **/ -cl_error cl_get_memnote_value(cl_counter_t *value, cl_memnote_t *note, unsigned type); -cl_error cl_get_memnote_value_from_key(cl_counter_t *value, unsigned key, unsigned type); +cl_error cl_get_memnote_value(cl_counter_t *value, cl_memnote_t *note, + cl_src_t type); +cl_error cl_get_memnote_value_from_key(cl_counter_t *value, unsigned key, + cl_src_t type); /* Populate a memory holder with values returned by the web API */ cl_error cl_init_memory(const char **pos); diff --git a/cl_script.h b/cl_script.h index ce70419..bac749d 100644 --- a/cl_script.h +++ b/cl_script.h @@ -20,12 +20,12 @@ typedef enum typedef struct cl_page_t { cl_action_t *actions; - unsigned action_count; + unsigned action_count; /* Temporary values (bitflags, counters) we can use for logic */ cl_counter_t counters[CL_COUNTERS_SIZE]; - uint32_t flags; + unsigned flags; } cl_page_t; typedef struct cl_script_t diff --git a/cl_types.h b/cl_types.h index d2dba38..2411462 100644 --- a/cl_types.h +++ b/cl_types.h @@ -3,7 +3,6 @@ #include "cl_config.h" -#include #include #include @@ -14,6 +13,14 @@ typedef unsigned char cl_bool; #define CL_TRUE 1 #define CL_FALSE 0 +#if CL_HOST_PLATFORM == _CL_PLATFORM_LINUX + typedef signed long cl_int64; + typedef unsigned long cl_uint64; +#else + typedef signed long long cl_int64; + typedef unsigned long long cl_uint64; +#endif + typedef enum { CL_OK = 0, @@ -205,9 +212,9 @@ typedef struct typedef union { - int64_t intval; + cl_int64 intval; double floatval; - uint64_t uintval; + cl_uint64 uintval; } cl_arg_t; typedef enum @@ -380,27 +387,27 @@ typedef struct char language[8]; } cl_user_t; -/** A virtual address for the emulated system. */ -typedef uintptr_t cl_addr_t; #if CL_HOST_BITNESS == _CL_BITNESS_32 #define CL_ADDRF "%08X" #define CL_SIZEF "%u" + typedef unsigned int cl_addr_t; #else #define CL_ADDRF "%016lX" #define CL_SIZEF "%lu" + typedef unsigned long cl_addr_t; #endif typedef struct cl_counter_t { union { - int64_t i64; - uint64_t raw; + cl_int64 i64; + cl_uint64 raw; } intval; union { double fp; - uint64_t raw; + cl_uint64 raw; } floatval; cl_value_type type; } cl_counter_t; From f08753e9183b5ebb7f1ac2c022a90ef6abdfd63b Mon Sep 17 00:00:00 2001 From: celerizer Date: Wed, 11 Feb 2026 15:23:57 -0600 Subject: [PATCH 51/57] add test for sizeof cl_int64 == 8 --- cl_test.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/cl_test.c b/cl_test.c index 84ff34f..325720c 100644 --- a/cl_test.c +++ b/cl_test.c @@ -380,6 +380,23 @@ cl_error cl_test(void) cl_string_bitness(CL_HOST_BITNESS), cl_string_endianness(CL_HOST_ENDIANNESS)); + printf("============================================================\n"); + printf("Performing sizeof int tests...\n"); + if (sizeof(cl_int64) != 8) + { + printf("Unexpected sizeof(cl_int64)! Tests cannot continue.\n"); + return CL_ERR_CLIENT_COMPILE; + } + else + printf("sizeof(cl_int64) test passed!\n"); + if (sizeof(cl_uint64) != 8) + { + printf("Unexpected sizeof(cl_uint64)! Tests cannot continue.\n"); + return CL_ERR_CLIENT_COMPILE; + } + else + printf("sizeof(cl_uint64) test passed!\n"); + printf("============================================================\n"); printf("Performing basic counter function tests...\n"); error = cl_ctr_tests(); From 38dfe602be96dc80ac953274f85737757d942321 Mon Sep 17 00:00:00 2001 From: celerizer Date: Wed, 11 Feb 2026 15:53:46 -0600 Subject: [PATCH 52/57] add cl_dma to remove stdlib from global namespace --- cl_abi.c | 2 +- cl_action.c | 3 ++- cl_counter.c | 1 + cl_dma.c | 18 ++++++++++++++++++ cl_dma.h | 8 ++++++++ cl_identify.c | 26 ++++++++++++++------------ cl_memory.c | 31 ++++++++++++++++++------------- cl_network.c | 4 +++- cl_script.c | 12 +++++++----- cl_search_new.c | 2 ++ cl_types.h | 7 +++---- classicslive-integration.mk | 1 + classicslive-integration.pri | 2 ++ 13 files changed, 80 insertions(+), 37 deletions(-) create mode 100644 cl_dma.c create mode 100644 cl_dma.h diff --git a/cl_abi.c b/cl_abi.c index b436a62..ad7cfa6 100644 --- a/cl_abi.c +++ b/cl_abi.c @@ -1,6 +1,6 @@ #include "cl_abi.h" -static const cl_abi_t *cl_g_abi = NULL; +static const cl_abi_t *cl_g_abi = CL_NULL; cl_error cl_abi_register(const cl_abi_t *abi) { diff --git a/cl_action.c b/cl_action.c index d6a5233..48b2873 100644 --- a/cl_action.c +++ b/cl_action.c @@ -1,5 +1,6 @@ #include "cl_action.h" #include "cl_common.h" +#include "cl_dma.h" #include "cl_memory.h" #include "cl_network.h" #include "cl_script.h" @@ -16,7 +17,7 @@ static cl_error cl_act_no_process(cl_action_t *action) cl_error cl_free_action(cl_action_t *action) { action->argument_count = 0; - free(action->arguments); + cl_free(action->arguments); action->arguments = NULL; action->type = CL_ACTTYPE_NO_PROCESS; action->function = cl_act_no_process; diff --git a/cl_counter.c b/cl_counter.c index 8284c48..fe9a632 100644 --- a/cl_counter.c +++ b/cl_counter.c @@ -269,6 +269,7 @@ cl_error cl_ctr_change_type(cl_counter_t *counter, cl_value_type type) #if CL_TESTS #include +#include static void cl_ctr_test_add(void) { diff --git a/cl_dma.c b/cl_dma.c new file mode 100644 index 0000000..06542af --- /dev/null +++ b/cl_dma.c @@ -0,0 +1,18 @@ +#include "cl_dma.h" + +#include "cl_types.h" + +#include + +void *cl_dma_alloc(unsigned size, unsigned zero) +{ + if (zero) + return calloc(1, size); + else + return malloc(size); +} + +void cl_dma_free(void *address) +{ + free(address); +} diff --git a/cl_dma.h b/cl_dma.h new file mode 100644 index 0000000..eac9906 --- /dev/null +++ b/cl_dma.h @@ -0,0 +1,8 @@ +#ifndef CL_DMA_H +#define CL_DMA_H + +void *cl_dma_alloc(unsigned size, unsigned zero); + +void cl_dma_free(void *address); + +#endif diff --git a/cl_identify.c b/cl_identify.c index a1b90ea..3324524 100644 --- a/cl_identify.c +++ b/cl_identify.c @@ -1,6 +1,8 @@ +#include "cl_identify.h" + #include "cl_abi.h" #include "cl_config.h" -#include "cl_identify.h" +#include "cl_dma.h" #include "cl_memory.h" #include @@ -64,15 +66,15 @@ static void cl_task_md5(struct cl_task_t *task) cl_log("Content MD5: %.32s\n", state->md5_final); if (state->free_on_finish) - free(state->data); + cl_dma_free(state->data); } } static void cl_push_md5_task(void *data, unsigned size, char *checksum, cl_bool free_on_finish, CL_TASK_CB_T callback) { - cl_task_t *task = (cl_task_t*)calloc(1, sizeof(cl_task_t)); - cl_md5_ctx_t *context = (cl_md5_ctx_t*)calloc(1, sizeof(cl_md5_ctx_t)); + cl_task_t *task = (cl_task_t*)cl_dma_alloc(sizeof(cl_task_t), CL_TRUE); + cl_md5_ctx_t *context = (cl_md5_ctx_t*)cl_dma_alloc(sizeof(cl_md5_ctx_t), CL_TRUE); context->data = data; context->size = size; @@ -114,7 +116,7 @@ static void cl_task_gcwii(cl_task_t *task) { uint8_t *buffer; - buffer = (uint8_t*)malloc(CL_DOLPHIN_SIZE); + buffer = (uint8_t*)cl_dma_alloc(CL_DOLPHIN_SIZE, CL_TRUE); memcpy(buffer, memory.regions[0].base_host, CL_DOLPHIN_SIZE); cl_log("(GC/Wii) Game to be identified: %.8s\n", buffer); @@ -132,8 +134,8 @@ static void cl_task_gcwii(cl_task_t *task) */ static void cl_push_gcwii_task(char *checksum, CL_TASK_CB_T callback) { - cl_task_t *task = (cl_task_t*)calloc(1, sizeof(cl_task_t)); - cl_md5_ctx_t *context = (cl_md5_ctx_t*)calloc(1, sizeof(cl_md5_ctx_t)); + cl_task_t *task = (cl_task_t*)cl_dma_alloc(sizeof(cl_task_t), CL_TRUE); + cl_md5_ctx_t *context = (cl_md5_ctx_t*)cl_dma_alloc(sizeof(cl_md5_ctx_t), CL_TRUE); context->md5_final = checksum; @@ -190,7 +192,7 @@ static uint8_t* cl_identify_iso9660(intfstream_t *stream) uint8_t *buffer; unsigned size, i; - buffer = (uint8_t*)malloc(CL_ISO9660_SIZE); + buffer = (uint8_t*)cl_dma_alloc(CL_ISO9660_SIZE, CL_TRUE); size = (unsigned)intfstream_get_size(stream); /* Seek to the identifier "CD001" */ @@ -210,7 +212,7 @@ static uint8_t* cl_identify_iso9660(intfstream_t *stream) } /* Not found */ intfstream_close(stream); - free(buffer); + cl_dma_free(buffer); return NULL; } @@ -242,12 +244,12 @@ static uint8_t* cl_identify_ncch(const char *path) * and seek backwards 0x0100. */ intfstream_seek(stream, 0x1000, SEEK_SET); - data = (uint8_t*)malloc(CL_NCCH_SIZE); + data = (uint8_t*)cl_dma_alloc(CL_NCCH_SIZE, CL_TRUE); read_bytes = intfstream_read(stream, data, CL_NCCH_SIZE); intfstream_close(stream); if (!read_bytes) - free(data); + cl_dma_free(data); else if (memcmp(&data[0x100], "NCCH", 4)) cl_message(CL_MSG_ERROR, "Invalid NCCH data."); else @@ -471,7 +473,7 @@ cl_error cl_identify(const void *info_data, const unsigned info_size, CL_UNUSED(library); if (info_data && info_size > 0) { - void *data = (uint8_t*)malloc(info_size); + void *data = (unsigned char*)cl_dma_alloc(info_size, CL_TRUE); if (data) { diff --git a/cl_memory.c b/cl_memory.c index 98b613a..08052ee 100644 --- a/cl_memory.c +++ b/cl_memory.c @@ -1,5 +1,6 @@ #include "cl_common.h" #include "cl_config.h" +#include "cl_dma.h" #include "cl_memory.h" #if CL_LIBRETRO @@ -18,7 +19,7 @@ cl_memory_t memory; cl_memory_region_t* cl_find_memory_region(cl_addr_t address) { if (memory.region_count == 0) - return NULL; + return CL_NULL; else if (memory.region_count == 1) return &memory.regions[0]; else @@ -37,7 +38,7 @@ cl_memory_region_t* cl_find_memory_region(cl_addr_t address) } } - return NULL; + return CL_NULL; } cl_memnote_t* cl_find_memnote(unsigned key) @@ -50,7 +51,7 @@ cl_memnote_t* cl_find_memnote(unsigned key) return &memory.notes[i]; } - return NULL; + return CL_NULL; } void cl_free_memnote(cl_memnote_t *note) @@ -65,13 +66,13 @@ void cl_memory_free(void) for (i = 0; i < memory.note_count; i++) cl_free_memnote(&memory.notes[i]); - free(memory.notes); + cl_dma_free(memory.notes); memory.note_count = 0; - memory.notes = NULL; + memory.notes = CL_NULL; - free(memory.regions); + cl_dma_free(memory.regions); memory.region_count = 0; - memory.regions = NULL; + memory.regions = CL_NULL; } cl_error cl_get_memnote_flag(cl_memnote_t *note, cl_memnote_flag flag) @@ -249,7 +250,7 @@ static void cl_memnote_ex_populate_values(cl_memnote_ex_t *ex) continue; *eq = '\0'; - unsigned val = (unsigned)strtoul(p, NULL, 0); + unsigned val = (unsigned)strtoul(p, CL_NULL, 0); /* Extract title text */ const char *title = eq + 1; @@ -337,6 +338,8 @@ cl_error cl_memory_init_notes(void) return CL_OK; } +#if CL_HAVE_EDITOR + cl_error cl_memory_add_note(const cl_memnote_t *note) { cl_memnote_t *new_array; @@ -363,6 +366,8 @@ cl_error cl_memory_add_note(const cl_memnote_t *note) return CL_OK; } +#endif + cl_error cl_read_memory_buffer_internal(void *buffer, const cl_memory_region_t *bank, cl_addr_t address, cl_addr_t size) { @@ -440,7 +445,7 @@ cl_error cl_read_memory_buffer_external(void *value, { if (bank) address += bank->base_guest; - return cl_abi_external_read_buffer(value, address, size, NULL); + return cl_abi_external_read_buffer(value, address, size, CL_NULL); } cl_error cl_read_memory_value_external(void *value, @@ -456,7 +461,7 @@ cl_error cl_write_memory_buffer_external(const void *value, { if (bank) address += bank->base_guest; - return cl_abi_external_write_buffer(value, address, size, NULL); + return cl_abi_external_write_buffer(value, address, size, CL_NULL); } cl_error cl_write_memory_value_external(const void *value, @@ -505,7 +510,7 @@ static cl_error cl_memnote_resolve_ptrs(cl_memnote_t *note) default: return CL_ERR_PARAMETER_INVALID; } - if (cl_read_memory_value(&final_addr, NULL, final_addr, + if (cl_read_memory_value(&final_addr, CL_NULL, final_addr, ptr_type) != CL_OK) return CL_ERR_CLIENT_RUNTIME; @@ -534,7 +539,7 @@ static cl_error cl_update_memnote(cl_memnote_t *note) /* The "previous" value is the value from the previous frame */ note->previous = note->current; - cl_read_memory_value(&new_val, NULL, note->address, note->type); + cl_read_memory_value(&new_val, CL_NULL, note->address, note->type); cl_ctr_store(¬e->current, &new_val, note->type); /* Logic for "last unique" values; the previous value will persist */ @@ -572,7 +577,7 @@ cl_error cl_write_memnote(cl_memnote_t *note, const cl_counter_t *value) return cl_write_memory_value(cl_ctr_is_float(value) == CL_OK ? (const void *)&value->floatval.fp : (const void *)&value->intval.i64, - NULL, note->address, note->type); + CL_NULL, note->address, note->type); } cl_error cl_write_memnote_from_key(unsigned key, const cl_counter_t *value) diff --git a/cl_network.c b/cl_network.c index a47bb99..c047ee0 100644 --- a/cl_network.c +++ b/cl_network.c @@ -2,17 +2,19 @@ #include "cl_common.h" #include "cl_abi.h" +#include "cl_dma.h" #include "cl_main.h" #include "cl_memory.h" #include +#include #include static char *cl_build_generic_post_data(void) { cl_counter_t value; unsigned bufsize = 256; - char *buf = malloc(bufsize); + char *buf = cl_dma_alloc(bufsize, CL_TRUE); char temp[128]; unsigned i; diff --git a/cl_script.c b/cl_script.c index dac44d7..7a28817 100644 --- a/cl_script.c +++ b/cl_script.c @@ -1,6 +1,7 @@ #include "cl_script.h" #include "cl_abi.h" +#include "cl_dma.h" #include #include @@ -15,10 +16,10 @@ static void cl_page_free(cl_page_t *page) return; for (i = 0; i < page->action_count; i++) cl_free_action(&page->actions[i]); - free(page->actions); + cl_dma_free(page->actions); page->actions = NULL; page->action_count = 0; - free(page); + cl_dma_free(page); } void cl_script_free(void) @@ -27,6 +28,7 @@ void cl_script_free(void) for (i = 0; i < script.page_count; i++) cl_page_free(&script.pages[i]); + cl_dma_free(script.pages); script.pages = NULL; script.page_count = 0; } @@ -39,7 +41,7 @@ static cl_error cl_init_page(const char **pos, cl_page_t *page) if (cl_strto(pos, &page->action_count, sizeof(page->action_count), CL_FALSE) != CL_OK) return CL_ERR_PARAMETER_INVALID; - page->actions = (cl_action_t*)calloc(page->action_count, sizeof(cl_action_t)); + page->actions = (cl_action_t*)cl_dma_alloc(page->action_count * sizeof(cl_action_t), CL_TRUE); if (!page->actions) return CL_ERR_PARAMETER_NULL; @@ -58,7 +60,7 @@ static cl_error cl_init_page(const char **pos, cl_page_t *page) return CL_ERR_CLIENT_RUNTIME; /* Allocate and initialize action arguments */ - action->arguments = (cl_arg_t*)calloc(action->argument_count, sizeof(cl_arg_t)); + action->arguments = (cl_arg_t*)cl_dma_alloc(action->argument_count * sizeof(cl_arg_t), CL_TRUE); if (!action->arguments) return CL_ERR_PARAMETER_NULL; for (j = 0; j < action->argument_count; j++) @@ -98,7 +100,7 @@ cl_error cl_script_init(const char **pos) if (cl_strto(pos, &script.page_count, sizeof(script.page_count), CL_FALSE) != CL_OK) return CL_ERR_PARAMETER_INVALID; - script.pages = (cl_page_t*)calloc(script.page_count, sizeof(cl_page_t)); + script.pages = (cl_page_t*)cl_dma_alloc(script.page_count * sizeof(cl_page_t), CL_TRUE); if (!script.pages) return CL_ERR_PARAMETER_NULL; diff --git a/cl_search_new.c b/cl_search_new.c index d1aece7..c773f52 100644 --- a/cl_search_new.c +++ b/cl_search_new.c @@ -5,7 +5,9 @@ #include "cl_memory.h" #include +#include #include +#include typedef union { diff --git a/cl_types.h b/cl_types.h index 2411462..1216b00 100644 --- a/cl_types.h +++ b/cl_types.h @@ -3,9 +3,6 @@ #include "cl_config.h" -#include -#include - #define CL_SESSION_ID_LENGTH 32 typedef unsigned char cl_bool; @@ -21,6 +18,8 @@ typedef unsigned char cl_bool; typedef unsigned long long cl_uint64; #endif +#define CL_NULL 0 + typedef enum { CL_OK = 0, @@ -339,7 +338,7 @@ typedef struct cl_session_t char generic_post[2048]; cl_session_flags_t flags; char id[CL_SESSION_ID_LENGTH]; - time_t last_status_update; + cl_int64 last_status_update; cl_session_state state; diff --git a/classicslive-integration.mk b/classicslive-integration.mk index 7bacd4f..aac6554 100644 --- a/classicslive-integration.mk +++ b/classicslive-integration.mk @@ -8,6 +8,7 @@ CLASSICS_LIVE_SOURCES_CLASSICSLIVE = \ $(CLASSICS_LIVE_DIR)/cl_common.c \ $(CLASSICS_LIVE_DIR)/cl_config.c \ $(CLASSICS_LIVE_DIR)/cl_counter.c \ + $(CLASSICS_LIVE_DIR)/cl_dma.c \ $(CLASSICS_LIVE_DIR)/cl_identify.c \ $(CLASSICS_LIVE_DIR)/cl_json.c \ $(CLASSICS_LIVE_DIR)/cl_main.c \ diff --git a/classicslive-integration.pri b/classicslive-integration.pri index f8705a9..0c58170 100644 --- a/classicslive-integration.pri +++ b/classicslive-integration.pri @@ -16,6 +16,7 @@ SOURCES += \ $$CL_DIR/cl_common.c \ $$CL_DIR/cl_config.c \ $$CL_DIR/cl_counter.c \ + $$CL_DIR/cl_dma.c \ $$CL_DIR/cl_identify.c \ $$CL_DIR/cl_json.c \ $$CL_DIR/cl_main.c \ @@ -33,6 +34,7 @@ HEADERS += \ $$CL_DIR/cl_common.h \ $$CL_DIR/cl_config.h \ $$CL_DIR/cl_counter.h \ + $$CL_DIR/cl_dma.h \ $$CL_DIR/cl_identify.h \ $$CL_DIR/cl_json.h \ $$CL_DIR/cl_main.h \ From 7329b0664287869a360443be4ae492aaf3c272e9 Mon Sep 17 00:00:00 2001 From: celerizer Date: Wed, 11 Feb 2026 16:03:23 -0600 Subject: [PATCH 53/57] fix double-free error --- cl_action.c | 2 +- cl_script.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/cl_action.c b/cl_action.c index 48b2873..452017a 100644 --- a/cl_action.c +++ b/cl_action.c @@ -17,7 +17,7 @@ static cl_error cl_act_no_process(cl_action_t *action) cl_error cl_free_action(cl_action_t *action) { action->argument_count = 0; - cl_free(action->arguments); + cl_dma_free(action->arguments); action->arguments = NULL; action->type = CL_ACTTYPE_NO_PROCESS; action->function = cl_act_no_process; diff --git a/cl_script.c b/cl_script.c index 7a28817..45a384d 100644 --- a/cl_script.c +++ b/cl_script.c @@ -28,7 +28,6 @@ void cl_script_free(void) for (i = 0; i < script.page_count; i++) cl_page_free(&script.pages[i]); - cl_dma_free(script.pages); script.pages = NULL; script.page_count = 0; } From cdceefc35e48f4788ca25e04e20f4fdbef3b00b7 Mon Sep 17 00:00:00 2001 From: celerizer Date: Tue, 3 Mar 2026 20:40:10 -0600 Subject: [PATCH 54/57] explicitly include stdlib in source files --- cl_common.c | 1 + cl_memory.c | 1 + cl_search.c | 2 ++ 3 files changed, 4 insertions(+) diff --git a/cl_common.c b/cl_common.c index 0ddae1d..5197fc2 100644 --- a/cl_common.c +++ b/cl_common.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #ifdef _MSC_VER diff --git a/cl_memory.c b/cl_memory.c index 08052ee..19aaef4 100644 --- a/cl_memory.c +++ b/cl_memory.c @@ -5,6 +5,7 @@ #if CL_LIBRETRO #include +#include #endif #if CL_HAVE_EDITOR diff --git a/cl_search.c b/cl_search.c index 5c43bef..d1c2fc2 100644 --- a/cl_search.c +++ b/cl_search.c @@ -5,6 +5,8 @@ #include "cl_memory.h" #include +#include +#include #include static cl_error compare_to_nothing(cl_addr_t previous, cl_addr_t current, cl_compare_type type) From 64aa7af208c12cb58f97227256e2cd362f00300a Mon Sep 17 00:00:00 2001 From: celerizer Date: Tue, 3 Mar 2026 20:40:28 -0600 Subject: [PATCH 55/57] get icon url on site login --- cl_json.c | 2 +- cl_main.c | 39 +++++++++++++++++++++++++++++++++------ cl_types.h | 2 ++ 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/cl_json.c b/cl_json.c index 92e3d6e..34ec2e3 100644 --- a/cl_json.c +++ b/cl_json.c @@ -72,7 +72,7 @@ static const cl_json_key_map_t cl_json_key_map[] = { CL_JSON_KEY_ENDIANNESS, "endianness" }, { CL_JSON_KEY_FLAGS, "flags" }, { CL_JSON_KEY_GAME_ID, "game_id" }, - { CL_JSON_KEY_ICON_URL, "icon_url" }, + { CL_JSON_KEY_ICON_URL, "icon" }, { CL_JSON_KEY_ID, "id" }, { CL_JSON_KEY_LANGUAGE, "language" }, { CL_JSON_KEY_LEADERBOARDS, "leaderboards" }, diff --git a/cl_main.c b/cl_main.c index c689a08..0d681ca 100644 --- a/cl_main.c +++ b/cl_main.c @@ -17,6 +17,8 @@ void cle_run(void); #include #include +#include + cl_session_t session; static cl_error cl_init_session(const char* json) @@ -27,12 +29,35 @@ static cl_error cl_init_session(const char* json) cl_error error; /* Get game info */ + /* Game title */ if (cl_json_get(&session.game_title, json, CL_JSON_KEY_TITLE, - CL_JSON_TYPE_STRING, sizeof(session.game_title)) == CL_OK) - cl_message(CL_MSG_INFO, "Game title: %s", session.game_title); + CL_JSON_TYPE_STRING, sizeof(session.game_title)) != CL_OK) + session.game_title[0] = '\0'; + else + { + cl_log("Game title: %s", session.game_title); + session.game_title[sizeof(session.game_title) - 1] = '\0'; + } + + /* Game ID */ if (cl_json_get(&misc, json, CL_JSON_KEY_GAME_ID, - CL_JSON_TYPE_NUMBER, sizeof(misc)) == CL_OK) + CL_JSON_TYPE_NUMBER, sizeof(misc)) != CL_OK) + session.game_id = 0; + else + { + cl_log("Game ID: %u", session.game_id); session.game_id = misc; + } + + /* Game icon URL */ + if (cl_json_get(&session.icon_url, json, CL_JSON_KEY_ICON_URL, + CL_JSON_TYPE_STRING, sizeof(session.icon_url)) != CL_OK) + session.icon_url[0] = '\0'; + else + { + cl_log("Game icon URL: %s", session.icon_url); + session.icon_url[sizeof(session.icon_url) - 1] = '\0'; + } /* Get default endianness of memory regions */ if (cl_json_get(&misc, json, CL_JSON_KEY_ENDIANNESS, @@ -326,6 +351,11 @@ cl_error cl_run(void) if (session.state == CL_SESSION_STARTED) { cl_update_memory(); + +#if CL_HAVE_EDITOR + cle_run(); +#endif + error = cl_script_update(); if (error != CL_OK) return error; @@ -336,9 +366,6 @@ cl_error cl_run(void) session.last_status_update = time(0); cl_network_post_clint(CL_END_CLINT_PING, NULL, NULL, NULL); } -#if CL_HAVE_EDITOR - cle_run(); -#endif return CL_OK; } diff --git a/cl_types.h b/cl_types.h index 1216b00..f80aac5 100644 --- a/cl_types.h +++ b/cl_types.h @@ -335,6 +335,8 @@ typedef struct cl_session_t char checksum[64]; unsigned game_id; char game_title[256]; + char icon_url[256]; + char generic_post[2048]; cl_session_flags_t flags; char id[CL_SESSION_ID_LENGTH]; From fff23654feea87963e684fffe2e9b54f4efc1697 Mon Sep 17 00:00:00 2001 From: celerizer Date: Thu, 5 Mar 2026 20:34:39 -0600 Subject: [PATCH 56/57] ignore mirrors and subregions of memory --- cl_memory.c | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/cl_memory.c b/cl_memory.c index 19aaef4..8b0004d 100644 --- a/cl_memory.c +++ b/cl_memory.c @@ -151,25 +151,46 @@ cl_error cl_init_membanks_libretro(const struct retro_memory_descriptor **descs, const unsigned num_descs) { const struct retro_memory_descriptor *desc; - unsigned i; + unsigned i, j; memory.regions = (cl_memory_region_t*)calloc(num_descs, sizeof(cl_memory_region_t)); - memory.region_count = num_descs; + memory.region_count = 0; for (i = 0; i < num_descs; i++) { + cl_memory_region_t *region = NULL; desc = descs[i]; - cl_memory_region_t *region = &memory.regions[i]; + cl_bool ignore = CL_FALSE; - /* Is this bank's data a null pointer? Ignore it */ + /* Is this region's data a null pointer? Ignore it */ if (!desc->ptr) - { - memory.region_count--; continue; + + /* Is this region a mirror or subregion of another? */ + for (j = 0; j < memory.region_count; j++) + { + if (desc->ptr == memory.regions[j].base_host) + { + cl_log("Ignoring mirror region of %s in %u\n", + memory.regions[j].title, i); + ignore = CL_TRUE; + break; + } + else if ((desc->ptr < memory.regions[j].base_host + memory.regions[j].size) && + (desc->ptr >= memory.regions[j].base_host)) + { + cl_log("Ignoring subregion of %s in %u\n", + memory.regions[j].title, i); + ignore = CL_TRUE; + break; + } } + if (ignore) + continue; /* Copy the libretro mmap parameters into our format */ + region = &memory.regions[memory.region_count]; region->base_alloc = CL_ADDRESS_INVALID; region->base_guest = desc->start; region->base_host = desc->ptr; @@ -184,12 +205,14 @@ cl_error cl_init_membanks_libretro(const struct retro_memory_descriptor **descs, region->pointer_length = 4; region->size = desc->len; - /* Setup the title of the memory bank */ + /* Setup the title of the memory region */ if (desc->addrspace) snprintf(region->title, sizeof(region->title), "%s", desc->addrspace); else - snprintf(region->title, sizeof(region->title), "Memory bank %u/%u", - i + 1, memory.region_count); + snprintf(region->title, sizeof(region->title), "Region %u/%u", + i + 1, num_descs); + + memory.region_count++; } cl_sort_memory_regions(memory.regions, memory.region_count); @@ -198,7 +221,7 @@ cl_error cl_init_membanks_libretro(const struct retro_memory_descriptor **descs, { cl_memory_region_t *region = &memory.regions[i]; - cl_log("Bank %02X: 0x%08X | %08X bytes | %s\n", i, region->base_guest, + cl_log("Region %02X: 0x%08X | %08X bytes | %s\n", i, region->base_guest, region->size, region->title); } From aa23439177e73025a9374c83d7f53839d244d906 Mon Sep 17 00:00:00 2001 From: celerizer Date: Thu, 5 Mar 2026 23:13:47 -0600 Subject: [PATCH 57/57] various fixes --- cl_memory.c | 4 - editor/cle_hex_view.cpp | 194 +++++++++++++++++++++++++------- editor/cle_hex_view.h | 19 ++-- editor/cle_main.cpp | 20 +++- editor/cle_memory_inspector.cpp | 118 +++++++++++++++++-- editor/cle_memory_inspector.h | 11 +- 6 files changed, 295 insertions(+), 71 deletions(-) diff --git a/cl_memory.c b/cl_memory.c index 8b0004d..15449eb 100644 --- a/cl_memory.c +++ b/cl_memory.c @@ -198,10 +198,6 @@ cl_error cl_init_membanks_libretro(const struct retro_memory_descriptor **descs, CL_ENDIAN_BIG : CL_ENDIAN_LITTLE; region->flags.bits.read = 1; region->flags.bits.write = desc->flags & RETRO_MEMDESC_CONST ? 0 : 1; - /** - * @todo Is there a commonly used libretro flag for this? Not a huge deal - * since this gets overwritten by the server later - */ region->pointer_length = 4; region->size = desc->len; diff --git a/editor/cle_hex_view.cpp b/editor/cle_hex_view.cpp index 109dc9e..2d6663e 100644 --- a/editor/cle_hex_view.cpp +++ b/editor/cle_hex_view.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -53,19 +54,67 @@ CleHexWidget::CleHexWidget(QWidget *parent, uint8_t size) : QWidget(parent) repaintAll(); } +void CleHexWidget::changeEvent(QEvent *event) +{ + if (event->type() == QEvent::PaletteChange) + { + /* Re-draw the address sidebar with the updated background color */ + m_Painter->setBrush(palette().color(backgroundRole())); + m_Painter->setPen(Qt::NoPen); + m_Painter->drawRect(QRect(0, 0, 64, 256)); + m_Painter->setPen(QColor("grey")); + for (uint8_t i = 0; i < 16; i++) + m_Painter->drawText(m_AddrRects[i], Qt::AlignRight | Qt::AlignVCenter, m_AddrTexts[i]); + update(); + } + QWidget::changeEvent(event); +} + void CleHexWidget::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Left: - if (isCursorTopLeft()) - movePosition(-0x10); - setCursorOffset(m_CursorOffset - 1); + if (m_CursorNybble > 0) + { + /* Move back one nybble within the current cell */ + m_CursorNybble--; + paintCursorCell(((m_CursorOffset - m_Position) & 0xFF) / m_Size); + update(); + } + else + { + /* Cross to the last nybble of the previous cell */ + if (isCursorTopLeft()) + movePosition(-0x10); + setCursorOffset(m_CursorOffset - m_Size); + m_CursorNybble = m_Size * 2 - 1; + paintCursorCell(((m_CursorOffset - m_Position) & 0xFF) / m_Size); + update(); + } break; case Qt::Key_Right: + if (m_CursorNybble < m_Size * 2 - 1) + { + /* Move forward one nybble within the current cell */ + m_CursorNybble++; + paintCursorCell(((m_CursorOffset - m_Position) & 0xFF) / m_Size); + update(); + } + else + { + /* Cross to the first nybble of the next cell */ + if (isCursorBottomRight()) + movePosition(0x10); + setCursorOffset(m_CursorOffset + m_Size); + } + break; + case Qt::Key_Return: + case Qt::Key_Enter: + emit valueEdited(m_CursorOffset, m_CursorValue, m_Size); if (isCursorBottomRight()) movePosition(0x10); - setCursorOffset(m_CursorOffset + 1); + setCursorOffset(m_CursorOffset + m_Size); break; case Qt::Key_Up: if (event->modifiers() & Qt::ShiftModifier) @@ -152,37 +201,42 @@ void CleHexWidget::keyPressEvent(QKeyEvent *event) void CleHexWidget::mousePressEvent(QMouseEvent *event) { - if (m_Size != 1) - return; //todo - else - { - QPoint pos = event->pos(); - uint32_t i; + QPoint pos = event->pos(); + uint32_t i; + uint32_t cell_count = 256 / m_Size; - for (i = 0; i < 256; i++) + for (i = 0; i < cell_count; i++) + { + if (m_Rects[i].contains(pos)) { - if (m_Rects[i].contains(pos)) - { - if (event->button() == Qt::LeftButton) - setCursorOffset(m_Position + i); - else if (event->button() == Qt::RightButton) - onRightClick(m_Position + i, pos); - return; - } + cl_addr_t address = m_Position + (cl_addr_t)(i * m_Size); + if (event->button() == Qt::LeftButton) + setCursorOffset(address); + else if (event->button() == Qt::RightButton) + onRightClick(address, pos); + return; } } } void CleHexWidget::movePosition(int32_t offset) { - uint32_t new_pos = m_Position + offset; - - if (new_pos < m_PositionMin) - setOffset(m_PositionMin); - else if (new_pos + 0x100 >= m_PositionMax) - setOffset(m_PositionMax - 0x100); + if (offset < 0) + { + cl_addr_t delta = static_cast(-offset); + if (delta > m_Position - m_PositionMin) + setOffset(m_PositionMin); + else + setOffset(m_Position - delta); + } else - setOffset(new_pos); + { + cl_addr_t new_pos = m_Position + static_cast(offset); + if (new_pos + 0x100 >= m_PositionMax) + setOffset(m_PositionMax - 0x100); + else + setOffset(new_pos); + } } void CleHexWidget::onClickAddMemoryNote() @@ -351,16 +405,45 @@ void CleHexWidget::setByteSwapEnabled(bool enabled) m_UseByteSwap = enabled; } +void CleHexWidget::paintCursorCell(uint8_t index) +{ + m_Painter->setFont(m_Font); + m_Painter->setBrush(m_RectColors[index]); + m_Painter->setPen(Qt::NoPen); + m_Painter->drawRect(m_Rects[index]); + m_Painter->setPen(QColor("white")); + m_Painter->drawText(m_Rects[index], Qt::AlignCenter, m_Texts[index]); + + /* Draw nybble-position underline on the active cursor cell */ + if (m_RectColors[index].blue() > 0) + { + uint8_t total_nybbles = m_Size * 2; + uint8_t nybble = (m_CursorNybble < total_nybbles) ? m_CursorNybble : total_nybbles - 1; + + QFontMetrics fm(m_Font); + int char_w = fm.horizontalAdvance(QLatin1Char('F')); + int text_w = char_w * total_nybbles; + int text_x = m_Rects[index].x() + (m_Rects[index].width() - text_w) / 2; + int line_x = text_x + nybble * char_w; + int line_y = m_Rects[index].bottom() - 1; + + m_Painter->setPen(QPen(QColor("white"), 2)); + m_Painter->drawLine(line_x, line_y, line_x + char_w - 1, line_y); + } +} + void CleHexWidget::setCursorOffset(cl_addr_t offset) { - uint8_t cursor = (m_CursorOffset - m_Position) & 0xFF; + uint8_t cursor = ((m_CursorOffset - m_Position) & 0xFF) / m_Size; - /* Repaint old highlight */ + /* Clear old highlight directly into m_Image */ m_RectColors[cursor].setBlue(0); - repaintRect(NULL, cursor); + paintCursorCell(cursor); - m_CursorNybble = 0; - m_CursorValue = 0; + m_CursorOffsetBase = offset; /* save before alignment for size changes */ + + /* Align to value size boundary */ + offset &= ~(cl_addr_t)(m_Size - 1); /* Check bounds */ if (offset < m_PositionMin) @@ -370,10 +453,13 @@ void CleHexWidget::setCursorOffset(cl_addr_t offset) else m_CursorOffset = offset; - /* Repaint new highlight */ - cursor = (m_CursorOffset - m_Position) & 0xFF; + /* Set new highlight directly into m_Image */ + cursor = ((m_CursorOffset - m_Position) & 0xFF) / m_Size; + m_CursorNybble = 0; + m_CursorValue = 0; + sscanf(m_Texts[cursor], "%llX", (unsigned long long*)&m_CursorValue); m_RectColors[cursor].setBlue(255); - repaintRect(NULL, cursor); + paintCursorCell(cursor); update(); } @@ -399,8 +485,8 @@ void CleHexWidget::setOffset(cl_addr_t offset) m_Painter->drawText(m_AddrRects[i], Qt::AlignRight | Qt::AlignVCenter, m_AddrTexts[i]); } resetColors(); - setCursorOffset(m_CursorOffset); m_Position = offset; + setCursorOffset(m_CursorOffset); emit offsetEdited(offset); } @@ -428,6 +514,19 @@ void CleHexWidget::setSize(uint8_t size) m_AsciiRects[i].moveTo(64 + 384 + ((i * 8) % 128), (i / 16) * 16); } resetColors(); + + /* Re-align cursor from the saved byte-level base to the new size boundary. + This preserves position when sizing down and snaps to alignment when sizing up. */ + m_CursorOffset = m_CursorOffsetBase & ~(cl_addr_t)(size - 1); + if (m_PositionMin != (cl_addr_t)-1 && m_CursorOffset < m_PositionMin) + m_CursorOffset = m_PositionMin & ~(cl_addr_t)(size - 1); + else if (m_PositionMax != (cl_addr_t)-1 && m_CursorOffset >= m_PositionMax) + m_CursorOffset = (m_PositionMax - size) & ~(cl_addr_t)(size - 1); + + uint8_t cursor = ((m_CursorOffset - m_Position) & 0xFF) / size; + m_RectColors[cursor].setBlue(255); + paintCursorCell(cursor); + update(); } QSize CleHexWidget::sizeHint() const @@ -437,15 +536,28 @@ QSize CleHexWidget::sizeHint() const void CleHexWidget::typeNybble(uint8_t value) { - /* TODO: Discern which byte of a (half)word just got edited here */ - if (m_CursorNybble % 2 == 0) - value <<= 4; + uint8_t total_nybbles = m_Size * 2; + uint8_t shift = (total_nybbles - 1 - m_CursorNybble) * 4; + + m_CursorValue &= ~((uint64_t)0xF << shift); + m_CursorValue |= (uint64_t)value << shift; m_CursorNybble++; - m_CursorValue += value; - if (m_CursorNybble >= m_Size * 2) + /* Update cell text to show the partial value being typed */ + uint8_t cursor = ((m_CursorOffset - m_Position) & 0xFF) / m_Size; + switch (m_Size) + { + case 1: snprintf(m_Texts[cursor], 16, "%02X", (unsigned)m_CursorValue); break; + case 2: snprintf(m_Texts[cursor], 16, "%04X", (unsigned)m_CursorValue); break; + case 4: snprintf(m_Texts[cursor], 16, "%08X", (unsigned)m_CursorValue); break; + case 8: snprintf(m_Texts[cursor], 16, "%016llX", (unsigned long long)m_CursorValue); break; + } + paintCursorCell(cursor); + update(); + + if (m_CursorNybble >= total_nybbles) { - emit valueEdited(m_CursorOffset, m_CursorValue); + emit valueEdited(m_CursorOffset, m_CursorValue, m_Size); setCursorOffset(m_CursorOffset + m_Size); } } diff --git a/editor/cle_hex_view.h b/editor/cle_hex_view.h index a6c0919..ac4fafd 100644 --- a/editor/cle_hex_view.h +++ b/editor/cle_hex_view.h @@ -29,9 +29,10 @@ class CleHexWidget : public QWidget void offsetEdited(cl_addr_t offset); void requestAddMemoryNote(cl_addr_t address); void requestPointerSearch(cl_addr_t address); - void valueEdited(cl_addr_t address, uint8_t value); + void valueEdited(cl_addr_t address, uint64_t value, uint8_t size); protected: + void changeEvent(QEvent *event) override; void keyPressEvent(QKeyEvent *event) override; void mousePressEvent(QMouseEvent *event) override; void paintEvent(QPaintEvent *event) override; @@ -56,12 +57,13 @@ private slots: return ((m_CursorOffset - m_Position) & 0xFF) >= 0xF0; } bool isCursorBottomRight() - { - return ((m_CursorOffset - m_Position) & 0xFF) == 0xFF; + { + return (m_CursorOffset - m_Position) / m_Size >= 256 / m_Size - 1; } void movePosition(int32_t offset); + void paintCursorCell(uint8_t index); void repaintAll(); void repaintAscii(const char new_char, uint8_t index); void repaintRect(const void *buffer, uint8_t index); @@ -74,7 +76,7 @@ private slots: QRect m_Rects[256]; QColor m_RectColors[256]; - uint8_t m_Size; + uint8_t m_Size = 1; char m_Texts[256][16]; QRect m_AsciiRects[256]; @@ -95,10 +97,11 @@ private slots: cl_addr_t m_PositionMax = -1; cl_addr_t m_PositionMin = -1; - QRect m_Cursor; - uint8_t m_CursorNybble; - uint32_t m_CursorOffset; - uint32_t m_CursorValue; + QRect m_Cursor; + uint8_t m_CursorNybble; + cl_addr_t m_CursorOffset = 0; + cl_addr_t m_CursorOffsetBase = 0; /* byte-level position before size alignment */ + uint64_t m_CursorValue = 0; }; #endif diff --git a/editor/cle_main.cpp b/editor/cle_main.cpp index cfbd656..af97f2e 100644 --- a/editor/cle_main.cpp +++ b/editor/cle_main.cpp @@ -13,8 +13,6 @@ void cle_init() { m_Application = new QApplication(app_argc, app_argv); - m_Application->setStyle(QStyleFactory::create("Fusion")); - QPalette darkPalette; darkPalette.setColor(QPalette::Window, QColor(53, 53, 53)); darkPalette.setColor(QPalette::WindowText, Qt::white); @@ -30,17 +28,31 @@ void cle_init() darkPalette.setColor(QPalette::Highlight, QColor(26, 183, 234)); darkPalette.setColor(QPalette::HighlightedText, Qt::black); - m_Application->setPalette(darkPalette); - m_Application->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }"); + QStyle *fusionStyle = QStyleFactory::create("Fusion"); + const QString editorSS = "QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }"; + + auto applyEditorTheme = [&](QWidget *w) { + w->setStyle(fusionStyle); + w->setPalette(darkPalette); + w->setStyleSheet(editorSS); + for (QWidget *child : w->findChildren()) + { + child->setStyle(fusionStyle); + child->setPalette(darkPalette); + } + }; m_MemoryInspector = new CleMemoryInspector(); m_MemoryInspector->show(); + applyEditorTheme(m_MemoryInspector); m_MemoryNotes = new CleMemoryNotes(nullptr); m_MemoryNotes->show(); + applyEditorTheme(m_MemoryNotes); m_ScriptEditor = new CleScriptEditorBlock(); m_ScriptEditor->show(); + applyEditorTheme(m_ScriptEditor); } void cle_run() diff --git a/editor/cle_memory_inspector.cpp b/editor/cle_memory_inspector.cpp index c1d15db..7fe17d4 100644 --- a/editor/cle_memory_inspector.cpp +++ b/editor/cle_memory_inspector.cpp @@ -11,6 +11,17 @@ extern "C" #include "../cl_main.h" } +void CleMemoryInspector::applyTheme(QWidget *w) +{ + w->setStyle(style()); + w->setPalette(palette()); + for (QWidget *child : w->findChildren()) + { + child->setStyle(style()); + child->setPalette(palette()); + } +} + void CleMemoryInspector::rebuildLayout() { if (layout()) @@ -27,8 +38,9 @@ void CleMemoryInspector::rebuildLayout() m_Layout->addWidget(m_TableStack, 2, 0, 2, 4); m_Layout->addWidget(m_HexWidget, 4, 0, 2, 3); m_Layout->addWidget(m_Slider, 4, 3, 2, 1); - m_Layout->addWidget(m_Status, 6, 0, 1, 3); - m_Layout->addWidget(m_NewButton, 6, 3, 1, 1); + m_Layout->addWidget(m_RegionTabs, 6, 0, 1, 4); + m_Layout->addWidget(m_Status, 7, 0, 1, 3); + m_Layout->addWidget(m_NewButton, 7, 3, 1, 1); setLayout(m_Layout); } @@ -97,15 +109,22 @@ CleMemoryInspector::CleMemoryInspector() m_BufferCurrent = (uint8_t*)malloc(256); connect(m_HexWidget, SIGNAL(offsetEdited(cl_addr_t)), this, SLOT(onAddressChanged(cl_addr_t))); - connect(m_HexWidget, SIGNAL(valueEdited(cl_addr_t, uint8_t)), - this, SLOT(onHexWidgetValueEdited(cl_addr_t, uint8_t))); + connect(m_HexWidget, SIGNAL(valueEdited(cl_addr_t, uint64_t, uint8_t)), + this, SLOT(onHexWidgetValueEdited(cl_addr_t, uint64_t, uint8_t))); connect(m_HexWidget, SIGNAL(requestAddMemoryNote(cl_addr_t)), this, SLOT(requestAddMemoryNote(cl_addr_t))); connect(m_HexWidget, SIGNAL(requestPointerSearch(cl_addr_t)), this, SLOT(requestPointerSearch(cl_addr_t))); - m_HexWidget->setByteSwapEnabled(memory.regions[0].endianness == CL_ENDIAN_BIG); - m_HexWidget->setOffset(memory.regions[0].base_guest); - m_HexWidget->setRange(memory.regions[0].base_guest, memory.regions[0].base_guest + memory.regions[0].size + 1); + if (memory.region_count > 0) + { + /* Block signals: m_RegionTabs doesn't exist yet, so offsetEdited must + not fire until after the constructor finishes. */ + m_HexWidget->blockSignals(true); + m_HexWidget->setByteSwapEnabled(memory.regions[0].endianness == CL_ENDIAN_BIG); + m_HexWidget->setOffset(memory.regions[0].base_guest); + m_HexWidget->setRange(memory.regions[0].base_guest, memory.regions[0].base_guest + memory.regions[0].size + 1); + m_HexWidget->blockSignals(false); + } /* Initialize status footer */ m_Status = new QLabel(tr("Matches: 0 | Scanned: 0 MB | Scan time: 0.00 s")); @@ -126,12 +145,18 @@ CleMemoryInspector::CleMemoryInspector() m_TableStack = new QStackedWidget(this); m_TableStack->addWidget(m_CurrentSearch->table()); + m_RegionTabs = new QTabBar(); + m_RegionTabs->setExpanding(false); + m_RegionTabs->hide(); + connect(m_RegionTabs, &QTabBar::currentChanged, + this, &CleMemoryInspector::onChangeRegionTab); + rebuildLayout(); setWindowTitle(tr("Live Editor")); /* Initialize other variables */ m_AddressOffset = 0; - m_CurrentMembank = &memory.regions[0]; + m_CurrentMembank = (memory.region_count > 0) ? &memory.regions[0] : nullptr; m_TabCount = 1; m_MemoryNoteSubmit = nullptr; @@ -158,10 +183,23 @@ void CleMemoryInspector::onAddressChanged(cl_addr_t address) if (m_CurrentMembank != new_bank) { m_CurrentMembank = new_bank; + m_CurrentRegionSize = new_bank->size; m_HexWidget->setRange(new_bank->base_guest, new_bank->base_guest + new_bank->size + 1); m_Slider->setMinimum(0); m_Slider->setMaximum(new_bank->size - 256); + + /* Sync the region tab to the newly active bank */ + for (unsigned i = 0; i < memory.region_count; i++) + { + if (&memory.regions[i] == new_bank) + { + m_RegionTabs->blockSignals(true); + m_RegionTabs->setCurrentIndex(static_cast(i)); + m_RegionTabs->blockSignals(false); + break; + } + } } m_AddressOffset = address - m_CurrentMembank->base_guest; @@ -219,6 +257,7 @@ void CleMemoryInspector::onChangeTab(void) m_Searches[new_tab]->setValueType(getCurrentSizeType()); m_SizeDropdown->setDisabled(false); m_TableStack->addWidget(m_Searches[new_tab]->table()); + applyTheme(m_Searches[new_tab]->table()); } m_CurrentSearch = m_Searches[new_tab]; m_CurrentSearch->rebuild(); @@ -244,6 +283,7 @@ void CleMemoryInspector::onClickNew() m_TableStack->insertWidget(m_Tabs->currentIndex(), m_CurrentSearch->table()); m_TableStack->setCurrentWidget(m_CurrentSearch->table()); + applyTheme(m_CurrentSearch->table()); m_Tabs->setTabTextColor(m_Tabs->currentIndex(), Qt::white); m_CurrentSearch->setCompareType(getCurrentCompareType()); @@ -275,9 +315,9 @@ void CleMemoryInspector::onClickSearch() } } -void CleMemoryInspector::onHexWidgetValueEdited(cl_addr_t address, uint8_t value) +void CleMemoryInspector::onHexWidgetValueEdited(cl_addr_t address, uint64_t value, uint8_t size) { - cl_write_memory_value(&value, NULL, address, CL_MEMTYPE_UINT8); + cl_write_memory_value(&value, NULL, address, cl_pointer_type(size)); } void CleMemoryInspector::onClickTabRename(void) @@ -323,7 +363,7 @@ void CleMemoryInspector::onTargetChanged(const QString& target) m_TextEntry->setStyleSheet("color: gray;"); } else - m_TextEntry->setStyleSheet("color: white;"); + m_TextEntry->setStyleSheet(""); } void CleMemoryInspector::requestAddMemoryNote(cl_memnote_t note) @@ -373,6 +413,7 @@ void CleMemoryInspector::requestPointerSearch(cl_addr_t address) m_TabCount++; m_TableStack->addWidget(m_Searches[m_TabCount-1]->table()); + applyTheme(m_Searches[m_TabCount-1]->table()); m_Tabs->setCurrentIndex(m_TabCount - 1); m_Tabs->setTabText(m_Tabs->currentIndex(), tr("Pointers")); m_Tabs->setTabTextColor(m_Tabs->currentIndex(), QColor(200, 180, 255)); @@ -380,8 +421,63 @@ void CleMemoryInspector::requestPointerSearch(cl_addr_t address) m_CurrentSearch = m_Searches[m_TabCount - 1]; } +void CleMemoryInspector::onChangeRegionTab(int index) +{ + if (index < 0 || (unsigned)index >= memory.region_count) + return; + + cl_memory_region_t *region = &memory.regions[index]; + m_CurrentMembank = region; + m_CurrentRegionSize = region->size; + m_HexWidget->setByteSwapEnabled(region->endianness == CL_ENDIAN_BIG); + m_HexWidget->setRange(region->base_guest, region->base_guest + region->size + 1); + m_Slider->setMinimum(0); + m_Slider->setMaximum(region->size - 256); + m_AddressOffset = 0; +} + void CleMemoryInspector::run() { + /* Rebuild region tabs when region count changes */ + if (memory.region_count != m_CurrentRegionCount) + { + m_CurrentRegionCount = memory.region_count; + m_RegionTabs->blockSignals(true); + while (m_RegionTabs->count()) + m_RegionTabs->removeTab(0); + for (unsigned i = 0; i < memory.region_count; i++) + { + const char *title = memory.regions[i].title; + QString label = (title && title[0]) + ? QString(title) + : QString("0x%1").arg(memory.regions[i].base_guest, 0, 16); + m_RegionTabs->addTab(label); + } + m_RegionTabs->blockSignals(false); + m_RegionTabs->setVisible(memory.region_count > 1); + + /* Memory regions just became available — initialize the active bank */ + if (!m_CurrentMembank && memory.region_count > 0) + { + m_CurrentMembank = &memory.regions[0]; + m_HexWidget->setByteSwapEnabled(m_CurrentMembank->endianness == CL_ENDIAN_BIG); + m_HexWidget->setOffset(m_CurrentMembank->base_guest); + } + } + + if (!m_CurrentMembank) + return; + + /* Detect region size changes (e.g. when a game is loaded after init) */ + if (m_CurrentMembank->size != m_CurrentRegionSize) + { + m_CurrentRegionSize = m_CurrentMembank->size; + m_HexWidget->setRange(m_CurrentMembank->base_guest, + m_CurrentMembank->base_guest + m_CurrentMembank->size + 1); + m_Slider->setMinimum(0); + m_Slider->setMaximum(m_CurrentMembank->size - 256); + } + m_CurrentSearch->run(); cl_read_memory_buffer(m_BufferCurrent, nullptr, m_AddressOffset + m_CurrentMembank->base_guest, 256); m_HexWidget->refresh(m_BufferCurrent, m_BufferPrevious); diff --git a/editor/cle_memory_inspector.h b/editor/cle_memory_inspector.h index d19c37d..4b56107 100644 --- a/editor/cle_memory_inspector.h +++ b/editor/cle_memory_inspector.h @@ -47,14 +47,17 @@ public slots: cl_memory_region_t *m_CurrentMembank = nullptr; - uint32_t m_AddressOffset; + cl_addr_t m_AddressOffset; + cl_addr_t m_CurrentRegionSize = 0; + unsigned m_CurrentRegionCount = 0; uint8_t *m_BufferPrevious = nullptr; uint8_t *m_BufferCurrent = nullptr; int8_t m_ClickedTab; uint8_t m_TabCount; - + QComboBox *m_CompareDropdown = nullptr; QGridLayout *m_Layout = nullptr; + QTabBar *m_RegionTabs = nullptr; QComboBox *m_SizeDropdown = nullptr; QLineEdit *m_TextEntry = nullptr; QPushButton *m_NewButton = nullptr; @@ -67,11 +70,13 @@ public slots: cl_compare_type getCurrentCompareType(void); cl_value_type getCurrentSizeType(void); + void applyTheme(QWidget *w); void rebuildLayout(void); private slots: void onAddressChanged(cl_addr_t address); void onChangeCompareType(); + void onChangeRegionTab(int index); void onChangeScrollbar(int value); void onChangeSizeType(); void onChangeTab(); @@ -79,7 +84,7 @@ private slots: void onClickSearch(); void onClickTabRename(); - void onHexWidgetValueEdited(cl_addr_t address, uint8_t value); + void onHexWidgetValueEdited(cl_addr_t address, uint64_t value, uint8_t size); void onRightClickTabs(const QPoint &pos);