Changeset View
Changeset View
Standalone View
Standalone View
source/blender/makesdna/intern/dna_genfile.c
| Show First 20 Lines • Show All 865 Lines • ▼ Show 20 Lines | while (1) { | ||||
| } | } | ||||
| if (name[a] == 0 || oname[a] == 0) { | if (name[a] == 0 || oname[a] == 0) { | ||||
| break; | break; | ||||
| } | } | ||||
| a++; | a++; | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| static bool elem_streq_name(const char *name, const char *oname) | |||||
| { | |||||
| while (name[0] == '*') { | |||||
| name++; | |||||
| }; | |||||
| while (oname[0] == '*') { | |||||
| oname++; | |||||
| } | |||||
| int a = 0; | |||||
| while (1) { | |||||
| const bool is_name_end = ELEM(name[a], '[', '\0'); | |||||
| const bool is_oname_end = ELEM(oname[a], '[', '\0'); | |||||
| if (is_name_end && is_oname_end) { | |||||
| break; | |||||
| } | |||||
| if (name[a] != oname[a]) { | |||||
| return false; | |||||
| } | |||||
| if (is_name_end != is_oname_end) { | |||||
| return false; | |||||
| } | |||||
| a++; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| /** | /** | ||||
| * Returns whether the specified field exists according to the struct format | * Returns whether the specified field exists according to the struct format | ||||
| * pointed to by old. | * pointed to by old. | ||||
| * | * | ||||
| * \param type: Current field type name. | * \param type: Current field type name. | ||||
| * \param name: Current field name. | * \param name: Current field name. | ||||
| * \param old: Pointer to struct information in `sdna`. | * \param old: Pointer to struct information in `sdna`. | ||||
| ▲ Show 20 Lines • Show All 194 Lines • ▼ Show 20 Lines | |||||
| typedef enum eReconstructStepType { | typedef enum eReconstructStepType { | ||||
| RECONSTRUCT_STEP_MEMCPY, | RECONSTRUCT_STEP_MEMCPY, | ||||
| RECONSTRUCT_STEP_CAST_PRIMITIVE, | RECONSTRUCT_STEP_CAST_PRIMITIVE, | ||||
| RECONSTRUCT_STEP_CAST_POINTER_TO_32, | RECONSTRUCT_STEP_CAST_POINTER_TO_32, | ||||
| RECONSTRUCT_STEP_CAST_POINTER_TO_64, | RECONSTRUCT_STEP_CAST_POINTER_TO_64, | ||||
| RECONSTRUCT_STEP_SUBSTRUCT, | RECONSTRUCT_STEP_SUBSTRUCT, | ||||
| RECONSTRUCT_STEP_INIT_ZERO, | RECONSTRUCT_STEP_INIT_ZERO, | ||||
| RECONSTRUCT_STEP_INLINE_TO_POINTER, | |||||
| } eReconstructStepType; | } eReconstructStepType; | ||||
| typedef struct ReconstructStep { | typedef struct ReconstructStep { | ||||
| eReconstructStepType type; | eReconstructStepType type; | ||||
| union { | union { | ||||
| struct { | struct { | ||||
| int old_offset; | int old_offset; | ||||
| int new_offset; | int new_offset; | ||||
| Show All 13 Lines | union { | ||||
| } cast_pointer; | } cast_pointer; | ||||
| struct { | struct { | ||||
| int old_offset; | int old_offset; | ||||
| int new_offset; | int new_offset; | ||||
| int array_len; | int array_len; | ||||
| short old_struct_nr; | short old_struct_nr; | ||||
| short new_struct_nr; | short new_struct_nr; | ||||
| } substruct; | } substruct; | ||||
| struct { | |||||
| int old_offset; | |||||
| int new_offset; | |||||
| int array_len; | |||||
| } inline_to_pointer; | |||||
| } data; | } data; | ||||
| } ReconstructStep; | } ReconstructStep; | ||||
| typedef struct DNA_ReconstructInfo { | typedef struct DNA_ReconstructInfo { | ||||
| const SDNA *oldsdna; | const SDNA *oldsdna; | ||||
| const SDNA *newsdna; | const SDNA *newsdna; | ||||
| const char *compare_flags; | const char *compare_flags; | ||||
| int *step_counts; | int *step_counts; | ||||
| ReconstructStep **steps; | ReconstructStep **steps; | ||||
| } DNA_ReconstructInfo; | } DNA_ReconstructInfo; | ||||
| static void reconstruct_structs(const DNA_ReconstructInfo *reconstruct_info, | static void reconstruct_structs(const DNA_ReconstructInfo *reconstruct_info, | ||||
| const int blocks, | const int blocks, | ||||
| const int old_struct_nr, | const int old_struct_nr, | ||||
| const int new_struct_nr, | const int new_struct_nr, | ||||
| const char *old_blocks, | const char *old_blocks, | ||||
| char *new_blocks); | char *new_blocks, | ||||
| const DNA_ReconstructParams *params); | |||||
| static void reconstruct_inline_to_pointer(const DNA_ReconstructInfo *reconstruct_info, | |||||
| const int array_len, | |||||
| const char *old_data, | |||||
| char *new_data, | |||||
| const DNA_ReconstructParams *params) | |||||
| { | |||||
| void *new_buffer = MEM_mallocN(array_len, __func__); | |||||
| memcpy(new_buffer, old_data, array_len); | |||||
| *(void **)new_data = new_data; | |||||
| params->add_data(params->userdata, new_data, new_buffer); | |||||
| } | |||||
| /** | /** | ||||
| * Converts the contents of an entire struct from oldsdna to newsdna format. | * Converts the contents of an entire struct from oldsdna to newsdna format. | ||||
| * | * | ||||
| * \param reconstruct_info: Preprocessed reconstruct information generated by | * \param reconstruct_info: Preprocessed reconstruct information generated by | ||||
| * #DNA_reconstruct_info_create. | * #DNA_reconstruct_info_create. | ||||
| * \param new_struct_nr: Index in `newsdna->structs` of the struct that is being reconstructed. | * \param new_struct_nr: Index in `newsdna->structs` of the struct that is being reconstructed. | ||||
| * \param old_block: Memory buffer containing the old struct. | * \param old_block: Memory buffer containing the old struct. | ||||
| * \param new_block: Where to put converted struct contents. | * \param new_block: Where to put converted struct contents. | ||||
| */ | */ | ||||
| static void reconstruct_struct(const DNA_ReconstructInfo *reconstruct_info, | static void reconstruct_struct(const DNA_ReconstructInfo *reconstruct_info, | ||||
| const int new_struct_nr, | const int new_struct_nr, | ||||
| const char *old_block, | const char *old_block, | ||||
| char *new_block) | char *new_block, | ||||
| const DNA_ReconstructParams *params) | |||||
| { | { | ||||
| const ReconstructStep *steps = reconstruct_info->steps[new_struct_nr]; | const ReconstructStep *steps = reconstruct_info->steps[new_struct_nr]; | ||||
| const int step_count = reconstruct_info->step_counts[new_struct_nr]; | const int step_count = reconstruct_info->step_counts[new_struct_nr]; | ||||
| /* Execute all preprocessed steps. */ | /* Execute all preprocessed steps. */ | ||||
| for (int a = 0; a < step_count; a++) { | for (int a = 0; a < step_count; a++) { | ||||
| const ReconstructStep *step = &steps[a]; | const ReconstructStep *step = &steps[a]; | ||||
| switch (step->type) { | switch (step->type) { | ||||
| Show All 20 Lines | switch (step->type) { | ||||
| (uint64_t *)(new_block + step->data.cast_pointer.new_offset)); | (uint64_t *)(new_block + step->data.cast_pointer.new_offset)); | ||||
| break; | break; | ||||
| case RECONSTRUCT_STEP_SUBSTRUCT: | case RECONSTRUCT_STEP_SUBSTRUCT: | ||||
| reconstruct_structs(reconstruct_info, | reconstruct_structs(reconstruct_info, | ||||
| step->data.substruct.array_len, | step->data.substruct.array_len, | ||||
| step->data.substruct.old_struct_nr, | step->data.substruct.old_struct_nr, | ||||
| step->data.substruct.new_struct_nr, | step->data.substruct.new_struct_nr, | ||||
| old_block + step->data.substruct.old_offset, | old_block + step->data.substruct.old_offset, | ||||
| new_block + step->data.substruct.new_offset); | new_block + step->data.substruct.new_offset, | ||||
| params); | |||||
| break; | break; | ||||
| case RECONSTRUCT_STEP_INIT_ZERO: | case RECONSTRUCT_STEP_INIT_ZERO: | ||||
| /* Do nothing, because the memory block are zeroed (from #MEM_callocN). | /* Do nothing, because the memory block are zeroed (from #MEM_callocN). | ||||
| * | * | ||||
| * Note that the struct could be initialized with the default struct, | * Note that the struct could be initialized with the default struct, | ||||
| * however this complicates versioning, especially with flags, see: D4500. */ | * however this complicates versioning, especially with flags, see: D4500. */ | ||||
| break; | break; | ||||
| case RECONSTRUCT_STEP_INLINE_TO_POINTER: | |||||
| reconstruct_inline_to_pointer(reconstruct_info, | |||||
| step->data.inline_to_pointer.array_len, | |||||
| old_block + step->data.inline_to_pointer.old_offset, | |||||
| new_block + step->data.inline_to_pointer.new_offset, | |||||
| params); | |||||
| break; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** Reconstructs an array of structs. */ | /** Reconstructs an array of structs. */ | ||||
| static void reconstruct_structs(const DNA_ReconstructInfo *reconstruct_info, | static void reconstruct_structs(const DNA_ReconstructInfo *reconstruct_info, | ||||
| const int blocks, | const int blocks, | ||||
| const int old_struct_nr, | const int old_struct_nr, | ||||
| const int new_struct_nr, | const int new_struct_nr, | ||||
| const char *old_blocks, | const char *old_blocks, | ||||
| char *new_blocks) | char *new_blocks, | ||||
| const DNA_ReconstructParams *params) | |||||
| { | { | ||||
| const SDNA_Struct *old_struct = reconstruct_info->oldsdna->structs[old_struct_nr]; | const SDNA_Struct *old_struct = reconstruct_info->oldsdna->structs[old_struct_nr]; | ||||
| const SDNA_Struct *new_struct = reconstruct_info->newsdna->structs[new_struct_nr]; | const SDNA_Struct *new_struct = reconstruct_info->newsdna->structs[new_struct_nr]; | ||||
| const int old_block_size = reconstruct_info->oldsdna->types_size[old_struct->type]; | const int old_block_size = reconstruct_info->oldsdna->types_size[old_struct->type]; | ||||
| const int new_block_size = reconstruct_info->newsdna->types_size[new_struct->type]; | const int new_block_size = reconstruct_info->newsdna->types_size[new_struct->type]; | ||||
| for (int a = 0; a < blocks; a++) { | for (int a = 0; a < blocks; a++) { | ||||
| const char *old_block = old_blocks + a * old_block_size; | const char *old_block = old_blocks + a * old_block_size; | ||||
| char *new_block = new_blocks + a * new_block_size; | char *new_block = new_blocks + a * new_block_size; | ||||
| reconstruct_struct(reconstruct_info, new_struct_nr, old_block, new_block); | reconstruct_struct(reconstruct_info, new_struct_nr, old_block, new_block, params); | ||||
| } | } | ||||
| } | } | ||||
| void *DNA_struct_reconstruct(const DNA_ReconstructInfo *reconstruct_info, | void *DNA_struct_reconstruct(const DNA_ReconstructInfo *reconstruct_info, | ||||
| int old_struct_nr, | int old_struct_nr, | ||||
| int blocks, | int blocks, | ||||
| const void *old_blocks) | const void *old_blocks, | ||||
| const DNA_ReconstructParams *params) | |||||
| { | { | ||||
| const SDNA *oldsdna = reconstruct_info->oldsdna; | const SDNA *oldsdna = reconstruct_info->oldsdna; | ||||
| const SDNA *newsdna = reconstruct_info->newsdna; | const SDNA *newsdna = reconstruct_info->newsdna; | ||||
| const SDNA_Struct *old_struct = oldsdna->structs[old_struct_nr]; | const SDNA_Struct *old_struct = oldsdna->structs[old_struct_nr]; | ||||
| const char *type_name = oldsdna->types[old_struct->type]; | const char *type_name = oldsdna->types[old_struct->type]; | ||||
| const int new_struct_nr = DNA_struct_find_nr(newsdna, type_name); | const int new_struct_nr = DNA_struct_find_nr(newsdna, type_name); | ||||
| if (new_struct_nr == -1) { | if (new_struct_nr == -1) { | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| const SDNA_Struct *new_struct = newsdna->structs[new_struct_nr]; | const SDNA_Struct *new_struct = newsdna->structs[new_struct_nr]; | ||||
| const int new_block_size = newsdna->types_size[new_struct->type]; | const int new_block_size = newsdna->types_size[new_struct->type]; | ||||
| char *new_blocks = MEM_callocN(blocks * new_block_size, "reconstruct"); | char *new_blocks = MEM_callocN(blocks * new_block_size, "reconstruct"); | ||||
| reconstruct_structs( | reconstruct_structs( | ||||
| reconstruct_info, blocks, old_struct_nr, new_struct_nr, old_blocks, new_blocks); | reconstruct_info, blocks, old_struct_nr, new_struct_nr, old_blocks, new_blocks, params); | ||||
| return new_blocks; | return new_blocks; | ||||
| } | } | ||||
| /** Finds a member in the given struct with the given name. */ | /** Finds a member in the given struct with the given name. */ | ||||
| static const SDNA_StructMember *find_member_with_matching_name(const SDNA *sdna, | static const SDNA_StructMember *find_member_with_matching_name(const SDNA *sdna, | ||||
| const SDNA_Struct *struct_info, | const SDNA_Struct *struct_info, | ||||
| const char *name, | const char *name, | ||||
| int *r_offset) | int *r_offset) | ||||
| { | { | ||||
| int offset = 0; | int offset = 0; | ||||
| for (int a = 0; a < struct_info->members_len; a++) { | for (int a = 0; a < struct_info->members_len; a++) { | ||||
| const SDNA_StructMember *member = &struct_info->members[a]; | const SDNA_StructMember *member = &struct_info->members[a]; | ||||
| const char *member_name = sdna->names[member->name]; | const char *member_name = sdna->names[member->name]; | ||||
| if (elem_streq(name, member_name)) { | if (elem_streq_name(name, member_name)) { | ||||
| *r_offset = offset; | *r_offset = offset; | ||||
| return member; | return member; | ||||
| } | } | ||||
| offset += get_member_size_in_bytes(sdna, member); | offset += get_member_size_in_bytes(sdna, member); | ||||
| } | } | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /** Initializes a single reconstruct step for a member in the new struct. */ | /** Initializes a single reconstruct step for a member in the new struct. */ | ||||
| static void init_reconstruct_step_for_member(const SDNA *oldsdna, | static void init_reconstruct_step_for_member(const SDNA *oldsdna, | ||||
| const SDNA *newsdna, | const SDNA *newsdna, | ||||
| const char *compare_flags, | const char *compare_flags, | ||||
| const SDNA_Struct *old_struct, | const SDNA_Struct *old_struct, | ||||
| const SDNA_StructMember *new_member, | const SDNA_StructMember *new_member, | ||||
| const int new_member_offset, | const int new_member_offset, | ||||
| ReconstructStep *r_step) | ReconstructStep *r_step) | ||||
| { | { | ||||
| /* Find the matching old member. */ | /* Find the matching old member. */ | ||||
| int old_member_offset; | int old_member_offset; | ||||
| const char *new_name = newsdna->names[new_member->name]; | const char *new_name = newsdna->names[new_member->name]; | ||||
| if (STREQ(new_name, "*hello1")) { | |||||
| int a = 0; | |||||
| } | |||||
| const SDNA_StructMember *old_member = find_member_with_matching_name( | const SDNA_StructMember *old_member = find_member_with_matching_name( | ||||
| oldsdna, old_struct, new_name, &old_member_offset); | oldsdna, old_struct, new_name, &old_member_offset); | ||||
| const char *old_name = old_member ? oldsdna->names[old_member->name] : "<none>"; | |||||
| printf("%s -> %s\n", new_name, old_name); | |||||
| if (old_member == NULL) { | if (old_member == NULL) { | ||||
| /* No matching member has been found in the old struct. */ | /* No matching member has been found in the old struct. */ | ||||
| r_step->type = RECONSTRUCT_STEP_INIT_ZERO; | r_step->type = RECONSTRUCT_STEP_INIT_ZERO; | ||||
| return; | return; | ||||
| } | } | ||||
| /* Determine the member category of the old an new members. */ | /* Determine the member category of the old an new members. */ | ||||
| const eStructMemberCategory new_category = get_struct_member_category(newsdna, new_member); | const eStructMemberCategory new_category = get_struct_member_category(newsdna, new_member); | ||||
| const eStructMemberCategory old_category = get_struct_member_category(oldsdna, old_member); | const eStructMemberCategory old_category = get_struct_member_category(oldsdna, old_member); | ||||
| if (new_category != old_category) { | |||||
| /* Can only reconstruct the new member based on the old member, when the belong to the same | |||||
| * category. */ | |||||
| r_step->type = RECONSTRUCT_STEP_INIT_ZERO; | |||||
| return; | |||||
| } | |||||
| const int new_array_length = newsdna->names_array_len[new_member->name]; | const int new_array_length = newsdna->names_array_len[new_member->name]; | ||||
| const int old_array_length = oldsdna->names_array_len[old_member->name]; | const int old_array_length = oldsdna->names_array_len[old_member->name]; | ||||
| const int shared_array_length = MIN2(new_array_length, old_array_length); | const int shared_array_length = MIN2(new_array_length, old_array_length); | ||||
| const char *new_type_name = newsdna->types[new_member->type]; | const char *new_type_name = newsdna->types[new_member->type]; | ||||
| const char *old_type_name = oldsdna->types[old_member->type]; | const char *old_type_name = oldsdna->types[old_member->type]; | ||||
| if (old_category == STRUCT_MEMBER_CATEGORY_PRIMITIVE && | |||||
| new_category == STRUCT_MEMBER_CATEGORY_POINTER) { | |||||
| if (STREQ(new_type_name, old_type_name)) { | |||||
| r_step->type = RECONSTRUCT_STEP_INLINE_TO_POINTER; | |||||
| r_step->data.inline_to_pointer.old_offset = old_member_offset; | |||||
| r_step->data.inline_to_pointer.new_offset = new_member_offset; | |||||
| r_step->data.inline_to_pointer.array_len = old_array_length; | |||||
| return; | |||||
| } | |||||
| } | |||||
| if (new_category != old_category) { | |||||
| /* Can only reconstruct the new member based on the old member, when the belong to the same | |||||
| * category. */ | |||||
| r_step->type = RECONSTRUCT_STEP_INIT_ZERO; | |||||
| return; | |||||
| } | |||||
| switch (new_category) { | switch (new_category) { | ||||
| case STRUCT_MEMBER_CATEGORY_STRUCT: { | case STRUCT_MEMBER_CATEGORY_STRUCT: { | ||||
| if (STREQ(new_type_name, old_type_name)) { | if (STREQ(new_type_name, old_type_name)) { | ||||
| const int old_struct_nr = DNA_struct_find_nr(oldsdna, old_type_name); | const int old_struct_nr = DNA_struct_find_nr(oldsdna, old_type_name); | ||||
| BLI_assert(old_struct_nr != -1); | BLI_assert(old_struct_nr != -1); | ||||
| enum eSDNA_StructCompare compare_flag = compare_flags[old_struct_nr]; | enum eSDNA_StructCompare compare_flag = compare_flags[old_struct_nr]; | ||||
| BLI_assert(compare_flag != SDNA_CMP_REMOVED); | BLI_assert(compare_flag != SDNA_CMP_REMOVED); | ||||
| if (compare_flag == SDNA_CMP_EQUAL) { | if (compare_flag == SDNA_CMP_EQUAL) { | ||||
| ▲ Show 20 Lines • Show All 123 Lines • ▼ Show 20 Lines | case RECONSTRUCT_STEP_SUBSTRUCT: { | ||||
| step->data.substruct.old_offset, | step->data.substruct.old_offset, | ||||
| step->data.substruct.new_offset, | step->data.substruct.new_offset, | ||||
| step->data.substruct.new_struct_nr, | step->data.substruct.new_struct_nr, | ||||
| newsdna->types[newsdna->structs[step->data.substruct.new_struct_nr]->type], | newsdna->types[newsdna->structs[step->data.substruct.new_struct_nr]->type], | ||||
| newsdna->types_size[newsdna->structs[step->data.substruct.new_struct_nr]->type], | newsdna->types_size[newsdna->structs[step->data.substruct.new_struct_nr]->type], | ||||
| step->data.substruct.array_len); | step->data.substruct.array_len); | ||||
| break; | break; | ||||
| } | } | ||||
| case RECONSTRUCT_STEP_INLINE_TO_POINTER: { | |||||
| printf("inline to pointer, old offset: %d, size: %d", | |||||
| step->data.inline_to_pointer.old_offset, | |||||
| step->data.inline_to_pointer.array_len); | |||||
| break; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Generate an array of reconstruct steps for the given #new_struct. There will be one | * Generate an array of reconstruct steps for the given #new_struct. There will be one | ||||
| * reconstruct step for every member. | * reconstruct step for every member. | ||||
| */ | */ | ||||
| static ReconstructStep *create_reconstruct_steps_for_struct(const SDNA *oldsdna, | static ReconstructStep *create_reconstruct_steps_for_struct(const SDNA *oldsdna, | ||||
| ▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | switch (step->type) { | ||||
| } | } | ||||
| steps[new_step_count] = *step; | steps[new_step_count] = *step; | ||||
| new_step_count++; | new_step_count++; | ||||
| break; | break; | ||||
| case RECONSTRUCT_STEP_CAST_PRIMITIVE: | case RECONSTRUCT_STEP_CAST_PRIMITIVE: | ||||
| case RECONSTRUCT_STEP_CAST_POINTER_TO_32: | case RECONSTRUCT_STEP_CAST_POINTER_TO_32: | ||||
| case RECONSTRUCT_STEP_CAST_POINTER_TO_64: | case RECONSTRUCT_STEP_CAST_POINTER_TO_64: | ||||
| case RECONSTRUCT_STEP_SUBSTRUCT: | case RECONSTRUCT_STEP_SUBSTRUCT: | ||||
| case RECONSTRUCT_STEP_INLINE_TO_POINTER: | |||||
| /* These steps are not changed at all for now. It should be possible to merge consecutive | /* These steps are not changed at all for now. It should be possible to merge consecutive | ||||
| * steps of the same type, but it is not really worth it. */ | * steps of the same type, but it is not really worth it. */ | ||||
| steps[new_step_count] = *step; | steps[new_step_count] = *step; | ||||
| new_step_count++; | new_step_count++; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| return new_step_count; | return new_step_count; | ||||
| ▲ Show 20 Lines • Show All 375 Lines • Show Last 20 Lines | |||||