Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenloader/intern/readblenentry.c55
-rw-r--r--source/blender/blenloader/intern/readfile.c97
-rw-r--r--source/blender/blenloader/intern/readfile.h5
3 files changed, 111 insertions, 46 deletions
diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c
index e8d7a46687f..6132a091116 100644
--- a/source/blender/blenloader/intern/readblenentry.c
+++ b/source/blender/blenloader/intern/readblenentry.c
@@ -303,7 +303,7 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFil
{
BlendFileData *bfd = NULL;
FileData *fd;
- ListBase mainlist;
+ ListBase old_mainlist;
fd = blo_openblendermemfile(memfile, reports);
if (fd) {
@@ -314,9 +314,9 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFil
blo_clear_proxy_pointers_from_lib(oldmain);
/* separate libraries from old main */
- blo_split_main(&mainlist, oldmain);
+ blo_split_main(&old_mainlist, oldmain);
/* add the library pointers in oldmap lookup */
- blo_add_library_pointer_map(&mainlist, fd);
+ blo_add_library_pointer_map(&old_mainlist, fd);
/* makes lookup of existing images in old main */
blo_make_image_pointer_map(fd, oldmain);
@@ -340,19 +340,44 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFil
/* ensures relinked sounds are not freed */
blo_end_sound_pointer_map(fd, oldmain);
- /* move libraries from old main to new main */
- if (bfd && mainlist.first != mainlist.last) {
-
- /* Library structs themselves */
- bfd->main->library = oldmain->library;
- BLI_listbase_clear(&oldmain->library);
-
- /* add the Library mainlist to the new main */
- BLI_remlink(&mainlist, oldmain);
- BLI_addhead(&mainlist, bfd->main);
+ /* Still in-use libraries have already been moved from oldmain to new mainlist,
+ * but oldmain itself shall *never* be 'transferred' to new mainlist! */
+ BLI_assert(old_mainlist.first == oldmain);
+
+ if (bfd && old_mainlist.first != old_mainlist.last) {
+ /* Even though directly used libs have been already moved to new main, indirect ones have not.
+ * This is a bit annoying, but we have no choice but to keep them all for now - means some now unused
+ * data may remain in memory, but think we'll have to live with it. */
+ Main *libmain;
+ Main *newmain = bfd->main;
+ ListBase new_mainlist = {newmain, newmain};
+
+ for (libmain = oldmain->next; libmain; libmain = libmain->next) {
+ /* Note that LIB_INDIRECT does not work with libraries themselves, so we use non-NULL parent
+ * to detect indirect-linked ones... */
+ if (libmain->curlib && (libmain->curlib->parent != NULL)) {
+ BLI_remlink(&old_mainlist, libmain);
+ BLI_addtail(&new_mainlist, libmain);
+ }
+#if 0
+ else {
+ printf("Dropped Main for lib: %s\n", libmain->curlib->id.name);
+ }
+#endif
+ }
+ /* In any case, we need to move all lib datablocks themselves - those are 'first level data',
+ * getting rid of them would imply updating spaces & co to prevent invalid pointers access. */
+ BLI_movelisttolist(&newmain->library, &oldmain->library);
+
+ blo_join_main(&new_mainlist);
}
- blo_join_main(&mainlist);
-
+
+ /* printf("Remaining mains/libs in oldmain: %d\n", BLI_listbase_count(&fd->old_mainlist) - 1); */
+
+ /* That way, libs (aka mains) we did not reuse in new undone/redone state
+ * will be cleared together with oldmain... */
+ blo_join_main(&old_mainlist);
+
blo_freefiledata(fd);
}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 2ce4a93d9ae..9760f219ed6 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -854,6 +854,12 @@ BHead *blo_nextbhead(FileData *fd, BHead *thisblock)
return(bhead);
}
+/* Warning! Caller's responsability to ensure given bhead **is** and ID one! */
+const char *bhead_id_name(const FileData *fd, const BHead *bhead)
+{
+ return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offs);
+}
+
static void decode_blender_header(FileData *fd)
{
char header[SIZEOFBLENDERHEADER], num[4];
@@ -1772,9 +1778,9 @@ void blo_end_packed_pointer_map(FileData *fd, Main *oldmain)
/* undo file support: add all library pointers in lookup */
-void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd)
+void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd)
{
- Main *ptr = mainlist->first;
+ Main *ptr = old_mainlist->first;
ListBase *lbarray[MAX_LIBARRAY];
for (ptr = ptr->next; ptr; ptr = ptr->next) {
@@ -1785,6 +1791,8 @@ void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd)
oldnewmap_insert(fd->libmap, id, id, GS(id->name));
}
}
+
+ fd->old_mainlist = old_mainlist;
}
@@ -7822,14 +7830,66 @@ static BHead *read_data_into_oldnewmap(FileData *fd, BHead *bhead, const char *a
static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID **r_id)
{
- /* this routine reads a libblock and its direct data. Use link functions
- * to connect it all
+ /* this routine reads a libblock and its direct data. Use link functions to connect it all
*/
ID *id;
ListBase *lb;
const char *allocname;
bool wrong_id = false;
-
+
+ /* In undo case, most libs and linked data should be kept as is from previous state (see BLO_read_from_memfile).
+ * However, some needed by the snapshot being read may have been removed in previous one, and would go missing.
+ * This leads e.g. to desappearing objects in some undo/redo case, see T34446.
+ * That means we have to carefully check whether current lib or libdata already exits in old main, if it does
+ * we merely copy it over into new main area, otherwise we have to do a full read of that bhead... */
+ if (fd->memfile && ELEM(bhead->code, ID_LI, ID_ID)) {
+ const char *idname = bhead_id_name(fd, bhead);
+
+ /* printf("Checking %s...\n", idname); */
+
+ if (bhead->code == ID_LI) {
+ Main *libmain = fd->old_mainlist->first;
+ /* Skip oldmain itself... */
+ for (libmain = libmain->next; libmain; libmain = libmain->next) {
+ /* printf("... against %s: ", libmain->curlib ? libmain->curlib->id.name : "<NULL>"); */
+ if (libmain->curlib && STREQ(idname, libmain->curlib->id.name)) {
+ Main *oldmain = fd->old_mainlist->first;
+ /* printf("FOUND!\n"); */
+ /* In case of a library, we need to re-add its main to fd->mainlist, because if we have later
+ * a missing ID_ID, we need to get the correct lib it is linked to!
+ * Order is crucial, we cannot bulk-add it in BLO_read_from_memfile() like it used to be... */
+ BLI_remlink(fd->old_mainlist, libmain);
+ BLI_remlink_safe(&oldmain->library, libmain->curlib);
+ BLI_addtail(fd->mainlist, libmain);
+ BLI_addtail(&main->library, libmain->curlib);
+
+ if (r_id) {
+ *r_id = NULL; /* Just in case... */
+ }
+ return blo_nextbhead(fd, bhead);
+ }
+ /* printf("nothing...\n"); */
+ }
+ }
+ else {
+ /* printf("... in %s (%s): ", main->curlib ? main->curlib->id.name : "<NULL>", main->curlib ? main->curlib->name : "<NULL>"); */
+ if ((id = BKE_libblock_find_name_ex(main, GS(idname), idname + 2))) {
+ /* printf("FOUND!\n"); */
+ /* Even though we found our linked ID, there is no guarantee its address is still the same... */
+ if (id != bhead->old) {
+ oldnewmap_insert(fd->libmap, bhead->old, id, GS(id->name));
+ }
+
+ /* No need to do anything else for ID_ID, it's assumed already present in its lib's main... */
+ if (r_id) {
+ *r_id = NULL; /* Just in case... */
+ }
+ return blo_nextbhead(fd, bhead);
+ }
+ /* printf("nothing...\n"); */
+ }
+ }
+
/* read libblock */
id = read_struct(fd, bhead, "lib block");
if (r_id)
@@ -8300,26 +8360,10 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
bhead = NULL;
break;
- case ID_LI:
- /* skip library datablocks in undo, this works together with
- * BLO_read_from_memfile, where the old main->library is restored
- * overwriting the libraries from the memory file. previously
- * it did not save ID_LI/ID_ID blocks in this case, but they are
- * needed to make quit.blend recover them correctly. */
- if (fd->memfile)
- bhead = blo_nextbhead(fd, bhead);
- else
- bhead = read_libblock(fd, bfd->main, bhead, LIB_LOCAL, NULL);
- break;
case ID_ID:
- /* same as above */
- if (fd->memfile)
- bhead = blo_nextbhead(fd, bhead);
- else
- /* always adds to the most recently loaded
- * ID_LI block, see direct_link_library.
- * this is part of the file format definition. */
- bhead = read_libblock(fd, mainlist.last, bhead, LIB_READ+LIB_EXTERN, NULL);
+ /* Always adds to the most recently loaded ID_LI block, see direct_link_library.
+ * This is part of the file format definition. */
+ bhead = read_libblock(fd, mainlist.last, bhead, LIB_READ | LIB_EXTERN, NULL);
break;
/* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
@@ -8473,11 +8517,6 @@ static BHead *find_bhead_from_idname(FileData *fd, const char *idname)
#endif
}
-const char *bhead_id_name(const FileData *fd, const BHead *bhead)
-{
- return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offs);
-}
-
static ID *is_yet_read(FileData *fd, Main *mainvar, BHead *bhead)
{
const char *idname= bhead_id_name(fd, bhead);
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index ed22daef9ec..f6c3b69c414 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -96,7 +96,8 @@ typedef struct FileData {
struct GHash *bhead_idname_hash;
ListBase *mainlist;
-
+ ListBase *old_mainlist; /* Used for undo. */
+
/* ick ick, used to return
* data through streamglue.
*/
@@ -139,7 +140,7 @@ void blo_make_sound_pointer_map(FileData *fd, Main *oldmain);
void blo_end_sound_pointer_map(FileData *fd, Main *oldmain);
void blo_make_packed_pointer_map(FileData *fd, Main *oldmain);
void blo_end_packed_pointer_map(FileData *fd, Main *oldmain);
-void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd);
+void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd);
void blo_freefiledata(FileData *fd);