Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenloader/intern/readfile.c
- This file is larger than 256 KB, so syntax highlighting is disabled by default.
| Show First 20 Lines • Show All 9,495 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| /* This routine reads a libblock and its direct data. Lib link functions will | /* This routine reads a libblock and its direct data. Lib link functions will | ||||
| * set points between datablocks. */ | * set points between datablocks. */ | ||||
| if (r_id) { | if (r_id) { | ||||
| *r_id = NULL; /* In case of early return. */ | *r_id = NULL; /* In case of early return. */ | ||||
| } | } | ||||
| /* Read libblock struct. */ | /* Read libblock struct. */ | ||||
| BHead *first_bhead = bhead; | BHead *id_bhead = bhead; | ||||
| ID *id = read_struct(fd, bhead, "lib block"); | ID *id = read_struct(fd, bhead, "lib block"); | ||||
| if (id == NULL) { | if (id == NULL) { | ||||
| return blo_bhead_next(fd, bhead); | return blo_bhead_next(fd, bhead); | ||||
| } | } | ||||
| /* Determine ID type. */ | /* Determine ID type. */ | ||||
| const short idcode = GS(id->name); | const short idcode = GS(id->name); | ||||
| ListBase *lb = which_libbase(main, idcode); | ListBase *lb = which_libbase(main, idcode); | ||||
| Show All 15 Lines | if (fd->memfile != NULL) { | ||||
| else if (bhead->code == ID_LINK_PLACEHOLDER) { | else if (bhead->code == ID_LINK_PLACEHOLDER) { | ||||
| if (read_libblock_undo_restore_linked(fd, main, id, bhead)) { | if (read_libblock_undo_restore_linked(fd, main, id, bhead)) { | ||||
| MEM_freeN(id); | MEM_freeN(id); | ||||
| return blo_bhead_next(fd, bhead); | return blo_bhead_next(fd, bhead); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* read libblock */ | |||||
| BHead *id_bhead = bhead; | |||||
| if (id_bhead->code != ID_LINK_PLACEHOLDER) { | |||||
| /* need a name for the mallocN, just for debugging and sane prints on leaks */ | |||||
| const char *allocname = dataname(idcode); | |||||
| /* read all data into fd->datamap */ | |||||
| /* TODO: for the undo case instead of building oldnewmap here we could just quickly check the | |||||
| * bheads... could save some more ticks. Probably not worth it though, bottleneck is full | |||||
| * depsgraph rebuild and evaluate, not actual file reading. */ | |||||
| bhead = read_data_into_datamap(fd, id_bhead, allocname); | |||||
| } | |||||
| /* Restore existing datablocks for undo. */ | /* Restore existing datablocks for undo. */ | ||||
| const bool do_partial_undo = (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0; | const bool do_partial_undo = (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0; | ||||
| /* Used when undoing from memfile, we swap changed IDs into their old addresses when found. */ | /* Used when undoing from memfile, we swap changed IDs into their old addresses when found. */ | ||||
| ID *id_old = NULL; | ID *id_old = NULL; | ||||
| bool do_id_swap = false; | bool do_id_swap = false; | ||||
| if (fd->memfile != NULL) { | if (fd->memfile != NULL) { | ||||
| if (id_bhead->code != ID_LINK_PLACEHOLDER) { | if (bhead->code != ID_LINK_PLACEHOLDER) { | ||||
| const bool is_identical = read_libblock_is_identical(fd, first_bhead); | const bool is_identical = read_libblock_is_identical(fd, id_bhead); | ||||
| DEBUG_PRINTF("%s: ID %s is unchanged: %d\n", __func__, id->name, is_identical); | DEBUG_PRINTF("%s: ID %s is unchanged: %d\n", __func__, id->name, is_identical); | ||||
| BLI_assert(fd->old_idmap != NULL || !do_partial_undo); | BLI_assert(fd->old_idmap != NULL || !do_partial_undo); | ||||
| /* This code should only ever be reached for local data-blocks. */ | /* This code should only ever be reached for local data-blocks. */ | ||||
| BLI_assert(main->curlib == NULL); | BLI_assert(main->curlib == NULL); | ||||
| /* Find the 'current' existing ID we want to reuse instead of the one we would read from | /* Find the 'current' existing ID we want to reuse instead of the one we would read from | ||||
| * the undo memfile. */ | * the undo memfile. */ | ||||
| Show All 32 Lines | if (bhead->code != ID_LINK_PLACEHOLDER) { | ||||
| BLI_remlink(old_lb, id_old); | BLI_remlink(old_lb, id_old); | ||||
| BLI_addtail(new_lb, id_old); | BLI_addtail(new_lb, id_old); | ||||
| can_finalize_and_return = true; | can_finalize_and_return = true; | ||||
| } | } | ||||
| if (can_finalize_and_return) { | if (can_finalize_and_return) { | ||||
| DEBUG_PRINTF("Re-using existing ID %s instead of newly read one\n", id_old->name); | DEBUG_PRINTF("Re-using existing ID %s instead of newly read one\n", id_old->name); | ||||
| oldnewmap_insert(fd->libmap, id_bhead->old, id_old, id_bhead->code); | oldnewmap_insert(fd->libmap, bhead->old, id_old, bhead->code); | ||||
| oldnewmap_insert(fd->libmap, id_old, id_old, id_bhead->code); | oldnewmap_insert(fd->libmap, id_old, id_old, bhead->code); | ||||
| if (r_id) { | if (r_id) { | ||||
| *r_id = id_old; | *r_id = id_old; | ||||
| } | } | ||||
| if (do_partial_undo) { | if (do_partial_undo) { | ||||
| /* Even though we re-use the old ID as-is, it does not mean that we are 100% safe from | /* Even though we re-use the old ID as-is, it does not mean that we are 100% safe from | ||||
| * needing some depsgraph updates for it (it could depend on another ID which address | * needing some depsgraph updates for it (it could depend on another ID which address | ||||
| Show All 18 Lines | if (bhead->code != ID_LINK_PLACEHOLDER) { | ||||
| /* We need to 'accumulate' the accumulated recalc flags of all undo steps until we | /* We need to 'accumulate' the accumulated recalc flags of all undo steps until we | ||||
| * actually perform a depsgraph update, otherwise we'd only ever use the flags from one | * actually perform a depsgraph update, otherwise we'd only ever use the flags from one | ||||
| * of the steps, and never get proper flags matching all others. */ | * of the steps, and never get proper flags matching all others. */ | ||||
| id_old->recalc_undo_accumulated |= id->recalc_undo_accumulated; | id_old->recalc_undo_accumulated |= id->recalc_undo_accumulated; | ||||
| } | } | ||||
| MEM_freeN(id); | MEM_freeN(id); | ||||
| oldnewmap_clear(fd->datamap); | |||||
| return bhead; | return blo_bhead_next(fd, bhead); | ||||
| } | } | ||||
| } | } | ||||
| /* Some re-used old IDs might also use newly read ones, so we have to check for old memory | /* Some re-used old IDs might also use newly read ones, so we have to check for old memory | ||||
| * addresses for those as well. */ | * addresses for those as well. */ | ||||
| if (do_partial_undo && id->lib == NULL) { | if (do_partial_undo && id->lib == NULL) { | ||||
| BLI_assert(fd->old_idmap != NULL); | BLI_assert(fd->old_idmap != NULL); | ||||
| DEBUG_PRINTF("\t Looking for ID %s with uuid %u instead of newly read one\n", | DEBUG_PRINTF("\t Looking for ID %s with uuid %u instead of newly read one\n", | ||||
| id->name, | id->name, | ||||
| id->session_uuid); | id->session_uuid); | ||||
| id_old = BKE_main_idmap_lookup_uuid(fd->old_idmap, id->session_uuid); | id_old = BKE_main_idmap_lookup_uuid(fd->old_idmap, id->session_uuid); | ||||
| if (id_old != NULL) { | if (id_old != NULL) { | ||||
| BLI_assert(MEM_allocN_len(id) == MEM_allocN_len(id_old)); | BLI_assert(MEM_allocN_len(id) == MEM_allocN_len(id_old)); | ||||
| /* UI IDs are always re-used from old bmain at higher-level calling code, so never swap | /* UI IDs are always re-used from old bmain at higher-level calling code, so never swap | ||||
| * those. Besides maybe custom properties, no other ID should have pointers to those | * those. Besides maybe custom properties, no other ID should have pointers to those | ||||
| * anyway... | * anyway... | ||||
| * And linked IDs are handled separately as well. */ | * And linked IDs are handled separately as well. */ | ||||
| do_id_swap = !ELEM(idcode, ID_WM, ID_SCR, ID_WS) && | do_id_swap = !ELEM(idcode, ID_WM, ID_SCR, ID_WS) && !(bhead->code == ID_LINK_PLACEHOLDER); | ||||
| !(id_bhead->code == ID_LINK_PLACEHOLDER); | |||||
| } | } | ||||
| } | } | ||||
| /* At this point, we know we are going to keep that newly read & allocated ID, so we need to | /* At this point, we know we are going to keep that newly read & allocated ID, so we need to | ||||
| * reallocate it to ensure we actually get a unique memory address for it. */ | * reallocate it to ensure we actually get a unique memory address for it. */ | ||||
| if (!do_id_swap) { | if (!do_id_swap) { | ||||
| DEBUG_PRINTF("using newly-read ID %s to a new mem address\n", id->name); | DEBUG_PRINTF("using newly-read ID %s to a new mem address\n", id->name); | ||||
| } | } | ||||
| else { | else { | ||||
| DEBUG_PRINTF("using newly-read ID %s to its old, already existing address\n", id->name); | DEBUG_PRINTF("using newly-read ID %s to its old, already existing address\n", id->name); | ||||
| } | } | ||||
| } | } | ||||
| /* for ID_LINK_PLACEHOLDER check */ | /* for ID_LINK_PLACEHOLDER check */ | ||||
| ID *id_target = do_id_swap ? id_old : id; | ID *id_target = do_id_swap ? id_old : id; | ||||
| oldnewmap_insert(fd->libmap, id_bhead->old, id_target, id_bhead->code); | oldnewmap_insert(fd->libmap, bhead->old, id_target, bhead->code); | ||||
| oldnewmap_insert(fd->libmap, id_old, id_target, id_bhead->code); | oldnewmap_insert(fd->libmap, id_old, id_target, bhead->code); | ||||
| BLI_addtail(lb, id); | BLI_addtail(lb, id); | ||||
| if (r_id) { | if (r_id) { | ||||
| *r_id = do_id_swap ? id_old : id; | *r_id = do_id_swap ? id_old : id; | ||||
| } | } | ||||
| /* Set tag for new datablock to indicate lib linking and versioning needs | /* Set tag for new datablock to indicate lib linking and versioning needs | ||||
| * to be done still. */ | * to be done still. */ | ||||
| int id_tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_NEW; | int id_tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_NEW; | ||||
| if (id_bhead->code == ID_LINK_PLACEHOLDER) { | /* Read placeholder for linked datablock. */ | ||||
| /* Tag to get replaced by the actual linked datablock. */ | if (bhead->code == ID_LINK_PLACEHOLDER) { | ||||
| id_tag |= LIB_TAG_ID_LINK_PLACEHOLDER; | id_tag |= LIB_TAG_ID_LINK_PLACEHOLDER; | ||||
| if (placeholder_set_indirect_extern) { | if (placeholder_set_indirect_extern) { | ||||
| if (id->flag & LIB_INDIRECT_WEAK_LINK) { | if (id->flag & LIB_INDIRECT_WEAK_LINK) { | ||||
| id_tag |= LIB_TAG_INDIRECT; | id_tag |= LIB_TAG_INDIRECT; | ||||
| } | } | ||||
| else { | else { | ||||
| id_tag |= LIB_TAG_EXTERN; | id_tag |= LIB_TAG_EXTERN; | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| /* Read datablock contents. */ | |||||
| const bool success = direct_link_id(fd, main, id_tag, id, id_old); | |||||
| /* For placeholders we are done here. */ | direct_link_id(fd, main, id_tag, id, id_old); | ||||
| if (id_bhead->code == ID_LINK_PLACEHOLDER) { | return blo_bhead_next(fd, bhead); | ||||
| return blo_bhead_next(fd, id_bhead); | |||||
| } | } | ||||
| /* Read datablock contents. | |||||
| * Use convenient malloc name for debugging and better memory link prints. */ | |||||
| const char *allocname = dataname(idcode); | |||||
| bhead = read_data_into_datamap(fd, bhead, allocname); | |||||
| const bool success = direct_link_id(fd, main, id_tag, id, id_old); | |||||
| oldnewmap_clear(fd->datamap); | oldnewmap_clear(fd->datamap); | ||||
| if (!success) { | if (!success) { | ||||
| /* XXX This is probably working OK currently given the very limited scope of that flag. | /* XXX This is probably working OK currently given the very limited scope of that flag. | ||||
| * However, it is absolutely **not** handled correctly: it is freeing an ID pointer that has | * However, it is absolutely **not** handled correctly: it is freeing an ID pointer that has | ||||
| * been added to the fd->libmap mapping, which in theory could lead to nice crashes... | * been added to the fd->libmap mapping, which in theory could lead to nice crashes... | ||||
| * This should be properly solved at some point. */ | * This should be properly solved at some point. */ | ||||
| BKE_id_free(main, id); | BKE_id_free(main, id); | ||||
| Show All 28 Lines | static BHead *read_libblock(FileData *fd, | ||||
| } | } | ||||
| else if (fd->memfile != NULL) { | else if (fd->memfile != NULL) { | ||||
| DEBUG_PRINTF("We had to fully re-recreate ID %s (old addr: %p, new addr: %p)...\n", | DEBUG_PRINTF("We had to fully re-recreate ID %s (old addr: %p, new addr: %p)...\n", | ||||
| id->name, | id->name, | ||||
| id_old, | id_old, | ||||
| id); | id); | ||||
| } | } | ||||
| return (bhead); | return bhead; | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Read Global Data | /** \name Read Global Data | ||||
| * \{ */ | * \{ */ | ||||
| ▲ Show 20 Lines • Show All 2,725 Lines • Show Last 20 Lines | |||||