From 00c36817a30059ffb329848449de65386501bafb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Do=CC=88ring?= Date: Mon, 30 Oct 2023 23:01:53 +0100 Subject: [PATCH] Buffer serializsation + fixed warnings --- generator/src/PHPGLFWBuffer.php | 32 +- generator/templates/phpglfw_buffer.c.php | 112 ++-- generator/templates/phpglfw_math.c.php | 10 +- phpglfw.c | 12 + phpglfw_buffer.c | 782 +++++++++++++++-------- phpglfw_math.c | 23 +- phpglfw_objparser.c | 2 +- vendor/cvector/cvector.h | 17 + 8 files changed, 667 insertions(+), 323 deletions(-) diff --git a/generator/src/PHPGLFWBuffer.php b/generator/src/PHPGLFWBuffer.php index 99b3745b..4b35441b 100644 --- a/generator/src/PHPGLFWBuffer.php +++ b/generator/src/PHPGLFWBuffer.php @@ -109,9 +109,33 @@ public function getPrintfFormat() : string { switch($this->type) { case "GLfloat": + return '%.9g'; + case "GLdouble": + return "%.17g"; + case "GLint": + return "%d"; + case "GLuint": + return "%u"; + case "GLshort": + return "%hd"; + case "GLushort": case "GLhalf": + return "%hu"; + case "GLbyte": + return "%hhd"; + case "GLubyte": + return "%hhu"; + default: + throw new \Exception("Unknown type {$this->type} for printf format"); + } + } + + public function getPrintfHexFormat() : string + { + switch($this->type) { + case "GLfloat": case "GLdouble": - return "%f"; + return "%a"; case "GLint": return "%d"; case "GLuint": @@ -119,6 +143,7 @@ public function getPrintfFormat() : string case "GLshort": return "%hd"; case "GLushort": + case "GLhalf": return "%hu"; case "GLbyte": return "%hhd"; @@ -128,4 +153,9 @@ public function getPrintfFormat() : string throw new \Exception("Unknown type {$this->type} for printf format"); } } + + public function isPrintfSameInHex() : bool + { + return $this->getPrintfFormat() === $this->getPrintfHexFormat(); + } } diff --git a/generator/templates/phpglfw_buffer.c.php b/generator/templates/phpglfw_buffer.c.php index af9ce1c7..c56dd38e 100644 --- a/generator/templates/phpglfw_buffer.c.php +++ b/generator/templates/phpglfw_buffer.c.php @@ -281,27 +281,55 @@ static int getHandlerMethodName('serialize'); ?>(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data) { +isPrintfSameInHex()) : ?> + bool serialize_hex_float = INI_BOOL("glfw.buffer_serialize_hex_float"); + getObjectName(); ?> *obj_ptr = objectFromZObjFunctionName(); ?>(Z_OBJ_P(object)); size_t num_elements = cvector_size(obj_ptr->vec); - - size_t required_size = snprintf(NULL, 0, "%zu:", num_elements); - - required_size += num_elements * snprintf(NULL, 0, "getPrintfFormat(); ?> ", 0); - - char *buf = emalloc(required_size + 1); // + null byte - if (!buf) { - return FAILURE; + // I want the standard serialization format to be human readable and easaly reconstructable + // which is why I use a simple format of: : ... + // More efficent serialization formats should be added as seperate, deticated functions + cvector_vector_type(char) buffer_string = NULL; + + // used to temporarly store the string representation of each element + // honestly I could not find a proper description of the maximum length of a double represented as + // string, after spending an hour down that rabbit hole I decided to just use a buffer of 256 bytes + char tmp[256]; + + // reserve some space for the string, its going to be more + // at the end but saves the first few reallocs + cvector_reserve(buffer_string, num_elements * sizeof(type; ?>)); + + // write the number of elements + int offset = sprintf(tmp, "%zu:", num_elements); + cvector_push_back_array(buffer_string, tmp, offset); + + // write each element +isPrintfSameInHex()) : ?> + if (serialize_hex_float) { + for (size_t i = 0; i < num_elements; i++) { + offset = sprintf(tmp, "getPrintfHexFormat(); ?> ", obj_ptr->vec[i]); + cvector_push_back_array(buffer_string, tmp, offset); + } + } else { + + for (size_t i = 0; i < num_elements; i++) { + offset = sprintf(tmp, "getPrintfFormat(); ?> ", obj_ptr->vec[i]); + cvector_push_back_array(buffer_string, tmp, offset); + } +isPrintfSameInHex()) : ?> } + - size_t offset = sprintf(buf, "%zu:", num_elements); - for (size_t i = 0; i < num_elements; i++) { - offset += sprintf(buf + offset, "getPrintfFormat(); ?> ", obj_ptr->vec[i]); - } + // trim away the trailing space + cvector_pop_back(buffer_string); - *buffer = (unsigned char *)estrndup(buf, required_size); - *buf_len = required_size; - efree(buf); + size_t total_size = cvector_size(buffer_string); + + *buffer = (unsigned char *)estrndup(buffer_string, total_size); + *buf_len = total_size; + // efree(buf); return SUCCESS; } @@ -310,49 +338,47 @@ { getObjectName(); ?> *obj; - size_t item_count; + size_t exp_item_count, item_count; char *endptr, *token; - - // print the buffer for debugging and the raw buffer as a normal string - printf("Raw Buffer: "); - for (size_t i = 0; i < buf_len; i++) { - printf("%c", buf[i]); - } - printf("\n"); - - token = strtok((char *)buf, ":"); - if (!token) { - zend_throw_error(NULL, "Invalid format during getObjectName(); ?> unserialization"); + + // prints the buffer for debugging + // for (size_t i = 0; i < buf_len; i++) { + // printf("%c", buf[i]); + // } + // printf("\n"); + + // read the number of elements + exp_item_count = item_count = strtoul((char *)buf, &endptr, 10); + if (endptr == (char *)buf || *endptr != ':') { + // Failed to parse the number of elements + zend_throw_error(NULL, "Invalid format during getObjectName(); ?> unserialization, could not parse the number of elements."); return FAILURE; } - printf("Token: %s\n", token); - item_count = strtoul(token, &endptr, 10); - if (*endptr != '\0') { - zend_throw_error(NULL, "Invalid item count during getObjectName(); ?> unserialization"); - return FAILURE; - } + // skip the ':' + endptr++; + // make the object object_init_ex(object, getClassEntryName(); ?>); obj = objectFromZObjFunctionName(); ?>(Z_OBJ_P(object)); - cvector_reserve(obj->vec, item_count); - cvector_set_size(obj->vec, item_count); + cvector_reserve(obj->vec, exp_item_count); - size_t index = 0; - while ((token = strtok(NULL, " ")) && index < item_count) { - /*type == "GLfloat" || $buffer->type == "GLhalf" || $buffer->type == "GLdouble"): ?> - obj->vec[index++] = atof(token); + // read the elements, check if our endptr is still valid and we have not reached the end of the buffer + while ((token = strtok(endptr, " ")) && item_count > 0 && endptr < (char *)buf + buf_len) { + type == "GLfloat" || $buffer->type == "GLhalf" || $buffer->type == "GLdouble"): ?> + cvector_push_back(obj->vec, atof(token)); type == "GLint" || $buffer->type == "GLuint" || $buffer->type == "GLshort" || $buffer->type == "GLushort" || $buffer->type == "GLbyte" || $buffer->type == "GLubyte"): ?> - obj->vec[index++] = strtol(token, NULL, 10); + cvector_push_back(obj->vec, strtol(token, NULL, 10)); zend_throw_error(NULL, "Unknown buffer type for deserialization."); return FAILURE; - */ + + item_count--; } - if (index != item_count) { - zend_throw_error(NULL, "Mismatch in expected item count during getObjectName(); ?> unserialization. Expected: %zu, Found: %zu", item_count, index); + if (cvector_size(obj->vec) != exp_item_count) { + zend_throw_error(NULL, "Mismatch in expected item count during getObjectName(); ?> unserialization. Expected: %zu, Found: %zu", exp_item_count, cvector_size(obj->vec)); return FAILURE; } diff --git a/generator/templates/phpglfw_math.c.php b/generator/templates/phpglfw_math.c.php index 8e17183f..138057d3 100644 --- a/generator/templates/phpglfw_math.c.php +++ b/generator/templates/phpglfw_math.c.php @@ -223,7 +223,7 @@ const unsigned char *buf_end = buf + buf_len; zval *zv; php_unserialize_data_t unserialize_data; - zend_object *zobj; + //zend_object *zobj; PHP_VAR_UNSERIALIZE_INIT(unserialize_data); @@ -234,7 +234,7 @@ for (int y = 0; y < 4; y++) { zv = var_tmp_var(&unserialize_data); if (!php_var_unserialize(zv, &buf_ptr, buf_end, &unserialize_data) || Z_TYPE_P(zv) != IS_DOUBLE) { - zend_throw_error(NULL, "Could not unserialize matrix element", 0); + zend_throw_error(NULL, "Could not unserialize matrix element"); zend_object_std_dtor(&obj->std); efree(obj); PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data); @@ -279,7 +279,7 @@ const unsigned char *buf_end = buf + buf_len; zval *zv; php_unserialize_data_t unserialize_data; - zend_object *zobj; + //zend_object *zobj; PHP_VAR_UNSERIALIZE_INIT(unserialize_data); @@ -289,7 +289,7 @@ for (int i = 0; i < size; ?>; i++) { zv = var_tmp_var(&unserialize_data); if (!php_var_unserialize(zv, &buf_ptr, buf_end, &unserialize_data) || Z_TYPE_P(zv) != IS_DOUBLE) { - zend_throw_error(NULL, "Could not unserialize vector element", 0); + zend_throw_error(NULL, "Could not unserialize vector element"); zend_object_std_dtor(&obj->std); efree(obj); PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data); @@ -750,9 +750,11 @@ PHP_METHOD(getFullNamespaceConstString(); ?>, __construct) { +isMatrix()) : ?> zval *obj; obj = getThis(); getObjectName(); ?> *obj_ptr = objectFromZObjFunctionName(); ?>(Z_OBJ_P(obj)); + isVector()) : ?> getVectorZendParseParamters()); ?> diff --git a/phpglfw.c b/phpglfw.c index 44a97d64..d4fd260a 100644 --- a/phpglfw.c +++ b/phpglfw.c @@ -57,12 +57,24 @@ zend_module_entry glfw_module_entry = { ZEND_GET_MODULE(glfw) #endif +ZEND_BEGIN_MODULE_GLOBALS(glfw) + bool buffer_serialize_hex_float; +ZEND_END_MODULE_GLOBALS(glfw) + +ZEND_DECLARE_MODULE_GLOBALS(glfw) + +PHP_INI_BEGIN() + STD_PHP_INI_ENTRY("glfw.buffer_serialize_hex_float", "false", PHP_INI_ALL, OnUpdateBool, buffer_serialize_hex_float, zend_glfw_globals, glfw_globals) +PHP_INI_END() + /** * MINIT * -------------------------------- */ PHP_MINIT_FUNCTION(glfw) { + REGISTER_INI_ENTRIES(); + // register constants phpglfw_register_constants(INIT_FUNC_ARGS_PASSTHRU); diff --git a/phpglfw_buffer.c b/phpglfw_buffer.c index c177cc79..7f7800bb 100644 --- a/phpglfw_buffer.c +++ b/phpglfw_buffer.c @@ -33,6 +33,7 @@ #include "zend_interfaces.h" #include "linmath.h" +#include "cvector.h" #define pglmax(a,b) ((a) > (b) ? (a) : (b)) #define pglmin(a,b) ((a) < (b) ? (a) : (b)) @@ -337,56 +338,91 @@ int phpglfw_buffer_glfloat_unserialize_handler(zval *object, zend_class_entry *c static int phpglfw_buffer_glfloat_serialize_handler(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data) { + bool serialize_hex_float = INI_BOOL("glfw.buffer_serialize_hex_float"); phpglfw_buffer_glfloat_object *obj_ptr = phpglfw_buffer_glfloat_objectptr_from_zobj_p(Z_OBJ_P(object)); + size_t num_elements = cvector_size(obj_ptr->vec); + + // I want the standard serialization format to be human readable and easaly reconstructable + // which is why I use a simple format of: : ... + // More efficent serialization formats should be added as seperate, deticated functions + cvector_vector_type(char) buffer_string = NULL; + + // used to temporarly store the string representation of each element + // honestly I could not find a proper description of the maximum length of a double represented as + // string, after spending an hour down that rabbit hole I decided to just use a buffer of 256 bytes + char tmp[256]; + + // reserve some space for the string, its going to be more + // at the end but saves the first few reallocs + cvector_reserve(buffer_string, num_elements * sizeof(GLfloat)); + + // write the number of elements + int offset = sprintf(tmp, "%zu:", num_elements); + cvector_push_back_array(buffer_string, tmp, offset); + + // write each element + if (serialize_hex_float) { + for (size_t i = 0; i < num_elements; i++) { + offset = sprintf(tmp, "%a ", obj_ptr->vec[i]); + cvector_push_back_array(buffer_string, tmp, offset); + } + } else { + for (size_t i = 0; i < num_elements; i++) { + offset = sprintf(tmp, "%.9g ", obj_ptr->vec[i]); + cvector_push_back_array(buffer_string, tmp, offset); + } + } - smart_str buf = {0}; - smart_str_append_printf(&buf, "%zu:", cvector_size(obj_ptr->vec)); + // trim away the trailing space + cvector_pop_back(buffer_string); - for (size_t i = 0; i < cvector_size(obj_ptr->vec); i++) { - smart_str_append_printf(&buf, "%f,", obj_ptr->vec[i]); - } + size_t total_size = cvector_size(buffer_string); - smart_str_0(&buf); - *buffer = (unsigned char *)estrndup(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s)); - *buf_len = ZSTR_LEN(buf.s); - smart_str_free(&buf); + *buffer = (unsigned char *)estrndup(buffer_string, total_size); + *buf_len = total_size; + // efree(buf); return SUCCESS; } -int phpglfw_buffer_glfloat_unserialize_handler(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data) +static int phpglfw_buffer_glfloat_unserialize_handler(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data) { phpglfw_buffer_glfloat_object *obj; - size_t item_count; + size_t exp_item_count, item_count; char *endptr, *token; - const char delimiter[] = ":"; - - token = strtok((char *)buf, delimiter); - if (!token) { - zend_throw_error(NULL, "Invalid format during phpglfw_buffer_glfloat_object unserialization"); + + // prints the buffer for debugging + // for (size_t i = 0; i < buf_len; i++) { + // printf("%c", buf[i]); + // } + // printf("\n"); + + // read the number of elements + exp_item_count = item_count = strtoul((char *)buf, &endptr, 10); + if (endptr == (char *)buf || *endptr != ':') { + // Failed to parse the number of elements + zend_throw_error(NULL, "Invalid format during phpglfw_buffer_glfloat_object unserialization, could not parse the number of elements."); return FAILURE; } - item_count = strtoul(token, &endptr, 10); - if (*endptr != '\0') { - zend_throw_error(NULL, "Invalid item count during phpglfw_buffer_glfloat_object unserialization"); - return FAILURE; - } + // skip the ':' + endptr++; + // make the object object_init_ex(object, phpglfw_buffer_glfloat_ce); obj = phpglfw_buffer_glfloat_objectptr_from_zobj_p(Z_OBJ_P(object)); - cvector_reserve(obj->vec, item_count); - cvector_set_size(obj->vec, item_count); + cvector_reserve(obj->vec, exp_item_count); - size_t index = 0; - while ((token = strtok(NULL, ",")) && index < item_count) { - obj->vec[index++] = atof(token); - } + // read the elements, check if our endptr is still valid and we have not reached the end of the buffer + while ((token = strtok(endptr, " ")) && item_count > 0 && endptr < (char *)buf + buf_len) { + cvector_push_back(obj->vec, atof(token)); + item_count--; + } - if (index != item_count) { - zend_throw_error(NULL, "Mismatch in expected item count during phpglfw_buffer_glfloat_object unserialization"); + if (cvector_size(obj->vec) != exp_item_count) { + zend_throw_error(NULL, "Mismatch in expected item count during phpglfw_buffer_glfloat_object unserialization. Expected: %zu, Found: %zu", exp_item_count, cvector_size(obj->vec)); return FAILURE; } @@ -865,55 +901,82 @@ int phpglfw_buffer_glhalf_unserialize_handler(zval *object, zend_class_entry *ce static int phpglfw_buffer_glhalf_serialize_handler(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data) { phpglfw_buffer_glhalf_object *obj_ptr = phpglfw_buffer_glhalf_objectptr_from_zobj_p(Z_OBJ_P(object)); + size_t num_elements = cvector_size(obj_ptr->vec); + + // I want the standard serialization format to be human readable and easaly reconstructable + // which is why I use a simple format of: : ... + // More efficent serialization formats should be added as seperate, deticated functions + cvector_vector_type(char) buffer_string = NULL; + + // used to temporarly store the string representation of each element + // honestly I could not find a proper description of the maximum length of a double represented as + // string, after spending an hour down that rabbit hole I decided to just use a buffer of 256 bytes + char tmp[256]; + + // reserve some space for the string, its going to be more + // at the end but saves the first few reallocs + cvector_reserve(buffer_string, num_elements * sizeof(GLhalf)); + + // write the number of elements + int offset = sprintf(tmp, "%zu:", num_elements); + cvector_push_back_array(buffer_string, tmp, offset); + + // write each element + for (size_t i = 0; i < num_elements; i++) { + offset = sprintf(tmp, "%hu ", obj_ptr->vec[i]); + cvector_push_back_array(buffer_string, tmp, offset); + } - smart_str buf = {0}; - smart_str_append_printf(&buf, "%zu:", cvector_size(obj_ptr->vec)); + // trim away the trailing space + cvector_pop_back(buffer_string); - for (size_t i = 0; i < cvector_size(obj_ptr->vec); i++) { - smart_str_append_printf(&buf, "%f,", obj_ptr->vec[i]); - } + size_t total_size = cvector_size(buffer_string); - smart_str_0(&buf); - *buffer = (unsigned char *)estrndup(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s)); - *buf_len = ZSTR_LEN(buf.s); - smart_str_free(&buf); + *buffer = (unsigned char *)estrndup(buffer_string, total_size); + *buf_len = total_size; + // efree(buf); return SUCCESS; } -int phpglfw_buffer_glhalf_unserialize_handler(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data) +static int phpglfw_buffer_glhalf_unserialize_handler(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data) { phpglfw_buffer_glhalf_object *obj; - size_t item_count; + size_t exp_item_count, item_count; char *endptr, *token; - const char delimiter[] = ":"; - - token = strtok((char *)buf, delimiter); - if (!token) { - zend_throw_error(NULL, "Invalid format during phpglfw_buffer_glhalf_object unserialization"); + + // prints the buffer for debugging + // for (size_t i = 0; i < buf_len; i++) { + // printf("%c", buf[i]); + // } + // printf("\n"); + + // read the number of elements + exp_item_count = item_count = strtoul((char *)buf, &endptr, 10); + if (endptr == (char *)buf || *endptr != ':') { + // Failed to parse the number of elements + zend_throw_error(NULL, "Invalid format during phpglfw_buffer_glhalf_object unserialization, could not parse the number of elements."); return FAILURE; } - item_count = strtoul(token, &endptr, 10); - if (*endptr != '\0') { - zend_throw_error(NULL, "Invalid item count during phpglfw_buffer_glhalf_object unserialization"); - return FAILURE; - } + // skip the ':' + endptr++; + // make the object object_init_ex(object, phpglfw_buffer_glhalf_ce); obj = phpglfw_buffer_glhalf_objectptr_from_zobj_p(Z_OBJ_P(object)); - cvector_reserve(obj->vec, item_count); - cvector_set_size(obj->vec, item_count); + cvector_reserve(obj->vec, exp_item_count); - size_t index = 0; - while ((token = strtok(NULL, ",")) && index < item_count) { - obj->vec[index++] = atof(token); - } + // read the elements, check if our endptr is still valid and we have not reached the end of the buffer + while ((token = strtok(endptr, " ")) && item_count > 0 && endptr < (char *)buf + buf_len) { + cvector_push_back(obj->vec, atof(token)); + item_count--; + } - if (index != item_count) { - zend_throw_error(NULL, "Mismatch in expected item count during phpglfw_buffer_glhalf_object unserialization"); + if (cvector_size(obj->vec) != exp_item_count) { + zend_throw_error(NULL, "Mismatch in expected item count during phpglfw_buffer_glhalf_object unserialization. Expected: %zu, Found: %zu", exp_item_count, cvector_size(obj->vec)); return FAILURE; } @@ -1317,56 +1380,91 @@ int phpglfw_buffer_gldouble_unserialize_handler(zval *object, zend_class_entry * static int phpglfw_buffer_gldouble_serialize_handler(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data) { + bool serialize_hex_float = INI_BOOL("glfw.buffer_serialize_hex_float"); phpglfw_buffer_gldouble_object *obj_ptr = phpglfw_buffer_gldouble_objectptr_from_zobj_p(Z_OBJ_P(object)); + size_t num_elements = cvector_size(obj_ptr->vec); + + // I want the standard serialization format to be human readable and easaly reconstructable + // which is why I use a simple format of: : ... + // More efficent serialization formats should be added as seperate, deticated functions + cvector_vector_type(char) buffer_string = NULL; + + // used to temporarly store the string representation of each element + // honestly I could not find a proper description of the maximum length of a double represented as + // string, after spending an hour down that rabbit hole I decided to just use a buffer of 256 bytes + char tmp[256]; + + // reserve some space for the string, its going to be more + // at the end but saves the first few reallocs + cvector_reserve(buffer_string, num_elements * sizeof(GLdouble)); + + // write the number of elements + int offset = sprintf(tmp, "%zu:", num_elements); + cvector_push_back_array(buffer_string, tmp, offset); + + // write each element + if (serialize_hex_float) { + for (size_t i = 0; i < num_elements; i++) { + offset = sprintf(tmp, "%a ", obj_ptr->vec[i]); + cvector_push_back_array(buffer_string, tmp, offset); + } + } else { + for (size_t i = 0; i < num_elements; i++) { + offset = sprintf(tmp, "%.17g ", obj_ptr->vec[i]); + cvector_push_back_array(buffer_string, tmp, offset); + } + } - smart_str buf = {0}; - smart_str_append_printf(&buf, "%zu:", cvector_size(obj_ptr->vec)); + // trim away the trailing space + cvector_pop_back(buffer_string); - for (size_t i = 0; i < cvector_size(obj_ptr->vec); i++) { - smart_str_append_printf(&buf, "%f,", obj_ptr->vec[i]); - } + size_t total_size = cvector_size(buffer_string); - smart_str_0(&buf); - *buffer = (unsigned char *)estrndup(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s)); - *buf_len = ZSTR_LEN(buf.s); - smart_str_free(&buf); + *buffer = (unsigned char *)estrndup(buffer_string, total_size); + *buf_len = total_size; + // efree(buf); return SUCCESS; } -int phpglfw_buffer_gldouble_unserialize_handler(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data) +static int phpglfw_buffer_gldouble_unserialize_handler(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data) { phpglfw_buffer_gldouble_object *obj; - size_t item_count; + size_t exp_item_count, item_count; char *endptr, *token; - const char delimiter[] = ":"; - - token = strtok((char *)buf, delimiter); - if (!token) { - zend_throw_error(NULL, "Invalid format during phpglfw_buffer_gldouble_object unserialization"); + + // prints the buffer for debugging + // for (size_t i = 0; i < buf_len; i++) { + // printf("%c", buf[i]); + // } + // printf("\n"); + + // read the number of elements + exp_item_count = item_count = strtoul((char *)buf, &endptr, 10); + if (endptr == (char *)buf || *endptr != ':') { + // Failed to parse the number of elements + zend_throw_error(NULL, "Invalid format during phpglfw_buffer_gldouble_object unserialization, could not parse the number of elements."); return FAILURE; } - item_count = strtoul(token, &endptr, 10); - if (*endptr != '\0') { - zend_throw_error(NULL, "Invalid item count during phpglfw_buffer_gldouble_object unserialization"); - return FAILURE; - } + // skip the ':' + endptr++; + // make the object object_init_ex(object, phpglfw_buffer_gldouble_ce); obj = phpglfw_buffer_gldouble_objectptr_from_zobj_p(Z_OBJ_P(object)); - cvector_reserve(obj->vec, item_count); - cvector_set_size(obj->vec, item_count); + cvector_reserve(obj->vec, exp_item_count); - size_t index = 0; - while ((token = strtok(NULL, ",")) && index < item_count) { - obj->vec[index++] = atof(token); - } + // read the elements, check if our endptr is still valid and we have not reached the end of the buffer + while ((token = strtok(endptr, " ")) && item_count > 0 && endptr < (char *)buf + buf_len) { + cvector_push_back(obj->vec, atof(token)); + item_count--; + } - if (index != item_count) { - zend_throw_error(NULL, "Mismatch in expected item count during phpglfw_buffer_gldouble_object unserialization"); + if (cvector_size(obj->vec) != exp_item_count) { + zend_throw_error(NULL, "Mismatch in expected item count during phpglfw_buffer_gldouble_object unserialization. Expected: %zu, Found: %zu", exp_item_count, cvector_size(obj->vec)); return FAILURE; } @@ -1771,55 +1869,82 @@ int phpglfw_buffer_glint_unserialize_handler(zval *object, zend_class_entry *ce, static int phpglfw_buffer_glint_serialize_handler(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data) { phpglfw_buffer_glint_object *obj_ptr = phpglfw_buffer_glint_objectptr_from_zobj_p(Z_OBJ_P(object)); + size_t num_elements = cvector_size(obj_ptr->vec); + + // I want the standard serialization format to be human readable and easaly reconstructable + // which is why I use a simple format of: : ... + // More efficent serialization formats should be added as seperate, deticated functions + cvector_vector_type(char) buffer_string = NULL; + + // used to temporarly store the string representation of each element + // honestly I could not find a proper description of the maximum length of a double represented as + // string, after spending an hour down that rabbit hole I decided to just use a buffer of 256 bytes + char tmp[256]; + + // reserve some space for the string, its going to be more + // at the end but saves the first few reallocs + cvector_reserve(buffer_string, num_elements * sizeof(GLint)); + + // write the number of elements + int offset = sprintf(tmp, "%zu:", num_elements); + cvector_push_back_array(buffer_string, tmp, offset); + + // write each element + for (size_t i = 0; i < num_elements; i++) { + offset = sprintf(tmp, "%d ", obj_ptr->vec[i]); + cvector_push_back_array(buffer_string, tmp, offset); + } - smart_str buf = {0}; - smart_str_append_printf(&buf, "%zu:", cvector_size(obj_ptr->vec)); + // trim away the trailing space + cvector_pop_back(buffer_string); - for (size_t i = 0; i < cvector_size(obj_ptr->vec); i++) { - smart_str_append_printf(&buf, "%d,", obj_ptr->vec[i]); - } + size_t total_size = cvector_size(buffer_string); - smart_str_0(&buf); - *buffer = (unsigned char *)estrndup(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s)); - *buf_len = ZSTR_LEN(buf.s); - smart_str_free(&buf); + *buffer = (unsigned char *)estrndup(buffer_string, total_size); + *buf_len = total_size; + // efree(buf); return SUCCESS; } -int phpglfw_buffer_glint_unserialize_handler(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data) +static int phpglfw_buffer_glint_unserialize_handler(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data) { phpglfw_buffer_glint_object *obj; - size_t item_count; + size_t exp_item_count, item_count; char *endptr, *token; - const char delimiter[] = ":"; - - token = strtok((char *)buf, delimiter); - if (!token) { - zend_throw_error(NULL, "Invalid format during phpglfw_buffer_glint_object unserialization"); + + // prints the buffer for debugging + // for (size_t i = 0; i < buf_len; i++) { + // printf("%c", buf[i]); + // } + // printf("\n"); + + // read the number of elements + exp_item_count = item_count = strtoul((char *)buf, &endptr, 10); + if (endptr == (char *)buf || *endptr != ':') { + // Failed to parse the number of elements + zend_throw_error(NULL, "Invalid format during phpglfw_buffer_glint_object unserialization, could not parse the number of elements."); return FAILURE; } - item_count = strtoul(token, &endptr, 10); - if (*endptr != '\0') { - zend_throw_error(NULL, "Invalid item count during phpglfw_buffer_glint_object unserialization"); - return FAILURE; - } + // skip the ':' + endptr++; + // make the object object_init_ex(object, phpglfw_buffer_glint_ce); obj = phpglfw_buffer_glint_objectptr_from_zobj_p(Z_OBJ_P(object)); - cvector_reserve(obj->vec, item_count); - cvector_set_size(obj->vec, item_count); + cvector_reserve(obj->vec, exp_item_count); - size_t index = 0; - while ((token = strtok(NULL, ",")) && index < item_count) { - obj->vec[index++] = strtol(token, NULL, 10); - } + // read the elements, check if our endptr is still valid and we have not reached the end of the buffer + while ((token = strtok(endptr, " ")) && item_count > 0 && endptr < (char *)buf + buf_len) { + cvector_push_back(obj->vec, strtol(token, NULL, 10)); + item_count--; + } - if (index != item_count) { - zend_throw_error(NULL, "Mismatch in expected item count during phpglfw_buffer_glint_object unserialization"); + if (cvector_size(obj->vec) != exp_item_count) { + zend_throw_error(NULL, "Mismatch in expected item count during phpglfw_buffer_glint_object unserialization. Expected: %zu, Found: %zu", exp_item_count, cvector_size(obj->vec)); return FAILURE; } @@ -2224,55 +2349,82 @@ int phpglfw_buffer_gluint_unserialize_handler(zval *object, zend_class_entry *ce static int phpglfw_buffer_gluint_serialize_handler(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data) { phpglfw_buffer_gluint_object *obj_ptr = phpglfw_buffer_gluint_objectptr_from_zobj_p(Z_OBJ_P(object)); + size_t num_elements = cvector_size(obj_ptr->vec); + + // I want the standard serialization format to be human readable and easaly reconstructable + // which is why I use a simple format of: : ... + // More efficent serialization formats should be added as seperate, deticated functions + cvector_vector_type(char) buffer_string = NULL; + + // used to temporarly store the string representation of each element + // honestly I could not find a proper description of the maximum length of a double represented as + // string, after spending an hour down that rabbit hole I decided to just use a buffer of 256 bytes + char tmp[256]; + + // reserve some space for the string, its going to be more + // at the end but saves the first few reallocs + cvector_reserve(buffer_string, num_elements * sizeof(GLuint)); + + // write the number of elements + int offset = sprintf(tmp, "%zu:", num_elements); + cvector_push_back_array(buffer_string, tmp, offset); + + // write each element + for (size_t i = 0; i < num_elements; i++) { + offset = sprintf(tmp, "%u ", obj_ptr->vec[i]); + cvector_push_back_array(buffer_string, tmp, offset); + } - smart_str buf = {0}; - smart_str_append_printf(&buf, "%zu:", cvector_size(obj_ptr->vec)); + // trim away the trailing space + cvector_pop_back(buffer_string); - for (size_t i = 0; i < cvector_size(obj_ptr->vec); i++) { - smart_str_append_printf(&buf, "%u,", obj_ptr->vec[i]); - } + size_t total_size = cvector_size(buffer_string); - smart_str_0(&buf); - *buffer = (unsigned char *)estrndup(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s)); - *buf_len = ZSTR_LEN(buf.s); - smart_str_free(&buf); + *buffer = (unsigned char *)estrndup(buffer_string, total_size); + *buf_len = total_size; + // efree(buf); return SUCCESS; } -int phpglfw_buffer_gluint_unserialize_handler(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data) +static int phpglfw_buffer_gluint_unserialize_handler(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data) { phpglfw_buffer_gluint_object *obj; - size_t item_count; + size_t exp_item_count, item_count; char *endptr, *token; - const char delimiter[] = ":"; - - token = strtok((char *)buf, delimiter); - if (!token) { - zend_throw_error(NULL, "Invalid format during phpglfw_buffer_gluint_object unserialization"); + + // prints the buffer for debugging + // for (size_t i = 0; i < buf_len; i++) { + // printf("%c", buf[i]); + // } + // printf("\n"); + + // read the number of elements + exp_item_count = item_count = strtoul((char *)buf, &endptr, 10); + if (endptr == (char *)buf || *endptr != ':') { + // Failed to parse the number of elements + zend_throw_error(NULL, "Invalid format during phpglfw_buffer_gluint_object unserialization, could not parse the number of elements."); return FAILURE; } - item_count = strtoul(token, &endptr, 10); - if (*endptr != '\0') { - zend_throw_error(NULL, "Invalid item count during phpglfw_buffer_gluint_object unserialization"); - return FAILURE; - } + // skip the ':' + endptr++; + // make the object object_init_ex(object, phpglfw_buffer_gluint_ce); obj = phpglfw_buffer_gluint_objectptr_from_zobj_p(Z_OBJ_P(object)); - cvector_reserve(obj->vec, item_count); - cvector_set_size(obj->vec, item_count); + cvector_reserve(obj->vec, exp_item_count); - size_t index = 0; - while ((token = strtok(NULL, ",")) && index < item_count) { - obj->vec[index++] = strtol(token, NULL, 10); - } + // read the elements, check if our endptr is still valid and we have not reached the end of the buffer + while ((token = strtok(endptr, " ")) && item_count > 0 && endptr < (char *)buf + buf_len) { + cvector_push_back(obj->vec, strtol(token, NULL, 10)); + item_count--; + } - if (index != item_count) { - zend_throw_error(NULL, "Mismatch in expected item count during phpglfw_buffer_gluint_object unserialization"); + if (cvector_size(obj->vec) != exp_item_count) { + zend_throw_error(NULL, "Mismatch in expected item count during phpglfw_buffer_gluint_object unserialization. Expected: %zu, Found: %zu", exp_item_count, cvector_size(obj->vec)); return FAILURE; } @@ -2677,55 +2829,82 @@ int phpglfw_buffer_glshort_unserialize_handler(zval *object, zend_class_entry *c static int phpglfw_buffer_glshort_serialize_handler(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data) { phpglfw_buffer_glshort_object *obj_ptr = phpglfw_buffer_glshort_objectptr_from_zobj_p(Z_OBJ_P(object)); + size_t num_elements = cvector_size(obj_ptr->vec); + + // I want the standard serialization format to be human readable and easaly reconstructable + // which is why I use a simple format of: : ... + // More efficent serialization formats should be added as seperate, deticated functions + cvector_vector_type(char) buffer_string = NULL; + + // used to temporarly store the string representation of each element + // honestly I could not find a proper description of the maximum length of a double represented as + // string, after spending an hour down that rabbit hole I decided to just use a buffer of 256 bytes + char tmp[256]; + + // reserve some space for the string, its going to be more + // at the end but saves the first few reallocs + cvector_reserve(buffer_string, num_elements * sizeof(GLshort)); + + // write the number of elements + int offset = sprintf(tmp, "%zu:", num_elements); + cvector_push_back_array(buffer_string, tmp, offset); + + // write each element + for (size_t i = 0; i < num_elements; i++) { + offset = sprintf(tmp, "%hd ", obj_ptr->vec[i]); + cvector_push_back_array(buffer_string, tmp, offset); + } - smart_str buf = {0}; - smart_str_append_printf(&buf, "%zu:", cvector_size(obj_ptr->vec)); + // trim away the trailing space + cvector_pop_back(buffer_string); - for (size_t i = 0; i < cvector_size(obj_ptr->vec); i++) { - smart_str_append_printf(&buf, "%hd,", obj_ptr->vec[i]); - } + size_t total_size = cvector_size(buffer_string); - smart_str_0(&buf); - *buffer = (unsigned char *)estrndup(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s)); - *buf_len = ZSTR_LEN(buf.s); - smart_str_free(&buf); + *buffer = (unsigned char *)estrndup(buffer_string, total_size); + *buf_len = total_size; + // efree(buf); return SUCCESS; } -int phpglfw_buffer_glshort_unserialize_handler(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data) +static int phpglfw_buffer_glshort_unserialize_handler(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data) { phpglfw_buffer_glshort_object *obj; - size_t item_count; + size_t exp_item_count, item_count; char *endptr, *token; - const char delimiter[] = ":"; - - token = strtok((char *)buf, delimiter); - if (!token) { - zend_throw_error(NULL, "Invalid format during phpglfw_buffer_glshort_object unserialization"); + + // prints the buffer for debugging + // for (size_t i = 0; i < buf_len; i++) { + // printf("%c", buf[i]); + // } + // printf("\n"); + + // read the number of elements + exp_item_count = item_count = strtoul((char *)buf, &endptr, 10); + if (endptr == (char *)buf || *endptr != ':') { + // Failed to parse the number of elements + zend_throw_error(NULL, "Invalid format during phpglfw_buffer_glshort_object unserialization, could not parse the number of elements."); return FAILURE; } - item_count = strtoul(token, &endptr, 10); - if (*endptr != '\0') { - zend_throw_error(NULL, "Invalid item count during phpglfw_buffer_glshort_object unserialization"); - return FAILURE; - } + // skip the ':' + endptr++; + // make the object object_init_ex(object, phpglfw_buffer_glshort_ce); obj = phpglfw_buffer_glshort_objectptr_from_zobj_p(Z_OBJ_P(object)); - cvector_reserve(obj->vec, item_count); - cvector_set_size(obj->vec, item_count); + cvector_reserve(obj->vec, exp_item_count); - size_t index = 0; - while ((token = strtok(NULL, ",")) && index < item_count) { - obj->vec[index++] = strtol(token, NULL, 10); - } + // read the elements, check if our endptr is still valid and we have not reached the end of the buffer + while ((token = strtok(endptr, " ")) && item_count > 0 && endptr < (char *)buf + buf_len) { + cvector_push_back(obj->vec, strtol(token, NULL, 10)); + item_count--; + } - if (index != item_count) { - zend_throw_error(NULL, "Mismatch in expected item count during phpglfw_buffer_glshort_object unserialization"); + if (cvector_size(obj->vec) != exp_item_count) { + zend_throw_error(NULL, "Mismatch in expected item count during phpglfw_buffer_glshort_object unserialization. Expected: %zu, Found: %zu", exp_item_count, cvector_size(obj->vec)); return FAILURE; } @@ -3130,55 +3309,82 @@ int phpglfw_buffer_glushort_unserialize_handler(zval *object, zend_class_entry * static int phpglfw_buffer_glushort_serialize_handler(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data) { phpglfw_buffer_glushort_object *obj_ptr = phpglfw_buffer_glushort_objectptr_from_zobj_p(Z_OBJ_P(object)); + size_t num_elements = cvector_size(obj_ptr->vec); + + // I want the standard serialization format to be human readable and easaly reconstructable + // which is why I use a simple format of: : ... + // More efficent serialization formats should be added as seperate, deticated functions + cvector_vector_type(char) buffer_string = NULL; + + // used to temporarly store the string representation of each element + // honestly I could not find a proper description of the maximum length of a double represented as + // string, after spending an hour down that rabbit hole I decided to just use a buffer of 256 bytes + char tmp[256]; + + // reserve some space for the string, its going to be more + // at the end but saves the first few reallocs + cvector_reserve(buffer_string, num_elements * sizeof(GLushort)); + + // write the number of elements + int offset = sprintf(tmp, "%zu:", num_elements); + cvector_push_back_array(buffer_string, tmp, offset); + + // write each element + for (size_t i = 0; i < num_elements; i++) { + offset = sprintf(tmp, "%hu ", obj_ptr->vec[i]); + cvector_push_back_array(buffer_string, tmp, offset); + } - smart_str buf = {0}; - smart_str_append_printf(&buf, "%zu:", cvector_size(obj_ptr->vec)); + // trim away the trailing space + cvector_pop_back(buffer_string); - for (size_t i = 0; i < cvector_size(obj_ptr->vec); i++) { - smart_str_append_printf(&buf, "%hu,", obj_ptr->vec[i]); - } + size_t total_size = cvector_size(buffer_string); - smart_str_0(&buf); - *buffer = (unsigned char *)estrndup(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s)); - *buf_len = ZSTR_LEN(buf.s); - smart_str_free(&buf); + *buffer = (unsigned char *)estrndup(buffer_string, total_size); + *buf_len = total_size; + // efree(buf); return SUCCESS; } -int phpglfw_buffer_glushort_unserialize_handler(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data) +static int phpglfw_buffer_glushort_unserialize_handler(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data) { phpglfw_buffer_glushort_object *obj; - size_t item_count; + size_t exp_item_count, item_count; char *endptr, *token; - const char delimiter[] = ":"; - - token = strtok((char *)buf, delimiter); - if (!token) { - zend_throw_error(NULL, "Invalid format during phpglfw_buffer_glushort_object unserialization"); + + // prints the buffer for debugging + // for (size_t i = 0; i < buf_len; i++) { + // printf("%c", buf[i]); + // } + // printf("\n"); + + // read the number of elements + exp_item_count = item_count = strtoul((char *)buf, &endptr, 10); + if (endptr == (char *)buf || *endptr != ':') { + // Failed to parse the number of elements + zend_throw_error(NULL, "Invalid format during phpglfw_buffer_glushort_object unserialization, could not parse the number of elements."); return FAILURE; } - item_count = strtoul(token, &endptr, 10); - if (*endptr != '\0') { - zend_throw_error(NULL, "Invalid item count during phpglfw_buffer_glushort_object unserialization"); - return FAILURE; - } + // skip the ':' + endptr++; + // make the object object_init_ex(object, phpglfw_buffer_glushort_ce); obj = phpglfw_buffer_glushort_objectptr_from_zobj_p(Z_OBJ_P(object)); - cvector_reserve(obj->vec, item_count); - cvector_set_size(obj->vec, item_count); + cvector_reserve(obj->vec, exp_item_count); - size_t index = 0; - while ((token = strtok(NULL, ",")) && index < item_count) { - obj->vec[index++] = strtol(token, NULL, 10); - } + // read the elements, check if our endptr is still valid and we have not reached the end of the buffer + while ((token = strtok(endptr, " ")) && item_count > 0 && endptr < (char *)buf + buf_len) { + cvector_push_back(obj->vec, strtol(token, NULL, 10)); + item_count--; + } - if (index != item_count) { - zend_throw_error(NULL, "Mismatch in expected item count during phpglfw_buffer_glushort_object unserialization"); + if (cvector_size(obj->vec) != exp_item_count) { + zend_throw_error(NULL, "Mismatch in expected item count during phpglfw_buffer_glushort_object unserialization. Expected: %zu, Found: %zu", exp_item_count, cvector_size(obj->vec)); return FAILURE; } @@ -3583,55 +3789,82 @@ int phpglfw_buffer_glbyte_unserialize_handler(zval *object, zend_class_entry *ce static int phpglfw_buffer_glbyte_serialize_handler(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data) { phpglfw_buffer_glbyte_object *obj_ptr = phpglfw_buffer_glbyte_objectptr_from_zobj_p(Z_OBJ_P(object)); + size_t num_elements = cvector_size(obj_ptr->vec); + + // I want the standard serialization format to be human readable and easaly reconstructable + // which is why I use a simple format of: : ... + // More efficent serialization formats should be added as seperate, deticated functions + cvector_vector_type(char) buffer_string = NULL; + + // used to temporarly store the string representation of each element + // honestly I could not find a proper description of the maximum length of a double represented as + // string, after spending an hour down that rabbit hole I decided to just use a buffer of 256 bytes + char tmp[256]; + + // reserve some space for the string, its going to be more + // at the end but saves the first few reallocs + cvector_reserve(buffer_string, num_elements * sizeof(GLbyte)); + + // write the number of elements + int offset = sprintf(tmp, "%zu:", num_elements); + cvector_push_back_array(buffer_string, tmp, offset); + + // write each element + for (size_t i = 0; i < num_elements; i++) { + offset = sprintf(tmp, "%hhd ", obj_ptr->vec[i]); + cvector_push_back_array(buffer_string, tmp, offset); + } - smart_str buf = {0}; - smart_str_append_printf(&buf, "%zu:", cvector_size(obj_ptr->vec)); + // trim away the trailing space + cvector_pop_back(buffer_string); - for (size_t i = 0; i < cvector_size(obj_ptr->vec); i++) { - smart_str_append_printf(&buf, "%hhd,", obj_ptr->vec[i]); - } + size_t total_size = cvector_size(buffer_string); - smart_str_0(&buf); - *buffer = (unsigned char *)estrndup(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s)); - *buf_len = ZSTR_LEN(buf.s); - smart_str_free(&buf); + *buffer = (unsigned char *)estrndup(buffer_string, total_size); + *buf_len = total_size; + // efree(buf); return SUCCESS; } -int phpglfw_buffer_glbyte_unserialize_handler(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data) +static int phpglfw_buffer_glbyte_unserialize_handler(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data) { phpglfw_buffer_glbyte_object *obj; - size_t item_count; + size_t exp_item_count, item_count; char *endptr, *token; - const char delimiter[] = ":"; - - token = strtok((char *)buf, delimiter); - if (!token) { - zend_throw_error(NULL, "Invalid format during phpglfw_buffer_glbyte_object unserialization"); + + // prints the buffer for debugging + // for (size_t i = 0; i < buf_len; i++) { + // printf("%c", buf[i]); + // } + // printf("\n"); + + // read the number of elements + exp_item_count = item_count = strtoul((char *)buf, &endptr, 10); + if (endptr == (char *)buf || *endptr != ':') { + // Failed to parse the number of elements + zend_throw_error(NULL, "Invalid format during phpglfw_buffer_glbyte_object unserialization, could not parse the number of elements."); return FAILURE; } - item_count = strtoul(token, &endptr, 10); - if (*endptr != '\0') { - zend_throw_error(NULL, "Invalid item count during phpglfw_buffer_glbyte_object unserialization"); - return FAILURE; - } + // skip the ':' + endptr++; + // make the object object_init_ex(object, phpglfw_buffer_glbyte_ce); obj = phpglfw_buffer_glbyte_objectptr_from_zobj_p(Z_OBJ_P(object)); - cvector_reserve(obj->vec, item_count); - cvector_set_size(obj->vec, item_count); + cvector_reserve(obj->vec, exp_item_count); - size_t index = 0; - while ((token = strtok(NULL, ",")) && index < item_count) { - obj->vec[index++] = strtol(token, NULL, 10); - } + // read the elements, check if our endptr is still valid and we have not reached the end of the buffer + while ((token = strtok(endptr, " ")) && item_count > 0 && endptr < (char *)buf + buf_len) { + cvector_push_back(obj->vec, strtol(token, NULL, 10)); + item_count--; + } - if (index != item_count) { - zend_throw_error(NULL, "Mismatch in expected item count during phpglfw_buffer_glbyte_object unserialization"); + if (cvector_size(obj->vec) != exp_item_count) { + zend_throw_error(NULL, "Mismatch in expected item count during phpglfw_buffer_glbyte_object unserialization. Expected: %zu, Found: %zu", exp_item_count, cvector_size(obj->vec)); return FAILURE; } @@ -4036,55 +4269,82 @@ int phpglfw_buffer_glubyte_unserialize_handler(zval *object, zend_class_entry *c static int phpglfw_buffer_glubyte_serialize_handler(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data) { phpglfw_buffer_glubyte_object *obj_ptr = phpglfw_buffer_glubyte_objectptr_from_zobj_p(Z_OBJ_P(object)); + size_t num_elements = cvector_size(obj_ptr->vec); + + // I want the standard serialization format to be human readable and easaly reconstructable + // which is why I use a simple format of: : ... + // More efficent serialization formats should be added as seperate, deticated functions + cvector_vector_type(char) buffer_string = NULL; + + // used to temporarly store the string representation of each element + // honestly I could not find a proper description of the maximum length of a double represented as + // string, after spending an hour down that rabbit hole I decided to just use a buffer of 256 bytes + char tmp[256]; + + // reserve some space for the string, its going to be more + // at the end but saves the first few reallocs + cvector_reserve(buffer_string, num_elements * sizeof(GLubyte)); + + // write the number of elements + int offset = sprintf(tmp, "%zu:", num_elements); + cvector_push_back_array(buffer_string, tmp, offset); + + // write each element + for (size_t i = 0; i < num_elements; i++) { + offset = sprintf(tmp, "%hhu ", obj_ptr->vec[i]); + cvector_push_back_array(buffer_string, tmp, offset); + } - smart_str buf = {0}; - smart_str_append_printf(&buf, "%zu:", cvector_size(obj_ptr->vec)); + // trim away the trailing space + cvector_pop_back(buffer_string); - for (size_t i = 0; i < cvector_size(obj_ptr->vec); i++) { - smart_str_append_printf(&buf, "%hhu,", obj_ptr->vec[i]); - } + size_t total_size = cvector_size(buffer_string); - smart_str_0(&buf); - *buffer = (unsigned char *)estrndup(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s)); - *buf_len = ZSTR_LEN(buf.s); - smart_str_free(&buf); + *buffer = (unsigned char *)estrndup(buffer_string, total_size); + *buf_len = total_size; + // efree(buf); return SUCCESS; } -int phpglfw_buffer_glubyte_unserialize_handler(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data) +static int phpglfw_buffer_glubyte_unserialize_handler(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data) { phpglfw_buffer_glubyte_object *obj; - size_t item_count; + size_t exp_item_count, item_count; char *endptr, *token; - const char delimiter[] = ":"; - - token = strtok((char *)buf, delimiter); - if (!token) { - zend_throw_error(NULL, "Invalid format during phpglfw_buffer_glubyte_object unserialization"); + + // prints the buffer for debugging + // for (size_t i = 0; i < buf_len; i++) { + // printf("%c", buf[i]); + // } + // printf("\n"); + + // read the number of elements + exp_item_count = item_count = strtoul((char *)buf, &endptr, 10); + if (endptr == (char *)buf || *endptr != ':') { + // Failed to parse the number of elements + zend_throw_error(NULL, "Invalid format during phpglfw_buffer_glubyte_object unserialization, could not parse the number of elements."); return FAILURE; } - item_count = strtoul(token, &endptr, 10); - if (*endptr != '\0') { - zend_throw_error(NULL, "Invalid item count during phpglfw_buffer_glubyte_object unserialization"); - return FAILURE; - } + // skip the ':' + endptr++; + // make the object object_init_ex(object, phpglfw_buffer_glubyte_ce); obj = phpglfw_buffer_glubyte_objectptr_from_zobj_p(Z_OBJ_P(object)); - cvector_reserve(obj->vec, item_count); - cvector_set_size(obj->vec, item_count); + cvector_reserve(obj->vec, exp_item_count); - size_t index = 0; - while ((token = strtok(NULL, ",")) && index < item_count) { - obj->vec[index++] = strtol(token, NULL, 10); - } + // read the elements, check if our endptr is still valid and we have not reached the end of the buffer + while ((token = strtok(endptr, " ")) && item_count > 0 && endptr < (char *)buf + buf_len) { + cvector_push_back(obj->vec, strtol(token, NULL, 10)); + item_count--; + } - if (index != item_count) { - zend_throw_error(NULL, "Mismatch in expected item count during phpglfw_buffer_glubyte_object unserialization"); + if (cvector_size(obj->vec) != exp_item_count) { + zend_throw_error(NULL, "Mismatch in expected item count during phpglfw_buffer_glubyte_object unserialization. Expected: %zu, Found: %zu", exp_item_count, cvector_size(obj->vec)); return FAILURE; } diff --git a/phpglfw_math.c b/phpglfw_math.c index c51dff7a..a8d0aec3 100644 --- a/phpglfw_math.c +++ b/phpglfw_math.c @@ -203,7 +203,7 @@ int phpglfw_math_vec2_unserialize_handler(zval *object, zend_class_entry *ce, co const unsigned char *buf_end = buf + buf_len; zval *zv; php_unserialize_data_t unserialize_data; - zend_object *zobj; + //zend_object *zobj; PHP_VAR_UNSERIALIZE_INIT(unserialize_data); @@ -213,7 +213,7 @@ int phpglfw_math_vec2_unserialize_handler(zval *object, zend_class_entry *ce, co for (int i = 0; i < 2; i++) { zv = var_tmp_var(&unserialize_data); if (!php_var_unserialize(zv, &buf_ptr, buf_end, &unserialize_data) || Z_TYPE_P(zv) != IS_DOUBLE) { - zend_throw_error(NULL, "Could not unserialize vector element", 0); + zend_throw_error(NULL, "Could not unserialize vector element"); zend_object_std_dtor(&obj->std); efree(obj); PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data); @@ -771,7 +771,7 @@ int phpglfw_math_vec3_unserialize_handler(zval *object, zend_class_entry *ce, co const unsigned char *buf_end = buf + buf_len; zval *zv; php_unserialize_data_t unserialize_data; - zend_object *zobj; + //zend_object *zobj; PHP_VAR_UNSERIALIZE_INIT(unserialize_data); @@ -781,7 +781,7 @@ int phpglfw_math_vec3_unserialize_handler(zval *object, zend_class_entry *ce, co for (int i = 0; i < 3; i++) { zv = var_tmp_var(&unserialize_data); if (!php_var_unserialize(zv, &buf_ptr, buf_end, &unserialize_data) || Z_TYPE_P(zv) != IS_DOUBLE) { - zend_throw_error(NULL, "Could not unserialize vector element", 0); + zend_throw_error(NULL, "Could not unserialize vector element"); zend_object_std_dtor(&obj->std); efree(obj); PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data); @@ -1408,7 +1408,7 @@ int phpglfw_math_vec4_unserialize_handler(zval *object, zend_class_entry *ce, co const unsigned char *buf_end = buf + buf_len; zval *zv; php_unserialize_data_t unserialize_data; - zend_object *zobj; + //zend_object *zobj; PHP_VAR_UNSERIALIZE_INIT(unserialize_data); @@ -1418,7 +1418,7 @@ int phpglfw_math_vec4_unserialize_handler(zval *object, zend_class_entry *ce, co for (int i = 0; i < 4; i++) { zv = var_tmp_var(&unserialize_data); if (!php_var_unserialize(zv, &buf_ptr, buf_end, &unserialize_data) || Z_TYPE_P(zv) != IS_DOUBLE) { - zend_throw_error(NULL, "Could not unserialize vector element", 0); + zend_throw_error(NULL, "Could not unserialize vector element"); zend_object_std_dtor(&obj->std); efree(obj); PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data); @@ -2006,7 +2006,7 @@ int phpglfw_math_quat_unserialize_handler(zval *object, zend_class_entry *ce, co const unsigned char *buf_end = buf + buf_len; zval *zv; php_unserialize_data_t unserialize_data; - zend_object *zobj; + //zend_object *zobj; PHP_VAR_UNSERIALIZE_INIT(unserialize_data); @@ -2016,7 +2016,7 @@ int phpglfw_math_quat_unserialize_handler(zval *object, zend_class_entry *ce, co for (int i = 0; i < 4; i++) { zv = var_tmp_var(&unserialize_data); if (!php_var_unserialize(zv, &buf_ptr, buf_end, &unserialize_data) || Z_TYPE_P(zv) != IS_DOUBLE) { - zend_throw_error(NULL, "Could not unserialize vector element", 0); + zend_throw_error(NULL, "Could not unserialize vector element"); zend_object_std_dtor(&obj->std); efree(obj); PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data); @@ -2731,7 +2731,7 @@ int phpglfw_math_mat4_unserialize_handler(zval *object, zend_class_entry *ce, co const unsigned char *buf_end = buf + buf_len; zval *zv; php_unserialize_data_t unserialize_data; - zend_object *zobj; + //zend_object *zobj; PHP_VAR_UNSERIALIZE_INIT(unserialize_data); @@ -2742,7 +2742,7 @@ int phpglfw_math_mat4_unserialize_handler(zval *object, zend_class_entry *ce, co for (int y = 0; y < 4; y++) { zv = var_tmp_var(&unserialize_data); if (!php_var_unserialize(zv, &buf_ptr, buf_end, &unserialize_data) || Z_TYPE_P(zv) != IS_DOUBLE) { - zend_throw_error(NULL, "Could not unserialize matrix element", 0); + zend_throw_error(NULL, "Could not unserialize matrix element"); zend_object_std_dtor(&obj->std); efree(obj); PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data); @@ -2876,9 +2876,6 @@ static int phpglfw_math_mat4_do_op_handler(zend_uchar opcode, zval *result, zval PHP_METHOD(GL_Math_Mat4, __construct) { - zval *obj; - obj = getThis(); - phpglfw_math_mat4_object *obj_ptr = phpglfw_math_mat4_objectptr_from_zobj_p(Z_OBJ_P(obj)); } diff --git a/phpglfw_objparser.c b/phpglfw_objparser.c index 4427ce50..68625813 100644 --- a/phpglfw_objparser.c +++ b/phpglfw_objparser.c @@ -775,7 +775,7 @@ PHP_METHOD(GL_Geometry_ObjFileParser, getMeshes) // construct a new float buffer object_init_ex(return_value, phpglfw_get_buffer_glfloat_ce()); - phpglfw_buffer_glfloat_object *buffer_intern = phpglfw_buffer_glfloat_objectptr_from_zobj_p(Z_OBJ_P(return_value)); + // phpglfw_buffer_glfloat_object *buffer_intern = phpglfw_buffer_glfloat_objectptr_from_zobj_p(Z_OBJ_P(return_value)); // group selection fastObjGroup group; diff --git a/vendor/cvector/cvector.h b/vendor/cvector/cvector.h index a54a070e..31bfb61c 100644 --- a/vendor/cvector/cvector.h +++ b/vendor/cvector/cvector.h @@ -162,6 +162,23 @@ cvector_set_size((vec), cvector_size(vec) + 1); \ } while (0) +/** + * @brief cvector_push_back_array - adds an array of elements to the end of the vector + * @param vec - the vector + * @param array - the array to add + * @param count - the count of elements to add + * @return void + */ +#define cvector_push_back_array(vec, array, count) \ + do { \ + size_t cv_cap__ = cvector_capacity(vec); \ + if (cv_cap__ <= cvector_size(vec) + (count)) { \ + cvector_grow((vec), cvector_compute_next_grow(cvector_size(vec) + (count))); \ + } \ + memcpy((vec) + cvector_size(vec), (array), sizeof(*(vec)) * (count)); \ + cvector_set_size((vec), cvector_size(vec) + (count)); \ + } while (0) + /** * @brief cvector_fill - sets all elements to the given value * @param vec - the vector