diff --git a/include/dl/dl.h b/include/dl/dl.h old mode 100755 new mode 100644 diff --git a/include/dl/dl_defines.h b/include/dl/dl_defines.h old mode 100755 new mode 100644 diff --git a/include/dl/dl_reflect.h b/include/dl/dl_reflect.h index b6a950a..2408efe 100755 --- a/include/dl/dl_reflect.h +++ b/include/dl/dl_reflect.h @@ -51,6 +51,7 @@ typedef struct dl_member_info { const char* name; const char* comment; + const void* default_data; dl_type_atom_t atom; dl_type_storage_t storage; dl_typeid_t type_id; diff --git a/src/dl.cpp b/src/dl.cpp index bb1b2d1..fbbe599 100644 --- a/src/dl.cpp +++ b/src/dl.cpp @@ -1,4 +1,5 @@ #include "dl_types.h" +#include "dl_store.h" #include "dl_swap.h" #include "dl_binary_writer.h" #include "dl_patch_ptr.h" @@ -142,63 +143,6 @@ dl_error_t DL_DLL_EXPORT dl_instance_load_inplace( dl_ctx_t dl_ctx, 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( void* 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 void* 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 void* 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; @@ -216,7 +160,7 @@ static void dl_internal_store_string( const uint8_t* instance, CDLBinStoreContex 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} ); + store_ctx->strings.Add( {{str, length}, hash, (uint32_t) offset} ); dl_binary_writer_seek_set(&store_ctx->writer, pos); } if( !store_ctx->writer.dummy ) @@ -224,9 +168,9 @@ 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; uintptr_t offset = store_ctx->FindWrittenPtr( data ); @@ -265,7 +209,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 ) { @@ -304,7 +248,7 @@ 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 ) +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(); @@ -377,8 +321,8 @@ 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; - uint32_t count = *(uint32_t*)( data_ptr + sizeof(void*) ); + const uint8_t* data_ptr = instance; + uint32_t count = *(const uint32_t*)( data_ptr + sizeof(void*) ); uintptr_t offset = 0; @@ -417,7 +361,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 +369,8 @@ 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) ); } return DL_ERROR_OK; @@ -440,7 +386,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; @@ -499,7 +445,11 @@ dl_error_t dl_instance_store( dl_ctx_t dl_ctx, dl_typeid_t type_id, 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_binary_writer writer; + dl_binary_writer_init( &writer, out_buffer, out_buffer_size, store_ctx_is_dummy, DL_ENDIAN_HOST, DL_ENDIAN_HOST, DL_PTR_SIZE_HOST ); + CArrayStatic ptrs( dl_ctx->alloc ); + CArrayStatic strings( dl_ctx->alloc ); + CDLBinStoreContext store_context( writer, dl_ctx->alloc, ptrs, strings ); dl_data_header* header = (dl_data_header*)out_buffer; size_t header_plus_alignment = dl_internal_align_up( sizeof( dl_data_header ), type->alignment[DL_PTR_SIZE_HOST] ); diff --git a/src/dl_convert.cpp b/src/dl_convert.cpp index ed0d3ca..ab982f6 100644 --- a/src/dl_convert.cpp +++ b/src/dl_convert.cpp @@ -295,7 +295,6 @@ static dl_error_t dl_internal_convert_collect_instances_from_member( dl_ctx_t dl_internal_find_type(ctx, member->type_id), base_data, convert_ctx ); - break; case DL_TYPE_STORAGE_STR: dl_internal_convert_collect_instances_from_str_array( member_data, member->inline_array_cnt(), @@ -513,7 +512,7 @@ static dl_error_t dl_internal_convert_write_member( dl_ctx_t ctx, 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: diff --git a/src/dl_patch_ptr.cpp b/src/dl_patch_ptr.cpp index eac634a..ce231b5 100644 --- a/src/dl_patch_ptr.cpp +++ b/src/dl_patch_ptr.cpp @@ -1,6 +1,30 @@ #include "dl_patch_ptr.h" #include "dl_types.h" +struct dl_patched_ptrs +{ + CArrayStatic addresses; + + explicit dl_patched_ptrs( dl_allocator alloc ) + : addresses( alloc ) + { + } + + void add( const uint8_t* addr ) + { + DL_ASSERT( !patched( addr ) ); + addresses.Add( addr ); + } + + bool patched( const uint8_t* addr ) + { + for( size_t i = 0; i < addresses.Len(); ++i ) + if( addr == addresses[i] ) + return true; + return false; + } +}; + static uintptr_t dl_internal_patch_ptr( uint8_t* ptrptr, uintptr_t patch_distance ) { union { uint8_t* src; uintptr_t* ptr; }; @@ -13,75 +37,69 @@ static uintptr_t dl_internal_patch_ptr( uint8_t* ptrptr, uintptr_t patch_distanc static void dl_internal_patch_struct( dl_ctx_t ctx, const dl_type_desc* type, uint8_t* struct_data, - uintptr_t base_address, + uint8_t* base_address, uintptr_t patch_distance, - dl_patched_ptrs* patched_ptrs, 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, + uint8_t* base_address, uintptr_t patch_distance, - dl_patched_ptrs* patched_ptrs, dl_patched_ptrs* patched_payloads ) { uintptr_t offset = dl_internal_patch_ptr( ptr_data, patch_distance ); if( offset == 0x0 ) return; - uintptr_t ptr = (uintptr_t)base_address + offset; + uint8_t* ptr = base_address + offset; if( patched_payloads->patched( ptr ) ) return; patched_payloads->add( ptr ); - dl_internal_patch_struct( ctx, sub_type, (uint8_t*)ptr, base_address, patch_distance, patched_ptrs, patched_payloads ); + dl_internal_patch_struct( ctx, sub_type, ptr, base_address, patch_distance, patched_payloads ); } -static void dl_internal_patch_str_array( uint8_t* array_data, uint32_t count, uintptr_t patch_distance, uintptr_t base_address, dl_patched_ptrs* patched_ptrs ) +static void dl_internal_patch_str_array( uint8_t* array_data, uint32_t count, uintptr_t patch_distance ) { for( uint32_t index = 0; index < count; ++index ) - if( dl_internal_patch_ptr( array_data + index * sizeof( char* ), patch_distance ) && patched_ptrs ) - patched_ptrs->add( uintptr_t( array_data + index * sizeof( char* ) - base_address ) ); + dl_internal_patch_ptr( array_data + index * sizeof( char* ), patch_distance ); } 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, + uint8_t* base_address, uintptr_t patch_distance, - dl_patched_ptrs* patched_ptrs, - dl_patched_ptrs* patched_payloads ) + dl_patched_ptrs* patched_payloads ) { for( uint32_t index = 0; index < count; ++index ) - dl_internal_patch_ptr_instance( ctx, sub_type, array_data + index * sizeof(void*), base_address, patch_distance, patched_ptrs, patched_payloads ); + dl_internal_patch_ptr_instance( ctx, sub_type, array_data + index * sizeof(void*), base_address, patch_distance, patched_payloads ); } static void dl_internal_patch_struct_array( dl_ctx_t ctx, const dl_type_desc* type, uint8_t* array_data, uint32_t count, - uintptr_t base_address, + uint8_t* base_address, uintptr_t patch_distance, - dl_patched_ptrs* patched_ptrs, dl_patched_ptrs* patched_payloads ) { uint32_t size = dl_internal_align_up( type->size[DL_PTR_SIZE_HOST], type->alignment[DL_PTR_SIZE_HOST] ); for( uint32_t index = 0; index < count; ++index ) { uint8_t* struct_data = array_data + index * size; - dl_internal_patch_struct( ctx, type, struct_data, base_address, patch_distance, patched_ptrs, patched_payloads ); + dl_internal_patch_struct( ctx, type, struct_data, base_address, patch_distance, patched_payloads ); } } 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, + uint8_t* base_address, + uintptr_t patch_distance, + dl_patched_ptrs* patched_payloads ) { dl_type_atom_t atom_type = member->AtomType(); dl_type_storage_t storage_type = member->StorageType(); @@ -93,8 +111,7 @@ static void dl_internal_patch_member( dl_ctx_t ctx, switch( storage_type ) { case DL_TYPE_STORAGE_STR: - if( dl_internal_patch_ptr( member_data, patch_distance ) && patched_ptrs ) - patched_ptrs->add( uintptr_t(member_data - base_address) ); + dl_internal_patch_ptr( member_data, patch_distance ); break; case DL_TYPE_STORAGE_PTR: dl_internal_patch_ptr_instance( ctx, @@ -102,7 +119,6 @@ static void dl_internal_patch_member( dl_ctx_t ctx, member_data, base_address, patch_distance, - patched_ptrs, patched_payloads ); break; case DL_TYPE_STORAGE_STRUCT: @@ -111,7 +127,6 @@ static void dl_internal_patch_member( dl_ctx_t ctx, member_data, base_address, patch_distance, - patched_ptrs, patched_payloads ); break; default: @@ -125,7 +140,7 @@ static void dl_internal_patch_member( dl_ctx_t ctx, switch( storage_type ) { case DL_TYPE_STORAGE_STR: - dl_internal_patch_str_array( member_data, member->inline_array_cnt(), patch_distance, base_address, patched_ptrs ); + dl_internal_patch_str_array( member_data, member->inline_array_cnt(), patch_distance ); break; case DL_TYPE_STORAGE_PTR: dl_internal_patch_ptr_array( ctx, @@ -134,7 +149,6 @@ static void dl_internal_patch_member( dl_ctx_t ctx, dl_internal_find_type( ctx, member->type_id ), base_address, patch_distance, - patched_ptrs, patched_payloads ); break; case DL_TYPE_STORAGE_STRUCT: @@ -144,7 +158,6 @@ static void dl_internal_patch_member( dl_ctx_t ctx, member->inline_array_cnt(), base_address, patch_distance, - patched_ptrs, patched_payloads ); break; default: @@ -156,8 +169,6 @@ static void dl_internal_patch_member( dl_ctx_t ctx, case DL_TYPE_ATOM_ARRAY: { uintptr_t offset = dl_internal_patch_ptr( member_data, patch_distance ); - if( offset && patched_ptrs ) - patched_ptrs->add( uintptr_t( member_data - base_address ) ); uint8_t* src = member_data + sizeof( void* ); uint32_t count = *(uint32_t*)src; @@ -168,7 +179,7 @@ static void dl_internal_patch_member( dl_ctx_t ctx, switch( storage_type ) { case DL_TYPE_STORAGE_STR: - dl_internal_patch_str_array( array_data, count, patch_distance, base_address, patched_ptrs ); + dl_internal_patch_str_array( array_data, count, patch_distance ); break; case DL_TYPE_STORAGE_PTR: dl_internal_patch_ptr_array( ctx, @@ -177,7 +188,6 @@ static void dl_internal_patch_member( dl_ctx_t ctx, dl_internal_find_type( ctx, member->type_id ), base_address, patch_distance, - patched_ptrs, patched_payloads ); break; case DL_TYPE_STORAGE_STRUCT: @@ -187,7 +197,6 @@ static void dl_internal_patch_member( dl_ctx_t ctx, count, base_address, patch_distance, - patched_ptrs, patched_payloads ); break; default: @@ -204,9 +213,8 @@ static void dl_internal_patch_member( dl_ctx_t ctx, static void dl_internal_patch_union( dl_ctx_t ctx, const dl_type_desc* type, uint8_t* union_data, - uintptr_t base_address, + uint8_t* base_address, uintptr_t patch_distance, - dl_patched_ptrs* patched_ptrs, dl_patched_ptrs* patched_payloads ) { DL_ASSERT(type->flags & DL_TYPE_FLAG_IS_UNION); @@ -216,29 +224,28 @@ static void dl_internal_patch_union( dl_ctx_t ctx, uint32_t union_type = *((uint32_t*)(union_data + type_offset)); const dl_member_desc* member = dl_internal_union_type_to_member(ctx, type, union_type); DL_ASSERT(member->offset[DL_PTR_SIZE_HOST] == 0); - dl_internal_patch_member( ctx, member, union_data, base_address, patch_distance, patched_ptrs, patched_payloads ); + dl_internal_patch_member( ctx, member, union_data, base_address, patch_distance, patched_payloads ); } static void dl_internal_patch_struct( dl_ctx_t ctx, const dl_type_desc* type, uint8_t* struct_data, - uintptr_t base_address, + uint8_t* base_address, uintptr_t patch_distance, - dl_patched_ptrs* patched_ptrs, dl_patched_ptrs* patched_payloads ) { if( type->flags & DL_TYPE_FLAG_HAS_SUBDATA ) { if( type->flags & DL_TYPE_FLAG_IS_UNION ) { - dl_internal_patch_union( ctx, type, struct_data, base_address, patch_distance, patched_ptrs, patched_payloads ); + dl_internal_patch_union( ctx, type, struct_data, base_address, patch_distance, patched_payloads ); } else { for( uint32_t member_index = 0; member_index < type->member_count; ++member_index ) { const dl_member_desc* member = dl_get_type_member( ctx, type, member_index ); - dl_internal_patch_member( ctx, member, struct_data + member->offset[DL_PTR_SIZE_HOST], base_address, patch_distance, patched_ptrs, patched_payloads ); + dl_internal_patch_member( ctx, member, struct_data + member->offset[DL_PTR_SIZE_HOST], base_address, patch_distance, patched_payloads ); } } } @@ -247,26 +254,25 @@ static void dl_internal_patch_struct( dl_ctx_t ctx, 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 ) + uint8_t* base_address, + uintptr_t patch_distance) { dl_patched_ptrs patched(ctx->alloc); - dl_internal_patch_member( ctx, member, member_data, base_address, patch_distance, patched_ptrs, &patched ); + dl_internal_patch_member( ctx, member, member_data, base_address, patch_distance, &patched ); } void dl_internal_patch_instance( dl_ctx_t ctx, const dl_type_desc* type, uint8_t* instance, - uintptr_t base_address, + uint8_t* base_address, uintptr_t patch_distance ) { dl_patched_ptrs patched(ctx->alloc); - patched.add( (uintptr_t)instance ); + patched.add( instance ); if( type->flags & DL_TYPE_FLAG_IS_UNION ) { - dl_internal_patch_union( ctx, type, instance, base_address, patch_distance, 0, &patched ); + dl_internal_patch_union( ctx, type, instance, base_address, patch_distance, &patched ); } else { @@ -275,7 +281,7 @@ void dl_internal_patch_instance( dl_ctx_t ctx, const dl_member_desc* member = dl_get_type_member( ctx, type, member_index ); uint8_t* member_data = instance + member->offset[DL_PTR_SIZE_HOST]; - dl_internal_patch_member( ctx, member, member_data, base_address, patch_distance, 0, &patched ); + dl_internal_patch_member( ctx, member, member_data, base_address, patch_distance, &patched ); } } } diff --git a/src/dl_patch_ptr.h b/src/dl_patch_ptr.h index 7c16f40..eeb6989 100644 --- a/src/dl_patch_ptr.h +++ b/src/dl_patch_ptr.h @@ -3,30 +3,6 @@ #include "dl_types.h" -struct dl_patched_ptrs -{ - CArrayStatic addresses; - - explicit dl_patched_ptrs( dl_allocator alloc ) - : addresses( alloc ) - { - } - - void add( uintptr_t addr ) - { - DL_ASSERT( !patched( addr ) ); - addresses.Add( addr ); - } - - bool patched( uintptr_t addr ) - { - for( size_t i = 0; i < addresses.Len(); ++i ) - if( addr == addresses[i] ) - return true; - return false; - } -}; - /** * Patch all pointers in an instance. * @@ -39,7 +15,7 @@ struct dl_patched_ptrs void dl_internal_patch_instance( dl_ctx_t ctx, const dl_type_desc* type, uint8_t* instance, - uintptr_t base_address, + uint8_t* base_address, uintptr_t patch_distance ); /** @@ -50,13 +26,11 @@ void dl_internal_patch_instance( dl_ctx_t ctx, * @param member_data pointer to member to patch. * @param base_address base address to patch the pointers against. * @param patch_distance distance in bytes to patch all pointers. - * @param patched_ptrs keeps a record of all patched ptrs. Can be nullptr */ 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 ); + uint8_t* base_address, + uintptr_t patch_distance ); #endif // DL_PATCH_PTR_H_INCLUDED diff --git a/src/dl_reflect.cpp b/src/dl_reflect.cpp index 9f369c2..9b0dd22 100755 --- a/src/dl_reflect.cpp +++ b/src/dl_reflect.cpp @@ -1,6 +1,7 @@ /* copyright (c) 2010 Fredrik Kihlander, see LICENSE for more info */ #include "dl_types.h" +#include "dl_patch_ptr.h" #include
@@ -122,12 +123,27 @@ dl_error_t DL_DLL_EXPORT dl_reflect_get_type_members( dl_ctx_t dl_ctx, dl_typeid if(members_size < type->member_count) return DL_ERROR_BUFFER_TOO_SMALL; + if (!dl_ctx->default_data_patched) + { + for( unsigned int i = 0; i < dl_ctx->member_count; ++i ) + { + dl_member_desc& member_desc = dl_ctx->member_descs[ i ]; + if( member_desc.default_value_size && member_desc.default_value_size != member_desc.size[DL_PTR_SIZE_HOST] ) + { + uint8_t* default_data = dl_ctx->default_data + member_desc.default_value_offset; + dl_internal_patch_member( dl_ctx, &member_desc, default_data, 0, (uintptr_t)default_data - sizeof(dl_data_header) ); + } + } + dl_ctx->default_data_patched = true; // This is not thread safe. It would be better to avoid moving around default data and keep it patched like meta data + } + 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 ); out_members[member_index].name = dl_internal_member_name( dl_ctx, member ); out_members[member_index].comment = dl_internal_member_comment( dl_ctx, member ); + out_members[member_index].default_data = reinterpret_cast(dl_ctx->default_data + member->default_value_offset); out_members[member_index].atom = member->AtomType(); out_members[member_index].storage = member->StorageType(); out_members[member_index].type_id = member->type_id; diff --git a/src/dl_store.h b/src/dl_store.h new file mode 100644 index 0000000..01520fb --- /dev/null +++ b/src/dl_store.h @@ -0,0 +1,70 @@ +/* copyright (c) 2010 Fredrik Kihlander, see LICENSE for more info */ + +#ifndef DL_DL_STORE_H_INCLUDED +#define DL_DL_STORE_H_INCLUDED + +struct CDLBinStoreContext +{ + struct SString; + + CDLBinStoreContext( struct dl_binary_writer& writer_, dl_allocator alloc, CArrayStatic& ptrs_, CArrayStatic& strings_ ) + : writer( writer_ ) + , written_ptrs( alloc ) + , ptrs( ptrs_ ) + , strings( strings_ ) + { + } + + uintptr_t FindWrittenPtr( const void* ptr ) const + { + 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 void* ptr, uintptr_t pos ) + { + written_ptrs.Add( { pos, ptr } ); + } + + uint32_t GetStringOffset( const char* str, uint32_t length, uint32_t hash ) const + { + for( size_t i = 0; i < strings.Len(); ++i ) + if( strings[i].hash == hash && strings[i].str.len == length && memcmp( str, strings[i].str.str, length ) == 0 ) + return strings[i].offset; + + return 0; + } + + struct dl_binary_writer& writer; + + // Used to know where all pointer payloads are, so two identical pointers will refer to the same offset + struct SWrittenPtr + { + uintptr_t pos; + const void* ptr; + }; + CArrayStatic written_ptrs; + + // Used to know where all pointers are, to speed up pointer patching + CArrayStatic& ptrs; + + // Used to merge identical strings + struct SString + { + dl_substr str; + uint32_t hash; + uint32_t offset; + }; + CArrayStatic& strings; +}; + +dl_error_t dl_internal_store_member( dl_ctx_t dl_ctx, const dl_member_desc* member, const uint8_t* instance, CDLBinStoreContext* store_ctx ); + +#endif // DL_DL_STORE_H_INCLUDED diff --git a/src/dl_txt_pack.cpp b/src/dl_txt_pack.cpp index f353507..f17ad53 100755 --- a/src/dl_txt_pack.cpp +++ b/src/dl_txt_pack.cpp @@ -1,6 +1,7 @@ /* copyright (c) 2010 Fredrik Kihlander, see LICENSE for more info */ #include "dl_types.h" +#include "dl_store.h" #include
#include "dl_binary_writer.h" #include "dl_patch_ptr.h" @@ -9,7 +10,6 @@ #include #include #include -#include #include #include @@ -60,14 +60,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 +114,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,23 +139,48 @@ 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) - , ptrs(alloc) + : subdata(alloc) + , strings(alloc) + , ptrs(alloc) + { + } + + uint32_t GetStringOffset( dl_substr str, uint32_t hash ) { + for( size_t i = 0; i < strings.Len(); ++i ) + if( strings[i].hash == hash && strings[i].str.len == str.len && memcmp( strings[i].str.str, str.str, str.len ) == 0 ) + return strings[i].offset; + + return 0; } dl_txt_read_ctx read_ctx; dl_binary_writer* writer; + + // Where the "__subdata" section starts const char* subdata_pos; + + // Used to know where all pointer payloads are, so two identical pointers will refer to the same offset struct SSubData { dl_substr name; uint32_t name_hash; const dl_type_desc* type; size_t patch_pos; - }; + }; CArrayStatic subdata; - dl_patched_ptrs ptrs; + + // Used to merge identical strings + struct SString + { + dl_substr name; + uint32_t name_hash; + uint32_t offset; + }; + CArrayStatic<::CDLBinStoreContext::SString, 128> strings; + + // Used to know where all pointers are, to speed up pointer patching + CArrayStatic ptrs; }; static void dl_txt_pack_eat_and_write_int8( dl_ctx_t dl_ctx, dl_txt_pack_ctx* packctx ) @@ -250,16 +275,20 @@ static void dl_txt_pack_eat_and_write_string( dl_ctx_t dl_ctx, dl_txt_pack_ctx* if( str.str == 0x0 ) dl_txt_read_failed( dl_ctx, &packctx->read_ctx, DL_ERROR_MALFORMED_DATA, "expected a value of type 'string' or 'null'" ); - size_t curr = dl_binary_writer_tell( packctx->writer ); - dl_binary_writer_seek_end( packctx->writer ); - size_t strpos = dl_binary_writer_tell( packctx->writer ); - for( int i = 0; i < str.len; ++i ) + uint32_t hash = dl_internal_hash_buffer( str ); + size_t strpos = packctx->GetStringOffset( str, hash ); + if( strpos == 0 ) { - if( str.str[i] == '\\' ) + size_t curr = dl_binary_writer_tell( packctx->writer ); + dl_binary_writer_seek_end( packctx->writer ); + strpos = dl_binary_writer_tell( packctx->writer ); + for( uint32_t i = 0; i < str.len; ++i ) { - ++i; - switch( str.str[i] ) + if( str.str[i] == '\\' ) { + ++i; + switch( str.str[i] ) + { case '\'': case '\"': case '\\': @@ -273,16 +302,18 @@ static void dl_txt_pack_eat_and_write_string( dl_ctx_t dl_ctx, dl_txt_pack_ctx* break; default: DL_ASSERT( false && "unhandled escape!" ); + } } + else + dl_binary_writer_write_uint8( packctx->writer, (uint8_t)str.str[i] ); } - else - dl_binary_writer_write_uint8( packctx->writer, (uint8_t)str.str[i] ); + dl_binary_writer_write_uint8( packctx->writer, '\0' ); + dl_binary_writer_seek_set( packctx->writer, curr ); + packctx->strings.Add( { str, hash, (uint32_t) strpos } ); } - dl_binary_writer_write_uint8( packctx->writer, '\0' ); - dl_binary_writer_seek_set( packctx->writer, curr ); if( !packctx->writer->dummy ) - packctx->ptrs.add( dl_binary_writer_tell( packctx->writer ) ); - dl_binary_writer_write( packctx->writer, &strpos, sizeof(size_t) ); + packctx->ptrs.Add( dl_binary_writer_tell( packctx->writer ) ); + dl_binary_writer_write( packctx->writer, &strpos, sizeof( size_t ) ); } static void dl_txt_pack_eat_and_write_enum( dl_ctx_t dl_ctx, dl_txt_pack_ctx* packctx, const dl_enum_desc* edesc ) @@ -312,24 +343,25 @@ 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 ) dl_txt_read_failed( dl_ctx, &packctx->read_ctx, DL_ERROR_TXT_INVALID_MEMBER_TYPE, "expected string" ); if( !packctx->writer->dummy ) - packctx->ptrs.add( patch_pos ); + packctx->ptrs.Add( patch_pos ); - packctx->subdata.Add({ ptr, dl_internal_hash_buffer(ptr), type, patch_pos }); + packctx->subdata.Add({ ptr, dl_internal_hash_buffer( ptr ), type, patch_pos }); + return true; } static void dl_txt_pack_validate_c_symbol_key( dl_ctx_t dl_ctx, dl_txt_pack_ctx* packctx, dl_substr symbol ) { - for(int i = 0; i < symbol.len; ++i) + for(uint32_t i = 0; i < symbol.len; ++i) { if(!isalnum(symbol.str[i]) || symbol.str[i] == '_') dl_txt_read_failed( dl_ctx, &packctx->read_ctx, DL_ERROR_TXT_PARSE_ERROR, "found a non-valid key \"%.*s\" in data, did you miss a string-terminator? (\" or \')", symbol.len, symbol.str ); @@ -536,7 +568,7 @@ static void dl_txt_pack_array_item_size_align( dl_ctx_t dl_ctx, } } -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 != '[' ) @@ -721,15 +753,16 @@ 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; uint32_t member_size = member->size[DL_PTR_SIZE_HOST]; + dl_error_t err = DL_ERROR_OK; // ... handle bitfields differently since they take up sub-parts of bytes. if(member->AtomType() == DL_TYPE_ATOM_BITFIELD) { @@ -781,22 +814,19 @@ static void dl_txt_pack_write_default_value( dl_ctx_t dl_ctx, else { dl_binary_writer_seek_set( packctx->writer, member_pos ); - dl_binary_writer_write( packctx->writer, member_default_value, member->size[DL_PTR_SIZE_HOST] ); - } - - if( member_size != member->default_value_size ) - { - uint8_t* subdata = member_default_value + member_size; - // ... sub ptrs, copy and patch ... - dl_binary_writer_seek_end( packctx->writer ); - uintptr_t subdata_pos = dl_binary_writer_tell( packctx->writer ); - - dl_binary_writer_write( packctx->writer, subdata, member->default_value_size - member_size ); - - uint8_t* member_data = packctx->writer->data + member_pos; - 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 ); + if( member_size == member->default_value_size ) + dl_binary_writer_write( packctx->writer, member_default_value, member->size[DL_PTR_SIZE_HOST] ); + else + { + CDLBinStoreContext store_ctx( *packctx->writer, dl_ctx->alloc, packctx->ptrs, packctx->strings ); + uint8_t* default_data = (uint8_t*)dl_alloc( &dl_ctx->alloc, member->default_value_size ); + memcpy( default_data, member_default_value, member->default_value_size ); + dl_internal_patch_member( dl_ctx, member, default_data, nullptr, (uintptr_t)default_data - sizeof( dl_data_header ) ); + err = dl_internal_store_member( dl_ctx, member, default_data, &store_ctx ); + dl_free( &dl_ctx->alloc, default_data ); + } } + return err; } 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 ) @@ -860,8 +890,8 @@ static dl_error_t dl_txt_pack_member( dl_ctx_t dl_ctx, dl_txt_pack_ctx* packctx, 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 ) ); + 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 ); @@ -909,7 +939,9 @@ 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( err != DL_ERROR_OK ) + return err; } current_member_array_position += sub_type->size[DL_PTR_SIZE_HOST]; } @@ -1022,7 +1054,7 @@ static const dl_substr dl_txt_eat_object_key( dl_txt_read_ctx* readctx ) if(key_start != key_end) { res.str = key_start; - res.len = (int)(key_end - key_start); + res.len = (uint32_t)(key_end - key_start); readctx->iter = res.str + res.len; return res; } @@ -1135,7 +1167,8 @@ static dl_error_t dl_txt_pack_eat_and_write_struct( dl_ctx_t dl_ctx, dl_txt_pack 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); + 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; @@ -1329,7 +1362,7 @@ dl_error_t dl_txt_pack_internal( dl_ctx_t dl_ctx, const char* txt_instance, unsi // write header if( out_buffer_size > 0 ) { - CArrayStatic& pointers = packctx.ptrs.addresses; + CArrayStatic& pointers = packctx.ptrs; dl_data_header& header = *(dl_data_header*)writer.data; header.id = DL_INSTANCE_ID; @@ -1337,7 +1370,6 @@ dl_error_t dl_txt_pack_internal( dl_ctx_t dl_ctx, const char* txt_instance, unsi header.root_instance_type = dl_internal_typeid_of( dl_ctx, root_type ); header.instance_size = uint32_t(dl_binary_writer_needed_size( &writer ) - dl_internal_align_up( sizeof( dl_data_header ), root_type->alignment[DL_PTR_SIZE_HOST] )); header.is_64_bit_ptr = sizeof( void* ) == 8 ? 1 : 0; - header.first_pointer_to_patch = pointers.Len() ? (uint32_t)pointers[0] : 0; uintptr_t offset_shift = sizeof( uintptr_t ) * 4; if( dl_binary_writer_needed_size( &writer ) >= ( 1ULL << offset_shift ) || !use_fast_ptr_patch ) @@ -1353,6 +1385,7 @@ dl_error_t dl_txt_pack_internal( dl_ctx_t dl_ctx, const char* txt_instance, unsi uintptr_t offset = *(uintptr_t*)&packctx.writer->data[pointers[i]]; *(uintptr_t*)&packctx.writer->data[pointers[i]] = offset | ( ( (uintptr_t)( pointers[i + 1] - pointers[i] ) ) << offset_shift ); } + header.first_pointer_to_patch = (uint32_t)pointers[0]; } } } diff --git a/src/dl_txt_read.h b/src/dl_txt_read.h index 8f1d8b3..86467e4 100644 --- a/src/dl_txt_read.h +++ b/src/dl_txt_read.h @@ -98,7 +98,7 @@ static dl_substr dl_txt_eat_string_quote( dl_txt_read_ctx* readctx, char quote ) if( *key_end == quote ) { res.str = key_start; - res.len = (int)(key_end - key_start); + res.len = (uint32_t)(key_end - key_start); readctx->iter = res.str + res.len + 1; return res; } diff --git a/src/dl_typelib_read_bin.cpp b/src/dl_typelib_read_bin.cpp index 16e880d..cb5a992 100644 --- a/src/dl_typelib_read_bin.cpp +++ b/src/dl_typelib_read_bin.cpp @@ -1,6 +1,7 @@ #include
#include "dl_internal_util.h" #include "dl_types.h" +#include "dl_patch_ptr.h" static void dl_internal_load_type_library_defaults( dl_ctx_t dl_ctx, const uint8_t* default_data, @@ -87,6 +88,20 @@ dl_error_t dl_context_load_type_library( dl_ctx_t dl_ctx, const unsigned char* l { if(lib_data_size < sizeof(dl_typelib_header)) return DL_ERROR_MALFORMED_DATA; + + if (dl_ctx->default_data_patched) + { + for( unsigned int i = 0; i < dl_ctx->member_count; ++i ) + { + dl_member_desc& member_desc = dl_ctx->member_descs[ i ]; + if( member_desc.default_value_size && member_desc.default_value_size != member_desc.size[DL_PTR_SIZE_HOST] ) + { + uint8_t* default_data = dl_ctx->default_data + member_desc.default_value_offset; + dl_internal_patch_member( dl_ctx, &member_desc, default_data, 0, static_cast( sizeof(dl_data_header) - (size_t)default_data ) ); + } + } + dl_ctx->default_data_patched = false; // This is not thread safe. It would be better to avoid moving around default data and keep it patched like meta data + } dl_typelib_header header; dl_internal_read_typelibrary_header(&header, lib_data); @@ -131,16 +146,15 @@ dl_error_t dl_context_load_type_library( dl_ctx_t dl_ctx, const unsigned char* l } } - memcpy( dl_ctx->type_ids + dl_ctx->type_count, lib_data + types_lookup_offset, sizeof( dl_typeid_t ) * header.type_count ); - memcpy( dl_ctx->enum_ids + dl_ctx->enum_count, lib_data + enums_lookup_offset, sizeof( dl_typeid_t ) * header.enum_count ); - memcpy( dl_ctx->type_descs + dl_ctx->type_count, lib_data + types_offset, sizeof( dl_type_desc ) * header.type_count ); - memcpy( dl_ctx->enum_descs + dl_ctx->enum_count, lib_data + enums_offset, sizeof( dl_enum_desc ) * header.enum_count ); - memcpy( dl_ctx->member_descs + dl_ctx->member_count, lib_data + members_offset, sizeof( dl_member_desc ) * header.member_count ); - memcpy( dl_ctx->enum_value_descs + dl_ctx->enum_value_count, lib_data + enum_values_offset, sizeof( dl_enum_value_desc ) * header.enum_value_count ); - memcpy( dl_ctx->enum_alias_descs + dl_ctx->enum_alias_count, lib_data + enum_aliases_offset, sizeof( dl_enum_alias_desc ) * header.enum_alias_count ); + memcpy( dl_ctx->type_ids + dl_ctx->type_count, lib_data + types_lookup_offset, sizeof( dl_typeid_t ) * header.type_count ); + memcpy( dl_ctx->enum_ids + dl_ctx->enum_count, lib_data + enums_lookup_offset, sizeof( dl_typeid_t ) * header.enum_count ); + memcpy( dl_ctx->type_descs + dl_ctx->type_count, lib_data + types_offset, sizeof( dl_type_desc ) * header.type_count ); + memcpy( dl_ctx->enum_descs + dl_ctx->enum_count, lib_data + enums_offset, sizeof( dl_enum_desc ) * header.enum_count ); + memcpy( dl_ctx->member_descs + dl_ctx->member_count, lib_data + members_offset, sizeof( dl_member_desc ) * header.member_count ); + memcpy( dl_ctx->enum_value_descs + dl_ctx->enum_value_count, lib_data + enum_values_offset, sizeof( dl_enum_value_desc ) * header.enum_value_count ); + memcpy( dl_ctx->enum_alias_descs + dl_ctx->enum_alias_count, lib_data + enum_aliases_offset, sizeof( dl_enum_alias_desc ) * header.enum_alias_count ); memcpy( dl_ctx->typedata_strings + dl_ctx->typedata_strings_size, lib_data + typedata_strings_offset, header.typeinfo_strings_size ); - if(header.c_includes_size) - memcpy( dl_ctx->c_includes + dl_ctx->c_includes_size, lib_data + c_includes_offset, header.c_includes_size ); + memcpy( dl_ctx->c_includes + dl_ctx->c_includes_size, lib_data + c_includes_offset, header.c_includes_size ); if( DL_ENDIAN_HOST == DL_ENDIAN_BIG ) { diff --git a/src/dl_typelib_read_txt.cpp b/src/dl_typelib_read_txt.cpp index 5343659..1a28832 100644 --- a/src/dl_typelib_read_txt.cpp +++ b/src/dl_typelib_read_txt.cpp @@ -4,18 +4,11 @@ #include "dl_types.h" #include "dl_alloc.h" #include "dl_txt_read.h" +#include "dl_patch_ptr.h" #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 ) { @@ -1138,7 +1131,7 @@ static void dl_context_load_txt_type_library_read_member( dl_ctx_t ctx, dl_txt_r while(*end != ',' && *end != '}') ++end; } default_val.str = start; - default_val.len = (int)(end - start); + default_val.len = (uint32_t)(end - start); read_state->iter = end; } else if( strncmp( "const", key.str, 5) == 0) @@ -1320,6 +1313,20 @@ static const dl_type_desc* dl_internal_member_owner( dl_ctx_t ctx, const dl_memb static void dl_context_load_txt_type_library_inner( dl_ctx_t ctx, dl_txt_read_ctx* read_state ) { + if (ctx->default_data_patched) + { + for( unsigned int i = 0; i < ctx->member_count; ++i ) + { + dl_member_desc& member_desc = ctx->member_descs[ i ]; + if( member_desc.default_value_size && member_desc.default_value_size != member_desc.size[DL_PTR_SIZE_HOST] ) + { + uint8_t* default_data = ctx->default_data + member_desc.default_value_offset; + dl_internal_patch_member( ctx, &member_desc, default_data, 0, static_cast(-(ptrdiff_t)default_data) ); + } + } + ctx->default_data_patched = false; // This is not thread safe. It would be better to avoid moving around default data and keep it patched like meta data + } + #if defined(_MSC_VER ) #pragma warning(push) #pragma warning(disable:4611) diff --git a/src/dl_typelib_write_bin.cpp b/src/dl_typelib_write_bin.cpp index 5b2804c..5da6071 100644 --- a/src/dl_typelib_write_bin.cpp +++ b/src/dl_typelib_write_bin.cpp @@ -1,5 +1,6 @@ #include
#include "dl_binary_writer.h" +#include "dl_patch_ptr.h" dl_error_t dl_context_write_type_library( dl_ctx_t dl_ctx, unsigned char* out_lib, size_t out_lib_size, size_t* produced_bytes ) { @@ -20,6 +21,20 @@ dl_error_t dl_context_write_type_library( dl_ctx_t dl_ctx, unsigned char* out_li header.typeinfo_strings_size = (uint32_t)dl_ctx->typedata_strings_size; header.c_includes_size = (uint32_t)dl_ctx->c_includes_size; header.metadatas_count = (uint32_t)dl_ctx->metadatas_count; + + if (dl_ctx->default_data_patched) + { + for( unsigned int i = 0; i < dl_ctx->member_count; ++i ) + { + dl_member_desc& member_desc = dl_ctx->member_descs[ i ]; + if( member_desc.default_value_size && member_desc.default_value_size != member_desc.size[DL_PTR_SIZE_HOST] ) + { + uint8_t* default_data = dl_ctx->default_data + member_desc.default_value_offset; + dl_internal_patch_member( dl_ctx, &member_desc, default_data, 0, static_cast(-(ptrdiff_t)default_data) ); + } + } + dl_ctx->default_data_patched = false; // This is not thread safe. It would be better to avoid moving around default data and keep it patched like meta data + } dl_binary_writer_write( &writer, &header, sizeof( dl_typelib_header ) ); if(dl_ctx->type_count) dl_binary_writer_write( &writer, dl_ctx->type_ids, sizeof( dl_typeid_t ) * dl_ctx->type_count ); diff --git a/src/dl_types.h b/src/dl_types.h index cbc4e99..1a2be0e 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" @@ -323,12 +331,13 @@ struct dl_context uint8_t* default_data; size_t default_data_size; + bool default_data_patched; }; struct dl_substr { const char* str; - int len; + uint32_t len; }; #ifdef _MSC_VER @@ -384,7 +393,7 @@ class CArrayStatic } } - inline size_t Len() + inline size_t Len() const { return m_nElements; } diff --git a/src/dl_util.cpp b/src/dl_util.cpp old mode 100755 new mode 100644 diff --git a/tests/dl_tests_array.cpp b/tests/dl_tests_array.cpp index 30f5dac..eb5a779 100644 --- a/tests/dl_tests_array.cpp +++ b/tests/dl_tests_array.cpp @@ -76,6 +76,13 @@ TYPED_TEST(DLBase, array_string_merge) this->do_the_round_about(StringArray::TYPE_ID, &original, &loaded[0], sizeof(loaded) / 2); + size_t merged_from_txt_size = 0; // Two long but identical strings, should be merged + EXPECT_DL_ERR_OK(dl_txt_unpack_loaded_calc_size(this->Ctx, original.TYPE_ID, (unsigned char*)&original, &merged_from_txt_size)); + char* txt_buffer = (char*)malloc( merged_from_txt_size ); + EXPECT_DL_ERR_OK(dl_txt_unpack_loaded(this->Ctx, original.TYPE_ID, (unsigned char*)&original, txt_buffer, merged_from_txt_size, &merged_from_txt_size)); + EXPECT_DL_ERR_OK(dl_txt_pack_calc_size(this->Ctx, txt_buffer, &merged_from_txt_size)); + free( txt_buffer ); + EXPECT_STREQ(original.Strings[0], loaded[0].Strings[0]); EXPECT_STREQ(original.Strings[1], loaded[0].Strings[1]); @@ -84,6 +91,13 @@ TYPED_TEST(DLBase, array_string_merge) this->do_the_round_about(StringArray::TYPE_ID, &original, &loaded[10], sizeof(loaded) / 2); + size_t unique_from_txt_size = 0; // Two shorter and different strings, should not be merged + EXPECT_DL_ERR_OK(dl_txt_unpack_loaded_calc_size(this->Ctx, original.TYPE_ID, (unsigned char*)&original, &unique_from_txt_size)); + txt_buffer = (char*)malloc( unique_from_txt_size ); + EXPECT_DL_ERR_OK(dl_txt_unpack_loaded(this->Ctx, original.TYPE_ID, (unsigned char*)&original, txt_buffer, unique_from_txt_size, &unique_from_txt_size)); + EXPECT_DL_ERR_OK(dl_txt_pack_calc_size(this->Ctx, txt_buffer, &unique_from_txt_size)); + free( txt_buffer ); + EXPECT_STREQ(original.Strings[0], loaded[10].Strings[0]); EXPECT_STREQ(original.Strings[1], loaded[10].Strings[1]); @@ -92,6 +106,7 @@ TYPED_TEST(DLBase, array_string_merge) size_t unique_store_size = 0; // Two shorter and different strings, should not be merged EXPECT_DL_ERR_OK(dl_instance_calc_size(this->Ctx, loaded[10].TYPE_ID, &loaded[10], &unique_store_size)); EXPECT_LT(merged_store_size, unique_store_size); // Check that long merged strings take less memory than short unique strings + EXPECT_LT(merged_from_txt_size, unique_from_txt_size); // Check that long merged strings take less memory than short unique strings } TYPED_TEST(DLBase, array_string_null) diff --git a/tests/dl_tests_base.cpp b/tests/dl_tests_base.cpp index 248abf2..4f258b7 100644 --- a/tests/dl_tests_base.cpp +++ b/tests/dl_tests_base.cpp @@ -30,9 +30,9 @@ void DL::SetUp() p.error_msg_func = test_log_error; EXPECT_DL_ERR_EQ( DL_ERROR_OK, dl_context_create( &Ctx, &p ) ); - EXPECT_DL_ERR_EQ( DL_ERROR_OK, dl_context_load_type_library(Ctx, typelib1, sizeof(typelib1)) ); EXPECT_DL_ERR_EQ( DL_ERROR_OK, dl_context_load_type_library(Ctx, typelib2, sizeof(typelib2)) ); EXPECT_DL_ERR_EQ( DL_ERROR_OK, dl_context_load_type_library(Ctx, typelib3, sizeof(typelib3)) ); + EXPECT_DL_ERR_EQ( DL_ERROR_OK, dl_context_load_type_library(Ctx, typelib1, sizeof(typelib1)) ); // Putting this last did expose errors } void DL::TearDown() diff --git a/tests/dl_tests_reflect.cpp b/tests/dl_tests_reflect.cpp index 2c67a00..4466716 100755 --- a/tests/dl_tests_reflect.cpp +++ b/tests/dl_tests_reflect.cpp @@ -23,12 +23,12 @@ TEST_F(DLReflect, pods) dl_member_info_t Members[128]; memset( &Info, 0x0, sizeof(dl_type_info_t) ); - EXPECT_DL_ERR_OK(dl_reflect_get_type_info( Ctx, Pods::TYPE_ID, &Info )); - EXPECT_DL_ERR_OK(dl_reflect_get_type_members( Ctx, Pods::TYPE_ID, Members, DL_ARRAY_LENGTH(Members) )); + EXPECT_DL_ERR_OK(dl_reflect_get_type_info( Ctx, PodsDefaults::TYPE_ID, &Info )); + EXPECT_DL_ERR_OK(dl_reflect_get_type_members( Ctx, PodsDefaults::TYPE_ID, Members, DL_ARRAY_LENGTH(Members) )); - EXPECT_EQ ((uint32_t)Pods::TYPE_ID, Info.tid ); - EXPECT_STREQ("Pods", Info.name); - EXPECT_EQ (10u, Info.member_count); + EXPECT_EQ ((uint32_t)PodsDefaults::TYPE_ID, Info.tid ); + EXPECT_STREQ("PodsDefaults", Info.name); + EXPECT_EQ (10u, Info.member_count); EXPECT_STREQ("i8", Members[0].name); EXPECT_EQ (DL_TYPE_ATOM_POD, Members[0].atom); @@ -69,6 +69,42 @@ TEST_F(DLReflect, pods) EXPECT_STREQ("f64", Members[9].name); EXPECT_EQ (DL_TYPE_ATOM_POD, Members[9].atom); EXPECT_EQ (DL_TYPE_STORAGE_FP64, Members[9].storage); + + EXPECT_EQ( 2, *reinterpret_cast( Members[0].default_data) ); + EXPECT_EQ( 3, *reinterpret_cast( Members[1].default_data) ); + EXPECT_EQ( 4, *reinterpret_cast( Members[2].default_data) ); + EXPECT_EQ( 5LL, *reinterpret_cast( Members[3].default_data) ); + EXPECT_EQ( 6U, *reinterpret_cast( Members[4].default_data) ); + EXPECT_EQ( 7U, *reinterpret_cast( Members[5].default_data) ); + EXPECT_EQ( 8U, *reinterpret_cast( Members[6].default_data) ); + EXPECT_EQ( 9ULL, *reinterpret_cast( Members[7].default_data) ); + EXPECT_EQ( 10.f, *reinterpret_cast( Members[8].default_data) ); + EXPECT_EQ( 11.0, *reinterpret_cast( Members[9].default_data) ); +} + +TEST_F(DLReflect, array_array_default) +{ + dl_type_info_t Info; + dl_member_info_t Members[16]; + memset( &Info, 0x0, sizeof(dl_type_info_t) ); + + EXPECT_DL_ERR_OK(dl_reflect_get_type_info( Ctx, DefaultArrayArray::TYPE_ID, &Info )); + EXPECT_DL_ERR_OK(dl_reflect_get_type_members( Ctx, DefaultArrayArray::TYPE_ID, Members, DL_ARRAY_LENGTH(Members) )); + + EXPECT_EQ ((uint32_t)DefaultArrayArray::TYPE_ID, Info.tid ); + EXPECT_STREQ("DefaultArrayArray", Info.name); + EXPECT_EQ (1u, Info.member_count); + + EXPECT_STREQ("Arr", Members[0].name); + EXPECT_EQ (nullptr, Members[0].comment); + + const DefaultArrayArray* array_array = reinterpret_cast(Members[0].default_data); + EXPECT_EQ (2U, array_array->Arr.count); + EXPECT_EQ (2U, array_array->Arr[0].u32_arr.count); + EXPECT_EQ (1U, array_array->Arr[0].u32_arr[0]); + EXPECT_EQ (3U, array_array->Arr[0].u32_arr[1]); + EXPECT_EQ (3U, array_array->Arr[1].u32_arr[0]); + EXPECT_EQ (7U, array_array->Arr[1].u32_arr[1]); } TEST_F(DLReflect, enums) diff --git a/tests/dl_tests_txt.cpp b/tests/dl_tests_txt.cpp index 3259790..3921e5b 100755 --- a/tests/dl_tests_txt.cpp +++ b/tests/dl_tests_txt.cpp @@ -194,6 +194,23 @@ TEST_F(DLText, default_value_with_data_in_struct) EXPECT_STREQ("who", loaded[0].Str); } +TEST_F(DLText, default_value_with_data_in_struct_merge_strings) +{ + // default-values should be set correctly! + + const char* text_data = STRINGIFY( { "DefaultWithOtherDataBefore" : { "t1" : "who" } } ); + + unsigned char out_data_text[1024]; + DefaultWithOtherDataBefore loaded[10]; // this is so ugly! + + 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, DefaultWithOtherDataBefore::TYPE_ID, loaded, sizeof(loaded), out_data_text, sizeof(out_data_text), 0x0)); + + EXPECT_STREQ("who", loaded[0].t1); + EXPECT_STREQ("who", loaded[0].Str); + EXPECT_EQ(loaded[0].Str, loaded[0].t1); +} + TEST_F(DLText, default_value_ptr) { // default-values should be set correctly! @@ -425,15 +442,42 @@ TEST_F(DLText, default_value_array_string) 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, DefaultArrayStr::TYPE_ID, loaded, sizeof(loaded), out_data_text, sizeof(out_data_text), 0x0)); - EXPECT_EQ(4u, loaded[0].Arr.count); + EXPECT_EQ(5u, loaded[0].Arr.count); EXPECT_STREQ("cow", loaded[0].Arr[0]); EXPECT_STREQ("bells", loaded[0].Arr[1]); EXPECT_STREQ("are", loaded[0].Arr[2]); EXPECT_STREQ("cool", loaded[0].Arr[3]); + EXPECT_STREQ("bells", loaded[0].Arr[4]); + EXPECT_EQ(loaded[0].Arr[1], loaded[0].Arr[4]); +} + +TEST_F( DLText, default_value_double_array_string ) +{ + // default-values should be set correctly! + + const char* text_data = STRINGIFY( { "ArrayDefaultArrayStr" : { "Arr1" : { "Arr" : ["are"] } } } ); + + unsigned char out_data_text[1024]; + ArrayDefaultArrayStr loaded[10]; + + 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, ArrayDefaultArrayStr::TYPE_ID, loaded, sizeof( loaded ), out_data_text, sizeof( out_data_text ), 0x0 ) ); + + EXPECT_EQ( 1u, loaded[0].Arr1.Arr.count ); + EXPECT_EQ( 5u, loaded[0].Arr2.Arr.count ); + + EXPECT_STREQ( "are", loaded[0].Arr1.Arr[0] ); + EXPECT_STREQ( "cow", loaded[0].Arr2.Arr[0] ); + EXPECT_STREQ( "bells", loaded[0].Arr2.Arr[1] ); + EXPECT_STREQ( "are", loaded[0].Arr2.Arr[2] ); + EXPECT_STREQ( "cool", loaded[0].Arr2.Arr[3] ); + EXPECT_STREQ( "bells", loaded[0].Arr2.Arr[4] ); + EXPECT_EQ( loaded[0].Arr1.Arr[0], loaded[0].Arr2.Arr[2] ); + EXPECT_EQ( loaded[0].Arr2.Arr[1], loaded[0].Arr2.Arr[4] ); } -TEST_F(DLText, default_value_array_array) +TEST_F( DLText, default_value_array_array ) { // default-values should be set correctly! diff --git a/tests/unittest.tld b/tests/unittest.tld index ee54258..f6361a0 100755 --- a/tests/unittest.tld +++ b/tests/unittest.tld @@ -277,7 +277,8 @@ ] }, ///* hard one "DefaultArrayPod" : { "members" : [ { "name" : "Arr", "type" : "uint32[]", "default" : [ 1, 3, 3, 7 ] } ] }, - "DefaultArrayStr" : { "members" : [ { "name" : "Arr", "type" : "string[]", "default" : [ "cow", "bells", "are", "cool" ] } ] }, + "DefaultArrayStr" : { "members" : [ { "name" : "Arr", "type" : "string[]", "default" : [ "cow", "bells", "are", "cool", "bells" ] } ] }, + "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", diff --git a/tests/unittest2.tld b/tests/unittest2.tld index f60e337..3e1aa20 100755 --- a/tests/unittest2.tld +++ b/tests/unittest2.tld @@ -100,6 +100,11 @@ "members" : [ { "name" : "member", "type" : "extern_enum" } ] + }, + "int_default" : { + "members" : [ + { "name" : "member", "type" : "int32", "default" : 1 } + ] } } } diff --git a/tool/dlpack/dlpack.cpp b/tool/dlpack/dlpack.cpp old mode 100755 new mode 100644