#include "rc_util.h" #include "rc_compat.h" #include "rc_error.h" #include #include #undef DEBUG_BUFFERS /* --- rc_buffer --- */ void rc_buffer_init(rc_buffer_t* buffer) { buffer->chunk.write = buffer->chunk.start = &buffer->data[0]; buffer->chunk.end = &buffer->data[sizeof(buffer->data)]; buffer->chunk.next = NULL; /* leave buffer->data uninitialized */ } void rc_buffer_destroy(rc_buffer_t* buffer) { rc_buffer_chunk_t* chunk; #ifdef DEBUG_BUFFERS int count = 0; int wasted = 0; int total = 0; #endif /* first chunk is not allocated. skip it. */ chunk = buffer->chunk.next; /* deallocate any additional buffers */ while (chunk) { rc_buffer_chunk_t* next = chunk->next; #ifdef DEBUG_BUFFERS total += (int)(chunk->end - chunk->start); wasted += (int)(chunk->end - chunk->write); ++count; #endif free(chunk); chunk = next; } #ifdef DEBUG_BUFFERS printf("-- %d allocated buffers (%d/%d used, %d wasted, %0.2f%% efficiency)\n", count, total - wasted, total, wasted, (float)(100.0 - (wasted * 100.0) / total)); #endif } uint8_t* rc_buffer_reserve(rc_buffer_t* buffer, size_t amount) { rc_buffer_chunk_t* chunk = &buffer->chunk; size_t remaining; while (chunk) { remaining = chunk->end - chunk->write; if (remaining >= amount) return chunk->write; if (!chunk->next) { /* allocate a chunk of memory that is a multiple of 256-bytes. the first 32 bytes will be associated * to the chunk header, and the remaining will be used for data. */ const size_t chunk_header_size = sizeof(rc_buffer_chunk_t); const size_t alloc_size = (chunk_header_size + amount + 0xFF) & ~0xFF; chunk->next = (rc_buffer_chunk_t*)malloc(alloc_size); if (!chunk->next) break; chunk->next->start = (uint8_t*)chunk->next + chunk_header_size; chunk->next->write = chunk->next->start; chunk->next->end = (uint8_t*)chunk->next + alloc_size; chunk->next->next = NULL; } chunk = chunk->next; } return NULL; } void rc_buffer_consume(rc_buffer_t* buffer, const uint8_t* start, uint8_t* end) { rc_buffer_chunk_t* chunk = &buffer->chunk; do { if (chunk->write == start) { size_t offset = (end - chunk->start); offset = (offset + 7) & ~7; chunk->write = &chunk->start[offset]; if (chunk->write > chunk->end) chunk->write = chunk->end; break; } chunk = chunk->next; } while (chunk); } void* rc_buffer_alloc(rc_buffer_t* buffer, size_t amount) { uint8_t* ptr = rc_buffer_reserve(buffer, amount); rc_buffer_consume(buffer, ptr, ptr + amount); return (void*)ptr; } char* rc_buffer_strncpy(rc_buffer_t* buffer, const char* src, size_t len) { uint8_t* dst = rc_buffer_reserve(buffer, len + 1); memcpy(dst, src, len); dst[len] = '\0'; rc_buffer_consume(buffer, dst, dst + len + 2); return (char*)dst; } char* rc_buffer_strcpy(rc_buffer_t* buffer, const char* src) { return rc_buffer_strncpy(buffer, src, strlen(src)); } /* --- other --- */ void rc_format_md5(char checksum[33], const uint8_t digest[16]) { snprintf(checksum, 33, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7], digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15] ); } uint32_t rc_djb2(const char* input) { uint32_t result = 5381; char c; while ((c = *input++) != '\0') result = ((result << 5) + result) + c; /* result = result * 33 + c */ return result; } const char* rc_error_str(int ret) { switch (ret) { case RC_OK: return "OK"; case RC_INVALID_LUA_OPERAND: return "Invalid Lua operand"; case RC_INVALID_MEMORY_OPERAND: return "Invalid memory operand"; case RC_INVALID_CONST_OPERAND: return "Invalid constant operand"; case RC_INVALID_FP_OPERAND: return "Invalid floating-point operand"; case RC_INVALID_CONDITION_TYPE: return "Invalid condition type"; case RC_INVALID_OPERATOR: return "Invalid operator"; case RC_INVALID_REQUIRED_HITS: return "Invalid required hits"; case RC_DUPLICATED_START: return "Duplicated start condition"; case RC_DUPLICATED_CANCEL: return "Duplicated cancel condition"; case RC_DUPLICATED_SUBMIT: return "Duplicated submit condition"; case RC_DUPLICATED_VALUE: return "Duplicated value expression"; case RC_DUPLICATED_PROGRESS: return "Duplicated progress expression"; case RC_MISSING_START: return "Missing start condition"; case RC_MISSING_CANCEL: return "Missing cancel condition"; case RC_MISSING_SUBMIT: return "Missing submit condition"; case RC_MISSING_VALUE: return "Missing value expression"; case RC_INVALID_LBOARD_FIELD: return "Invalid field in leaderboard"; case RC_MISSING_DISPLAY_STRING: return "Missing display string"; case RC_OUT_OF_MEMORY: return "Out of memory"; case RC_INVALID_VALUE_FLAG: return "Invalid flag in value expression"; case RC_MISSING_VALUE_MEASURED: return "Missing measured flag in value expression"; case RC_MULTIPLE_MEASURED: return "Multiple measured targets"; case RC_INVALID_MEASURED_TARGET: return "Invalid measured target"; case RC_INVALID_COMPARISON: return "Invalid comparison"; case RC_INVALID_STATE: return "Invalid state"; case RC_INVALID_JSON: return "Invalid JSON"; case RC_API_FAILURE: return "API call failed"; case RC_LOGIN_REQUIRED: return "Login required"; case RC_NO_GAME_LOADED: return "No game loaded"; case RC_HARDCORE_DISABLED: return "Hardcore disabled"; case RC_ABORTED: return "Aborted"; case RC_NO_RESPONSE: return "No response"; case RC_ACCESS_DENIED: return "Access denied"; case RC_INVALID_CREDENTIALS: return "Invalid credentials"; case RC_EXPIRED_TOKEN: return "Expired token"; case RC_INSUFFICIENT_BUFFER: return "Buffer not large enough"; case RC_INVALID_VARIABLE_NAME: return "Invalid variable name"; case RC_UNKNOWN_VARIABLE_NAME: return "Unknown variable name"; default: return "Unknown error"; } }