diff --git a/README.md b/README.md index c973886..2576529 100644 --- a/README.md +++ b/README.md @@ -60,16 +60,18 @@ tool\ ## Supported POD-Types in Defined Structs -| name | tld-type | C-storage | comment | -|----------------|------------------------------|---------------------------------------|-----------------------------------------------------------------| -| signed int | int8, int16, int32, int64 | int8_t, int16_t, int32_t, int64_t | | -| unsigned int | int8, uint16, uint32, uint64 | uint8_t, uint16_t, uint32_t, uint64_t | | -| floating point | fp32, fp64 | float/double | | -| bitfield | bitfield: | uint32_t bf : 3 | unsigned integer with specified amount of bits | -| string | string | const char* | utf8 encoded, null-terminated | -| inline_array | int8[20], some_type[20] | type[20] | fixed length, type can be any POD-type or user defined struct | -| array | int8[], some_type[] | struct { type* data; uint32_t count } | dynamic length, type can be any POD-type or user defined struct | -| pointer | some_type* | type* | pointer to any user-defined type | +| name | tld-type | C-storage | comment | +|----------------|------------------------------|---------------------------------------------|----------------------------------------------------------------------| +| signed int | int8, int16, int32, int64 | int8_t, int16_t, int32_t, int64_t | | +| unsigned int | int8, uint16, uint32, uint64 | uint8_t, uint16_t, uint32_t, uint64_t | | +| floating point | fp32, fp64 | float/double | | +| bitfield | bitfield: | uint32_t bf : 3 | unsigned integer with specified amount of bits | +| string | string | const char* | utf8 encoded, null-terminated | +| inline_array | int8[20], some_type[20] | type[20] | fixed length, type can be any POD-type or user defined struct | +| array | int8[], some_type[] | struct { type* data; uint32_t count } | dynamic length, type can be any POD-type or user defined struct | +| pointer | some_type* | type* | pointer to any user-defined type | +| any_pointer | any_pointer | struct { void* ptr; dl_typeid_t tid; } | pointer to any struct type, where the type is decided on assignment | +| any_array | any_array | struct { dl_array array; dl_typeid_t tid; } | all elements are of the same type, the type is decided on assignment | ## DL-JSON @@ -104,6 +106,10 @@ and DL will always error out if the value do not fit the type. * scientific float notation, such as 3.2e+12, 1.2e-5 * constants `inf`, `infinity` and `nan` ( ignoring case! ) +### Any types + +These types are based on un-typed pointers and the actual type is set when assigning the data. + ## TLD (Type Library Definition) Format Type-libs in text-format follows this format. @@ -286,6 +292,22 @@ left untouched!", // inline arrays are just arrays with the correct type ... "inline_array_member1" : [1, 2, 3], + // an any_pointer can be null, and then it is typeless + "any_pointer_member1": null, + // but when it has a value then that will be stored in the "__subdata" section, and there will be a "__any_type_" entry right after the member. + "any_pointer_member2": "ptr1234" + "__any_type_any_pointer_member2" : "my_struct", + + // any_array members will also have the "__any_type_" entry right after the member + "any_array_member": [ + { + "x" : 1, + "y" : 2 + }, + ] + "__any_type_any_array_member" : "my_struct", + + // ... it could be a struct with x and y members. "inline_array_member2" : [ { @@ -328,7 +350,12 @@ left untouched!", "another_sub_data" : { "some_float" : 1.23 - } + }, + + "ptr1234" : { + "x" : 1, + "y" : 2 + }, } } ``` diff --git a/include/dl/dl.h b/include/dl/dl.h index c14699f..d142e4a 100755 --- a/include/dl/dl.h +++ b/include/dl/dl.h @@ -135,6 +135,8 @@ typedef enum DL_TYPE_STORAGE_STR, DL_TYPE_STORAGE_PTR, DL_TYPE_STORAGE_STRUCT, + DL_TYPE_STORAGE_ANY_POINTER, + DL_TYPE_STORAGE_ANY_ARRAY, DL_TYPE_STORAGE_CNT } dl_type_storage_t; diff --git a/src/dl.cpp b/src/dl.cpp index bb1b2d1..fc6acd0 100644 --- a/src/dl.cpp +++ b/src/dl.cpp @@ -72,9 +72,9 @@ static dl_error_t dl_ptr_chain_patching( const dl_data_header* header, uint8_t* } dl_error_t dl_instance_load( dl_ctx_t dl_ctx, dl_typeid_t type_id, - void* instance, size_t instance_size, - const unsigned char* packed_instance, size_t packed_instance_size, - size_t* consumed ) + void* instance, size_t instance_size, + const unsigned char* packed_instance, size_t packed_instance_size, + size_t* consumed ) { dl_data_header* header = (dl_data_header*)packed_instance; @@ -152,7 +152,7 @@ struct CDLBinStoreContext dl_binary_writer_init( &writer, out_data, out_data_size, is_dummy, DL_ENDIAN_HOST, DL_ENDIAN_HOST, DL_PTR_SIZE_HOST ); } - uintptr_t FindWrittenPtr( void* ptr ) + uintptr_t FindWrittenPtr( const uint8_t* ptr ) { if( ptr == 0 ) return (uintptr_t)0; @@ -165,7 +165,7 @@ struct CDLBinStoreContext return (uintptr_t)0; } - void AddWrittenPtr( const void* ptr, uintptr_t pos ) + void AddWrittenPtr( const uint8_t* ptr, uintptr_t pos ) { written_ptrs.Add( { pos, ptr } ); } @@ -183,8 +183,8 @@ struct CDLBinStoreContext struct SWrittenPtr { - uintptr_t pos; - const void* ptr; + uintptr_t pos; + const uint8_t* ptr; }; CArrayStatic written_ptrs; CArrayStatic ptrs; @@ -224,11 +224,11 @@ static void dl_internal_store_string( const uint8_t* instance, CDLBinStoreContex dl_binary_writer_write( &store_ctx->writer, &offset, sizeof(uintptr_t) ); } -static dl_error_t dl_internal_instance_store( dl_ctx_t dl_ctx, const dl_type_desc* type, uint8_t* instance, CDLBinStoreContext* store_ctx ); +static dl_error_t dl_internal_instance_store( dl_ctx_t dl_ctx, const dl_type_desc* type, const uint8_t* instance, CDLBinStoreContext* store_ctx ); -static dl_error_t dl_internal_store_ptr( dl_ctx_t dl_ctx, uint8_t* instance, const dl_type_desc* sub_type, CDLBinStoreContext* store_ctx ) +static dl_error_t dl_internal_store_ptr( dl_ctx_t dl_ctx, const uint8_t* instance, const dl_type_desc* sub_type, CDLBinStoreContext* store_ctx ) { - uint8_t* data = *(uint8_t**)instance; + const uint8_t* data = *(const uint8_t* const*)instance; uintptr_t offset = store_ctx->FindWrittenPtr( data ); if( data == 0x0 ) // Null-pointer, store pint(-1) to signal to patching! @@ -265,7 +265,7 @@ static dl_error_t dl_internal_store_ptr( dl_ctx_t dl_ctx, uint8_t* instance, con return DL_ERROR_OK; } -static dl_error_t dl_internal_store_array( dl_ctx_t dl_ctx, dl_type_storage_t storage_type, const dl_type_desc* sub_type, uint8_t* instance, uint32_t count, uintptr_t size, CDLBinStoreContext* store_ctx ) +static dl_error_t dl_internal_store_array( dl_ctx_t dl_ctx, dl_type_storage_t storage_type, const dl_type_desc* sub_type, const uint8_t* instance, uint32_t count, uintptr_t size, CDLBinStoreContext* store_ctx ) { switch( storage_type ) { @@ -297,6 +297,19 @@ static dl_error_t dl_internal_store_array( dl_ctx_t dl_ctx, dl_type_storage_t st return err; } break; + case DL_TYPE_STORAGE_ANY_POINTER: + for( uint32_t elem = 0; elem < count; ++elem ) + { + dl_typeid_t tid = *reinterpret_cast( instance + ( ( elem * 2 + 1 ) * sizeof( void* ) ) ); + sub_type = dl_internal_find_type( dl_ctx, tid ); + dl_error_t err = dl_internal_store_ptr( dl_ctx, instance + ( elem * sizeof( void* ) * 2 ), sub_type, store_ctx ); + if( DL_ERROR_OK != err ) + return err; + dl_binary_writer_write_uint32( &store_ctx->writer, tid ); + if DL_CONSTANT_EXPRESSION(sizeof(uintptr_t) == 8) + dl_binary_writer_write_zero( &store_ctx->writer, 4 ); + } + break; default: // default is a standard pod-type dl_binary_writer_write( &store_ctx->writer, instance, count * size ); break; @@ -304,11 +317,57 @@ static dl_error_t dl_internal_store_array( dl_ctx_t dl_ctx, dl_type_storage_t st return DL_ERROR_OK; } -static dl_error_t dl_internal_store_member( dl_ctx_t dl_ctx, const dl_member_desc* member, uint8_t* instance, CDLBinStoreContext* store_ctx ) +static dl_error_t dl_internal_store_anyarray( dl_ctx_t dl_ctx, const uint8_t* data_ptr, uint32_t count, CDLBinStoreContext* store_ctx ) +{ + for (uint32_t i = 0; i < count; ++i) + { + uintptr_t sub_pos = dl_binary_writer_tell( &store_ctx->writer ); + dl_binary_writer_seek_end( &store_ctx->writer ); + + const uint8_t* sub_data_ptr = data_ptr + i * 3 * sizeof(void*); + const uint8_t* sub_data = *(const uint8_t* const*)sub_data_ptr; + uint32_t sub_count = *(const uint32_t*)( sub_data_ptr + sizeof(void*) ); + dl_typeid_t sub_type_id = *(const dl_typeid_t*)( sub_data_ptr + 2 * sizeof(void*) ); + const dl_type_desc* sub_type = dl_internal_find_type( dl_ctx, sub_type_id ); + size_t sub_size = dl_internal_align_up( sub_type->size[DL_PTR_SIZE_HOST], sub_type->alignment[DL_PTR_SIZE_HOST] ); + dl_binary_writer_align( &store_ctx->writer, sub_type->alignment[DL_PTR_SIZE_HOST] ); + + uintptr_t sub_offset = dl_binary_writer_tell( &store_ctx->writer ); + + // write data! + dl_binary_writer_reserve( &store_ctx->writer, sub_count * sub_size ); // reserve space for array so subdata is placed correctly + + dl_error_t err = dl_internal_store_array(dl_ctx, DL_TYPE_STORAGE_STRUCT, sub_type, sub_data, sub_count, sub_size, store_ctx); + if (DL_ERROR_OK != err) + return err; + dl_binary_writer_seek_set( &store_ctx->writer, sub_pos ); + + if( !store_ctx->writer.dummy ) + store_ctx->ptrs.Add( dl_binary_writer_tell( &store_ctx->writer ) ); + + // make room for ptr + dl_binary_writer_write( &store_ctx->writer, &sub_offset, sizeof(uintptr_t) ); + + // write count + dl_binary_writer_write( &store_ctx->writer, &sub_count, sizeof(uint32_t) ); + if DL_CONSTANT_EXPRESSION(sizeof(uintptr_t) == 8) + dl_binary_writer_write_zero( &store_ctx->writer, sizeof(uint32_t) ); + + // write type id + dl_binary_writer_write( &store_ctx->writer, &sub_type_id, sizeof(uint32_t) ); + if DL_CONSTANT_EXPRESSION(sizeof(uintptr_t) == 8) + dl_binary_writer_write_zero( &store_ctx->writer, sizeof(uint32_t) ); + } + return DL_ERROR_OK; +} + +dl_error_t dl_internal_store_member( dl_ctx_t dl_ctx, const dl_member_desc* member, const uint8_t* instance, CDLBinStoreContext* store_ctx ) { dl_type_atom_t atom_type = member->AtomType(); dl_type_storage_t storage_type = member->StorageType(); + if (storage_type == DL_TYPE_STORAGE_ANY_ARRAY) + atom_type = DL_TYPE_ATOM_ARRAY; // To avoid code duplification and simplify implementation switch ( atom_type ) { case DL_TYPE_ATOM_POD: @@ -320,7 +379,7 @@ static dl_error_t dl_internal_store_member( dl_ctx_t dl_ctx, const dl_member_des const dl_type_desc* sub_type = dl_internal_find_type( dl_ctx, member->type_id ); if( sub_type == 0x0 ) { - dl_log_error( dl_ctx, "Could not find subtype for member %s", dl_internal_member_name( dl_ctx, member ) ); + dl_log_error( dl_ctx, "Could not find struct subtype %X for member %s", member->type_id, dl_internal_member_name( dl_ctx, member ) ); return DL_ERROR_TYPE_NOT_FOUND; } dl_error_t err = dl_internal_instance_store(dl_ctx, sub_type, instance, store_ctx); @@ -331,12 +390,31 @@ static dl_error_t dl_internal_store_member( dl_ctx_t dl_ctx, const dl_member_des case DL_TYPE_STORAGE_STR: dl_internal_store_string( instance, store_ctx ); break; + case DL_TYPE_STORAGE_ANY_POINTER: + { + dl_typeid_t tid = *reinterpret_cast( instance + sizeof( void* ) ); + const dl_type_desc* sub_type = nullptr; + if( *reinterpret_cast( instance ) ) + { + sub_type = dl_internal_find_type( dl_ctx, tid ); + if( sub_type == 0x0 ) + { + dl_log_error( dl_ctx, "Could not find any_pointer subtype %X for member %s", tid, dl_internal_member_name( dl_ctx, member ) ); + return DL_ERROR_TYPE_NOT_FOUND; + } + } + dl_error_t err = dl_internal_store_ptr( dl_ctx, instance, sub_type, store_ctx ); + if( DL_ERROR_OK != err ) + return err; + dl_binary_writer_write( &store_ctx->writer, &tid, sizeof(dl_typeid_t) ); + } + break; case DL_TYPE_STORAGE_PTR: { const dl_type_desc* sub_type = dl_internal_find_type( dl_ctx, member->type_id ); if( sub_type == 0x0 ) { - dl_log_error( dl_ctx, "Could not find subtype for member %s", dl_internal_member_name( dl_ctx, member ) ); + dl_log_error( dl_ctx, "Could not find pointer subtype %X for member %s", member->type_id, dl_internal_member_name( dl_ctx, member ) ); return DL_ERROR_TYPE_NOT_FOUND; } dl_error_t err = dl_internal_store_ptr( dl_ctx, instance, sub_type, store_ctx ); @@ -366,7 +444,7 @@ static dl_error_t dl_internal_store_member( dl_ctx_t dl_ctx, const dl_member_des return DL_ERROR_TYPE_NOT_FOUND; } } - else if( storage_type != DL_TYPE_STORAGE_STR ) + else if( storage_type != DL_TYPE_STORAGE_STR && storage_type != DL_TYPE_STORAGE_ANY_POINTER) count = member->size[DL_PTR_SIZE_HOST]; return dl_internal_store_array( dl_ctx, storage_type, sub_type, instance, count, 1, store_ctx ); @@ -377,7 +455,7 @@ static dl_error_t dl_internal_store_member( dl_ctx_t dl_ctx, const dl_member_des uintptr_t size = 0; const dl_type_desc* sub_type = 0x0; - uint8_t* data_ptr = instance; + const uint8_t* data_ptr = instance; uint32_t count = *(uint32_t*)( data_ptr + sizeof(void*) ); uintptr_t offset = 0; @@ -396,6 +474,45 @@ static dl_error_t dl_internal_store_member( dl_ctx_t dl_ctx, const dl_member_des size = dl_internal_align_up( sub_type->size[DL_PTR_SIZE_HOST], sub_type->alignment[DL_PTR_SIZE_HOST] ); dl_binary_writer_align( &store_ctx->writer, sub_type->alignment[DL_PTR_SIZE_HOST] ); break; + case DL_TYPE_STORAGE_ANY_ARRAY: + storage_type = DL_TYPE_STORAGE_STRUCT; + if (member->AtomType() == DL_TYPE_ATOM_POD) + { + dl_typeid_t type_id = *(dl_typeid_t*)( data_ptr + 2 * sizeof(void*) ); + sub_type = dl_internal_find_type( dl_ctx, type_id ); + size = dl_internal_align_up( sub_type->size[DL_PTR_SIZE_HOST], sub_type->alignment[DL_PTR_SIZE_HOST] ); + dl_binary_writer_align( &store_ctx->writer, sub_type->alignment[DL_PTR_SIZE_HOST] ); + } + else if( member->AtomType() == DL_TYPE_ATOM_INLINE_ARRAY ) + { + dl_binary_writer_seek_set( &store_ctx->writer, pos ); + return dl_internal_store_anyarray( dl_ctx, data_ptr, member->inline_array_cnt(), store_ctx ); + } + else if( member->AtomType() == DL_TYPE_ATOM_ARRAY ) + { + dl_binary_writer_align( &store_ctx->writer, sizeof(void*) ); + offset = dl_binary_writer_tell( &store_ctx->writer ); + dl_binary_writer_reserve( &store_ctx->writer, count * 3 * sizeof(void*) ); // reserve space for array so subdata is placed correctly + dl_error_t err = dl_internal_store_anyarray( dl_ctx, *(const uint8_t* const*)data_ptr, count, store_ctx ); + if (DL_ERROR_OK != err) return err; + + dl_binary_writer_seek_set( &store_ctx->writer, pos ); + + if( !store_ctx->writer.dummy ) + store_ctx->ptrs.Add( dl_binary_writer_tell( &store_ctx->writer ) ); + + // make room for ptr + dl_binary_writer_write( &store_ctx->writer, &offset, sizeof(uintptr_t) ); + + // write count + dl_binary_writer_write( &store_ctx->writer, &count, sizeof(uint32_t) ); + if DL_CONSTANT_EXPRESSION(sizeof(uintptr_t) == 8) + dl_binary_writer_write_zero( &store_ctx->writer, sizeof(uint32_t) ); + return DL_ERROR_OK; + } + else + DL_ASSERT(false && "Invalid ATOM-type!"); + break; case DL_TYPE_STORAGE_PTR: sub_type = dl_internal_find_type( dl_ctx, member->type_id ); /*fallthrough*/ @@ -417,7 +534,7 @@ static dl_error_t dl_internal_store_member( dl_ctx_t dl_ctx, const dl_member_des dl_binary_writer_seek_set( &store_ctx->writer, pos ); if( !store_ctx->writer.dummy ) - store_ctx->ptrs.Add( dl_binary_writer_tell( &store_ctx->writer ) ); + store_ctx->ptrs.Add( dl_binary_writer_tell( &store_ctx->writer ) ); } // make room for ptr @@ -425,6 +542,16 @@ static dl_error_t dl_internal_store_member( dl_ctx_t dl_ctx, const dl_member_des // write count dl_binary_writer_write( &store_ctx->writer, &count, sizeof(uint32_t) ); + if DL_CONSTANT_EXPRESSION(sizeof(uintptr_t) == 8) + dl_binary_writer_write_zero( &store_ctx->writer, sizeof(uint32_t) ); + + if (member->StorageType() == DL_TYPE_STORAGE_ANY_ARRAY) + { + // write type id + dl_binary_writer_write( &store_ctx->writer, (data_ptr + 2 * sizeof(void*)), sizeof(uint32_t) ); + if DL_CONSTANT_EXPRESSION(sizeof(uintptr_t) == 8) + dl_binary_writer_write_zero( &store_ctx->writer, sizeof(uint32_t) ); + } } return DL_ERROR_OK; @@ -440,7 +567,7 @@ static dl_error_t dl_internal_store_member( dl_ctx_t dl_ctx, const dl_member_des return DL_ERROR_OK; } -static dl_error_t dl_internal_instance_store( dl_ctx_t dl_ctx, const dl_type_desc* type, uint8_t* instance, CDLBinStoreContext* store_ctx ) +static dl_error_t dl_internal_instance_store( dl_ctx_t dl_ctx, const dl_type_desc* type, const uint8_t* instance, CDLBinStoreContext* store_ctx ) { bool last_was_bitfield = false; @@ -519,9 +646,9 @@ dl_error_t dl_instance_store( dl_ctx_t dl_ctx, dl_typeid_t type_id, dl_binary_writer_update_needed_size( &store_context.writer ); dl_binary_writer_reserve( &store_context.writer, type->size[DL_PTR_SIZE_HOST] ); - store_context.AddWrittenPtr( instance, header_plus_alignment ); // if pointer refers to root-node, it can be found at offset "sizeof(dl_data_header)" plus alignment + store_context.AddWrittenPtr( (const uint8_t*)instance, header_plus_alignment ); // if pointer refers to root-node, it can be found at offset "sizeof(dl_data_header)" plus alignment - dl_error_t err = dl_internal_instance_store( dl_ctx, type, (uint8_t*)instance, &store_context ); + dl_error_t err = dl_internal_instance_store( dl_ctx, type, (const uint8_t*)instance, &store_context ); // write instance size! dl_binary_writer_seek_end( &store_context.writer ); diff --git a/src/dl.cpp.bak b/src/dl.cpp.bak new file mode 100644 index 0000000..ebb0b33 --- /dev/null +++ b/src/dl.cpp.bak @@ -0,0 +1,754 @@ +#include "dl_types.h" +#include "dl_swap.h" +#include "dl_binary_writer.h" +#include "dl_patch_ptr.h" + +#include
+ +#include + +dl_error_t dl_context_create( dl_ctx_t* dl_ctx, dl_create_params_t* create_params ) +{ + dl_allocator alloc; + dl_allocator_initialize( &alloc, create_params->alloc_func, create_params->realloc_func, create_params->free_func, create_params->alloc_ctx ); + + dl_context* ctx = (dl_context*)dl_alloc( &alloc, sizeof( dl_context ) ); + + if(ctx == 0x0) + return DL_ERROR_OUT_OF_LIBRARY_MEMORY; + + memset(ctx, 0x0, sizeof(dl_context)); + memcpy(&ctx->alloc, &alloc, sizeof( dl_allocator ) ); + + ctx->error_msg_func = create_params->error_msg_func; + ctx->error_msg_ctx = create_params->error_msg_ctx; + + *dl_ctx = ctx; + + return DL_ERROR_OK; +} + +dl_error_t dl_context_destroy(dl_ctx_t dl_ctx) +{ + dl_free( &dl_ctx->alloc, dl_ctx->type_ids ); + dl_free( &dl_ctx->alloc, dl_ctx->type_descs ); + dl_free( &dl_ctx->alloc, dl_ctx->enum_ids ); + dl_free( &dl_ctx->alloc, dl_ctx->enum_descs ); + dl_free( &dl_ctx->alloc, dl_ctx->member_descs ); + dl_free( &dl_ctx->alloc, dl_ctx->enum_value_descs ); + dl_free( &dl_ctx->alloc, dl_ctx->enum_alias_descs ); + dl_free( &dl_ctx->alloc, dl_ctx->typedata_strings ); + dl_free( &dl_ctx->alloc, dl_ctx->default_data ); + dl_free( &dl_ctx->alloc, dl_ctx->c_includes ); + for( size_t i = 0; i < dl_ctx->metadatas_count; ++i) + dl_free( &dl_ctx->alloc, dl_ctx->metadatas[i] ); + dl_free( &dl_ctx->alloc, dl_ctx->metadatas ); + dl_free( &dl_ctx->alloc, dl_ctx->metadata_infos ); + dl_free( &dl_ctx->alloc, dl_ctx->metadata_typeinfos ); + dl_free( &dl_ctx->alloc, dl_ctx ); + return DL_ERROR_OK; +} + +static dl_error_t dl_ptr_chain_patching( const dl_data_header* header, uint8_t* instance ) +{ + uintptr_t offset_shift = sizeof(uintptr_t) * 4; + uintptr_t offset_mask = (1ULL << offset_shift) - 1; + uint8_t* base_ptr = (uint8_t*)instance - sizeof(dl_data_header); + uint8_t* patch_mem = base_ptr; + uintptr_t offset_to_pointer = header->first_pointer_to_patch; // 0 is the patch terminator + while( offset_to_pointer != 0 ) + { + patch_mem += offset_to_pointer; + if( patch_mem > instance + header->instance_size ) + return DL_ERROR_MALFORMED_DATA; + uintptr_t offsets = *(uintptr_t*)patch_mem; + if( (offsets & offset_mask) > (header->instance_size + sizeof(*header)) ) + return DL_ERROR_MALFORMED_DATA; + offset_to_pointer = offsets >> offset_shift; + *(uint8_t**)patch_mem = (offsets & offset_mask) + base_ptr; + } + return DL_ERROR_OK; +} + +dl_error_t dl_instance_load( dl_ctx_t dl_ctx, dl_typeid_t type_id, + void* instance, size_t instance_size, + const unsigned char* packed_instance, size_t packed_instance_size, + size_t* consumed ) +{ + dl_data_header* header = (dl_data_header*)packed_instance; + + if( packed_instance_size < sizeof(dl_data_header) ) return DL_ERROR_MALFORMED_DATA; + if( header->id == DL_INSTANCE_ID_SWAPED ) return DL_ERROR_ENDIAN_MISMATCH; + if( header->id != DL_INSTANCE_ID ) return DL_ERROR_MALFORMED_DATA; + if( header->version != DL_INSTANCE_VERSION ) return DL_ERROR_VERSION_MISMATCH; + if( header->root_instance_type != type_id ) return DL_ERROR_TYPE_MISMATCH; + if( header->instance_size > instance_size ) return DL_ERROR_BUFFER_TOO_SMALL; + + const dl_type_desc* root_type = dl_internal_find_type( dl_ctx, header->root_instance_type ); + if( root_type == 0x0 ) + return DL_ERROR_TYPE_NOT_FOUND; + + // TODO: Temporary disabled due to CL doing some magic stuff!!! + // Structs allocated on qstack seems to be unaligned!!! + // if( !dl_internal_is_align( instance, pType->m_Alignment[DL_PTR_SIZE_HOST] ) ) + // return DL_ERROR_BAD_ALIGNMENT; + + DL_ASSERT( (uint8_t*)instance + header->instance_size > packed_instance || (uint8_t*)instance < packed_instance + header->instance_size ); + memcpy( instance, packed_instance + sizeof(dl_data_header), header->instance_size ); + + if (consumed) + *consumed = (size_t)header->instance_size + sizeof(dl_data_header); + + if( header->not_using_ptr_chain_patching ) + dl_internal_patch_instance( dl_ctx, root_type, (uint8_t*)instance, 0x0, (uintptr_t)instance - sizeof( dl_data_header ) ); + else + return dl_ptr_chain_patching( header, (uint8_t*)instance ); + + return DL_ERROR_OK; +} + +dl_error_t DL_DLL_EXPORT dl_instance_load_inplace( dl_ctx_t dl_ctx, dl_typeid_t type_id, + unsigned char* packed_instance, size_t packed_instance_size, + void** loaded_instance, size_t* consumed) +{ + dl_data_header* header = (dl_data_header*)packed_instance; + + if( packed_instance_size < sizeof(dl_data_header) ) return DL_ERROR_MALFORMED_DATA; + if( header->id == DL_INSTANCE_ID_SWAPED ) return DL_ERROR_ENDIAN_MISMATCH; + if( header->id != DL_INSTANCE_ID ) return DL_ERROR_MALFORMED_DATA; + if( header->version != DL_INSTANCE_VERSION ) return DL_ERROR_VERSION_MISMATCH; + if( header->root_instance_type != type_id ) return DL_ERROR_TYPE_MISMATCH; + + *loaded_instance = packed_instance + sizeof(dl_data_header); + + if (consumed) + *consumed = header->instance_size + sizeof(dl_data_header); + + if( header->version == DL_INSTANCE_VERSION && !header->not_using_ptr_chain_patching ) + { + return dl_ptr_chain_patching( header, (uint8_t*)*loaded_instance ); + } + else if( header->not_using_ptr_chain_patching ) + { + const dl_type_desc* type = dl_internal_find_type( dl_ctx, header->root_instance_type ); + if( type == 0x0 ) + return DL_ERROR_TYPE_NOT_FOUND; + + dl_internal_patch_instance( dl_ctx, type, packed_instance + sizeof( dl_data_header ), 0x0, (uintptr_t)packed_instance ); + } + return DL_ERROR_OK; +} + +struct CDLBinStoreContext +{ + CDLBinStoreContext( uint8_t* out_data, size_t out_data_size, bool is_dummy, dl_allocator alloc ) + : written_ptrs(alloc) + , ptrs(alloc) + , strings(alloc) + { + dl_binary_writer_init( &writer, out_data, out_data_size, is_dummy, DL_ENDIAN_HOST, DL_ENDIAN_HOST, DL_PTR_SIZE_HOST ); + } + + uintptr_t FindWrittenPtr( const uint8_t* ptr ) + { + if( ptr == 0 ) + return (uintptr_t)0; + + size_t len = written_ptrs.Len(); + for( size_t i = 0; i < len; ++i ) + if( written_ptrs[i].ptr == ptr ) + return written_ptrs[i].pos; + + return (uintptr_t)0; + } + + void AddWrittenPtr( const uint8_t* ptr, uintptr_t pos ) + { + written_ptrs.Add( { pos, ptr } ); + } + + uint32_t GetStringOffset(const char* str, uint32_t length, uint32_t hash) + { + for (size_t i = 0; i < strings.Len(); ++i) + if (strings[i].hash == hash && strings[i].length == length && strcmp(str, strings[i].str) == 0) + return strings[i].offset; + + return 0; + } + + dl_binary_writer writer; + + struct SWrittenPtr + { + uintptr_t pos; + const uint8_t* ptr; + }; + CArrayStatic written_ptrs; + CArrayStatic ptrs; + + struct SString + { + const char* str; + uint32_t length; + uint32_t hash; + uint32_t offset; + }; + CArrayStatic strings; +}; + +static void dl_internal_store_string( const uint8_t* instance, CDLBinStoreContext* store_ctx ) +{ + char* str = *(char**)instance; + if( str == 0x0 ) + { + dl_binary_writer_write( &store_ctx->writer, &DL_NULL_PTR_OFFSET[ DL_PTR_SIZE_HOST ], sizeof(uintptr_t) ); + return; + } + uint32_t hash = dl_internal_hash_string(str); + uint32_t length = (uint32_t) strlen(str); + uintptr_t offset = store_ctx->GetStringOffset(str, length, hash); + if (offset == 0) // Merge identical strings + { + uintptr_t pos = dl_binary_writer_tell(&store_ctx->writer); + dl_binary_writer_seek_end(&store_ctx->writer); + offset = dl_binary_writer_tell(&store_ctx->writer); + dl_binary_writer_write(&store_ctx->writer, str, length + 1); + store_ctx->strings.Add( {str, length, hash, (uint32_t) offset} ); + dl_binary_writer_seek_set(&store_ctx->writer, pos); + } + if( !store_ctx->writer.dummy ) + store_ctx->ptrs.Add( dl_binary_writer_tell( &store_ctx->writer ) ); + dl_binary_writer_write( &store_ctx->writer, &offset, sizeof(uintptr_t) ); +} + +static dl_error_t dl_internal_instance_store( dl_ctx_t dl_ctx, const dl_type_desc* type, const uint8_t* instance, CDLBinStoreContext* store_ctx ); + +static dl_error_t dl_internal_store_ptr( dl_ctx_t dl_ctx, const uint8_t* instance, const dl_type_desc* sub_type, CDLBinStoreContext* store_ctx ) +{ + const uint8_t* data = *(const uint8_t* const*)instance; + uintptr_t offset = store_ctx->FindWrittenPtr( data ); + + if( data == 0x0 ) // Null-pointer, store pint(-1) to signal to patching! + { + DL_ASSERT(offset == (uintptr_t)0 && "This pointer should not have been found among the written ptrs!"); + // keep the 0 in Offset and store it to ptr. + } + else if( offset == (uintptr_t)0 ) // has not been written yet! + { + uintptr_t pos = dl_binary_writer_tell( &store_ctx->writer ); + dl_binary_writer_seek_end( &store_ctx->writer ); + + // const dl_type_desc* sub_type = dl_internal_find_type( dl_ctx, member->type_id ); + uintptr_t size = dl_internal_align_up( sub_type->size[DL_PTR_SIZE_HOST], sub_type->alignment[DL_PTR_SIZE_HOST] ); + dl_binary_writer_align( &store_ctx->writer, sub_type->alignment[DL_PTR_SIZE_HOST] ); + + offset = dl_binary_writer_tell( &store_ctx->writer ); + + // write data! + dl_binary_writer_reserve( &store_ctx->writer, size ); // reserve space for ptr so subdata is placed correctly + + store_ctx->AddWrittenPtr(data, offset); + + dl_error_t err = dl_internal_instance_store(dl_ctx, sub_type, data, store_ctx); + if (DL_ERROR_OK != err) + return err; + dl_binary_writer_seek_set( &store_ctx->writer, pos ); + } + + if( !store_ctx->writer.dummy && data != 0x0 ) + store_ctx->ptrs.Add( dl_binary_writer_tell( &store_ctx->writer ) ); + + dl_binary_writer_write( &store_ctx->writer, &offset, sizeof(uintptr_t) ); + return DL_ERROR_OK; +} + +static dl_error_t dl_internal_store_array( dl_ctx_t dl_ctx, dl_type_storage_t storage_type, const dl_type_desc* sub_type, const uint8_t* instance, uint32_t count, uintptr_t size, CDLBinStoreContext* store_ctx ) +{ + switch( storage_type ) + { + case DL_TYPE_STORAGE_STRUCT: + { + uintptr_t size_ = sub_type->size[DL_PTR_SIZE_HOST]; + if( sub_type->flags & DL_TYPE_FLAG_HAS_SUBDATA ) + { + for (uint32_t elem = 0; elem < count; ++elem) + { + dl_error_t err = dl_internal_instance_store(dl_ctx, sub_type, instance + (elem * size_), store_ctx); + if (DL_ERROR_OK != err) + return err; + } + } + else + dl_binary_writer_write( &store_ctx->writer, instance, count * size_ ); + } + break; + case DL_TYPE_STORAGE_STR: + for( uint32_t elem = 0; elem < count; ++elem ) + dl_internal_store_string( instance + (elem * sizeof(char*)), store_ctx ); + break; + case DL_TYPE_STORAGE_PTR: + for( uint32_t elem = 0; elem < count; ++elem ) + { + dl_error_t err = dl_internal_store_ptr( dl_ctx, instance + ( elem * sizeof( void* ) ), sub_type, store_ctx ); + if( DL_ERROR_OK != err ) + return err; + } + break; + case DL_TYPE_STORAGE_ANY_POINTER: + for( uint32_t elem = 0; elem < count; ++elem ) + { + dl_typeid_t tid = *reinterpret_cast( instance + ( ( elem * 2 + 1 ) * sizeof( void* ) ) ); + sub_type = dl_internal_find_type( dl_ctx, tid ); + dl_error_t err = dl_internal_store_ptr( dl_ctx, instance + ( elem * sizeof( void* ) * 2 ), sub_type, store_ctx ); + if( DL_ERROR_OK != err ) + return err; + dl_binary_writer_write_uint32( &store_ctx->writer, tid ); + if (sizeof(uintptr_t) == 8) + dl_binary_writer_write_zero( &store_ctx->writer, 4 ); + } + break; + default: // default is a standard pod-type + dl_binary_writer_write( &store_ctx->writer, instance, count * size ); + break; + } + return DL_ERROR_OK; +} + +static dl_error_t dl_internal_store_anyarray( dl_ctx_t dl_ctx, const uint8_t* data_ptr, uint32_t count, CDLBinStoreContext* store_ctx ) +{ + for (uint32_t i = 0; i < count; ++i) + { + uintptr_t sub_pos = dl_binary_writer_tell( &store_ctx->writer ); + dl_binary_writer_seek_end( &store_ctx->writer ); + + const uint8_t* sub_data_ptr = data_ptr + i * 3 * sizeof(void*); + const uint8_t* sub_data = *(const uint8_t* const*)sub_data_ptr; + uint32_t sub_count = *(const uint32_t*)( sub_data_ptr + sizeof(void*) ); + dl_typeid_t sub_type_id = *(const dl_typeid_t*)( sub_data_ptr + 2 * sizeof(void*) ); + const dl_type_desc* sub_type = dl_internal_find_type( dl_ctx, sub_type_id ); + size_t sub_size = dl_internal_align_up( sub_type->size[DL_PTR_SIZE_HOST], sub_type->alignment[DL_PTR_SIZE_HOST] ); + dl_binary_writer_align( &store_ctx->writer, sub_type->alignment[DL_PTR_SIZE_HOST] ); + + uintptr_t sub_offset = dl_binary_writer_tell( &store_ctx->writer ); + + // write data! + dl_binary_writer_reserve( &store_ctx->writer, sub_count * sub_size ); // reserve space for array so subdata is placed correctly + + dl_error_t err = dl_internal_store_array(dl_ctx, DL_TYPE_STORAGE_STRUCT, sub_type, sub_data, sub_count, sub_size, store_ctx); + if (DL_ERROR_OK != err) + return err; + dl_binary_writer_seek_set( &store_ctx->writer, sub_pos ); + + if( !store_ctx->writer.dummy ) + store_ctx->ptrs.Add( dl_binary_writer_tell( &store_ctx->writer ) ); + + // make room for ptr + dl_binary_writer_write( &store_ctx->writer, &sub_offset, sizeof(uintptr_t) ); + + // write count + dl_binary_writer_write( &store_ctx->writer, &sub_count, sizeof(uint32_t) ); + if (sizeof(uintptr_t) == 8) + dl_binary_writer_write_zero( &store_ctx->writer, sizeof(uint32_t) ); + + // write type id + dl_binary_writer_write( &store_ctx->writer, &sub_type_id, sizeof(uint32_t) ); + if (sizeof(uintptr_t) == 8) + dl_binary_writer_write_zero( &store_ctx->writer, sizeof(uint32_t) ); + } + return DL_ERROR_OK; +} + +dl_error_t dl_internal_store_member( dl_ctx_t dl_ctx, const dl_member_desc* member, const uint8_t* instance, CDLBinStoreContext* store_ctx ) +{ + dl_type_atom_t atom_type = member->AtomType(); + dl_type_storage_t storage_type = member->StorageType(); + + if (storage_type == DL_TYPE_STORAGE_ANY_ARRAY) + atom_type = DL_TYPE_ATOM_ARRAY; // To avoid code duplification and simplify implementation + switch ( atom_type ) + { + case DL_TYPE_ATOM_POD: + { + switch( storage_type ) + { + case DL_TYPE_STORAGE_STRUCT: + { + const dl_type_desc* sub_type = dl_internal_find_type( dl_ctx, member->type_id ); + if( sub_type == 0x0 ) + { + dl_log_error( dl_ctx, "Could not find struct subtype %X for member %s", member->type_id, dl_internal_member_name( dl_ctx, member ) ); + return DL_ERROR_TYPE_NOT_FOUND; + } + dl_error_t err = dl_internal_instance_store(dl_ctx, sub_type, instance, store_ctx); + if (DL_ERROR_OK != err) + return err; + } + break; + case DL_TYPE_STORAGE_STR: + dl_internal_store_string( instance, store_ctx ); + break; + case DL_TYPE_STORAGE_ANY_POINTER: + { + dl_typeid_t tid = *reinterpret_cast( instance + sizeof( void* ) ); + const dl_type_desc* sub_type = nullptr; + if( *reinterpret_cast( instance ) ) + { + sub_type = dl_internal_find_type( dl_ctx, tid ); + if( sub_type == 0x0 ) + { + dl_log_error( dl_ctx, "Could not find any_pointer subtype %X for member %s", tid, dl_internal_member_name( dl_ctx, member ) ); + return DL_ERROR_TYPE_NOT_FOUND; + } + } + dl_error_t err = dl_internal_store_ptr( dl_ctx, instance, sub_type, store_ctx ); + if( DL_ERROR_OK != err ) + return err; + dl_binary_writer_write( &store_ctx->writer, &tid, sizeof(dl_typeid_t) ); + } + break; + case DL_TYPE_STORAGE_PTR: + { + const dl_type_desc* sub_type = dl_internal_find_type( dl_ctx, member->type_id ); + if( sub_type == 0x0 ) + { + dl_log_error( dl_ctx, "Could not find pointer subtype %X for member %s", member->type_id, dl_internal_member_name( dl_ctx, member ) ); + return DL_ERROR_TYPE_NOT_FOUND; + } + dl_error_t err = dl_internal_store_ptr( dl_ctx, instance, sub_type, store_ctx ); + if (DL_ERROR_OK != err) + return err; + } + break; + default: // default is a standard pod-type + DL_ASSERT( member->IsSimplePod() ); + dl_binary_writer_write( &store_ctx->writer, instance, member->size[DL_PTR_SIZE_HOST] ); + break; + } + } + return DL_ERROR_OK; + + case DL_TYPE_ATOM_INLINE_ARRAY: + { + const dl_type_desc* sub_type = 0x0; + uint32_t count = member->inline_array_cnt(); + if( storage_type == DL_TYPE_STORAGE_STRUCT || + storage_type == DL_TYPE_STORAGE_PTR ) + { + sub_type = dl_internal_find_type(dl_ctx, member->type_id); + if (sub_type == 0x0) + { + dl_log_error(dl_ctx, "Could not find subtype for member %s", dl_internal_member_name(dl_ctx, member)); + return DL_ERROR_TYPE_NOT_FOUND; + } + } + else if( storage_type != DL_TYPE_STORAGE_STR && storage_type != DL_TYPE_STORAGE_ANY_POINTER) + count = member->size[DL_PTR_SIZE_HOST]; + + return dl_internal_store_array( dl_ctx, storage_type, sub_type, instance, count, 1, store_ctx ); + } + + case DL_TYPE_ATOM_ARRAY: + { + uintptr_t size = 0; + const dl_type_desc* sub_type = 0x0; + + const uint8_t* data_ptr = instance; + uint32_t count = *(uint32_t*)( data_ptr + sizeof(void*) ); + + uintptr_t offset = 0; + + if( count == 0 ) + offset = DL_NULL_PTR_OFFSET[ DL_PTR_SIZE_HOST ]; + else + { + uintptr_t pos = dl_binary_writer_tell( &store_ctx->writer ); + dl_binary_writer_seek_end( &store_ctx->writer ); + + switch(storage_type) + { + case DL_TYPE_STORAGE_STRUCT: + sub_type = dl_internal_find_type( dl_ctx, member->type_id ); + size = dl_internal_align_up( sub_type->size[DL_PTR_SIZE_HOST], sub_type->alignment[DL_PTR_SIZE_HOST] ); + dl_binary_writer_align( &store_ctx->writer, sub_type->alignment[DL_PTR_SIZE_HOST] ); + break; + case DL_TYPE_STORAGE_ANY_ARRAY: + storage_type = DL_TYPE_STORAGE_STRUCT; + if (member->AtomType() == DL_TYPE_ATOM_POD) + { + dl_typeid_t type_id = *(dl_typeid_t*)( data_ptr + 2 * sizeof(void*) ); + sub_type = dl_internal_find_type( dl_ctx, type_id ); + size = dl_internal_align_up( sub_type->size[DL_PTR_SIZE_HOST], sub_type->alignment[DL_PTR_SIZE_HOST] ); + dl_binary_writer_align( &store_ctx->writer, sub_type->alignment[DL_PTR_SIZE_HOST] ); + } + else if( member->AtomType() == DL_TYPE_ATOM_INLINE_ARRAY ) + { + dl_binary_writer_seek_set( &store_ctx->writer, pos ); + return dl_internal_store_anyarray( dl_ctx, data_ptr, member->inline_array_cnt(), store_ctx ); + } + else if( member->AtomType() == DL_TYPE_ATOM_ARRAY ) + { + dl_binary_writer_align( &store_ctx->writer, sizeof(void*) ); + offset = dl_binary_writer_tell( &store_ctx->writer ); + dl_binary_writer_reserve( &store_ctx->writer, count * 3 * sizeof(void*) ); // reserve space for array so subdata is placed correctly + dl_error_t err = dl_internal_store_anyarray( dl_ctx, *(const uint8_t* const*)data_ptr, count, store_ctx ); + if (DL_ERROR_OK != err) return err; + + dl_binary_writer_seek_set( &store_ctx->writer, pos ); + + if( !store_ctx->writer.dummy ) + store_ctx->ptrs.Add( dl_binary_writer_tell( &store_ctx->writer ) ); + + // make room for ptr + dl_binary_writer_write( &store_ctx->writer, &offset, sizeof(uintptr_t) ); + + // write count + dl_binary_writer_write( &store_ctx->writer, &count, sizeof(uint32_t) ); + if (sizeof(uintptr_t) == 8) + dl_binary_writer_write_zero( &store_ctx->writer, sizeof(uint32_t) ); + return DL_ERROR_OK; + } + else + DL_ASSERT(false && "Invalid ATOM-type!"); + break; + case DL_TYPE_STORAGE_PTR: + sub_type = dl_internal_find_type( dl_ctx, member->type_id ); + /*fallthrough*/ + default: + size = dl_pod_size( member->StorageType() ); + dl_binary_writer_align( &store_ctx->writer, size ); + } + + offset = dl_binary_writer_tell( &store_ctx->writer ); + + // write data! + dl_binary_writer_reserve( &store_ctx->writer, count * size ); // reserve space for array so subdata is placed correctly + + uint8_t* data = *(uint8_t**)data_ptr; + + dl_error_t err = dl_internal_store_array(dl_ctx, storage_type, sub_type, data, count, size, store_ctx); + if (DL_ERROR_OK != err) + return err; + dl_binary_writer_seek_set( &store_ctx->writer, pos ); + + if( !store_ctx->writer.dummy ) + store_ctx->ptrs.Add( dl_binary_writer_tell( &store_ctx->writer ) ); + } + + // make room for ptr + dl_binary_writer_write( &store_ctx->writer, &offset, sizeof(uintptr_t) ); + + // write count + dl_binary_writer_write( &store_ctx->writer, &count, sizeof(uint32_t) ); + if (sizeof(uintptr_t) == 8) + dl_binary_writer_write_zero( &store_ctx->writer, sizeof(uint32_t) ); + + if (member->StorageType() == DL_TYPE_STORAGE_ANY_ARRAY) + { + // write type id + dl_binary_writer_write( &store_ctx->writer, (data_ptr + 2 * sizeof(void*)), sizeof(uint32_t) ); + if (sizeof(uintptr_t) == 8) + dl_binary_writer_write_zero( &store_ctx->writer, sizeof(uint32_t) ); + } + } + return DL_ERROR_OK; + + case DL_TYPE_ATOM_BITFIELD: + dl_binary_writer_write( &store_ctx->writer, instance, member->size[DL_PTR_SIZE_HOST] ); + break; + + default: + DL_ASSERT(false && "Invalid ATOM-type!"); + break; + } + + return DL_ERROR_OK; +} + +static dl_error_t dl_internal_instance_store( dl_ctx_t dl_ctx, const dl_type_desc* type, const uint8_t* instance, CDLBinStoreContext* store_ctx ) +{ + bool last_was_bitfield = false; + + dl_binary_writer_align( &store_ctx->writer, type->alignment[DL_PTR_SIZE_HOST] ); + + uintptr_t instance_pos = dl_binary_writer_tell( &store_ctx->writer ); + if( type->flags & DL_TYPE_FLAG_IS_UNION ) + { + size_t type_offset = dl_internal_union_type_offset( dl_ctx, type, DL_PTR_SIZE_HOST ); + + // find member index from union type ... + uint32_t union_type = *((uint32_t*)(instance + type_offset)); + const dl_member_desc* member = dl_internal_union_type_to_member(dl_ctx, type, union_type); + if (member == nullptr) + { + dl_log_error(dl_ctx, "Could not find union type %X for type %s", union_type, dl_internal_type_name(dl_ctx, type)); + return DL_ERROR_MALFORMED_DATA; + } + + dl_error_t err = dl_internal_store_member( dl_ctx, member, instance + member->offset[DL_PTR_SIZE_HOST], store_ctx ); + if( err != DL_ERROR_OK ) + return err; + + dl_binary_writer_seek_set( &store_ctx->writer, instance_pos + type_offset ); + dl_binary_writer_write_uint32( &store_ctx->writer, union_type ); + } + else + { + for( uint32_t member_index = 0; member_index < type->member_count; ++member_index ) + { + const dl_member_desc* member = dl_get_type_member( dl_ctx, type, member_index ); + + if( !last_was_bitfield || member->AtomType() != DL_TYPE_ATOM_BITFIELD ) + { + dl_binary_writer_seek_set( &store_ctx->writer, instance_pos + member->offset[DL_PTR_SIZE_HOST] ); + dl_error_t err = dl_internal_store_member( dl_ctx, member, instance + member->offset[DL_PTR_SIZE_HOST], store_ctx ); + if( err != DL_ERROR_OK ) + return err; + } + + last_was_bitfield = member->AtomType() == DL_TYPE_ATOM_BITFIELD; + } + } + + return DL_ERROR_OK; +} + +dl_error_t dl_instance_store( dl_ctx_t dl_ctx, dl_typeid_t type_id, const void* instance, + unsigned char* out_buffer, size_t out_buffer_size, size_t* produced_bytes ) +{ + if( out_buffer_size > 0 && out_buffer_size <= sizeof(dl_data_header) ) + return DL_ERROR_BUFFER_TOO_SMALL; + + const dl_type_desc* type = dl_internal_find_type( dl_ctx, type_id ); + if( type == 0x0 ) + return DL_ERROR_TYPE_NOT_FOUND; + + bool store_ctx_is_dummy = out_buffer_size == 0; + CDLBinStoreContext store_context( out_buffer, out_buffer_size, store_ctx_is_dummy, dl_ctx->alloc ); + + dl_data_header* header = (dl_data_header*)out_buffer; + if( out_buffer_size > 0 ) + { + if( instance == out_buffer + sizeof(dl_data_header) ) + memset( out_buffer, 0, sizeof(dl_data_header) ); + else + memset( out_buffer, 0, out_buffer_size ); + + header->id = DL_INSTANCE_ID; + header->version = DL_INSTANCE_VERSION; + header->root_instance_type = type_id; + header->is_64_bit_ptr = sizeof( void* ) == 8 ? 1 : 0; + } + dl_binary_writer_seek_set( &store_context.writer, sizeof( dl_data_header ) ); + dl_binary_writer_update_needed_size( &store_context.writer ); + + dl_binary_writer_reserve( &store_context.writer, type->size[DL_PTR_SIZE_HOST] ); + store_context.AddWrittenPtr( (const uint8_t*)instance, sizeof( dl_data_header ) ); // if pointer refere to root-node, it can be found at offset "sizeof(dl_data_header)" + + dl_error_t err = dl_internal_instance_store( dl_ctx, type, (const uint8_t*)instance, &store_context ); + + // write instance size! + dl_binary_writer_seek_end( &store_context.writer ); + if( header ) + { + header->instance_size = uint32_t( dl_binary_writer_tell( &store_context.writer ) - sizeof( dl_data_header ) ); + + uintptr_t offset_shift = sizeof( uintptr_t ) * 4; + if( dl_binary_writer_tell( &store_context.writer ) >= ( 1ULL << offset_shift ) ) + header->not_using_ptr_chain_patching = 1; + else + { + std::sort( store_context.ptrs.m_Ptr, store_context.ptrs.m_Ptr + store_context.ptrs.m_nElements ); + if( out_buffer && store_context.ptrs.Len() ) + { + store_context.ptrs.Add( store_context.ptrs[store_context.ptrs.Len() - 1] ); // Adding last pointer again so the offset to next pointer becomes 0 which terminates patching + for( size_t i = 0; i < store_context.ptrs.Len() - 1; ++i ) + { + uintptr_t offset = *(uintptr_t*)&out_buffer[store_context.ptrs[i]]; + *(uintptr_t*)&out_buffer[store_context.ptrs[i]] = offset | ( ( (uintptr_t)( store_context.ptrs[i + 1] - store_context.ptrs[i] ) ) << offset_shift ); + } + header->first_pointer_to_patch = (uint32_t)store_context.ptrs[0]; + } + } + } + + if( produced_bytes ) + *produced_bytes = (uint32_t)dl_binary_writer_tell( &store_context.writer ); + + if( out_buffer_size > 0 && dl_binary_writer_tell( &store_context.writer ) > out_buffer_size ) + return DL_ERROR_BUFFER_TOO_SMALL; + + return err; +} + +dl_error_t dl_instance_calc_size( dl_ctx_t dl_ctx, dl_typeid_t type, const void* instance, size_t* out_size ) +{ + return dl_instance_store( dl_ctx, type, instance, 0x0, 0, out_size ); +} + +const char* dl_error_to_string( dl_error_t error ) +{ +#define DL_ERR_TO_STR(ERR) case ERR: return #ERR + switch(error) + { + DL_ERR_TO_STR(DL_ERROR_OK); + DL_ERR_TO_STR(DL_ERROR_MALFORMED_DATA); + DL_ERR_TO_STR(DL_ERROR_VERSION_MISMATCH); + DL_ERR_TO_STR(DL_ERROR_OUT_OF_LIBRARY_MEMORY); + DL_ERR_TO_STR(DL_ERROR_OUT_OF_INSTANCE_MEMORY); + DL_ERR_TO_STR(DL_ERROR_DYNAMIC_SIZE_TYPES_AND_NO_INSTANCE_ALLOCATOR); + DL_ERR_TO_STR(DL_ERROR_OUT_OF_DEFAULT_VALUE_SLOTS); + DL_ERR_TO_STR(DL_ERROR_TYPE_MISMATCH); + DL_ERR_TO_STR(DL_ERROR_TYPE_NOT_FOUND); + DL_ERR_TO_STR(DL_ERROR_BUFFER_TOO_SMALL); + DL_ERR_TO_STR(DL_ERROR_ENDIAN_MISMATCH); + DL_ERR_TO_STR(DL_ERROR_BAD_ALIGNMENT); + DL_ERR_TO_STR(DL_ERROR_INVALID_PARAMETER); + DL_ERR_TO_STR(DL_ERROR_INVALID_DEFAULT_VALUE); + DL_ERR_TO_STR(DL_ERROR_UNSUPPORTED_OPERATION); + + DL_ERR_TO_STR(DL_ERROR_TXT_PARSE_ERROR); + DL_ERR_TO_STR(DL_ERROR_TXT_MISSING_MEMBER); + DL_ERR_TO_STR(DL_ERROR_TXT_MEMBER_SET_TWICE); + DL_ERR_TO_STR(DL_ERROR_TXT_INVALID_MEMBER); + DL_ERR_TO_STR(DL_ERROR_TXT_RANGE_ERROR); + DL_ERR_TO_STR(DL_ERROR_TXT_INVALID_MEMBER_TYPE); + DL_ERR_TO_STR(DL_ERROR_TXT_INVALID_ENUM_VALUE); + DL_ERR_TO_STR(DL_ERROR_TXT_MISSING_SECTION); + DL_ERR_TO_STR(DL_ERROR_TXT_MULTIPLE_MEMBERS_IN_UNION_SET); + + DL_ERR_TO_STR(DL_ERROR_TYPELIB_MISSING_MEMBERS_IN_TYPE); + + DL_ERR_TO_STR(DL_ERROR_UTIL_FILE_NOT_FOUND); + DL_ERR_TO_STR(DL_ERROR_UTIL_FILE_TYPE_MISMATCH); + + DL_ERR_TO_STR(DL_ERROR_INTERNAL_ERROR); + default: return "Unknown error!"; + } +#undef DL_ERR_TO_STR +} + +dl_error_t dl_instance_get_info( const unsigned char* packed_instance, size_t packed_instance_size, dl_instance_info_t* out_info ) +{ + dl_data_header* header = (dl_data_header*)packed_instance; + + if( packed_instance_size < sizeof(dl_data_header) && header->id != DL_INSTANCE_ID_SWAPED && header->id != DL_INSTANCE_ID ) + return DL_ERROR_MALFORMED_DATA; + if( header->version != DL_INSTANCE_VERSION && header->version != DL_INSTANCE_VERSION_SWAPED ) + return DL_ERROR_VERSION_MISMATCH; + + out_info->ptrsize = header->is_64_bit_ptr ? 8 : 4; + if( header->id == DL_INSTANCE_ID ) + { + out_info->load_size = header->instance_size; + out_info->endian = DL_ENDIAN_HOST; + out_info->root_type = header->root_instance_type ; + } + else + { + out_info->load_size = dl_swap_endian_uint32( header->instance_size ); + out_info->endian = dl_other_endian( DL_ENDIAN_HOST ); + out_info->root_type = dl_swap_endian_uint32( header->root_instance_type ); + } + + return DL_ERROR_OK; +} diff --git a/src/dl_convert.cpp b/src/dl_convert.cpp index ed0d3ca..6648bb0 100644 --- a/src/dl_convert.cpp +++ b/src/dl_convert.cpp @@ -38,8 +38,8 @@ class SConvertContext , tgt_endian(tgt_endian) , src_ptr_size(src_ptr_size) , target_ptr_size(tgt_ptr_size) - , instances(allocator) - , m_lPatchOffset(allocator) + , instances(allocator) + , m_lPatchOffset(allocator) {} bool IsSwapped( const uint8_t* ptr ) @@ -81,8 +81,8 @@ static inline void dl_swap_header( dl_data_header* header ) } static uintptr_t dl_internal_read_ptr_data( const uint8_t* data, - dl_endian_t src_endian, - dl_ptr_size_t ptr_size ) + dl_endian_t src_endian, + dl_ptr_size_t ptr_size ) { switch(ptr_size) { @@ -188,10 +188,10 @@ static void dl_internal_convert_collect_instances_from_str( const uint8_t* } static dl_error_t dl_internal_convert_collect_instances_from_ptr( dl_ctx_t ctx, - const dl_type_desc* sub_type, - const uint8_t* member_data, - const uint8_t* base_data, - SConvertContext& convert_ctx ) + const dl_type_desc* sub_type, + const uint8_t* member_data, + const uint8_t* base_data, + SConvertContext& convert_ctx ) { uintptr_t offset = dl_internal_read_ptr_data(member_data, convert_ctx.src_endian, convert_ctx.src_ptr_size); @@ -256,6 +256,53 @@ static dl_error_t dl_internal_convert_collect_instances_from_ptr_array( dl_ctx_t return DL_ERROR_OK; } +static dl_error_t dl_internal_convert_collect_instances_from_anyptr_array( dl_ctx_t ctx, + const uint8_t* array_data, + uintptr_t array_count, + const uint8_t* base_data, + SConvertContext& convert_ctx ) +{ + uint32_t ptr_size = (uint32_t)dl_internal_ptr_size(convert_ctx.src_ptr_size); + for( uintptr_t elem = 0; elem < array_count; ++elem ) + { + dl_typeid_t tid = *reinterpret_cast( array_data + ( elem * ptr_size * 2 ) + ptr_size ); + if( convert_ctx.src_endian != DL_ENDIAN_HOST ) tid = dl_swap_endian_uint32( tid ); + dl_error_t err = dl_internal_convert_collect_instances_from_ptr( ctx, dl_internal_find_type( ctx, tid ), array_data + (elem * ptr_size * 2), base_data, convert_ctx ); + if( err != DL_ERROR_OK ) + return err; + } + return DL_ERROR_OK; +} + +static dl_error_t dl_internal_convert_collect_instances_from_anyarray_array( dl_ctx_t ctx, + const uint8_t* array_data, + uintptr_t array_count, + const uint8_t* base_data, + SConvertContext& convert_ctx ) +{ + uint32_t ptr_size = (uint32_t)dl_internal_ptr_size(convert_ctx.src_ptr_size); + for( uintptr_t elem = 0; elem < array_count; ++elem ) + { + uintptr_t sub_array_offset = dl_internal_read_ptr_data( array_data + ( elem * ptr_size * 3 ), convert_ctx.src_endian, convert_ctx.src_ptr_size ); + uint32_t sub_count = *reinterpret_cast( array_data + ( elem * ptr_size * 3 ) + ptr_size ); + dl_typeid_t tid = *reinterpret_cast( array_data + ( elem * ptr_size * 3 ) + 2 * ptr_size ); + if( convert_ctx.src_endian != DL_ENDIAN_HOST ) + { + sub_count = dl_swap_endian_uint32( sub_count ); + tid = dl_swap_endian_uint32( tid ); + } + const dl_type_desc* sub_type = dl_internal_find_type(ctx, tid); + convert_ctx.instances.Add(SInstance(base_data + sub_array_offset, sub_type, sub_count, dl_make_type(DL_TYPE_ATOM_ARRAY, DL_TYPE_STORAGE_STRUCT))); + for( uintptr_t sub_elem = 0; sub_elem < sub_count; ++sub_elem ) + { + dl_error_t err = dl_internal_convert_collect_instances(ctx, sub_type, base_data + sub_array_offset + sub_elem * sub_type->size[convert_ctx.src_ptr_size], base_data, convert_ctx); + if( err != DL_ERROR_OK ) + return err; + } + } + return DL_ERROR_OK; +} + static dl_error_t dl_internal_convert_collect_instances_from_member( dl_ctx_t ctx, const dl_member_desc* member, const uint8_t* member_data, @@ -275,7 +322,32 @@ static dl_error_t dl_internal_convert_collect_instances_from_member( dl_ctx_t dl_internal_convert_collect_instances_from_str( member_data, base_data, convert_ctx ); break; case DL_TYPE_STORAGE_PTR: - return dl_internal_convert_collect_instances_from_ptr( ctx, dl_internal_find_type(ctx, member->type_id), member_data, base_data, convert_ctx ); + return dl_internal_convert_collect_instances_from_ptr( ctx, dl_internal_find_type( ctx, member->type_id ), member_data, base_data, convert_ctx ); + case DL_TYPE_STORAGE_ANY_POINTER: + { + dl_typeid_t tid = *reinterpret_cast( member_data + dl_internal_ptr_size( convert_ctx.src_ptr_size ) ); + if( convert_ctx.src_endian != DL_ENDIAN_HOST ) tid = dl_swap_endian_uint32( tid ); + return dl_internal_convert_collect_instances_from_ptr( ctx, dl_internal_find_type( ctx, tid ), member_data, base_data, convert_ctx ); + } + case DL_TYPE_STORAGE_ANY_ARRAY: + { + uintptr_t offset = dl_internal_read_ptr_data( member_data, convert_ctx.src_endian, convert_ctx.src_ptr_size ); + uint32_t array_count = *reinterpret_cast( member_data + dl_internal_ptr_size( convert_ctx.src_ptr_size ) ); + dl_typeid_t type_id = *reinterpret_cast( member_data + 2 * dl_internal_ptr_size( convert_ctx.src_ptr_size ) ); + if( convert_ctx.src_endian != DL_ENDIAN_HOST ) + { + array_count = dl_swap_endian_uint32( array_count ); + type_id = dl_swap_endian_uint32( type_id ); + } + const dl_type_desc* sub_type = dl_internal_find_type( ctx, type_id ); + convert_ctx.instances.Add( SInstance( base_data + offset, sub_type, array_count, member->type ) ); + return dl_internal_convert_collect_instances_from_struct_array( ctx, + member_data, + array_count, + sub_type, + base_data, + convert_ctx ); + } case DL_TYPE_STORAGE_STRUCT: return dl_internal_convert_collect_instances(ctx, dl_internal_find_type(ctx, member->type_id), member_data, base_data, convert_ctx); break; @@ -304,12 +376,23 @@ static dl_error_t dl_internal_convert_collect_instances_from_member( dl_ctx_t break; case DL_TYPE_STORAGE_PTR: return dl_internal_convert_collect_instances_from_ptr_array( ctx, - member_data, - member->inline_array_cnt(), - dl_internal_find_type(ctx, member->type_id), - base_data, - convert_ctx ); - break; + member_data, + member->inline_array_cnt(), + dl_internal_find_type( ctx, member->type_id ), + base_data, + convert_ctx ); + case DL_TYPE_STORAGE_ANY_POINTER: + return dl_internal_convert_collect_instances_from_anyptr_array( ctx, + member_data, + member->inline_array_cnt(), + base_data, + convert_ctx ); + case DL_TYPE_STORAGE_ANY_ARRAY: + return dl_internal_convert_collect_instances_from_anyarray_array( ctx, + member_data, + member->inline_array_cnt(), + base_data, + convert_ctx ); default: DL_ASSERT(member->IsSimplePod()); // ignore @@ -331,12 +414,26 @@ static dl_error_t dl_internal_convert_collect_instances_from_member( dl_ctx_t const uint8_t* array_data = base_data + offset; const dl_type_desc* sub_type = 0x0; - dl_error_t err; + dl_error_t err = DL_ERROR_OK; switch(storage_type) { case DL_TYPE_STORAGE_STR: dl_internal_convert_collect_instances_from_str_array(array_data, array_count, base_data, convert_ctx); break; + case DL_TYPE_STORAGE_ANY_POINTER: + err = dl_internal_convert_collect_instances_from_anyptr_array( ctx, + array_data, + array_count, + base_data, + convert_ctx ); + break; + case DL_TYPE_STORAGE_ANY_ARRAY: + err = dl_internal_convert_collect_instances_from_anyarray_array( ctx, + array_data, + array_count, + base_data, + convert_ctx ); + break; case DL_TYPE_STORAGE_PTR: sub_type = dl_internal_find_type(ctx, member->type_id); err = dl_internal_convert_collect_instances_from_ptr_array( ctx, @@ -345,7 +442,6 @@ static dl_error_t dl_internal_convert_collect_instances_from_member( dl_ctx_t sub_type, base_data, convert_ctx ); - if( DL_ERROR_OK != err ) return err; break; case DL_TYPE_STORAGE_STRUCT: sub_type = dl_internal_find_type(ctx, member->type_id); @@ -355,13 +451,12 @@ static dl_error_t dl_internal_convert_collect_instances_from_member( dl_ctx_t sub_type, base_data, convert_ctx ); - if( DL_ERROR_OK != err ) return err; break; default: DL_ASSERT(member->IsSimplePod()); break; } - + if( DL_ERROR_OK != err ) return err; convert_ctx.instances.Add(SInstance(array_data, sub_type, array_count, member->type)); } break; @@ -509,11 +604,33 @@ static dl_error_t dl_internal_convert_write_member( dl_ctx_t ctx, return dl_internal_convert_write_struct( ctx, member_data, sub_type, conv_ctx, writer ); } break; + case DL_TYPE_STORAGE_ANY_POINTER: + { + uintptr_t offset = dl_internal_read_ptr_data( member_data, conv_ctx.src_endian, conv_ctx.src_ptr_size ); + dl_internal_convert_save_patch_pos( &conv_ctx, writer, dl_binary_writer_tell( writer ), offset ); + dl_binary_writer_write_4byte( writer, member_data + dl_internal_ptr_size( conv_ctx.src_ptr_size ) ); + if( conv_ctx.target_ptr_size == DL_PTR_SIZE_64BIT ) + dl_binary_writer_write_zero( writer, 4 ); + } + break; + case DL_TYPE_STORAGE_ANY_ARRAY: + { + uintptr_t offset = 0; uint32_t count = 0; + dl_internal_read_array_data( member_data, &offset, &count, conv_ctx.src_endian, conv_ctx.src_ptr_size ); + dl_internal_convert_save_patch_pos( &conv_ctx, writer, dl_binary_writer_tell( writer ), offset ); + dl_binary_writer_write_4byte( writer, member_data + dl_internal_ptr_size( conv_ctx.src_ptr_size ) ); + if( conv_ctx.target_ptr_size == DL_PTR_SIZE_64BIT ) + dl_binary_writer_write_zero( writer, 4 ); + dl_binary_writer_write_4byte( writer, member_data + 2 * dl_internal_ptr_size( conv_ctx.src_ptr_size ) ); + if( conv_ctx.target_ptr_size == DL_PTR_SIZE_64BIT ) + dl_binary_writer_write_zero( writer, 4 ); + } + break; case DL_TYPE_STORAGE_STR: case DL_TYPE_STORAGE_PTR: { uintptr_t offset = dl_internal_read_ptr_data(member_data, conv_ctx.src_endian, conv_ctx.src_ptr_size); - dl_internal_convert_save_patch_pos( &conv_ctx, writer, dl_binary_writer_tell( writer), offset ); + dl_internal_convert_save_patch_pos( &conv_ctx, writer, dl_binary_writer_tell(writer), offset ); } break; default: @@ -530,12 +647,12 @@ static dl_error_t dl_internal_convert_write_member( dl_ctx_t ctx, case DL_TYPE_STORAGE_STRUCT: { const dl_type_desc* sub_type = dl_internal_find_type(ctx, member->type_id); - if(sub_type == 0x0) + if( sub_type == 0x0 ) return DL_ERROR_TYPE_NOT_FOUND; uintptr_t SubtypeSize = sub_type->size[conv_ctx.src_ptr_size]; for( uint32_t i = 0; i < member->inline_array_cnt(); ++i ) - { + { dl_error_t err = dl_internal_convert_write_struct( ctx, member_data + i * SubtypeSize, sub_type, conv_ctx, writer ); if( DL_ERROR_OK != err ) return err; } @@ -548,13 +665,45 @@ static dl_error_t dl_internal_convert_write_member( dl_ctx_t ctx, uintptr_t tgt_ptr_size = dl_internal_ptr_size(conv_ctx.target_ptr_size); uintptr_t array_pos = dl_binary_writer_tell( writer ); - for (uintptr_t elem_index = 0; elem_index < member->inline_array_cnt(); ++elem_index) + for( uintptr_t elem_index = 0; elem_index < member->inline_array_cnt(); ++elem_index ) { uintptr_t offset = dl_internal_read_ptr_data(member_data + (elem_index * src_ptr_size), conv_ctx.src_endian, conv_ctx.src_ptr_size); dl_internal_convert_save_patch_pos( &conv_ctx, writer, array_pos + (elem_index * tgt_ptr_size), offset ); } } break; + case DL_TYPE_STORAGE_ANY_POINTER: + { + uintptr_t src_ptr_size = dl_internal_ptr_size(conv_ctx.src_ptr_size); + for( uintptr_t elem = 0; elem < member->inline_array_cnt(); ++elem ) + { + uintptr_t offset = dl_internal_read_ptr_data( member_data + src_ptr_size * ( elem * 2 ), conv_ctx.src_endian, conv_ctx.src_ptr_size ); + dl_internal_convert_save_patch_pos( &conv_ctx, writer, dl_binary_writer_tell( writer ), offset ); + dl_typeid_t tid = *(const dl_typeid_t*)( member_data + src_ptr_size * ( elem * 2 + 1 ) ); + dl_binary_writer_write_4byte( writer, &tid ); + if( dl_internal_ptr_size(conv_ctx.target_ptr_size) == 8 ) + dl_binary_writer_write_zero( writer, 4 ); + } + } + break; + case DL_TYPE_STORAGE_ANY_ARRAY: + { + uintptr_t src_ptr_size = dl_internal_ptr_size(conv_ctx.src_ptr_size); + for( uintptr_t elem = 0; elem < member->inline_array_cnt(); ++elem ) + { + uintptr_t offset = dl_internal_read_ptr_data( member_data + src_ptr_size * ( elem * 3 ), conv_ctx.src_endian, conv_ctx.src_ptr_size ); + dl_internal_convert_save_patch_pos( &conv_ctx, writer, dl_binary_writer_tell( writer ), offset ); + uint32_t count = *(const uint32_t*)( member_data + src_ptr_size * ( elem * 3 + 1 ) ); + dl_typeid_t tid = *(const dl_typeid_t*)( member_data + src_ptr_size * ( elem * 3 + 2 ) ); + dl_binary_writer_write_4byte( writer, &count ); + if( dl_internal_ptr_size(conv_ctx.target_ptr_size) == 8 ) + dl_binary_writer_write_zero( writer, 4 ); + dl_binary_writer_write_4byte( writer, &tid ); + if( dl_internal_ptr_size(conv_ctx.target_ptr_size) == 8 ) + dl_binary_writer_write_zero( writer, 4 ); + } + } + break; default: { DL_ASSERT(member->IsSimplePod()); @@ -705,6 +854,8 @@ static dl_error_t dl_internal_convert_write_instance( dl_ctx_t dl_ctx, { case DL_TYPE_STORAGE_STR: case DL_TYPE_STORAGE_PTR: + case DL_TYPE_STORAGE_ANY_POINTER: + case DL_TYPE_STORAGE_ANY_ARRAY: dl_binary_writer_align( writer, conv_ctx.target_ptr_size == DL_PTR_SIZE_32BIT ? 4 : 8 ); break; default: @@ -735,7 +886,7 @@ static dl_error_t dl_internal_convert_write_instance( dl_ctx_t dl_ctx, case DL_TYPE_STORAGE_STR: { uintptr_t type_size = dl_internal_ptr_size(conv_ctx.src_ptr_size); - for(uintptr_t elem = 0; elem < inst.array_count; ++elem ) + for( uintptr_t elem = 0; elem < inst.array_count; ++elem ) { uintptr_t offset = dl_internal_read_ptr_data(u8 + ( elem * type_size ), conv_ctx.src_endian, conv_ctx.src_ptr_size); dl_internal_convert_save_patch_pos( &conv_ctx, writer, dl_binary_writer_tell( writer ), offset ); @@ -746,7 +897,7 @@ static dl_error_t dl_internal_convert_write_instance( dl_ctx_t dl_ctx, case DL_TYPE_STORAGE_PTR: { uintptr_t ptr_size = dl_internal_ptr_size(conv_ctx.src_ptr_size); - for(uintptr_t elem = 0; elem < inst.array_count; ++elem ) + for( uintptr_t elem = 0; elem < inst.array_count; ++elem ) { uintptr_t offset = dl_internal_read_ptr_data(u8 + ( elem * ptr_size ), conv_ctx.src_endian, conv_ctx.src_ptr_size); dl_internal_convert_save_patch_pos( &conv_ctx, writer, dl_binary_writer_tell( writer ), offset ); @@ -754,6 +905,40 @@ static dl_error_t dl_internal_convert_write_instance( dl_ctx_t dl_ctx, } break; + case DL_TYPE_STORAGE_ANY_POINTER: + { + uintptr_t src_ptr_size = dl_internal_ptr_size(conv_ctx.src_ptr_size); + for( uintptr_t elem = 0; elem < inst.array_count; ++elem ) + { + uintptr_t offset = dl_internal_read_ptr_data( u8 + src_ptr_size * ( elem * 2 ), conv_ctx.src_endian, conv_ctx.src_ptr_size ); + dl_internal_convert_save_patch_pos( &conv_ctx, writer, dl_binary_writer_tell( writer ), offset ); + dl_typeid_t tid = *(const dl_typeid_t*)( u8 + src_ptr_size * ( elem * 2 + 1 ) ); + dl_binary_writer_write_4byte( writer, &tid ); + if( dl_internal_ptr_size(conv_ctx.target_ptr_size) == 8 ) + dl_binary_writer_write_zero( writer, 4 ); + } + } + break; + + case DL_TYPE_STORAGE_ANY_ARRAY: + { + uintptr_t src_ptr_size = dl_internal_ptr_size(conv_ctx.src_ptr_size); + for( uintptr_t elem = 0; elem < inst.array_count; ++elem ) + { + uintptr_t offset = dl_internal_read_ptr_data( u8 + src_ptr_size * ( elem * 3 ), conv_ctx.src_endian, conv_ctx.src_ptr_size ); + dl_internal_convert_save_patch_pos( &conv_ctx, writer, dl_binary_writer_tell( writer ), offset ); + uint32_t count = *(const uint32_t*)( u8 + src_ptr_size * ( elem * 3 + 1 ) ); + dl_typeid_t tid = *(const dl_typeid_t*)( u8 + src_ptr_size * ( elem * 3 + 2 ) ); + dl_binary_writer_write_4byte( writer, &count ); + if( dl_internal_ptr_size(conv_ctx.target_ptr_size) == 8 ) + dl_binary_writer_write_zero( writer, 4 ); + dl_binary_writer_write_4byte( writer, &tid ); + if( dl_internal_ptr_size(conv_ctx.target_ptr_size) == 8 ) + dl_binary_writer_write_zero( writer, 4 ); + } + } + break; + case DL_TYPE_STORAGE_INT8: case DL_TYPE_STORAGE_UINT8: case DL_TYPE_STORAGE_ENUM_INT8: @@ -791,7 +976,18 @@ static dl_error_t dl_internal_convert_write_instance( dl_ctx_t dl_ctx, return DL_ERROR_OK; case DL_TYPE_STORAGE_STRUCT: case DL_TYPE_STORAGE_PTR: + case DL_TYPE_STORAGE_ANY_POINTER: return dl_internal_convert_write_struct( dl_ctx, u8, inst.type, conv_ctx, writer ); + case DL_TYPE_STORAGE_ANY_ARRAY: + { + uintptr_t type_size = inst.type->size[conv_ctx.src_ptr_size]; + for( uintptr_t elem = 0; elem < inst.array_count; ++elem ) + { + dl_error_t err = dl_internal_convert_write_struct( dl_ctx, u8 + ( elem * type_size ), inst.type, conv_ctx, writer ); + if(err != DL_ERROR_OK) return err; + } + return DL_ERROR_OK; + } default: // ignore ... break; @@ -914,7 +1110,7 @@ static dl_error_t dl_internal_convert_instance( dl_ctx_t dl_ctx, default: return DL_ERROR_INVALID_PARAMETER; } - // converting to larger pointersize in an inplace conversion is not possible! + // converting to larger pointer size in an inplace conversion is not possible! if( dst_ptr_size > src_ptr_size && packed_instance == out_instance ) return DL_ERROR_UNSUPPORTED_OPERATION; @@ -1018,9 +1214,9 @@ extern "C" { #endif // __cplusplus dl_error_t dl_convert_inplace( dl_ctx_t dl_ctx, dl_typeid_t type, - unsigned char* packed_instance, size_t packed_instance_size, - dl_endian_t out_endian, size_t out_ptr_size, - size_t* produced_bytes ) + unsigned char* packed_instance, size_t packed_instance_size, + dl_endian_t out_endian, size_t out_ptr_size, + size_t* produced_bytes ) { size_t dummy; if( produced_bytes == 0x0 ) @@ -1029,10 +1225,10 @@ dl_error_t dl_convert_inplace( dl_ctx_t dl_ctx, dl_typeid_t type, } dl_error_t dl_convert( dl_ctx_t dl_ctx, dl_typeid_t type, - unsigned char* packed_instance, size_t packed_instance_size, - unsigned char* out_instance, size_t out_instance_size, - dl_endian_t out_endian, size_t out_ptr_size, - size_t* produced_bytes ) + unsigned char* packed_instance, size_t packed_instance_size, + unsigned char* out_instance, size_t out_instance_size, + dl_endian_t out_endian, size_t out_ptr_size, + size_t* produced_bytes ) { DL_ASSERT(out_instance != packed_instance && "Src and destination can not be the same!"); size_t dummy; @@ -1042,8 +1238,8 @@ dl_error_t dl_convert( dl_ctx_t dl_ctx, dl_typeid_t type, } dl_error_t dl_convert_calc_size( dl_ctx_t dl_ctx, dl_typeid_t type, - unsigned char* packed_instance, size_t packed_instance_size, - size_t out_ptr_size, size_t* out_size ) + unsigned char* packed_instance, size_t packed_instance_size, + size_t out_ptr_size, size_t* out_size ) { return dl_convert( dl_ctx, type, packed_instance, packed_instance_size, 0x0, 0, DL_ENDIAN_HOST, out_ptr_size, out_size ); } diff --git a/src/dl_patch_ptr.cpp b/src/dl_patch_ptr.cpp index eac634a..083260d 100644 --- a/src/dl_patch_ptr.cpp +++ b/src/dl_patch_ptr.cpp @@ -19,7 +19,7 @@ static void dl_internal_patch_struct( dl_ctx_t ctx, dl_patched_ptrs* patched_payloads ); static void dl_internal_patch_ptr_instance( dl_ctx_t ctx, - const dl_type_desc* sub_type, + const dl_type_desc* sub_type, uint8_t* ptr_data, uintptr_t base_address, uintptr_t patch_distance, @@ -46,7 +46,7 @@ static void dl_internal_patch_str_array( uint8_t* array_data, uint32_t count, ui } static void dl_internal_patch_ptr_array( dl_ctx_t ctx, - uint8_t* array_data, + uint8_t* array_data, uint32_t count, const dl_type_desc* sub_type, uintptr_t base_address, @@ -58,6 +58,44 @@ static void dl_internal_patch_ptr_array( dl_ctx_t ctx, dl_internal_patch_ptr_instance( ctx, sub_type, array_data + index * sizeof(void*), base_address, patch_distance, patched_ptrs, patched_payloads ); } +static void dl_internal_patch_anyptr_array( dl_ctx_t ctx, + uint8_t* array_data, + uint32_t count, + uintptr_t base_address, + uintptr_t patch_distance, + dl_patched_ptrs* patched_ptrs, + dl_patched_ptrs* patched_payloads ) +{ + for( uint32_t index = 0; index < count; ++index ) + { + const dl_type_desc* sub_type = dl_internal_find_type( ctx, *reinterpret_cast( array_data + ( index * 2 + 1 ) * sizeof(void*) ) ); + dl_internal_patch_ptr_instance( ctx, sub_type, array_data + index * 2 * sizeof(void*), base_address, patch_distance, patched_ptrs, patched_payloads ); + } +} + +static void dl_internal_patch_anyarray_array( dl_ctx_t ctx, + uint8_t* array_data, + uint32_t count, + uintptr_t base_address, + uintptr_t patch_distance, + dl_patched_ptrs* patched_ptrs, + dl_patched_ptrs* patched_payloads ) +{ + for( uint32_t index = 0; index < count; ++index ) + { + uintptr_t offset = dl_internal_patch_ptr( array_data + ( index * 3 ) * sizeof(void*), patch_distance ); + uint8_t* inner_array = (uint8_t*)base_address + offset; + uint32_t inner_count = *reinterpret_cast( array_data + ( index * 3 + 1 ) * sizeof(void*) ); + const dl_type_desc* sub_type = dl_internal_find_type( ctx, *reinterpret_cast( array_data + ( index * 3 + 2 ) * sizeof(void*) ) ); + uint32_t size = dl_internal_align_up( sub_type->size[DL_PTR_SIZE_HOST], sub_type->alignment[DL_PTR_SIZE_HOST] ); + for( uint32_t j = 0; j < inner_count; ++j ) + { + uint8_t* struct_data = inner_array + j * size; + dl_internal_patch_struct( ctx, sub_type, struct_data, base_address, patch_distance, patched_ptrs, patched_payloads ); + } + } +} + static void dl_internal_patch_struct_array( dl_ctx_t ctx, const dl_type_desc* type, uint8_t* array_data, @@ -76,12 +114,12 @@ static void dl_internal_patch_struct_array( dl_ctx_t ctx, } static void dl_internal_patch_member( dl_ctx_t ctx, - const dl_member_desc* member, - uint8_t* member_data, - uintptr_t base_address, - uintptr_t patch_distance, - dl_patched_ptrs* patched_ptrs, - dl_patched_ptrs* patched_payloads ) + const dl_member_desc* member, + uint8_t* member_data, + uintptr_t base_address, + uintptr_t patch_distance, + dl_patched_ptrs* patched_ptrs, + dl_patched_ptrs* patched_payloads ) { dl_type_atom_t atom_type = member->AtomType(); dl_type_storage_t storage_type = member->StorageType(); @@ -96,6 +134,24 @@ static void dl_internal_patch_member( dl_ctx_t ctx, if( dl_internal_patch_ptr( member_data, patch_distance ) && patched_ptrs ) patched_ptrs->add( uintptr_t(member_data - base_address) ); break; + case DL_TYPE_STORAGE_ANY_POINTER: + dl_internal_patch_ptr_instance( ctx, + dl_internal_find_type( ctx, *reinterpret_cast(member_data + sizeof(void*)) ), + member_data, + base_address, + patch_distance, + patched_ptrs, + patched_payloads ); + break; + case DL_TYPE_STORAGE_ANY_ARRAY: + dl_internal_patch_anyarray_array( ctx, + member_data, + 1, + base_address, + patch_distance, + patched_ptrs, + patched_payloads ); + break; case DL_TYPE_STORAGE_PTR: dl_internal_patch_ptr_instance( ctx, dl_internal_find_type( ctx, member->type_id ), @@ -127,6 +183,24 @@ static void dl_internal_patch_member( dl_ctx_t ctx, case DL_TYPE_STORAGE_STR: dl_internal_patch_str_array( member_data, member->inline_array_cnt(), patch_distance, base_address, patched_ptrs ); break; + case DL_TYPE_STORAGE_ANY_POINTER: + dl_internal_patch_anyptr_array( ctx, + member_data, + member->inline_array_cnt(), + base_address, + patch_distance, + patched_ptrs, + patched_payloads ); + break; + case DL_TYPE_STORAGE_ANY_ARRAY: + dl_internal_patch_anyarray_array( ctx, + member_data, + member->inline_array_cnt(), + base_address, + patch_distance, + patched_ptrs, + patched_payloads ); + break; case DL_TYPE_STORAGE_PTR: dl_internal_patch_ptr_array( ctx, member_data, @@ -170,6 +244,24 @@ static void dl_internal_patch_member( dl_ctx_t ctx, case DL_TYPE_STORAGE_STR: dl_internal_patch_str_array( array_data, count, patch_distance, base_address, patched_ptrs ); break; + case DL_TYPE_STORAGE_ANY_POINTER: + dl_internal_patch_anyptr_array( ctx, + array_data, + count, + base_address, + patch_distance, + patched_ptrs, + patched_payloads ); + break; + case DL_TYPE_STORAGE_ANY_ARRAY: + dl_internal_patch_anyarray_array( ctx, + array_data, + count, + base_address, + patch_distance, + patched_ptrs, + patched_payloads ); + break; case DL_TYPE_STORAGE_PTR: dl_internal_patch_ptr_array( ctx, array_data, diff --git a/src/dl_txt_pack.cpp b/src/dl_txt_pack.cpp index f353507..9b7832f 100755 --- a/src/dl_txt_pack.cpp +++ b/src/dl_txt_pack.cpp @@ -3,6 +3,7 @@ #include "dl_types.h" #include
#include "dl_binary_writer.h" +#include "dl_internal_util.h" #include "dl_patch_ptr.h" #include "dl_txt_read.h" @@ -60,14 +61,14 @@ inline double dl_strtod(const char* str, char** endptr) } #endif if( tolower(str[1]) == 'a' && - tolower(str[2]) == 'x' && + tolower(str[2]) == 'x' && !isalnum(str[3]) ) { *endptr = (char*)str + 3; return DBL_MAX * sign; } if( tolower(str[1]) == 'i' && - tolower(str[2]) == 'n' && + tolower(str[2]) == 'n' && !isalnum(str[3])) { *endptr = (char*)str + 3; @@ -114,14 +115,14 @@ inline float dl_strtof(const char* str, char** endptr) } #endif if( tolower(str[1]) == 'a' && - tolower(str[2]) == 'x' && + tolower(str[2]) == 'x' && !isalnum(str[3]) ) { *endptr = (char*)str + 3; return FLT_MAX * sign; } if( tolower(str[1]) == 'i' && - tolower(str[2]) == 'n' && + tolower(str[2]) == 'n' && !isalnum(str[3])) { *endptr = (char*)str + 3; @@ -139,7 +140,7 @@ static inline uint32_t dl_internal_hash_buffer( dl_substr str ) struct dl_txt_pack_ctx { explicit dl_txt_pack_ctx(dl_allocator alloc) - : subdata(alloc) + : subdata(alloc) , ptrs(alloc) { } @@ -312,10 +313,10 @@ static void dl_txt_pack_eat_and_write_enum( dl_ctx_t dl_ctx, dl_txt_pack_ctx* pa packctx->read_ctx.iter = ename.str + ename.len + 1; } -static void dl_txt_pack_eat_and_write_ptr( dl_ctx_t dl_ctx, dl_txt_pack_ctx* packctx, const dl_type_desc* type, size_t patch_pos ) +static bool dl_txt_pack_eat_and_write_ptr( dl_ctx_t dl_ctx, dl_txt_pack_ctx* packctx, const dl_type_desc* type, size_t patch_pos ) { if( dl_txt_pack_eat_and_write_null(packctx) ) - return; + return false; dl_substr ptr = dl_txt_eat_string( &packctx->read_ctx ); if( ptr.str == 0x0 ) @@ -325,6 +326,83 @@ static void dl_txt_pack_eat_and_write_ptr( dl_ctx_t dl_ctx, dl_txt_pack_ctx* pac packctx->ptrs.add( patch_pos ); packctx->subdata.Add({ ptr, dl_internal_hash_buffer(ptr), type, patch_pos }); + return true; +} + +static const dl_substr dl_txt_eat_object_key( dl_txt_read_ctx* readctx ); +static const char* dl_txt_skip_array( const char* iter, const char* end ); +static uint32_t dl_txt_pack_find_array_length( dl_ctx_t dl_ctx, dl_txt_pack_ctx* packctx, dl_type_storage_t storage_type ); +static dl_error_t dl_txt_pack_eat_and_write_struct( dl_ctx_t dl_ctx, dl_txt_pack_ctx* packctx, const dl_type_desc* type ); +static dl_error_t dl_txt_pack_eat_and_write_array( dl_ctx_t dl_ctx, dl_txt_pack_ctx* packctx, dl_type_storage_t storage_type, dl_typeid_t type_id, const char* member_name, uint32_t array_length ); + +static void dl_txt_pack_eat_and_write_anyptr( dl_ctx_t dl_ctx, dl_txt_pack_ctx* packctx, dl_substr member_name ) +{ + size_t data_pos = dl_binary_writer_tell( packctx->writer ); + if( dl_txt_pack_eat_and_write_null( packctx ) ) + { + dl_binary_writer_write_zero(packctx->writer, sizeof(uintptr_t)); + return; + } + + dl_substr ptr{ }; + const dl_type_desc* type{ }; + // ... find open { + dl_txt_eat_char( dl_ctx, &packctx->read_ctx, '{' ); + while (true) + { + // ... read keys, there should be one 'type' and one 'data' ... + dl_txt_eat_white( &packctx->read_ctx ); + if( *packctx->read_ctx.iter == ',' ) ++packctx->read_ctx.iter; + // We allow trailing commas, so consume whitespaces to see if we have a struct termination. + dl_txt_eat_white( &packctx->read_ctx ); + if( *packctx->read_ctx.iter == '}' ) break; + + dl_txt_eat_white( &packctx->read_ctx ); + dl_substr key_name = dl_txt_eat_object_key( &packctx->read_ctx ); + if( key_name.str == 0x0 ) + dl_txt_read_failed( dl_ctx, &packctx->read_ctx, DL_ERROR_MALFORMED_DATA, "When reading member \"%.*s\": expected map-key containing member name.", member_name.len, member_name.str ); + + if( strncmp( key_name.str, "type", 4 ) == 0 ) + { + dl_txt_eat_char( dl_ctx, &packctx->read_ctx, ':' ); + dl_txt_eat_white( &packctx->read_ctx ); + dl_substr type_name = dl_txt_eat_string( &packctx->read_ctx ); + type = dl_internal_find_type_by_name( dl_ctx, &type_name ); + if( type == 0 ) + dl_txt_read_failed( dl_ctx, &packctx->read_ctx, DL_ERROR_MALFORMED_DATA, "When reading member \"%.*s\": the type '%.*s' isn't known", member_name.len, member_name.str, type_name.len, type_name.str ); + } + else if( strncmp( key_name.str, "data", 4 ) == 0 ) + { + dl_txt_eat_char( dl_ctx, &packctx->read_ctx, ':' ); + dl_txt_eat_white( &packctx->read_ctx ); + if (dl_txt_pack_eat_and_write_null(packctx)) + { + dl_binary_writer_write_zero(packctx->writer, sizeof(uintptr_t)); + dl_txt_eat_char(dl_ctx, &packctx->read_ctx, '}'); + return; + } + ptr = dl_txt_eat_string( &packctx->read_ctx ); + if( ptr.str == 0x0 ) + dl_txt_read_failed( dl_ctx, &packctx->read_ctx, DL_ERROR_TXT_INVALID_MEMBER_TYPE, "When reading member \"%.*s\": expected pointer name as string", member_name.len, member_name.str ); + } + else + dl_txt_read_failed( dl_ctx, &packctx->read_ctx, DL_ERROR_MALFORMED_DATA, "When reading member \"%.*s\": expected \"type\" or \"data\" but got \"%.*s\"", member_name.len, member_name.str, key_name.len, key_name.str ); + } + if( type == nullptr || ptr.str == nullptr ) + dl_txt_read_failed(dl_ctx, &packctx->read_ctx, DL_ERROR_MALFORMED_DATA, "When reading member \"%.*s\": didn't provide both \"type\" and \"data\"", member_name.len, member_name.str ); + + dl_txt_eat_char(dl_ctx, &packctx->read_ctx, '}'); + + if( !packctx->writer->dummy ) + packctx->ptrs.add( data_pos ); + + packctx->subdata.Add({ ptr, dl_internal_hash_buffer( ptr ), type, data_pos }); + + packctx->subdata[packctx->subdata.Len() - 1].type = type; + dl_binary_writer_seek_set( packctx->writer, data_pos + sizeof(void*) ); + dl_binary_writer_write_uint32( packctx->writer, dl_internal_typeid_of( dl_ctx, packctx->subdata[packctx->subdata.Len() - 1].type ) ); + if DL_CONSTANT_EXPRESSION( sizeof(uintptr_t) == 8 ) + dl_binary_writer_write_zero( packctx->writer, sizeof(uint32_t) ); } static void dl_txt_pack_validate_c_symbol_key( dl_ctx_t dl_ctx, dl_txt_pack_ctx* packctx, dl_substr symbol ) @@ -336,11 +414,99 @@ static void dl_txt_pack_validate_c_symbol_key( dl_ctx_t dl_ctx, dl_txt_pack_ctx* } } -static dl_error_t dl_txt_pack_eat_and_write_struct( dl_ctx_t dl_ctx, dl_txt_pack_ctx* packctx, const dl_type_desc* type ); +static void dl_txt_pack_eat_and_write_anyarray( dl_ctx_t dl_ctx, dl_txt_pack_ctx* packctx, dl_substr member_name ) +{ + uint32_t array_length = 0; + const char* array = nullptr; + const dl_type_desc* type = nullptr; + // ... find open { + dl_txt_eat_char( dl_ctx, &packctx->read_ctx, '{' ); + while( true ) + { + // ... read keys, there should be one 'data' and if the data isn't an empty array there should be one 'type' ... + dl_txt_eat_white( &packctx->read_ctx ); + if( *packctx->read_ctx.iter == ',' ) ++packctx->read_ctx.iter; + // We allow trailing commas, so consume whitespaces to see if we have a struct termination. + dl_txt_eat_white( &packctx->read_ctx ); + if( *packctx->read_ctx.iter == '}' ) break; + + dl_txt_eat_white( &packctx->read_ctx ); + dl_substr key_name = dl_txt_eat_object_key( &packctx->read_ctx ); + if( key_name.str == 0x0 ) + dl_txt_read_failed( dl_ctx, &packctx->read_ctx, DL_ERROR_MALFORMED_DATA, "When reading member \"%.*s\": expected map-key containing member name.", member_name.len, member_name.str ); + + if( strncmp( key_name.str, "type", 4 ) == 0 ) + { + dl_txt_eat_char( dl_ctx, &packctx->read_ctx, ':' ); + dl_txt_eat_white( &packctx->read_ctx ); + dl_substr type_name = dl_txt_eat_string( &packctx->read_ctx ); + type = dl_internal_find_type_by_name( dl_ctx, &type_name ); + if( type == 0 ) + dl_txt_read_failed( dl_ctx, &packctx->read_ctx, DL_ERROR_MALFORMED_DATA, "When reading member \"%.*s\": the type '%.*s' isn't known", member_name.len, member_name.str, type_name.len, type_name.str ); + } + else if( strncmp( key_name.str, "data", 4 ) == 0 ) + { + dl_txt_eat_char( dl_ctx, &packctx->read_ctx, ':' ); + dl_txt_eat_white( &packctx->read_ctx ); + dl_txt_eat_char( dl_ctx, &packctx->read_ctx, '[' ); + array = packctx->read_ctx.iter; + array_length = dl_txt_pack_find_array_length( dl_ctx, packctx, DL_TYPE_STORAGE_STRUCT ); + if( array_length == 0 ) + { + dl_txt_eat_white( &packctx->read_ctx ); + dl_txt_eat_char( dl_ctx, &packctx->read_ctx, ']' ); + array = nullptr; + break; + } + else + { + packctx->read_ctx.iter = dl_txt_skip_array( array - 1, packctx->read_ctx.end ); + } + } + else + dl_txt_read_failed( dl_ctx, &packctx->read_ctx, DL_ERROR_MALFORMED_DATA, "When reading member \"%.*s\": expected \"type\" or \"data\" but got \"%.*s\"", member_name.len, member_name.str, key_name.len, key_name.str ); + } + if( array != nullptr && type == nullptr ) + dl_txt_read_failed( dl_ctx, &packctx->read_ctx, DL_ERROR_MALFORMED_DATA, "Member's \"%.*s\"'s any_array didn't provide a \"type\" though the \"data\" array wasn't empty", member_name.len, member_name.str ); + + dl_txt_eat_white( &packctx->read_ctx ); + dl_txt_eat_char( dl_ctx, &packctx->read_ctx, '}' ); + if( array == nullptr ) + { + dl_binary_writer_write_zero( packctx->writer, dl_pod_size( DL_TYPE_STORAGE_ANY_ARRAY ) ); + } + else + { + dl_typeid_t type_id = dl_internal_typeid_of( dl_ctx, type ); + size_t element_size = type->size[DL_PTR_SIZE_HOST]; + size_t element_align = type->alignment[DL_PTR_SIZE_HOST]; + size_t array_pos = dl_binary_writer_needed_size( packctx->writer ); + array_pos = dl_internal_align_up( array_pos, element_align ); + + if( !packctx->writer->dummy ) + packctx->ptrs.add( dl_binary_writer_tell( packctx->writer ) ); + + dl_binary_writer_write_pint( packctx->writer, array_pos ); + dl_binary_writer_write_uint32( packctx->writer, array_length ); + if DL_CONSTANT_EXPRESSION( sizeof(uintptr_t) == 8 ) + dl_binary_writer_write_zero( packctx->writer, sizeof(uint32_t) ); + dl_binary_writer_write_uint32( packctx->writer, type_id ); + if DL_CONSTANT_EXPRESSION( sizeof(uintptr_t) == 8 ) + dl_binary_writer_write_zero( packctx->writer, sizeof(uint32_t) ); + dl_binary_writer_seek_end( packctx->writer ); + dl_binary_writer_reserve( packctx->writer, array_length * element_size ); + const char* continuation = packctx->read_ctx.iter; + packctx->read_ctx.iter = array; + dl_error_t err = dl_txt_pack_eat_and_write_array( dl_ctx, packctx, DL_TYPE_STORAGE_STRUCT, type_id, nullptr, array_length ); + if( DL_ERROR_OK != err ) + dl_txt_read_failed( dl_ctx, &packctx->read_ctx, DL_ERROR_MALFORMED_DATA, "error while packing array of member \"%.*s\"", member_name.len, member_name.str ); + packctx->read_ctx.iter = continuation; + } +} -static dl_error_t dl_txt_pack_eat_and_write_array( dl_ctx_t dl_ctx, dl_txt_pack_ctx* packctx, const dl_member_desc* member, uint32_t array_length ) +static dl_error_t dl_txt_pack_eat_and_write_array( dl_ctx_t dl_ctx, dl_txt_pack_ctx* packctx, dl_type_storage_t storage_type, dl_typeid_t type_id, const char* member_name, uint32_t array_length ) { - switch( member->StorageType() ) + switch( storage_type ) { case DL_TYPE_STORAGE_INT8: { @@ -454,7 +620,7 @@ static dl_error_t dl_txt_pack_eat_and_write_array( dl_ctx_t dl_ctx, dl_txt_pack_ break; case DL_TYPE_STORAGE_PTR: { - const dl_type_desc* type = dl_internal_find_type( dl_ctx, member->type_id ); + const dl_type_desc* type = dl_internal_find_type( dl_ctx, type_id ); size_t array_pos = dl_binary_writer_tell( packctx->writer ); for( uint32_t i = 0; i < array_length - 1; ++i ) { @@ -464,9 +630,38 @@ static dl_error_t dl_txt_pack_eat_and_write_array( dl_ctx_t dl_ctx, dl_txt_pack_ dl_txt_pack_eat_and_write_ptr( dl_ctx, packctx, type, array_pos + ( array_length - 1 ) * sizeof(void*) ); } break; + case DL_TYPE_STORAGE_ANY_POINTER: + { + char number[16]; + for( uint32_t i = 0; i < array_length - 1; ++i ) + { + dl_substr name = { number, dl_internal_str_format( number, sizeof(number), "%u", i ) }; + dl_txt_pack_eat_and_write_anyptr( dl_ctx, packctx, name ); + dl_txt_eat_char( dl_ctx, &packctx->read_ctx, ',' ); + } + dl_substr name = { number, dl_internal_str_format( number, sizeof(number), "%u", array_length - 1 ) }; + dl_txt_pack_eat_and_write_anyptr( dl_ctx, packctx, name ); + } + break; + case DL_TYPE_STORAGE_ANY_ARRAY: + { + size_t array_pos = dl_binary_writer_tell( packctx->writer ); + char number[16]; + for( uint32_t i = 0; i < array_length - 1; ++i ) + { + dl_binary_writer_seek_set( packctx->writer, array_pos + i * 3 * sizeof(void*) ); + dl_substr name = { number, dl_internal_str_format( number, sizeof(number), "%u", i ) }; + dl_txt_pack_eat_and_write_anyarray( dl_ctx, packctx, name ); + dl_txt_eat_char( dl_ctx, &packctx->read_ctx, ',' ); + } + dl_binary_writer_seek_set( packctx->writer, array_pos + (array_length - 1) * 3 * sizeof(void*) ); + dl_substr name = { number, dl_internal_str_format( number, sizeof(number), "%u", array_length - 1 ) }; + dl_txt_pack_eat_and_write_anyarray( dl_ctx, packctx, name ); + } + break; case DL_TYPE_STORAGE_STRUCT: { - const dl_type_desc* type = dl_internal_find_type( dl_ctx, member->type_id ); + const dl_type_desc* type = dl_internal_find_type( dl_ctx, type_id ); size_t array_pos = dl_binary_writer_tell( packctx->writer ); // TODO: this seek/set dance will only be needed if type has subptrs, optimize by making different code-paths? for( uint32_t i = 0; i < array_length -1; ++i ) { @@ -489,9 +684,9 @@ static dl_error_t dl_txt_pack_eat_and_write_array( dl_ctx_t dl_ctx, dl_txt_pack_ case DL_TYPE_STORAGE_ENUM_UINT32: case DL_TYPE_STORAGE_ENUM_UINT64: { - const dl_enum_desc* edesc = dl_internal_find_enum( dl_ctx, member->type_id ); + const dl_enum_desc* edesc = dl_internal_find_enum( dl_ctx, type_id ); if( edesc == 0x0 ) - dl_txt_read_failed( dl_ctx, &packctx->read_ctx, DL_ERROR_TYPE_NOT_FOUND, "couldn't find enum-type of .%s", dl_internal_member_name( dl_ctx, member ) ); + dl_txt_read_failed( dl_ctx, &packctx->read_ctx, DL_ERROR_TYPE_NOT_FOUND, "couldn't find enum-type of .%s", member_name ); for( uint32_t i = 0; i < array_length -1; ++i ) { @@ -515,28 +710,29 @@ static dl_error_t dl_txt_pack_eat_and_write_array( dl_ctx_t dl_ctx, dl_txt_pack_ } static void dl_txt_pack_array_item_size_align( dl_ctx_t dl_ctx, - const dl_member_desc* member, + dl_type_storage_t storage_type, + dl_typeid_t type_id, size_t* size, size_t* align ) { // TODO: store this in typelib? - switch( member->StorageType() ) + switch( storage_type ) { case DL_TYPE_STORAGE_STRUCT: { - const dl_type_desc* type = dl_internal_find_type( dl_ctx, member->type_id ); + const dl_type_desc* type = dl_internal_find_type( dl_ctx, type_id ); *size = type->size[DL_PTR_SIZE_HOST]; *align = type->alignment[DL_PTR_SIZE_HOST]; break; } default: - *size = dl_pod_size( member->StorageType() ); + *size = dl_pod_size( storage_type ); *align = *size; break; } } -const char* dl_txt_skip_array( const char* iter, const char* end ) +static const char* dl_txt_skip_array( const char* iter, const char* end ) { iter = dl_txt_skip_white( iter, end ); if( *iter != '[' ) @@ -605,7 +801,7 @@ const char* dl_txt_skip_string( const char* str, const char* end ) return str; } -static uint32_t dl_txt_pack_find_array_length( dl_ctx_t dl_ctx, dl_txt_pack_ctx* packctx, const dl_member_desc* member ) +static uint32_t dl_txt_pack_find_array_length( dl_ctx_t dl_ctx, dl_txt_pack_ctx* packctx, dl_type_storage_t storage_type ) { const char* iter = packctx->read_ctx.iter; const char* end = packctx->read_ctx.end; @@ -614,7 +810,7 @@ static uint32_t dl_txt_pack_find_array_length( dl_ctx_t dl_ctx, dl_txt_pack_ctx* if( *iter == ']' ) return 0; - switch( member->StorageType() ) + switch( storage_type ) { case DL_TYPE_STORAGE_INT8: // TODO: for pods there are no need to check array length! case DL_TYPE_STORAGE_INT16: @@ -657,6 +853,34 @@ static uint32_t dl_txt_pack_find_array_length( dl_ctx_t dl_ctx, dl_txt_pack_ctx* } } break; + case DL_TYPE_STORAGE_ANY_POINTER: + case DL_TYPE_STORAGE_ANY_ARRAY: + { + bool last_was_comma = false; + uint32_t array_length = 1; + uint32_t types = 0; + while(true) + { + iter = dl_txt_skip_white( iter, end ); + switch( *iter ) + { + case ',': + ++array_length; + break; + case '{': + last_was_comma = false; + iter = dl_txt_skip_map(iter, end); + continue; + case '\0': + case ']': + return types + (last_was_comma ? array_length - 1 : array_length) - 2 * types; + // TODO: I guess one can fool this parser by adding a ] or , in a comment at "the right place(tm)" + } + last_was_comma = *iter == ','; + ++iter; + } + } + break; case DL_TYPE_STORAGE_STR: { bool last_was_comma = false; @@ -721,10 +945,10 @@ static uint32_t dl_txt_pack_find_array_length( dl_ctx_t dl_ctx, dl_txt_pack_ctx* return (uint32_t)-1; } -static void dl_txt_pack_write_default_value( dl_ctx_t dl_ctx, - dl_txt_pack_ctx* packctx, - const dl_member_desc* member, - size_t member_pos ) +static dl_error_t dl_txt_pack_write_default_value( dl_ctx_t dl_ctx, + dl_txt_pack_ctx* packctx, + const dl_member_desc* member, + size_t member_pos ) { uint8_t* member_default_value = dl_ctx->default_data + member->default_value_offset; @@ -797,6 +1021,7 @@ static void dl_txt_pack_write_default_value( dl_ctx_t dl_ctx, if( !packctx->writer->dummy ) dl_internal_patch_member( dl_ctx, member, member_data, (uintptr_t)packctx->writer->data, subdata_pos - member_size - sizeof( dl_data_header ), &packctx->ptrs ); } + return DL_ERROR_OK; } static dl_error_t dl_txt_pack_member( dl_ctx_t dl_ctx, dl_txt_pack_ctx* packctx, size_t instance_pos, const dl_member_desc* member ) @@ -810,19 +1035,21 @@ static dl_error_t dl_txt_pack_member( dl_ctx_t dl_ctx, dl_txt_pack_ctx* packctx, // write switch( member->StorageType() ) { - case DL_TYPE_STORAGE_INT8: dl_txt_pack_eat_and_write_int8( dl_ctx, packctx ); break; - case DL_TYPE_STORAGE_INT16: dl_txt_pack_eat_and_write_int16( dl_ctx, packctx ); break; - case DL_TYPE_STORAGE_INT32: dl_txt_pack_eat_and_write_int32( dl_ctx, packctx ); break; - case DL_TYPE_STORAGE_INT64: dl_txt_pack_eat_and_write_int64( dl_ctx, packctx ); break; - case DL_TYPE_STORAGE_UINT8: dl_txt_pack_eat_and_write_uint8( dl_ctx, packctx ); break; - case DL_TYPE_STORAGE_UINT16: dl_txt_pack_eat_and_write_uint16( dl_ctx, packctx ); break; - case DL_TYPE_STORAGE_UINT32: dl_txt_pack_eat_and_write_uint32( dl_ctx, packctx ); break; - case DL_TYPE_STORAGE_UINT64: dl_txt_pack_eat_and_write_uint64( dl_ctx, packctx ); break; - case DL_TYPE_STORAGE_FP32: dl_txt_pack_eat_and_write_fp32( dl_ctx, packctx ); break; - case DL_TYPE_STORAGE_FP64: dl_txt_pack_eat_and_write_fp64( dl_ctx, packctx ); break; - case DL_TYPE_STORAGE_STR: dl_txt_pack_eat_and_write_string( dl_ctx, packctx ); break; - case DL_TYPE_STORAGE_PTR: dl_txt_pack_eat_and_write_ptr( dl_ctx, packctx, dl_internal_find_type( dl_ctx, member->type_id ), member_pos ); break; - case DL_TYPE_STORAGE_STRUCT: return dl_txt_pack_eat_and_write_struct( dl_ctx, packctx, dl_internal_find_type( dl_ctx, member->type_id ) ); + case DL_TYPE_STORAGE_INT8: dl_txt_pack_eat_and_write_int8( dl_ctx, packctx ); break; + case DL_TYPE_STORAGE_INT16: dl_txt_pack_eat_and_write_int16( dl_ctx, packctx ); break; + case DL_TYPE_STORAGE_INT32: dl_txt_pack_eat_and_write_int32( dl_ctx, packctx ); break; + case DL_TYPE_STORAGE_INT64: dl_txt_pack_eat_and_write_int64( dl_ctx, packctx ); break; + case DL_TYPE_STORAGE_UINT8: dl_txt_pack_eat_and_write_uint8( dl_ctx, packctx ); break; + case DL_TYPE_STORAGE_UINT16: dl_txt_pack_eat_and_write_uint16( dl_ctx, packctx ); break; + case DL_TYPE_STORAGE_UINT32: dl_txt_pack_eat_and_write_uint32( dl_ctx, packctx ); break; + case DL_TYPE_STORAGE_UINT64: dl_txt_pack_eat_and_write_uint64( dl_ctx, packctx ); break; + case DL_TYPE_STORAGE_FP32: dl_txt_pack_eat_and_write_fp32( dl_ctx, packctx ); break; + case DL_TYPE_STORAGE_FP64: dl_txt_pack_eat_and_write_fp64( dl_ctx, packctx ); break; + case DL_TYPE_STORAGE_STR: dl_txt_pack_eat_and_write_string( dl_ctx, packctx ); break; + case DL_TYPE_STORAGE_PTR: dl_txt_pack_eat_and_write_ptr( dl_ctx, packctx, dl_internal_find_type( dl_ctx, member->type_id ), member_pos ); break; + case DL_TYPE_STORAGE_ANY_POINTER: dl_txt_pack_eat_and_write_anyptr( dl_ctx, packctx, dl_string_to_substr( dl_internal_member_name( dl_ctx, member ) ) ); break; + case DL_TYPE_STORAGE_ANY_ARRAY: dl_txt_pack_eat_and_write_anyarray( dl_ctx, packctx, dl_string_to_substr( dl_internal_member_name( dl_ctx, member ) ) ); break; + case DL_TYPE_STORAGE_STRUCT: return dl_txt_pack_eat_and_write_struct( dl_ctx, packctx, dl_internal_find_type( dl_ctx, member->type_id ) ); case DL_TYPE_STORAGE_ENUM_INT8: case DL_TYPE_STORAGE_ENUM_INT16: case DL_TYPE_STORAGE_ENUM_INT32: @@ -847,7 +1074,7 @@ static dl_error_t dl_txt_pack_member( dl_ctx_t dl_ctx, dl_txt_pack_ctx* packctx, case DL_TYPE_ATOM_ARRAY: { dl_txt_eat_char( dl_ctx, &packctx->read_ctx, '[' ); - uint32_t array_length = dl_txt_pack_find_array_length( dl_ctx, packctx, member ); + uint32_t array_length = dl_txt_pack_find_array_length( dl_ctx, packctx, member->StorageType() ); if( array_length == 0 ) { dl_binary_writer_write_pint( packctx->writer, (size_t)0 ); @@ -856,7 +1083,7 @@ static dl_error_t dl_txt_pack_member( dl_ctx_t dl_ctx, dl_txt_pack_ctx* packctx, else { size_t element_size, element_align; - dl_txt_pack_array_item_size_align( dl_ctx, member, &element_size, &element_align ); + dl_txt_pack_array_item_size_align( dl_ctx, member->StorageType(), member->type_id, &element_size, &element_align ); size_t array_pos = dl_binary_writer_needed_size( packctx->writer ); array_pos = dl_internal_align_up( array_pos, element_align ); @@ -868,7 +1095,7 @@ static dl_error_t dl_txt_pack_member( dl_ctx_t dl_ctx, dl_txt_pack_ctx* packctx, dl_binary_writer_seek_end( packctx->writer ); dl_binary_writer_align( packctx->writer, element_align ); dl_binary_writer_reserve( packctx->writer, array_length * element_size ); - dl_error_t err = dl_txt_pack_eat_and_write_array( dl_ctx, packctx, member, array_length ); + dl_error_t err = dl_txt_pack_eat_and_write_array( dl_ctx, packctx, member->StorageType(), member->type_id, dl_internal_member_name( dl_ctx, member ), array_length ); if( DL_ERROR_OK != err ) return err; } dl_txt_eat_char( dl_ctx, &packctx->read_ctx, ']' ); @@ -877,18 +1104,18 @@ static dl_error_t dl_txt_pack_member( dl_ctx_t dl_ctx, dl_txt_pack_ctx* packctx, case DL_TYPE_ATOM_INLINE_ARRAY: { dl_txt_eat_char( dl_ctx, &packctx->read_ctx, '[' ); - uint32_t array_length = dl_txt_pack_find_array_length( dl_ctx, packctx, member ); + uint32_t array_length = dl_txt_pack_find_array_length( dl_ctx, packctx, member->StorageType() ); if(array_length > member->inline_array_cnt()) { dl_txt_read_failed( dl_ctx, &packctx->read_ctx, DL_ERROR_MALFORMED_DATA, - "to many elements in inline array, %u > %u", array_length, member->inline_array_cnt() ); + "too many elements in inline array, %u > %u", array_length, member->inline_array_cnt() ); } if(array_length > 0) { - dl_error_t err = dl_txt_pack_eat_and_write_array( dl_ctx, packctx, member, array_length ); + dl_error_t err = dl_txt_pack_eat_and_write_array( dl_ctx, packctx, member->StorageType(), member->type_id, dl_internal_member_name( dl_ctx, member ), array_length ); if( DL_ERROR_OK != err ) return err; } @@ -909,7 +1136,8 @@ static dl_error_t dl_txt_pack_member( dl_ctx_t dl_ctx, dl_txt_pack_ctx* packctx, for(uint32_t sub_member_i = 0; sub_member_i < sub_type->member_count; ++sub_member_i) { const dl_member_desc* sub_member = dl_get_type_member(dl_ctx, sub_type, sub_member_i); - dl_txt_pack_write_default_value(dl_ctx, packctx, sub_member, current_member_array_position + sub_member->offset[DL_PTR_SIZE_HOST]); + dl_error_t err = dl_txt_pack_write_default_value(dl_ctx, packctx, sub_member, current_member_array_position + sub_member->offset[DL_PTR_SIZE_HOST]); + if (DL_ERROR_OK != err) return err; } current_member_array_position += sub_type->size[DL_PTR_SIZE_HOST]; } @@ -1134,8 +1362,9 @@ static dl_error_t dl_txt_pack_eat_and_write_struct( dl_ctx_t dl_ctx, dl_txt_pack if( member->default_value_offset == UINT32_MAX ) dl_txt_read_failed( dl_ctx, &packctx->read_ctx, DL_ERROR_TXT_MISSING_MEMBER, "member %s.%s is not set and has no default value", dl_internal_type_name( dl_ctx, type ), dl_internal_member_name( dl_ctx, member ) ); - size_t member_pos = instance_pos + member->offset[DL_PTR_SIZE_HOST]; - dl_txt_pack_write_default_value(dl_ctx, packctx, member, member_pos); + size_t member_pos = instance_pos + member->offset[DL_PTR_SIZE_HOST]; + dl_error_t err = dl_txt_pack_write_default_value(dl_ctx, packctx, member, member_pos); + if (DL_ERROR_OK != err) return err; } } return DL_ERROR_OK; @@ -1200,14 +1429,10 @@ static dl_error_t dl_txt_pack_finalize_subdata( dl_ctx_t dl_ctx, dl_txt_pack_ctx while (results != packctx->subdata.m_Ptr + packctx->subdata.Len()) { if( results->name_hash != name_hash ) - { dl_txt_read_failed( dl_ctx, &packctx->read_ctx, DL_ERROR_MALFORMED_DATA, "non-used subdata '%.*s'", subdata_name.len, subdata_name.str ); - } if( results->name.len == subdata_name.len && strncmp(results->name.str, subdata_name.str, (size_t)subdata_name.len) == 0 ) - { break; - } ++results; } diff --git a/src/dl_txt_unpack.cpp b/src/dl_txt_unpack.cpp index a06ad58..b2d4030 100755 --- a/src/dl_txt_unpack.cpp +++ b/src/dl_txt_unpack.cpp @@ -150,6 +150,9 @@ static void dl_txt_unpack_enum( dl_ctx_t dl_ctx, dl_binary_writer* writer, const DL_ASSERT_MSG(false, "failed to find enum value " DL_PINT_FMT_STR, value); } +static dl_error_t dl_txt_unpack_struct( dl_ctx_t dl_ctx, dl_txt_unpack_ctx* unpack_ctx, dl_binary_writer* writer, const dl_type_desc* type, const uint8_t* struct_data ); +static dl_error_t dl_txt_unpack_array( dl_ctx_t dl_ctx, dl_txt_unpack_ctx* unpack_ctx, dl_binary_writer* writer, dl_type_storage_t storage, const uint8_t* array_data, uint32_t array_count, dl_typeid_t tid ); + static void dl_txt_unpack_ptr( dl_binary_writer* writer, dl_txt_unpack_ctx* unpack_ctx, const uint8_t* ptr ) { if( ptr == 0 ) @@ -168,17 +171,70 @@ static void dl_txt_unpack_ptr( dl_binary_writer* writer, dl_txt_unpack_ctx* unpa } } -static dl_error_t dl_txt_unpack_struct( dl_ctx_t dl_ctx, dl_txt_unpack_ctx* unpack_ctx, dl_binary_writer* writer, const dl_type_desc* type, const uint8_t* struct_data ); +static void dl_txt_unpack_anyptr( dl_ctx_t dl_ctx, dl_binary_writer* writer, dl_txt_unpack_ctx* unpack_ctx, const uint8_t* anyptr ) +{ + if( *(const uint8_t* const*)anyptr ) + { + unpack_ctx->has_ptrs = true; + dl_binary_writer_write( writer, "{\n", 2 ); + unpack_ctx->indent += 2; + dl_txt_unpack_write_indent( writer, unpack_ctx ); + dl_binary_writer_write( writer, "\"type\" : ", 9 ); + dl_typeid_t tid = *(const dl_typeid_t*)(anyptr + sizeof(void*)); + dl_txt_unpack_write_string( writer, dl_internal_type_name( dl_ctx, dl_internal_find_type( dl_ctx, tid ) ) ); + dl_binary_writer_write( writer, ",\n", 2); + dl_txt_unpack_write_indent( writer, unpack_ctx ); + dl_binary_writer_write( writer, "\"data\" : ", 9 ); + dl_txt_unpack_ptr( writer, unpack_ctx, *(const uint8_t* const*)anyptr ); + dl_binary_writer_write( writer, "\n", 1 ); + unpack_ctx->indent -= 2; + dl_txt_unpack_write_indent( writer, unpack_ctx ); + dl_binary_writer_write( writer, "}", 1 ); + } + else + { + dl_binary_writer_write(writer, "null", 4); + } +} + +static dl_error_t dl_txt_unpack_anyarray( dl_ctx_t dl_ctx, dl_binary_writer* writer, dl_txt_unpack_ctx* unpack_ctx, const uint8_t* mem ) +{ + uint32_t array_count = *(uint32_t*)( mem + sizeof( uintptr_t ) ); + dl_binary_writer_write( writer, "{\n", 2 ); + unpack_ctx->indent += 2; + dl_txt_unpack_write_indent( writer, unpack_ctx ); + dl_binary_writer_write( writer, "\"data\" : ", 9 ); + if( array_count ) + { + const uint8_t* array = *(const uint8_t**) mem; + dl_typeid_t type_id = *(dl_typeid_t*)( mem + 2 * sizeof(uintptr_t) ); + dl_error_t err = dl_txt_unpack_array( dl_ctx, unpack_ctx, writer, DL_TYPE_STORAGE_STRUCT, array, array_count, type_id ); + if( DL_ERROR_OK != err ) return err; + dl_binary_writer_write( writer, ",\n", 2 ); + dl_txt_unpack_write_indent( writer, unpack_ctx ); + dl_binary_writer_write( writer, "\"type\" : ", 9 ); + dl_txt_unpack_write_string( writer, dl_internal_type_name( dl_ctx, dl_internal_find_type( dl_ctx, type_id ) ) ); + dl_binary_writer_write( writer, "\n", 1 ); + } + else + { + dl_binary_writer_write( writer, "[]\n", 2 ); + } + unpack_ctx->indent -= 2; + dl_txt_unpack_write_indent( writer, unpack_ctx ); + dl_binary_writer_write( writer, "}", 1 ); + return DL_ERROR_OK; +} static dl_error_t dl_txt_unpack_array( dl_ctx_t dl_ctx, - dl_txt_unpack_ctx* unpack_ctx, - dl_binary_writer* writer, - dl_type_storage_t storage, - const uint8_t* array_data, - uint32_t array_count, - dl_typeid_t tid ) -{ - dl_error_t err; + dl_txt_unpack_ctx* unpack_ctx, + dl_binary_writer* writer, + dl_type_storage_t storage, + const uint8_t* array_data, + uint32_t array_count, + dl_typeid_t tid ) +{ + dl_error_t err = DL_ERROR_OK; dl_binary_writer_write_uint8( writer, '[' ); switch( storage ) { @@ -315,17 +371,51 @@ static dl_error_t dl_txt_unpack_array( dl_ctx_t dl_ctx, unpack_ctx->has_ptrs = true; break; } - case DL_TYPE_STORAGE_STRUCT: + case DL_TYPE_STORAGE_ANY_POINTER: { dl_binary_writer_write( writer, "\n", 1 ); + unpack_ctx->indent += 2; + dl_txt_unpack_write_indent( writer, unpack_ctx ); + for( uint32_t i = 0; i < array_count - 1; ++i ) + { + dl_txt_unpack_anyptr( dl_ctx, writer, unpack_ctx, array_data + sizeof(void*) * 2 * i ); + dl_binary_writer_write( writer, ",\n", 2 ); + dl_txt_unpack_write_indent( writer, unpack_ctx ); + } + dl_txt_unpack_anyptr( dl_ctx, writer, unpack_ctx, array_data + sizeof(void*) * 2 * (array_count - 1) ); + unpack_ctx->has_ptrs = true; + unpack_ctx->indent -= 2; + break; + } + case DL_TYPE_STORAGE_ANY_ARRAY: + { + dl_binary_writer_write( writer, "\n", 1 ); + unpack_ctx->indent += 2; dl_txt_unpack_write_indent( writer, unpack_ctx ); + for( uint32_t i = 0; i < array_count - 1; ++i ) + { + err = dl_txt_unpack_anyarray( dl_ctx, writer, unpack_ctx, array_data + sizeof(void*) * 3 * i ); + if( DL_ERROR_OK != err ) return err; + dl_binary_writer_write( writer, ",\n", 2 ); + dl_txt_unpack_write_indent( writer, unpack_ctx ); + } + err = dl_txt_unpack_anyarray( dl_ctx, writer, unpack_ctx, array_data + sizeof(void*) * 3 * (array_count - 1) ); + if( DL_ERROR_OK != err ) return err; + unpack_ctx->indent -= 2; + break; + } + case DL_TYPE_STORAGE_STRUCT: + { + dl_binary_writer_write( writer, "\n", 1 ); unpack_ctx->indent += 2; + dl_txt_unpack_write_indent( writer, unpack_ctx ); const dl_type_desc* type = dl_internal_find_type( dl_ctx, tid ); for( uint32_t i = 0; i < array_count - 1; ++i ) { err = dl_txt_unpack_struct( dl_ctx, unpack_ctx, writer, type, array_data + i * type->size[DL_PTR_SIZE_HOST] ); if( DL_ERROR_OK != err ) return err; - dl_binary_writer_write( writer, ", ", 2 ); + dl_binary_writer_write( writer, ",\n", 2 ); + dl_txt_unpack_write_indent( writer, unpack_ctx ); } err = dl_txt_unpack_struct( dl_ctx, unpack_ctx, writer, type, array_data + (array_count - 1) * type->size[DL_PTR_SIZE_HOST] ); if( DL_ERROR_OK != err ) return err; @@ -431,7 +521,6 @@ static dl_error_t dl_txt_unpack_array( dl_ctx_t dl_ctx, { dl_txt_unpack_enum( dl_ctx, writer, e, (uint64_t)mem[i] ); dl_binary_writer_write( writer, ", ", 2 ); - } dl_txt_unpack_enum( dl_ctx, writer, e, (uint64_t)mem[array_count - 1] ); } @@ -446,7 +535,6 @@ static dl_error_t dl_txt_unpack_array( dl_ctx_t dl_ctx, { dl_txt_unpack_enum( dl_ctx, writer, e, (uint64_t)mem[i] ); dl_binary_writer_write( writer, ", ", 2 ); - } dl_txt_unpack_enum( dl_ctx, writer, e, (uint64_t)mem[array_count - 1] ); } @@ -454,8 +542,10 @@ static dl_error_t dl_txt_unpack_array( dl_ctx_t dl_ctx, default: DL_ASSERT( false ); } + dl_binary_writer_write( writer, "\n", 1 ); + dl_txt_unpack_write_indent( writer, unpack_ctx ); dl_binary_writer_write_uint8( writer, ']' ); - return DL_ERROR_OK; + return err; } static dl_error_t dl_txt_unpack_member( dl_ctx_t dl_ctx, dl_txt_unpack_ctx* unpack_ctx, dl_binary_writer* writer, const dl_member_desc* member, const uint8_t* member_data ) @@ -489,9 +579,11 @@ static dl_error_t dl_txt_unpack_member( dl_ctx_t dl_ctx, dl_txt_unpack_ctx* unpa case DL_TYPE_STORAGE_ENUM_INT64: dl_txt_unpack_enum ( dl_ctx, writer, dl_internal_find_enum( dl_ctx, member->type_id ), (uint64_t)*( int64_t*) member_data ); break; case DL_TYPE_STORAGE_ENUM_UINT64: dl_txt_unpack_enum ( dl_ctx, writer, dl_internal_find_enum( dl_ctx, member->type_id ), (uint64_t)*(uint64_t*) member_data ); break; case DL_TYPE_STORAGE_STR: dl_txt_unpack_write_string_or_null( writer, *(const char**)member_data ); break; + case DL_TYPE_STORAGE_ANY_POINTER: dl_txt_unpack_anyptr( dl_ctx, writer, unpack_ctx, member_data ); break; + case DL_TYPE_STORAGE_ANY_ARRAY: return dl_txt_unpack_anyarray( dl_ctx, writer, unpack_ctx, member_data ); break; case DL_TYPE_STORAGE_PTR: { - dl_txt_unpack_ptr( writer, unpack_ctx, ( const uint8_t* ) * (uintptr_t*)member_data ); + dl_txt_unpack_ptr( writer, unpack_ctx, *(const uint8_t* const*)member_data ); unpack_ctx->has_ptrs = true; } break; @@ -588,6 +680,52 @@ static dl_error_t dl_txt_unpack_write_subdata_ptr_array( dl_ctx_t dl_ return DL_ERROR_OK; } +static dl_error_t dl_txt_unpack_write_subdata_anyptr_array( dl_ctx_t dl_ctx, + dl_txt_unpack_ctx* unpack_ctx, + dl_binary_writer* writer, + const uint8_t* array, + uint32_t array_count ) +{ + for( uint32_t element = 0; element < array_count; ++element ) + { + const dl_type_desc* sub_type = dl_internal_find_type( dl_ctx, *(dl_typeid_t*)( array + sizeof(void*) * (element * 2 + 1) ) ); + dl_error_t err = dl_txt_unpack_write_subdata_ptr( dl_ctx, + unpack_ctx, + writer, + array + sizeof(void*) * element * 2, + sub_type ); + if( DL_ERROR_OK != err ) return err; + } + return DL_ERROR_OK; +} + +static dl_error_t dl_txt_unpack_write_subdata_anyarray_array( dl_ctx_t dl_ctx, + dl_txt_unpack_ctx* unpack_ctx, + dl_binary_writer* writer, + const uint8_t* array, + uint32_t array_count ) +{ + for( uint32_t element = 0; element < array_count; ++element ) + { + const dl_type_desc* sub_type = dl_internal_find_type( dl_ctx, *(dl_typeid_t*)( array + sizeof(void*) * (element * 3 + 2) ) ); + if( sub_type->flags & DL_TYPE_FLAG_HAS_SUBDATA ) + { + const uint8_t* sub_array = *reinterpret_cast( array + sizeof(void*) * element * 3 ); + uint32_t sub_count = *reinterpret_cast( array + sizeof(void*) * (element * 3 + 1) ); + for( uint32_t sub_element = 0; sub_element < sub_count; ++sub_element ) + { + dl_error_t err = dl_txt_unpack_write_subdata( dl_ctx, + unpack_ctx, + writer, + sub_type, + sub_array + sub_element * sub_type->size[DL_PTR_SIZE_HOST] ); + if( DL_ERROR_OK != err ) return err; + } + } + } + return DL_ERROR_OK; +} + static dl_error_t dl_txt_unpack_write_member_subdata( dl_ctx_t dl_ctx, dl_txt_unpack_ctx* unpack_ctx, dl_binary_writer* writer, const dl_member_desc* member, const uint8_t* member_data ) { switch( member->AtomType() ) @@ -596,14 +734,19 @@ static dl_error_t dl_txt_unpack_write_member_subdata( dl_ctx_t dl_ctx, dl_txt_un { switch( member->StorageType() ) { + case DL_TYPE_STORAGE_ANY_POINTER: case DL_TYPE_STORAGE_PTR: return dl_txt_unpack_write_subdata_ptr( dl_ctx, unpack_ctx, writer, member_data, - dl_internal_find_type( dl_ctx, member->type_id ) ); - break; - + dl_internal_find_type( dl_ctx, member->StorageType() == DL_TYPE_STORAGE_ANY_POINTER ? *(dl_typeid_t*)(member_data + sizeof(void*)) : member->type_id ) ); + case DL_TYPE_STORAGE_ANY_ARRAY: + return dl_txt_unpack_write_subdata_anyarray_array( dl_ctx, + unpack_ctx, + writer, + member_data, + 1 ); case DL_TYPE_STORAGE_STRUCT: { const dl_type_desc* subtype = dl_internal_find_type( dl_ctx, member->type_id ); @@ -625,6 +768,18 @@ static dl_error_t dl_txt_unpack_write_member_subdata( dl_ctx_t dl_ctx, dl_txt_un { switch( member->StorageType() ) { + case DL_TYPE_STORAGE_ANY_POINTER: + return dl_txt_unpack_write_subdata_anyptr_array( dl_ctx, + unpack_ctx, + writer, + member_data, + member->inline_array_cnt() ); + case DL_TYPE_STORAGE_ANY_ARRAY: + return dl_txt_unpack_write_subdata_anyarray_array( dl_ctx, + unpack_ctx, + writer, + member_data, + member->inline_array_cnt() ); case DL_TYPE_STORAGE_PTR: return dl_txt_unpack_write_subdata_ptr_array( dl_ctx, unpack_ctx, @@ -632,7 +787,6 @@ static dl_error_t dl_txt_unpack_write_member_subdata( dl_ctx_t dl_ctx, dl_txt_un member_data, member->inline_array_cnt(), dl_internal_find_type( dl_ctx, member->type_id ) ); - break; case DL_TYPE_STORAGE_STRUCT: { const dl_type_desc* subtype = dl_internal_find_type( dl_ctx, member->type_id ); @@ -671,6 +825,26 @@ static dl_error_t dl_txt_unpack_write_member_subdata( dl_ctx_t dl_ctx, dl_txt_un } } break; + case DL_TYPE_STORAGE_ANY_POINTER: + { + const uint8_t* array = *(const uint8_t**)member_data; + uint32_t array_count = *(uint32_t*)(member_data + sizeof(uintptr_t) ); + return dl_txt_unpack_write_subdata_anyptr_array( dl_ctx, + unpack_ctx, + writer, + array, + array_count ); + } + case DL_TYPE_STORAGE_ANY_ARRAY: + { + const uint8_t* array = *(const uint8_t**)member_data; + uint32_t array_count = *(uint32_t*)(member_data + sizeof(uintptr_t) ); + return dl_txt_unpack_write_subdata_anyarray_array( dl_ctx, + unpack_ctx, + writer, + array, + array_count ); + } case DL_TYPE_STORAGE_PTR: { const uint8_t* array = *(const uint8_t**)member_data; @@ -682,7 +856,6 @@ static dl_error_t dl_txt_unpack_write_member_subdata( dl_ctx_t dl_ctx, dl_txt_un array_count, dl_internal_find_type( dl_ctx, member->type_id ) ); } - break; default: // ignore ... break; @@ -733,7 +906,10 @@ static dl_error_t dl_txt_unpack_struct( dl_ctx_t dl_ctx, dl_txt_unpack_ctx* unpa const dl_member_desc* member = dl_internal_union_type_to_member(dl_ctx, type, union_type); dl_error_t err = dl_txt_unpack_member( dl_ctx, unpack_ctx, writer, member, struct_data + member->offset[DL_PTR_SIZE_HOST] ); if( DL_ERROR_OK != err ) return err; - dl_binary_writer_write( writer, "\n", 1 ); + if( struct_data == unpack_ctx->packed_instance && unpack_ctx->has_ptrs ) + dl_binary_writer_write( writer, ",\n", 2 ); + else + dl_binary_writer_write( writer, "\n", 1 ); } else { @@ -744,30 +920,25 @@ static dl_error_t dl_txt_unpack_struct( dl_ctx_t dl_ctx, dl_txt_unpack_ctx* unpa if( DL_ERROR_OK != err ) return err; if( member_index < type->member_count - 1 ) dl_binary_writer_write( writer, ",\n", 2 ); + else if( struct_data == unpack_ctx->packed_instance && unpack_ctx->has_ptrs ) + dl_binary_writer_write( writer, ",\n", 2 ); else dl_binary_writer_write( writer, "\n", 1 ); } } - if( struct_data == unpack_ctx->packed_instance ) + if( struct_data == unpack_ctx->packed_instance && unpack_ctx->has_ptrs ) { - if( unpack_ctx->has_ptrs ) - { - unpack_ctx->indent += 2; - - dl_txt_unpack_write_indent( writer, unpack_ctx ); - dl_binary_writer_write( writer, ", \"__subdata\" : {\n", 18 ); - - unpack_ctx->indent += 2; - dl_error_t err = dl_txt_unpack_write_subdata( dl_ctx, unpack_ctx, writer, type, struct_data ); - if( DL_ERROR_OK != err ) return err; - unpack_ctx->indent -= 2; + dl_txt_unpack_write_indent( writer, unpack_ctx ); + dl_binary_writer_write( writer, "\"__subdata\" : {\n", 16 ); - dl_txt_unpack_write_indent( writer, unpack_ctx ); - dl_binary_writer_write( writer, "}\n", 2 ); + unpack_ctx->indent += 2; + dl_error_t err = dl_txt_unpack_write_subdata( dl_ctx, unpack_ctx, writer, type, struct_data ); + if( DL_ERROR_OK != err ) return err; + unpack_ctx->indent -= 2; - unpack_ctx->indent -= 2; - } + dl_txt_unpack_write_indent( writer, unpack_ctx ); + dl_binary_writer_write( writer, "}\n", 2 ); } unpack_ctx->indent -= 2; diff --git a/src/dl_typelib_read_bin.cpp b/src/dl_typelib_read_bin.cpp index 16e880d..ae02850 100644 --- a/src/dl_typelib_read_bin.cpp +++ b/src/dl_typelib_read_bin.cpp @@ -58,7 +58,7 @@ static void dl_endian_swap_enum_desc( dl_enum_desc* desc ) static void dl_endian_swap_member_desc( dl_member_desc* desc ) { desc->type = (dl_type_t)dl_swap_endian_uint32( (uint32_t)desc->type ); - desc->type_id = dl_swap_endian_uint32( desc->type_id ); + desc->type_id = dl_swap_endian_uint32( desc->type_id ); desc->size[DL_PTR_SIZE_32BIT] = dl_swap_endian_uint32( desc->size[DL_PTR_SIZE_32BIT] ); desc->size[DL_PTR_SIZE_64BIT] = dl_swap_endian_uint32( desc->size[DL_PTR_SIZE_64BIT] ); desc->offset[DL_PTR_SIZE_32BIT] = dl_swap_endian_uint32( desc->offset[DL_PTR_SIZE_32BIT] ); diff --git a/src/dl_typelib_read_txt.cpp b/src/dl_typelib_read_txt.cpp index 5343659..c5be165 100644 --- a/src/dl_typelib_read_txt.cpp +++ b/src/dl_typelib_read_txt.cpp @@ -8,14 +8,6 @@ #include // strtoul #include -#if (__cplusplus >= 201703L) // C++17 -# define DL_CONSTANT_EXPRESSION(expr) constexpr(expr) -#elif defined(_MSC_VER) -# define DL_CONSTANT_EXPRESSION(expr) (0, (expr)) -#else -# define DL_CONSTANT_EXPRESSION(expr) (expr) -#endif - template static inline T* dl_grow_array( dl_allocator* alloc, T* ptr, size_t* cap, size_t min_inc ) { @@ -166,6 +158,14 @@ static void dl_set_member_size_and_align_from_builtin( dl_type_storage_t storage member->set_size( 4, 8 ); member->set_align( 4, 8 ); break; + case DL_TYPE_STORAGE_ANY_POINTER: + member->set_size( 8, 16 ); + member->set_align( 4, 8 ); + break; + case DL_TYPE_STORAGE_ANY_ARRAY: + member->set_size( 12, 24 ); + member->set_align( 4, 8 ); + break; default: { uint32_t size = (uint32_t)dl_pod_size(storage); @@ -182,17 +182,19 @@ struct dl_builtin_type }; static const dl_builtin_type BUILTIN_TYPES[] = { - { "int8", DL_TYPE_STORAGE_INT8 }, - { "uint8", DL_TYPE_STORAGE_UINT8 }, - { "int16", DL_TYPE_STORAGE_INT16 }, - { "uint16", DL_TYPE_STORAGE_UINT16 }, - { "int32", DL_TYPE_STORAGE_INT32 }, - { "uint32", DL_TYPE_STORAGE_UINT32 }, - { "int64", DL_TYPE_STORAGE_INT64 }, - { "uint64", DL_TYPE_STORAGE_UINT64 }, - { "fp32", DL_TYPE_STORAGE_FP32 }, - { "fp64", DL_TYPE_STORAGE_FP64 }, - { "string", DL_TYPE_STORAGE_STR }, + { "int8", DL_TYPE_STORAGE_INT8 }, + { "uint8", DL_TYPE_STORAGE_UINT8 }, + { "int16", DL_TYPE_STORAGE_INT16 }, + { "uint16", DL_TYPE_STORAGE_UINT16 }, + { "int32", DL_TYPE_STORAGE_INT32 }, + { "uint32", DL_TYPE_STORAGE_UINT32 }, + { "int64", DL_TYPE_STORAGE_INT64 }, + { "uint64", DL_TYPE_STORAGE_UINT64 }, + { "fp32", DL_TYPE_STORAGE_FP32 }, + { "fp64", DL_TYPE_STORAGE_FP64 }, + { "string", DL_TYPE_STORAGE_STR }, + { "any_pointer", DL_TYPE_STORAGE_ANY_POINTER }, + { "any_array", DL_TYPE_STORAGE_ANY_ARRAY }, }; static const dl_builtin_type* dl_find_builtin_type( const char* name ) @@ -533,6 +535,7 @@ static bool dl_context_load_txt_type_has_subdata( dl_ctx_t ctx, dl_txt_read_ctx* { case DL_TYPE_STORAGE_STR: case DL_TYPE_STORAGE_PTR: + case DL_TYPE_STORAGE_ANY_POINTER: return true; case DL_TYPE_STORAGE_STRUCT: { @@ -621,8 +624,8 @@ static bool dl_txt_try_eat_char( dl_txt_read_ctx* read_state, char c ) } static uint64_t dl_context_load_txt_type_library_read_enum_value( dl_ctx_t ctx, - dl_type_storage_t storage, - dl_txt_read_ctx* read_state ) + dl_type_storage_t storage, + dl_txt_read_ctx* read_state ) { switch(storage) { diff --git a/src/dl_typelib_write_c_header.cpp b/src/dl_typelib_write_c_header.cpp index d8debdf..ff62458 100644 --- a/src/dl_typelib_write_c_header.cpp +++ b/src/dl_typelib_write_c_header.cpp @@ -135,29 +135,29 @@ static void dl_context_write_c_header_begin( dl_binary_writer* writer, const cha " {\n" " inline const T& operator[](size_t i) const\n" " {\n" - " DL_DATA_ASSERT(i < count);\n" - " return data[i];\n" + " DL_DATA_ASSERT(i < count);\n" + " return data[i];\n" " }\n" " inline T& operator[](size_t i)\n" " {\n" - " DL_DATA_ASSERT(i < count);\n" - " return data[i];\n" + " DL_DATA_ASSERT(i < count);\n" + " return data[i];\n" " }\n" " inline const T* begin() const\n" " {\n" - " return data;\n" + " return data;\n" " }\n" " inline const T* end() const\n" " {\n" - " return data + count;\n" + " return data + count;\n" " }\n" " inline T* begin()\n" " {\n" - " return data;\n" + " return data;\n" " }\n" " inline T* end()\n" " {\n" - " return data + count;\n" + " return data + count;\n" " }\n" " T* data;\n" " uint32_t count;\n" @@ -166,33 +166,55 @@ static void dl_context_write_c_header_begin( dl_binary_writer* writer, const cha " struct dl_array {\n" " inline const char*& operator[](size_t i) const\n" " {\n" - " DL_DATA_ASSERT(i < count);\n" - " return data[i];\n" + " DL_DATA_ASSERT(i < count);\n" + " return data[i];\n" " }\n" " inline const char*& operator[](size_t i)\n" " {\n" - " DL_DATA_ASSERT(i < count);\n" - " return data[i];\n" + " DL_DATA_ASSERT(i < count);\n" + " return data[i];\n" " }\n" " inline const char* const* begin() const\n" " {\n" - " return data;\n" + " return data;\n" " }\n" " inline const char* const* end() const\n" " {\n" - " return data + count;\n" + " return data + count;\n" " }\n" " inline const char** begin()\n" " {\n" - " return data;\n" + " return data;\n" " }\n" " inline const char** end()\n" " {\n" - " return data + count;\n" + " return data + count;\n" " }\n" " const char** data;\n" " uint32_t count;\n" " };\n" + " template <>\n" + " struct dl_array {\n" + " template \n" + " inline const T& operator[](size_t i) const\n" + " {\n" + " DL_DATA_ASSERT(i < count);\n" + " return reinterpret_cast(data)[i];\n" + " }\n" + " template \n" + " inline T& operator[](size_t i)\n" + " {\n" + " DL_DATA_ASSERT(i < count);\n" + " return reinterpret_cast(data)[i];\n" + " }\n" + " template \n" + " inline explicit operator dl_array&()\n" + " {\n" + " return *reinterpret_cast*>(this);\n" + " }\n" + " void* data;\n" + " uint32_t count;\n" + " };\n" "# define DL_DECLARE_ARRAY(type) dl_array\n" "# else\n" "# define DL_DECLARE_ARRAY(type) \\\n" @@ -202,6 +224,35 @@ static void dl_context_write_c_header_begin( dl_binary_writer* writer, const cha " uint32_t count; \\\n" " }\n" "# endif\n" + "\n" + " // ... DL_DECLARE_ANY ...\n" + " typedef uint32_t dl_typeid_t;\n" + "\n" + " struct dl_any_pointer {\n" + "# if defined(__cplusplus)\n" + " template \n" + " inline explicit operator T*()\n" + " {\n" + " DL_DATA_ASSERT(T::TYPE_ID == tid);\n" + " return reinterpret_cast(ptr);\n" + " }\n" + "# endif\n" + " void* ptr;\n" + " dl_typeid_t tid;\n" + " };\n" + "\n" + " struct dl_any_array {\n" + "# if defined(__cplusplus)\n" + " template \n" + " inline explicit operator dl_array&()\n" + " {\n" + " DL_DATA_ASSERT(T::TYPE_ID == tid);\n" + " return static_cast&>(array);\n" + " }\n" + "# endif\n" + " DL_DECLARE_ARRAY(void) array;\n" + " dl_typeid_t tid;\n" + " };\n" "#endif // __DL_AUTOGEN_HEADER_DL_ALIGN_DEFINED\n\n" ); } @@ -509,7 +560,7 @@ static dl_error_t dl_context_write_type( dl_ctx_t ctx, dl_type_storage_t storage dl_error_t err = dl_reflect_get_type_info( ctx, tid, &sub_type ); if (DL_ERROR_OK != err) return err; dl_binary_writer_write_string_fmt(writer, "struct %s", sub_type.name); - return DL_ERROR_OK; + return DL_ERROR_OK; } case DL_TYPE_STORAGE_ENUM_INT8: case DL_TYPE_STORAGE_ENUM_INT16: @@ -522,7 +573,7 @@ static dl_error_t dl_context_write_type( dl_ctx_t ctx, dl_type_storage_t storage dl_error_t err = dl_reflect_get_enum_info( ctx, tid, &enum_info ); if (DL_ERROR_OK != err) return err; dl_binary_writer_write_string_fmt(writer, "%s", enum_info.name); - return DL_ERROR_OK; + return DL_ERROR_OK; } case DL_TYPE_STORAGE_ENUM_INT64: case DL_TYPE_STORAGE_ENUM_UINT64: @@ -531,7 +582,7 @@ static dl_error_t dl_context_write_type( dl_ctx_t ctx, dl_type_storage_t storage dl_error_t err = dl_reflect_get_enum_info( ctx, tid, &enum_info ); if (DL_ERROR_OK != err) return err; dl_binary_writer_write_string_fmt(writer, "DL_ALIGN(8) %s", enum_info.name); - return DL_ERROR_OK; + return DL_ERROR_OK; } case DL_TYPE_STORAGE_INT8: dl_binary_writer_write_string_fmt(writer, "int8_t"); return DL_ERROR_OK; case DL_TYPE_STORAGE_UINT8: dl_binary_writer_write_string_fmt(writer, "uint8_t"); return DL_ERROR_OK; @@ -543,18 +594,20 @@ static dl_error_t dl_context_write_type( dl_ctx_t ctx, dl_type_storage_t storage case DL_TYPE_STORAGE_UINT64: dl_binary_writer_write_string_fmt(writer, "DL_ALIGN(8) uint64_t"); return DL_ERROR_OK; case DL_TYPE_STORAGE_FP32: dl_binary_writer_write_string_fmt(writer, "float"); return DL_ERROR_OK; case DL_TYPE_STORAGE_FP64: dl_binary_writer_write_string_fmt(writer, "DL_ALIGN(8) double"); return DL_ERROR_OK; - case DL_TYPE_STORAGE_STR: dl_binary_writer_write_string_fmt(writer, "const char*"); return DL_ERROR_OK; + case DL_TYPE_STORAGE_STR: dl_binary_writer_write_string_fmt(writer, "const char*"); return DL_ERROR_OK; + case DL_TYPE_STORAGE_ANY_POINTER: dl_binary_writer_write_string_fmt(writer, "struct dl_any_pointer"); return DL_ERROR_OK; + case DL_TYPE_STORAGE_ANY_ARRAY: dl_binary_writer_write_string_fmt(writer, "struct dl_any_array"); return DL_ERROR_OK; case DL_TYPE_STORAGE_PTR: { dl_type_info_t sub_type; dl_error_t err = dl_reflect_get_type_info( ctx, tid, &sub_type ); if (DL_ERROR_OK != err) return err; dl_binary_writer_write_string_fmt(writer, "struct %s*", sub_type.name); - return DL_ERROR_OK; - } + return DL_ERROR_OK; + } default: dl_binary_writer_write_string_fmt(writer, "UNKNOWN"); - return DL_ERROR_OK; + return DL_ERROR_TYPE_NOT_FOUND; } } @@ -659,10 +712,10 @@ static dl_error_t dl_context_write_c_header_member( dl_binary_writer* writer, dl break; case DL_TYPE_ATOM_ARRAY: { - dl_binary_writer_write_string_fmt(writer, " DL_DECLARE_ARRAY("); - dl_error_t err = dl_context_write_operator_array_access_type(ctx, member->storage, member->type_id, writer); + dl_binary_writer_write_string_fmt(writer, " DL_DECLARE_ARRAY("); + dl_error_t err = dl_context_write_operator_array_access_type(ctx, member->storage, member->type_id, writer); if (DL_ERROR_OK != err) return err; - dl_binary_writer_write_string_fmt(writer, ") %s;\n", member->name); + dl_binary_writer_write_string_fmt(writer, ") %s;\n", member->name); } break; case DL_TYPE_ATOM_INLINE_ARRAY: diff --git a/src/dl_typelib_write_txt.cpp b/src/dl_typelib_write_txt.cpp index 8716aea..2f36889 100644 --- a/src/dl_typelib_write_txt.cpp +++ b/src/dl_typelib_write_txt.cpp @@ -24,17 +24,19 @@ static const char* dl_context_type_to_string( dl_ctx_t ctx, dl_type_storage_t st return nullptr; return sub_type.name; } - case DL_TYPE_STORAGE_INT8: return "int8"; - case DL_TYPE_STORAGE_UINT8: return "uint8"; - case DL_TYPE_STORAGE_INT16: return "int16"; - case DL_TYPE_STORAGE_UINT16: return "uint16"; - case DL_TYPE_STORAGE_INT32: return "int32"; - case DL_TYPE_STORAGE_UINT32: return "uint32"; - case DL_TYPE_STORAGE_INT64: return "int64"; - case DL_TYPE_STORAGE_UINT64: return "uint64"; - case DL_TYPE_STORAGE_FP32: return "fp32"; - case DL_TYPE_STORAGE_FP64: return "fp64"; - case DL_TYPE_STORAGE_STR: return "string"; + case DL_TYPE_STORAGE_INT8: return "int8"; + case DL_TYPE_STORAGE_UINT8: return "uint8"; + case DL_TYPE_STORAGE_INT16: return "int16"; + case DL_TYPE_STORAGE_UINT16: return "uint16"; + case DL_TYPE_STORAGE_INT32: return "int32"; + case DL_TYPE_STORAGE_UINT32: return "uint32"; + case DL_TYPE_STORAGE_INT64: return "int64"; + case DL_TYPE_STORAGE_UINT64: return "uint64"; + case DL_TYPE_STORAGE_FP32: return "fp32"; + case DL_TYPE_STORAGE_FP64: return "fp64"; + case DL_TYPE_STORAGE_STR: return "string"; + case DL_TYPE_STORAGE_ANY_POINTER: return "any_pointer"; + case DL_TYPE_STORAGE_ANY_ARRAY: return "any_array"; default: DL_ASSERT(false); return 0x0; @@ -66,7 +68,7 @@ static dl_error_t dl_context_write_txt_enum( dl_ctx_t ctx, dl_binary_writer* wri if( DL_ERROR_OK != err ) return err; dl_binary_writer_write_fmt( writer, " \"%s\" : {\n" - " \"values\" : {\n", enum_info.name ); + " \"values\" : {\n", enum_info.name ); dl_enum_value_info_t* values = (dl_enum_value_info_t*)malloc( enum_info.value_count * sizeof( dl_enum_value_info_t ) ); err = dl_reflect_get_enum_values( ctx, tid, values, enum_info.value_count ); @@ -166,7 +168,11 @@ static dl_error_t dl_context_write_txt_member( dl_ctx_t ctx, dl_binary_writer* w dl_binary_writer_write_fmt( writer, "\"type\" : \"bitfield:%u\"", member->bitfield_bits ); break; case DL_TYPE_ATOM_ARRAY: - dl_binary_writer_write_fmt( writer, "\"type\" : \"%s[]\"", dl_context_type_to_string( ctx, member->storage, member->type_id ) ); + dl_binary_writer_write_fmt( writer, + member->storage == DL_TYPE_STORAGE_ANY_ARRAY + ? "\"type\" : \"%s\"" + : "\"type\" : \"%s[]\"", + dl_context_type_to_string( ctx, member->storage, member->type_id ) ); break; case DL_TYPE_ATOM_INLINE_ARRAY: dl_binary_writer_write_fmt( writer, diff --git a/src/dl_types.h b/src/dl_types.h index cbc4e99..9bfad04 100755 --- a/src/dl_types.h +++ b/src/dl_types.h @@ -27,6 +27,14 @@ #define DL_ARRAY_LENGTH(Array) (sizeof(Array)/sizeof(Array[0])) +#if (__cplusplus >= 201703L) // C++17 +# define DL_CONSTANT_EXPRESSION(expr) constexpr(expr) +#elif defined(_MSC_VER) +# define DL_CONSTANT_EXPRESSION(expr) (0, (expr)) +#else +# define DL_CONSTANT_EXPRESSION(expr) (expr) +#endif + #if defined( __LP64__ ) && !defined(__APPLE__) #define DL_INT64_FMT_STR "%ld" #define DL_UINT64_FMT_STR "%lu" @@ -163,8 +171,10 @@ struct dl_member_desc bool IsSimplePod() const { return StorageType() != DL_TYPE_STORAGE_STR && - StorageType() != DL_TYPE_STORAGE_PTR && - StorageType() != DL_TYPE_STORAGE_STRUCT; + StorageType() != DL_TYPE_STORAGE_PTR && + StorageType() != DL_TYPE_STORAGE_ANY_POINTER && + StorageType() != DL_TYPE_STORAGE_ANY_ARRAY && + StorageType() != DL_TYPE_STORAGE_STRUCT; } void set_size( uint32_t bit32, uint32_t bit64 ) @@ -331,6 +341,11 @@ struct dl_substr int len; }; +static inline dl_substr dl_string_to_substr( const char* str ) +{ + return dl_substr{ str, int(strlen(str)) }; +} + #ifdef _MSC_VER # define DL_FORCEINLINE __forceinline #else @@ -519,6 +534,12 @@ static inline size_t dl_pod_size( dl_type_storage_t storage ) case DL_TYPE_STORAGE_PTR: return sizeof(void*); + case DL_TYPE_STORAGE_ANY_POINTER: + return 2 * sizeof(void*); + + case DL_TYPE_STORAGE_ANY_ARRAY: + return 3 * sizeof(void*); + default: DL_ASSERT(false && "This should not happen!"); return 0; diff --git a/src/dl_util.cpp b/src/dl_util.cpp index 8ec0975..e64a96f 100755 --- a/src/dl_util.cpp +++ b/src/dl_util.cpp @@ -127,7 +127,7 @@ static dl_error_t dl_util_load_from_buffer( dl_ctx_t dl_ctx, dl_t if( type == 0 ) // autodetect type { - error = dl_instance_get_info( load_instance, packed_size, &info ); + error = dl_instance_get_info( load_instance, packed_size, &info ); if(error != DL_ERROR_OK) { free_func( load_instance, alloc_ctx ); return error; } type = info.root_type; } @@ -274,7 +274,7 @@ dl_error_t dl_util_store_to_stream( dl_ctx_t dl_ctx, dl_typeid_t case DL_UTIL_FILE_TYPE_TEXT: { // calculate pack-size - error = dl_txt_unpack_calc_size( dl_ctx, type, packed_instance, packed_size, &out_size ); + error = dl_txt_unpack_calc_size( dl_ctx, type, packed_instance, packed_size, &out_size ); if( error != DL_ERROR_OK ) { free_func( packed_instance, alloc_ctx ); return error; } // alloc data diff --git a/tests/dl_tests_anyarray.cpp b/tests/dl_tests_anyarray.cpp new file mode 100644 index 0000000..0931b24 --- /dev/null +++ b/tests/dl_tests_anyarray.cpp @@ -0,0 +1,87 @@ +#include +#include "dl_tests_base.h" + +TYPED_TEST(DLBase, AnyArray) +{ + Pods2 ps[] = { { 1, 2 }, { 3, 4 } }; + anyArray original = { { { ps, DL_ARRAY_LENGTH(ps) }, Pods2::TYPE_ID } }; + anyArray loaded[64]; + + this->do_the_round_about( anyArray::TYPE_ID, &original, loaded, sizeof( loaded ) ); + + EXPECT_EQ( original.arr.array.count, loaded[0].arr.array.count ); + EXPECT_EQ( original.arr.tid, loaded[0].arr.tid ); + dl_array& loaded_array = static_cast&>(loaded[0].arr); + EXPECT_EQ( ps[0].Int1, loaded_array[0].Int1 ); + EXPECT_EQ( ps[0].Int2, loaded_array[0].Int2 ); + EXPECT_EQ( ps[1].Int1, loaded_array[1].Int1 ); + EXPECT_EQ( ps[1].Int2, loaded_array[1].Int2 ); +} + +TYPED_TEST(DLBase, ArrayOfAnyArray) +{ + Pods2 ps1[] = { { 1, 2 }, { 3, 4 }, { 5, 6 } }; + PodPtr ps2[] = { { &ps1[2] }, { &ps1[1] }, { &ps1[0] } }; + dl_any_array arr[] = { { { ps1, DL_ARRAY_LENGTH(ps1) }, ps1[0].TYPE_ID }, { { ps2, DL_ARRAY_LENGTH(ps2) }, ps2[0].TYPE_ID } }; + anyArrayArray original = { { arr, DL_ARRAY_LENGTH(arr) } }; + anyArrayArray loaded[64]; + + this->do_the_round_about( original.TYPE_ID, &original, loaded, sizeof( loaded ) ); + + EXPECT_EQ( original.arr.count, loaded[0].arr.count ); + EXPECT_EQ( original.arr[0].array.count, loaded[0].arr[0].array.count ); + EXPECT_EQ( original.arr[1].array.count, loaded[0].arr[1].array.count ); + EXPECT_EQ( original.arr[0].tid, loaded[0].arr[0].tid ); + EXPECT_EQ( original.arr[1].tid, loaded[0].arr[1].tid ); + dl_array& loaded_pods2 = static_cast&>(loaded[0].arr[0]); + EXPECT_EQ( ps1[0].Int1, loaded_pods2[0].Int1 ); + EXPECT_EQ( ps1[0].Int2, loaded_pods2[0].Int2 ); + EXPECT_EQ( ps1[1].Int1, loaded_pods2[1].Int1 ); + EXPECT_EQ( ps1[1].Int2, loaded_pods2[1].Int2 ); + EXPECT_EQ( ps1[2].Int1, loaded_pods2[2].Int1 ); + EXPECT_EQ( ps1[2].Int2, loaded_pods2[2].Int2 ); + dl_array& loaded_podptr = static_cast&>(loaded[0].arr[1]); + EXPECT_EQ( ps1[0].Int1, loaded_podptr[2].PodPtr1->Int1 ); + EXPECT_EQ( ps1[0].Int2, loaded_podptr[2].PodPtr1->Int2 ); + EXPECT_EQ( ps1[1].Int1, loaded_podptr[1].PodPtr1->Int1 ); + EXPECT_EQ( ps1[1].Int2, loaded_podptr[1].PodPtr1->Int2 ); + EXPECT_EQ( ps1[2].Int1, loaded_podptr[0].PodPtr1->Int1 ); + EXPECT_EQ( ps1[2].Int2, loaded_podptr[0].PodPtr1->Int2 ); +} + +TYPED_TEST(DLBase, InlineArrayOfAnyArray) +{ + Pods2 ps1[] = { { 1, 2 }, { 3, 4 }, { 5, 6 } }; + PodPtr ps2[] = { { &ps1[2] }, { &ps1[1] }, { &ps1[0] } }; + AnyPtr any[] = { { { &ps1[0], ps1[0].TYPE_ID }, { &ps1[1], ps1[1].TYPE_ID } } }; + WithInlineAnyarrayArray original = { { { { ps1, DL_ARRAY_LENGTH(ps1) }, ps1[0].TYPE_ID }, { { ps2, DL_ARRAY_LENGTH(ps2) }, ps2[0].TYPE_ID }, { { any, DL_ARRAY_LENGTH(any) }, any[0].TYPE_ID } } }; + WithInlineAnyarrayArray loaded[64]; + + this->do_the_round_about( original.TYPE_ID, &original, loaded, sizeof( loaded ) ); + + EXPECT_EQ( original.Array[0].array.count, loaded[0].Array[0].array.count ); + EXPECT_EQ( original.Array[1].array.count, loaded[0].Array[1].array.count ); + EXPECT_EQ( original.Array[2].array.count, loaded[0].Array[2].array.count ); + EXPECT_EQ( original.Array[0].tid, loaded[0].Array[0].tid ); + EXPECT_EQ( original.Array[1].tid, loaded[0].Array[1].tid ); + EXPECT_EQ( original.Array[2].tid, loaded[0].Array[2].tid ); + dl_array& loaded_pods2 = static_cast&>(loaded[0].Array[0]); + EXPECT_EQ( ps1[0].Int1, loaded_pods2[0].Int1 ); + EXPECT_EQ( ps1[0].Int2, loaded_pods2[0].Int2 ); + EXPECT_EQ( ps1[1].Int1, loaded_pods2[1].Int1 ); + EXPECT_EQ( ps1[1].Int2, loaded_pods2[1].Int2 ); + EXPECT_EQ( ps1[2].Int1, loaded_pods2[2].Int1 ); + EXPECT_EQ( ps1[2].Int2, loaded_pods2[2].Int2 ); + dl_array& loaded_podptr = static_cast&>(loaded[0].Array[1]); + EXPECT_EQ( ps1[0].Int1, loaded_podptr[2].PodPtr1->Int1 ); + EXPECT_EQ( ps1[0].Int2, loaded_podptr[2].PodPtr1->Int2 ); + EXPECT_EQ( ps1[1].Int1, loaded_podptr[1].PodPtr1->Int1 ); + EXPECT_EQ( ps1[1].Int2, loaded_podptr[1].PodPtr1->Int2 ); + EXPECT_EQ( ps1[2].Int1, loaded_podptr[0].PodPtr1->Int1 ); + EXPECT_EQ( ps1[2].Int2, loaded_podptr[0].PodPtr1->Int2 ); + dl_array& loaded_any = static_cast&>(loaded[0].Array[2]); + EXPECT_EQ( ps1[0].Int1, static_cast(loaded_any[0].Ptr1)->Int1 ); + EXPECT_EQ( ps1[0].Int2, static_cast(loaded_any[0].Ptr1)->Int2 ); + EXPECT_EQ( ps1[1].Int1, static_cast(loaded_any[0].Ptr2)->Int1 ); + EXPECT_EQ( ps1[1].Int2, static_cast(loaded_any[0].Ptr2)->Int2 ); +} diff --git a/tests/dl_tests_anyptr.cpp b/tests/dl_tests_anyptr.cpp new file mode 100644 index 0000000..99caa38 --- /dev/null +++ b/tests/dl_tests_anyptr.cpp @@ -0,0 +1,183 @@ +#include +#include "dl_tests_base.h" + +TYPED_TEST(DLBase, anyptr) +{ + Pods pods = { 1, 2, 3, 4, 5, 6, 7, 8, 8.1f, 8.2 }; + AnyPtr orignal = { { &pods, Pods::TYPE_ID }, { &pods, Pods::TYPE_ID } }; + AnyPtr DL_ALIGN( 8 ) loaded[64]; + + this->do_the_round_about( AnyPtr::TYPE_ID, &orignal, loaded, sizeof( loaded ) ); + + EXPECT_NE(orignal.Ptr1.ptr, loaded[0].Ptr1.ptr); + EXPECT_EQ(orignal.Ptr1.tid, loaded[0].Ptr1.tid); + EXPECT_EQ(loaded[0].Ptr1.ptr, loaded[0].Ptr2.ptr); + EXPECT_EQ(loaded[0].Ptr1.tid, loaded[0].Ptr2.tid); + + const Pods* loaded_pods = static_cast(loaded[0].Ptr1); + EXPECT_EQ(pods.i8, loaded_pods->i8); + EXPECT_EQ(pods.i16, loaded_pods->i16); + EXPECT_EQ(pods.i32, loaded_pods->i32); + EXPECT_EQ(pods.i64, loaded_pods->i64); + EXPECT_EQ(pods.u8, loaded_pods->u8); + EXPECT_EQ(pods.u16, loaded_pods->u16); + EXPECT_EQ(pods.u32, loaded_pods->u32); + EXPECT_EQ(pods.u64, loaded_pods->u64); + EXPECT_EQ(pods.f32, loaded_pods->f32); + EXPECT_EQ(pods.f64, loaded_pods->f64); +} + +TYPED_TEST(DLBase, anyptr_null) +{ + Pods pods = { 1, 2, 3, 4, 5, 6, 7, 8, 8.1f, 8.2 }; + AnyPtr orignal = { { nullptr, 0 }, { &pods, Pods::TYPE_ID } }; + AnyPtr DL_ALIGN( 8 ) loaded[64]; + + this->do_the_round_about( AnyPtr::TYPE_ID, &orignal, loaded, sizeof( loaded ) ); + + EXPECT_EQ(orignal.Ptr1.ptr, loaded[0].Ptr1.ptr); // nullptr + EXPECT_EQ(orignal.Ptr2.tid, loaded[0].Ptr2.tid); + EXPECT_NE(orignal.Ptr2.ptr, loaded[0].Ptr2.ptr); + + const Pods* loaded_pods = static_cast(loaded[0].Ptr2); + EXPECT_EQ(pods.i8, loaded_pods->i8); + EXPECT_EQ(pods.i16, loaded_pods->i16); + EXPECT_EQ(pods.i32, loaded_pods->i32); + EXPECT_EQ(pods.i64, loaded_pods->i64); + EXPECT_EQ(pods.u8, loaded_pods->u8); + EXPECT_EQ(pods.u16, loaded_pods->u16); + EXPECT_EQ(pods.u32, loaded_pods->u32); + EXPECT_EQ(pods.u64, loaded_pods->u64); + EXPECT_EQ(pods.f32, loaded_pods->f32); + EXPECT_EQ(pods.f64, loaded_pods->f64); +} + +TYPED_TEST(DLBase, anyptr_with_pointers) +{ + Pods2 pods = { 1, 2 }; + PodPtr ptr = { &pods }; + AnyPtr orignal = { { &ptr, ptr.TYPE_ID }, { &ptr, ptr.TYPE_ID } }; + AnyPtr DL_ALIGN( 8 ) loaded[64]; + + this->do_the_round_about( AnyPtr::TYPE_ID, &orignal, loaded, sizeof( loaded ) ); + + EXPECT_NE(orignal.Ptr1.ptr, loaded[0].Ptr1.ptr); + EXPECT_EQ(orignal.Ptr1.tid, loaded[0].Ptr1.tid); + EXPECT_EQ(loaded[0].Ptr1.ptr, loaded[0].Ptr2.ptr); + EXPECT_EQ(loaded[0].Ptr1.tid, loaded[0].Ptr2.tid); + + const PodPtr* loaded_pods = static_cast(loaded[0].Ptr1); + EXPECT_EQ(pods.Int1, loaded_pods->PodPtr1->Int1); + EXPECT_EQ(pods.Int2, loaded_pods->PodPtr1->Int2); +} + +TYPED_TEST(DLBase, anyptr_with_array) +{ + Pods pods = { 1, 2, 3, 4, 5, 6, 7, 8, 8.1f, 8.2 }; + Pods* pod_ptr[3] = { &pods, nullptr, &pods }; + ptrArray ptr = { { pod_ptr, DL_ARRAY_LENGTH(pod_ptr) } }; + AnyPtr orignal = { { &ptr, ptr.TYPE_ID }, { &ptr, ptr.TYPE_ID } }; + AnyPtr DL_ALIGN( 8 ) loaded[64]; + + this->do_the_round_about( AnyPtr::TYPE_ID, &orignal, loaded, sizeof( loaded ) ); + + EXPECT_NE(orignal.Ptr1.ptr, loaded[0].Ptr1.ptr); + EXPECT_EQ(orignal.Ptr1.tid, loaded[0].Ptr1.tid); + EXPECT_EQ(loaded[0].Ptr1.ptr, loaded[0].Ptr2.ptr); + EXPECT_EQ(loaded[0].Ptr1.tid, loaded[0].Ptr2.tid); + + const ptrArray* loaded_pods = static_cast(loaded[0].Ptr1); + EXPECT_EQ(loaded_pods->arr[0], loaded_pods->arr[2]); + EXPECT_EQ(pods.i8, loaded_pods->arr[0]->i8); + EXPECT_EQ(pods.i16, loaded_pods->arr[0]->i16); + EXPECT_EQ(pods.i32, loaded_pods->arr[0]->i32); + EXPECT_EQ(pods.i64, loaded_pods->arr[0]->i64); + EXPECT_EQ(pods.u8, loaded_pods->arr[0]->u8); + EXPECT_EQ(pods.u16, loaded_pods->arr[0]->u16); + EXPECT_EQ(pods.u32, loaded_pods->arr[0]->u32); + EXPECT_EQ(pods.u64, loaded_pods->arr[0]->u64); + EXPECT_EQ(pods.f32, loaded_pods->arr[0]->f32); + EXPECT_EQ(pods.f64, loaded_pods->arr[0]->f64); +} + +TYPED_TEST(DLBase, anyptr_chain_circle) +{ + // tests both circualar ptrs and reference to root-node! + + AnyPtr ptr1 = { { 0x0, AnyPtr::TYPE_ID }, { 0x0, AnyPtr::TYPE_ID } }; + AnyPtr ptr2 = { { &ptr1, AnyPtr::TYPE_ID }, { 0x0, AnyPtr::TYPE_ID } }; + AnyPtr ptr3 = { { &ptr2, AnyPtr::TYPE_ID }, { 0x0, AnyPtr::TYPE_ID } }; + AnyPtr ptr4 = { { &ptr3, AnyPtr::TYPE_ID }, { 0x0, AnyPtr::TYPE_ID } }; + + ptr1.Ptr2.ptr = &ptr2; + ptr2.Ptr2.ptr = &ptr3; + ptr3.Ptr2.ptr = &ptr4; + + AnyPtr loaded[10]; + + this->do_the_round_about( AnyPtr::TYPE_ID, &ptr4, loaded, sizeof( loaded ) ); + + // Ptr4 + EXPECT_NE(ptr4.Ptr1.ptr, loaded[0].Ptr1.ptr); + EXPECT_EQ(ptr4.Ptr2.ptr, loaded[0].Ptr2.ptr); // is a null-ptr + EXPECT_EQ(ptr4.Ptr1.tid, loaded[0].Ptr1.tid); + + // Ptr3 + EXPECT_EQ(&loaded[0], static_cast(loaded[0].Ptr1.ptr)->Ptr2.ptr); + + // Ptr2 + EXPECT_EQ(loaded[0].Ptr1.ptr, static_cast(static_cast(loaded[0].Ptr1.ptr)->Ptr1.ptr)->Ptr2.ptr); + + // Ptr1 + EXPECT_EQ(static_cast(loaded[0].Ptr1.ptr)->Ptr1.ptr, static_cast(static_cast(static_cast(loaded[0].Ptr1.ptr)->Ptr1.ptr)->Ptr1.ptr)->Ptr2.ptr); + EXPECT_EQ(0, static_cast(static_cast(static_cast(loaded[0].Ptr1.ptr)->Ptr1.ptr)->Ptr1.ptr)->Ptr1.ptr); +} + +TYPED_TEST(DLBase, inline_anyptr_array) +{ + Pods2 p1 = { 1, 2 }; + Pods2 p2 = { 3, 4 }; + WithInlineAnyptrArray ptr_array = { { { &p1, Pods2::TYPE_ID }, { &p2, Pods2::TYPE_ID }, { nullptr, 0 }, { &p1, Pods2::TYPE_ID } } }; + + WithInlineAnyptrArray loaded[32]; + + this->do_the_round_about( WithInlineAnyptrArray::TYPE_ID, &ptr_array, &loaded, sizeof( loaded ) ); + + EXPECT_EQ( p1.Int1, static_cast(loaded[0].Array[0].ptr)->Int1 ); + EXPECT_EQ( p1.Int2, static_cast(loaded[0].Array[0].ptr)->Int2 ); + EXPECT_EQ( p2.Int1, static_cast(loaded[0].Array[1].ptr)->Int1 ); + EXPECT_EQ( p2.Int2, static_cast(loaded[0].Array[1].ptr)->Int2 ); + EXPECT_EQ( nullptr, loaded[0].Array[2].ptr ); + EXPECT_EQ( p1.Int1, static_cast(loaded[0].Array[3].ptr)->Int1 ); + EXPECT_EQ( p1.Int2, static_cast(loaded[0].Array[3].ptr)->Int2 ); + + EXPECT_NE( loaded[0].Array[0].ptr, loaded[0].Array[1].ptr ); + EXPECT_EQ( loaded[0].Array[0].ptr, loaded[0].Array[3].ptr ); +} + +TYPED_TEST(DLBase, anyptr_array) +{ + Pods2 p1 = { 1, 2 }; + Pods2 p2 = { 3, 4 }; + dl_any_pointer arr[] = { { &p1, Pods2::TYPE_ID }, { &p2, Pods2::TYPE_ID }, { nullptr, 0 }, { &p1, Pods2::TYPE_ID } }; + anyptrArray original; + original.arr.data = arr; + original.arr.count = DL_ARRAY_LENGTH(arr); + + anyptrArray loaded[32]; + + this->do_the_round_about( anyptrArray::TYPE_ID, &original, &loaded, sizeof( loaded ) ); + + EXPECT_EQ( original.arr.count, loaded[0].arr.count ); + EXPECT_EQ( p1.Int1, static_cast(loaded[0].arr[0].ptr)->Int1 ); + EXPECT_EQ( p1.Int2, static_cast(loaded[0].arr[0].ptr)->Int2 ); + EXPECT_EQ( p2.Int1, static_cast(loaded[0].arr[1].ptr)->Int1 ); + EXPECT_EQ( p2.Int2, static_cast(loaded[0].arr[1].ptr)->Int2 ); + EXPECT_EQ( nullptr, loaded[0].arr[2].ptr ); + EXPECT_EQ( p1.Int1, static_cast(loaded[0].arr[3].ptr)->Int1 ); + EXPECT_EQ( p1.Int2, static_cast(loaded[0].arr[3].ptr)->Int2 ); + + EXPECT_NE( &p2, loaded[0].arr[1].ptr ); + EXPECT_NE( loaded[0].arr[0].ptr, loaded[0].arr[1].ptr ); + EXPECT_EQ( loaded[0].arr[0].ptr, loaded[0].arr[3].ptr ); +} diff --git a/tests/dl_tests_base.cpp b/tests/dl_tests_base.cpp index 248abf2..acbb4d9 100644 --- a/tests/dl_tests_base.cpp +++ b/tests/dl_tests_base.cpp @@ -46,7 +46,7 @@ void pack_text_test::do_it( dl_ctx_t dl_ctx, dl_typeid_t type, { // unpack binary to txt size_t text_size = 0; - EXPECT_DL_ERR_OK( dl_txt_unpack_calc_size( dl_ctx, type, store_buffer, store_size, &text_size ) ); + ASSERT_DL_ERR_OK( dl_txt_unpack_calc_size( dl_ctx, type, store_buffer, store_size, &text_size ) ); char *text_buffer = (char*)malloc(text_size+1); memset(text_buffer, 0xFE, text_size+1); @@ -56,7 +56,7 @@ void pack_text_test::do_it( dl_ctx_t dl_ctx, dl_typeid_t type, // printf("%s\n", text_buffer); // pack txt to binary - EXPECT_DL_ERR_OK( dl_txt_pack_calc_size( dl_ctx, text_buffer, out_size ) ); + ASSERT_DL_ERR_OK( dl_txt_pack_calc_size( dl_ctx, text_buffer, out_size ) ); *out_buffer = (unsigned char*)malloc(*out_size+1); memset(*out_buffer, 0xFE, *out_size+1); diff --git a/tests/dl_tests_base.h b/tests/dl_tests_base.h index be17219..fbb4840 100644 --- a/tests/dl_tests_base.h +++ b/tests/dl_tests_base.h @@ -54,8 +54,8 @@ template struct convert_inplace_test { static void do_it( dl_ctx_t dl_ctx, dl_typeid_t type, - unsigned char* store_buffer, size_t store_size, - unsigned char** out_buffer, size_t* out_size ) + unsigned char* store_buffer, size_t store_size, + unsigned char** out_buffer, size_t* out_size ) { convert_inplace_test_do_it( dl_ctx, type, store_buffer, store_size, out_buffer, out_size, conv_ptr_size, conv_endian ); } @@ -75,7 +75,7 @@ struct DLBase : public DL dl_ctx_t dl_ctx = this->Ctx; // calc size of stored instance size_t store_size = 0; - EXPECT_DL_ERR_OK(dl_instance_calc_size(dl_ctx, type, pack_me, &store_size)); + ASSERT_DL_ERR_OK(dl_instance_calc_size(dl_ctx, type, pack_me, &store_size)); unsigned char* store_buffer = (unsigned char*)malloc(store_size+1); for( unsigned int i = 0; i < TEST_REPS; ++i ) { diff --git a/tests/dl_tests_txt.cpp b/tests/dl_tests_txt.cpp index 3259790..95f9e19 100755 --- a/tests/dl_tests_txt.cpp +++ b/tests/dl_tests_txt.cpp @@ -201,7 +201,7 @@ TEST_F(DLText, default_value_ptr) const char* text_data = STRINGIFY( { "DefaultPtr" : {} } ); unsigned char out_data_text[1024]; - DefaultPtr P1 = { 0 }; // this is so ugly! + DefaultPtr P1; EXPECT_DL_ERR_OK(dl_txt_pack(Ctx, text_data, out_data_text, sizeof(out_data_text), 0x0)); EXPECT_DL_ERR_OK(dl_instance_load(Ctx, DefaultPtr::TYPE_ID, &P1, sizeof(DefaultPtr), out_data_text, sizeof(out_data_text), 0x0)); @@ -209,6 +209,21 @@ TEST_F(DLText, default_value_ptr) EXPECT_EQ(0x0, P1.Ptr); } +TEST_F(DLText, default_value_anyptr) +{ + // default-values should be set correctly! + + const char* text_data = STRINGIFY( { "DefaultAnyPtr" : {} } ); + + unsigned char out_data_text[1024]; + DefaultAnyPtr P1; + + EXPECT_DL_ERR_OK(dl_txt_pack(Ctx, text_data, out_data_text, sizeof(out_data_text), 0x0)); + EXPECT_DL_ERR_OK(dl_instance_load(Ctx, DefaultAnyPtr::TYPE_ID, &P1, sizeof(DefaultAnyPtr), out_data_text, sizeof(out_data_text), 0x0)); + + EXPECT_EQ(0x0, P1.Ptr.ptr); +} + TEST_F(DLText, zero_as_ptr_fail) { // when referring to the root item, item 0, the types need to match. @@ -223,7 +238,7 @@ TEST_F(DLText, default_value_struct) const char* text_data = STRINGIFY( { "DefaultStruct" : {} } ); unsigned char out_data_text[1024]; - DefaultStruct loaded; // this is so ugly! + DefaultStruct loaded; EXPECT_DL_ERR_OK(dl_txt_pack(Ctx, text_data, out_data_text, sizeof(out_data_text), 0x0)); EXPECT_DL_ERR_OK(dl_instance_load(Ctx, DefaultStruct::TYPE_ID, &loaded, sizeof(DefaultStruct), out_data_text, sizeof(out_data_text), 0x0)); @@ -299,6 +314,22 @@ TEST_F(DLText, default_value_inline_array_pod) EXPECT_EQ(7u, loaded.Arr[3]); } +TEST_F(DLText, default_value_inline_array_anyptr) +{ + // default-values should be set correctly! + + const char* text_data = STRINGIFY( { "DefaultInlArrayAnyPtr" : {} } ); + + unsigned char out_data_text[1024]; + DefaultInlArrayAnyPtr loaded; + + EXPECT_DL_ERR_OK(dl_txt_pack(Ctx, text_data, out_data_text, sizeof(out_data_text), 0x0)); + EXPECT_DL_ERR_OK(dl_instance_load(Ctx, DefaultInlArrayAnyPtr::TYPE_ID, &loaded, sizeof(DefaultInlArrayAnyPtr), out_data_text, sizeof(out_data_text), 0x0)); + + EXPECT_EQ(nullptr, loaded.Arr[0].ptr); + EXPECT_EQ(nullptr, loaded.Arr[1].ptr); +} + TEST_F(DLText, default_value_inline_array_enum) { // default-values should be set correctly! @@ -826,6 +857,40 @@ TEST_F( DLText, unquoted_object_keys ) } } +TEST_F( DLText, any_pointers_missing_fields ) +{ + //"DefaultAnyArray" : { "members" : [ { "name" : "Arr", "type" : "any_array", "default" : {"data":[]} } ] }, + unsigned char out_text_data[1024]; + { + const char* test_text = STRINGIFY({ "DefaultAnyPtr" : { "Ptr" : { "type": "single_int", "data" : "ptr1" }, "__subdata" : { "ptr1": { "val": 1 } } } }); + EXPECT_DL_ERR_OK( dl_txt_pack( Ctx, test_text, out_text_data, DL_ARRAY_LENGTH(out_text_data), 0x0 ) ); + } + + { + const char* test_text = STRINGIFY({ "DefaultAnyPtr" : { "Ptr" : { "type": "single_int", "data" : null } } }); + EXPECT_DL_ERR_OK( dl_txt_pack(Ctx, test_text, out_text_data, DL_ARRAY_LENGTH(out_text_data), 0x0) ); + } + + { + const char* test_text = STRINGIFY({ "DefaultAnyPtr" : { "Ptr" : { "data" : null } } }); + EXPECT_DL_ERR_OK( dl_txt_pack( Ctx, test_text, out_text_data, DL_ARRAY_LENGTH(out_text_data), 0x0 ) ); + } + + { + const char* test_text = STRINGIFY({ "DefaultAnyPtr" : { "Ptr" : { "data" : "ptr1" }, "__subdata" : { "ptr1": { "val": 1 } } } }); + EXPECT_DL_ERR_EQ( DL_ERROR_MALFORMED_DATA, dl_txt_pack( Ctx, test_text, out_text_data, DL_ARRAY_LENGTH(out_text_data), 0x0 ) ); + } + + { + const char* test_text = STRINGIFY({ "DefaultAnyPtr" : { "Ptr" : { "type": "single_int" } } }); + EXPECT_DL_ERR_EQ( DL_ERROR_MALFORMED_DATA, dl_txt_pack( Ctx, test_text, out_text_data, DL_ARRAY_LENGTH(out_text_data), 0x0 ) ); + } + + { + const char* test_text = STRINGIFY({ "DefaultAnyPtr" : { "Ptr" : { } } }); + EXPECT_DL_ERR_EQ( DL_ERROR_MALFORMED_DATA, dl_txt_pack( Ctx, test_text, out_text_data, DL_ARRAY_LENGTH(out_text_data), 0x0 ) ); + } +} TEST_F( DLText, single_line_comments ) { diff --git a/tests/dl_tests_typelib.cpp b/tests/dl_tests_typelib.cpp index 7aa592e..08162ed 100644 --- a/tests/dl_tests_typelib.cpp +++ b/tests/dl_tests_typelib.cpp @@ -143,6 +143,20 @@ TEST_F( DLTypeLibTxt, missing_comma ) EXPECT_DL_ERR_EQ( DL_ERROR_TXT_PARSE_ERROR, dl_context_load_txt_type_library( ctx, single_member_typelib, sizeof(single_member_typelib)-1 ) ); } +TEST_F( DLTypeLibTxt, ptr_to_anyptr ) +{ + const char ptr_to_anyptr_typelib[] = STRINGIFY({ + "types" : { + "ptr_to_anyptr" : { "members" : [ + { "name" : "member1", "type" : "any_pointer*" } + ] } + } + }); + + // ... load typelib ... + EXPECT_DL_ERR_EQ( DL_ERROR_TXT_PARSE_ERROR, dl_context_load_txt_type_library( ctx, ptr_to_anyptr_typelib, sizeof(ptr_to_anyptr_typelib)-1 ) ); +} + TEST_F( DLTypeLibTxt, crash1 ) { const char single_member_typelib[] = STRINGIFY({ diff --git a/tests/unittest.tld b/tests/unittest.tld index ee54258..1293c06 100755 --- a/tests/unittest.tld +++ b/tests/unittest.tld @@ -78,6 +78,9 @@ "strArray" : { "members" : [ { "name" : "arr", "type" : "string[]" } ] }, "ptrArray" : { "members" : [ { "name" : "arr", "type" : "Pods*[]" } ] }, "enumArray" : { "members" : [ { "name" : "arr", "type" : "TestEnum1[]" } ] }, + "anyptrArray" : { "members" : [ { "name" : "arr", "type" : "any_pointer[]" } ] }, + "anyArrayArray" : { "members" : [ { "name" : "arr", "type" : "any_array[]" } ] }, + "anyArray" : { "members" : [ { "name" : "arr", "type" : "any_array" } ] }, "default_empty_type" : { "members" : [ { "name" : "empty", "type" : "uint32", "default" : 0 } ] }, "type_with_meta" : { "members" : [ @@ -121,6 +124,8 @@ "WithInlineArray" : { "members" : [ { "name" : "Array", "type" : "uint32[3]" } ] }, "WithInlineStructArray" : { "members" : [ { "name" : "Array", "type" : "Pods2[3]" } ] }, "WithInlineStructStructArray" : { "members" : [ { "name" : "Array", "type" : "WithInlineStructArray[2]" } ] }, + "WithInlineAnyptrArray" : { "members" : [ { "name" : "Array", "type" : "any_pointer[4]" } ] }, + "WithInlineAnyarrayArray" : { "members" : [ { "name" : "Array", "type" : "any_array[3]" } ] }, "SubString" : { "members" : [ { "name" : "Str", "type" : "string" } ] }, "InlineArrayWithSubString" : { "members" : [ { "name" : "Array", "type" : "SubString[2]" } ] }, @@ -172,6 +177,13 @@ ] }, + "AnyPtr" : { + "members" : [ + { "name" : "Ptr1", "type" : "any_pointer" }, + { "name" : "Ptr2", "type" : "any_pointer" } + ] + }, + "PtrChain" : { "members" : [ { "name" : "Int", "type" : "uint32" }, @@ -255,20 +267,23 @@ /* And a multiline comment here */ - "DefaultStr" : { "members" : [ { "name" : "Str", "type" : "string", "default" : "cowbells ftw!" } ] }, - "DefaultEnum" : { "members" : [ { "name" : "Enum", "type" : "TestEnum1", "default" : "TESTENUM1_VALUE3" } ] }, - "DefaultStruct" : { "members" : [ { "name" : "Struct", "type" : "Pods2", "default" : { "Int1" : 13, "Int2" : 37 } } ] }, - "DefaultPtr" : { "members" : [ { "name" : "Ptr", "type" : "Pods*", "default" : null } ] }, + "DefaultStr" : { "members" : [ { "name" : "Str", "type" : "string", "default" : "cowbells ftw!" } ] }, + "DefaultEnum" : { "members" : [ { "name" : "Enum", "type" : "TestEnum1", "default" : "TESTENUM1_VALUE3" } ] }, + "DefaultStruct" : { "members" : [ { "name" : "Struct", "type" : "Pods2", "default" : { "Int1" : 13, "Int2" : 37 } } ] }, + "DefaultPtr" : { "members" : [ { "name" : "Ptr", "type" : "Pods*", "default" : null } ] }, + "DefaultAnyPtr" : { "members" : [ { "name" : "Ptr", "type" : "any_pointer", "default" : null } ] }, + "DefaultAnyArray" : { "members" : [ { "name" : "Arr", "type" : "any_array", "default" : {"data":[]} } ] }, /** another comment */ - "DefaultInlArrayPod" : { "members" : [ { "name" : "Arr", "type" : "uint32[4]", "default" : [ 1, 3, 3, 7 ] } ] }, - "DefaultInlArrayStr" : { "members" : [ { "name" : "Arr", "type" : "string[4]", "default" : [ "cow", "bells", "are", "cool" ] } ] }, - "DefaultInlArrayEnum" : { "members" : [ { "name" : "Arr", "type" : "TestEnum1[4]", "default" : [ "TESTENUM1_VALUE3", - "TESTENUM1_VALUE1", - "TESTENUM1_VALUE2", - "TESTENUM1_VALUE4" ] } ] }, + "DefaultInlArrayPod" : { "members" : [ { "name" : "Arr", "type" : "uint32[4]", "default" : [ 1, 3, 3, 7 ] } ] }, + "DefaultInlArrayAnyPtr":{ "members" : [ { "name" : "Arr", "type" : "any_pointer[2]", "default" : [ null, null ] } ] }, + "DefaultInlArrayStr" : { "members" : [ { "name" : "Arr", "type" : "string[4]", "default" : [ "cow", "bells", "are", "cool" ] } ] }, + "DefaultInlArrayEnum" : { "members" : [ { "name" : "Arr", "type" : "TestEnum1[4]", "default" : [ "TESTENUM1_VALUE3", + "TESTENUM1_VALUE1", + "TESTENUM1_VALUE2", + "TESTENUM1_VALUE4" ] } ] }, "DefaultInlArrayArray" : { "members" : [ { "name" : "Arr", "type" : "PodArray1[2]", @@ -277,7 +292,9 @@ ] }, ///* hard one "DefaultArrayPod" : { "members" : [ { "name" : "Arr", "type" : "uint32[]", "default" : [ 1, 3, 3, 7 ] } ] }, + "DefaultArrayAnyPtr" : { "members" : [ { "name" : "Arr", "type" : "any_pointer[]", "default" : [ null, null ] } ] }, "DefaultArrayStr" : { "members" : [ { "name" : "Arr", "type" : "string[]", "default" : [ "cow", "bells", "are", "cool" ] } ] }, + "ArrayDefaultArrayStr" :{ "members" : [ { "name" : "Arr1", "type" : "DefaultArrayStr" }, { "name" : "Arr2", "type" : "DefaultArrayStr", "default" : { "Arr" : [ "cow", "bells", "are", "cool", "bells" ] } } ] }, "DefaultArrayEnum" : { "members" : [ { "name" : "Arr", "type" : "TestEnum1[]", "default" : [ "TESTENUM1_VALUE3", "TESTENUM1_VALUE1", "TESTENUM1_VALUE2",