|
|
|
|
@@ -1754,19 +1754,19 @@ static void *newlibadr_real_us(FileData *fd, const void *lib, const void *adr)
|
|
|
|
|
return id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void change_idid_adr_fd(FileData *fd, const void *old, void *new)
|
|
|
|
|
static void change_link_placeholder_to_real_ID_pointer_fd(FileData *fd, const void *old, void *new)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < fd->libmap->nentries; i++) {
|
|
|
|
|
OldNew *entry = &fd->libmap->entries[i];
|
|
|
|
|
|
|
|
|
|
if (old == entry->newp && entry->nr == ID_ID) {
|
|
|
|
|
if (old == entry->newp && entry->nr == ID_LINK_PLACEHOLDER) {
|
|
|
|
|
entry->newp = new;
|
|
|
|
|
if (new) entry->nr = GS( ((ID *)new)->name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void change_idid_adr(ListBase *mainlist, FileData *basefd, void *old, void *new)
|
|
|
|
|
static void change_link_placeholder_to_real_ID_pointer(ListBase *mainlist, FileData *basefd, void *old, void *new)
|
|
|
|
|
{
|
|
|
|
|
Main *mainptr;
|
|
|
|
|
|
|
|
|
|
@@ -1779,7 +1779,7 @@ static void change_idid_adr(ListBase *mainlist, FileData *basefd, void *old, voi
|
|
|
|
|
fd = basefd;
|
|
|
|
|
|
|
|
|
|
if (fd) {
|
|
|
|
|
change_idid_adr_fd(fd, old, new);
|
|
|
|
|
change_link_placeholder_to_real_ID_pointer_fd(fd, old, new);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -8156,8 +8156,8 @@ static void direct_link_library(FileData *fd, Library *lib, Main *main)
|
|
|
|
|
TIP_("Library '%s', '%s' had multiple instances, save and reload!"),
|
|
|
|
|
lib->name, lib->filepath);
|
|
|
|
|
|
|
|
|
|
change_idid_adr(fd->mainlist, fd, lib, newmain->curlib);
|
|
|
|
|
/* change_idid_adr_fd(fd, lib, newmain->curlib); */
|
|
|
|
|
change_link_placeholder_to_real_ID_pointer(fd->mainlist, fd, lib, newmain->curlib);
|
|
|
|
|
/* change_link_placeholder_to_real_ID_pointer_fd(fd, lib, newmain->curlib); */
|
|
|
|
|
|
|
|
|
|
BLI_remlink(&main->library, lib);
|
|
|
|
|
MEM_freeN(lib);
|
|
|
|
|
@@ -8927,7 +8927,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const int ta
|
|
|
|
|
* 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)) {
|
|
|
|
|
if (fd->memfile && ELEM(bhead->code, ID_LI, ID_LINK_PLACEHOLDER)) {
|
|
|
|
|
const char *idname = blo_bhead_id_name(fd, bhead);
|
|
|
|
|
|
|
|
|
|
DEBUG_PRINTF("Checking %s...\n", idname);
|
|
|
|
|
@@ -8941,7 +8941,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const int ta
|
|
|
|
|
Main *oldmain = fd->old_mainlist->first;
|
|
|
|
|
DEBUG_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!
|
|
|
|
|
* a missing ID_LINK_PLACEHOLDER, 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);
|
|
|
|
|
@@ -8965,7 +8965,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const int ta
|
|
|
|
|
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... */
|
|
|
|
|
/* No need to do anything else for ID_LINK_PLACEHOLDER, it's assumed already present in its lib's main... */
|
|
|
|
|
if (r_id) {
|
|
|
|
|
*r_id = NULL; /* Just in case... */
|
|
|
|
|
}
|
|
|
|
|
@@ -8983,7 +8983,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const int ta
|
|
|
|
|
/* do after read_struct, for dna reconstruct */
|
|
|
|
|
lb = which_libbase(main, idcode);
|
|
|
|
|
if (lb) {
|
|
|
|
|
oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code); /* for ID_ID check */
|
|
|
|
|
oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code); /* for ID_LINK_PLACEHOLDER check */
|
|
|
|
|
BLI_addtail(lb, id);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
@@ -9007,7 +9007,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const int ta
|
|
|
|
|
id->recalc = 0;
|
|
|
|
|
|
|
|
|
|
/* this case cannot be direct_linked: it's just the ID part */
|
|
|
|
|
if (bhead->code == ID_ID) {
|
|
|
|
|
if (bhead->code == ID_LINK_PLACEHOLDER) {
|
|
|
|
|
/* That way, we know which datablock needs do_versions (required currently for linking). */
|
|
|
|
|
id->tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_NEW;
|
|
|
|
|
|
|
|
|
|
@@ -9516,14 +9516,17 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
|
|
|
|
|
bhead = NULL;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ID_ID:
|
|
|
|
|
/* Always adds to the most recently loaded ID_LI block, see direct_link_library.
|
|
|
|
|
* This is part of the file format definition. */
|
|
|
|
|
case ID_LINK_PLACEHOLDER:
|
|
|
|
|
if (fd->skip_flags & BLO_READ_SKIP_DATA) {
|
|
|
|
|
bhead = blo_bhead_next(fd, bhead);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
bhead = read_libblock(fd, mainlist.last, bhead, LIB_TAG_ID_ID | LIB_TAG_EXTERN, NULL);
|
|
|
|
|
/* Add link placeholder to the main of the library it belongs to.
|
|
|
|
|
* The library is the most recently loaded ID_LI block, according
|
|
|
|
|
* to the file format definition. So we can use the entry at the
|
|
|
|
|
* end of mainlist, added in direct_link_library. */
|
|
|
|
|
Main *libmain = mainlist.last;
|
|
|
|
|
bhead = read_libblock(fd, libmain, bhead, LIB_TAG_ID_LINK_PLACEHOLDER | LIB_TAG_EXTERN, NULL);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
/* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
|
|
|
|
|
@@ -9727,83 +9730,89 @@ static ID *is_yet_read(FileData *fd, Main *mainvar, BHead *bhead)
|
|
|
|
|
|
|
|
|
|
static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
|
|
|
|
|
{
|
|
|
|
|
BHead *bhead;
|
|
|
|
|
FileData *fd = fdhandle;
|
|
|
|
|
ID *id;
|
|
|
|
|
|
|
|
|
|
bhead = find_bhead(fd, old);
|
|
|
|
|
if (bhead) {
|
|
|
|
|
/* from another library? */
|
|
|
|
|
if (bhead->code == ID_ID) {
|
|
|
|
|
BHead *bheadlib = find_previous_lib(fd, bhead);
|
|
|
|
|
BHead *bhead = find_bhead(fd, old);
|
|
|
|
|
if (bhead == NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bheadlib) {
|
|
|
|
|
Library *lib = read_struct(fd, bheadlib, "Library");
|
|
|
|
|
Main *ptr = blo_find_main(fd, lib->name, fd->relabase);
|
|
|
|
|
if (bhead->code == ID_LINK_PLACEHOLDER) {
|
|
|
|
|
/* Placeholder link to datablock in another library. */
|
|
|
|
|
BHead *bheadlib = find_previous_lib(fd, bhead);
|
|
|
|
|
if (bheadlib == NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ptr->curlib == NULL) {
|
|
|
|
|
const char *idname = blo_bhead_id_name(fd, bhead);
|
|
|
|
|
Library *lib = read_struct(fd, bheadlib, "Library");
|
|
|
|
|
Main *libmain = blo_find_main(fd, lib->name, fd->relabase);
|
|
|
|
|
|
|
|
|
|
blo_reportf_wrap(fd->reports, RPT_WARNING, TIP_("LIB: Data refers to main .blend file: '%s' from %s"),
|
|
|
|
|
idname, mainvar->curlib->filepath);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
id = is_yet_read(fd, ptr, bhead);
|
|
|
|
|
if (libmain->curlib == NULL) {
|
|
|
|
|
const char *idname = blo_bhead_id_name(fd, bhead);
|
|
|
|
|
|
|
|
|
|
if (id == NULL) {
|
|
|
|
|
read_libblock(fd, ptr, bhead, LIB_TAG_ID_ID | LIB_TAG_INDIRECT, NULL);
|
|
|
|
|
// commented because this can print way too much
|
|
|
|
|
// if (G.debug & G_DEBUG) printf("expand_doit: other lib %s\n", lib->name);
|
|
|
|
|
blo_reportf_wrap(fd->reports, RPT_WARNING, TIP_("LIB: Data refers to main .blend file: '%s' from %s"),
|
|
|
|
|
idname, mainvar->curlib->filepath);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* for outliner dependency only */
|
|
|
|
|
ptr->curlib->parent = mainvar->curlib;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* The line below was commented by Ton (I assume), when Hos did the merge from the orange branch. rev 6568
|
|
|
|
|
* This line is NEEDED, the case is that you have 3 blend files...
|
|
|
|
|
* user.blend, lib.blend and lib_indirect.blend - if user.blend already references a "tree" from
|
|
|
|
|
* lib_indirect.blend but lib.blend does too, linking in a Scene or Group from lib.blend can result in an
|
|
|
|
|
* empty without the dupli group referenced. Once you save and reload the group would appear. - Campbell */
|
|
|
|
|
/* This crashes files, must look further into it */
|
|
|
|
|
ID *id = is_yet_read(fd, libmain, bhead);
|
|
|
|
|
|
|
|
|
|
/* Update: the issue is that in file reading, the oldnewmap is OK, but for existing data, it has to be
|
|
|
|
|
* inserted in the map to be found! */
|
|
|
|
|
if (id == NULL) {
|
|
|
|
|
/* ID has not been read yet, add placeholder to the main of the
|
|
|
|
|
* library it belongs to, so that it will be read later. */
|
|
|
|
|
read_libblock(fd, libmain, bhead, LIB_TAG_ID_LINK_PLACEHOLDER | LIB_TAG_INDIRECT, NULL);
|
|
|
|
|
// commented because this can print way too much
|
|
|
|
|
// if (G.debug & G_DEBUG) printf("expand_doit: other lib %s\n", lib->name);
|
|
|
|
|
|
|
|
|
|
/* Update: previously it was checking for id->tag & LIB_TAG_PRE_EXISTING, however that
|
|
|
|
|
* does not affect file reading. For file reading we may need to insert it into the libmap as well,
|
|
|
|
|
* because you might have two files indirectly linking the same datablock, and in that case
|
|
|
|
|
* we need this in the libmap for the fd of both those files.
|
|
|
|
|
*
|
|
|
|
|
* The crash that this check avoided earlier was because bhead->code wasn't properly passed in, making
|
|
|
|
|
* change_idid_adr not detect the mapping was for an ID_ID datablock. */
|
|
|
|
|
oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code);
|
|
|
|
|
change_idid_adr_fd(fd, bhead->old, id);
|
|
|
|
|
|
|
|
|
|
// commented because this can print way too much
|
|
|
|
|
// if (G.debug & G_DEBUG) printf("expand_doit: already linked: %s lib: %s\n", id->name, lib->name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MEM_freeN(lib);
|
|
|
|
|
}
|
|
|
|
|
/* for outliner dependency only */
|
|
|
|
|
libmain->curlib->parent = mainvar->curlib;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* in 2.50+ file identifier for screens is patched, forward compatibility */
|
|
|
|
|
if (bhead->code == ID_SCRN) {
|
|
|
|
|
bhead->code = ID_SCR;
|
|
|
|
|
}
|
|
|
|
|
/* "id" is either a placeholder or real ID that is already in the
|
|
|
|
|
* main of the library (A) it belongs to. However it might have been
|
|
|
|
|
* put there by another library (C) which only updated its own
|
|
|
|
|
* fd->libmap. In that case we also need to update the fd->libmap
|
|
|
|
|
* of the current library (B) so we can find it for lookups.
|
|
|
|
|
*
|
|
|
|
|
* An example of such a setup is:
|
|
|
|
|
* (A) tree.blend: contains Tree object.
|
|
|
|
|
* (B) forest.blend: contains Forest collection linking in Tree from tree.blend.
|
|
|
|
|
* (C) shot.blend: links in both Tree from tree.blend and Forest from forest.blend.
|
|
|
|
|
*/
|
|
|
|
|
oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code);
|
|
|
|
|
|
|
|
|
|
id = is_yet_read(fd, mainvar, bhead);
|
|
|
|
|
if (id == NULL) {
|
|
|
|
|
read_libblock(fd, mainvar, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, NULL);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* this is actually only needed on UI call? when ID was already read before, and another append
|
|
|
|
|
* happens which invokes same ID... in that case the lookup table needs this entry */
|
|
|
|
|
oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code);
|
|
|
|
|
// commented because this can print way too much
|
|
|
|
|
// if (G.debug & G_DEBUG) printf("expand: already read %s\n", id->name);
|
|
|
|
|
}
|
|
|
|
|
/* If "id" is a real datablock and not a placeholder, we need to
|
|
|
|
|
* update fd->libmap to replace ID_LINK_PLACEHOLDER with the real
|
|
|
|
|
* ID_* code.
|
|
|
|
|
*
|
|
|
|
|
* When the real ID is read this replacement happens for all
|
|
|
|
|
* libraries read so far, but not for libraries that have not been
|
|
|
|
|
* read yet at that point. */
|
|
|
|
|
change_link_placeholder_to_real_ID_pointer_fd(fd, bhead->old, id);
|
|
|
|
|
|
|
|
|
|
// commented because this can print way too much
|
|
|
|
|
// if (G.debug & G_DEBUG) printf("expand_doit: already linked: %s lib: %s\n", id->name, lib->name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MEM_freeN(lib);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Datablock in same library. */
|
|
|
|
|
/* In 2.50+ file identifier for screens is patched, forward compatibility. */
|
|
|
|
|
if (bhead->code == ID_SCRN) {
|
|
|
|
|
bhead->code = ID_SCR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ID *id = is_yet_read(fd, mainvar, bhead);
|
|
|
|
|
if (id == NULL) {
|
|
|
|
|
read_libblock(fd, mainvar, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, NULL);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* this is actually only needed on UI call? when ID was already read before, and another append
|
|
|
|
|
* happens which invokes same ID... in that case the lookup table needs this entry */
|
|
|
|
|
oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code);
|
|
|
|
|
// commented because this can print way too much
|
|
|
|
|
// if (G.debug & G_DEBUG) printf("expand: already read %s\n", id->name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -11072,48 +11081,6 @@ ID *BLO_library_link_named_part_ex(
|
|
|
|
|
return link_named_part_ex(mainl, fd, idcode, name, flag);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void link_id_part(ReportList *reports, FileData *fd, Main *mainvar, ID *id, ID **r_id)
|
|
|
|
|
{
|
|
|
|
|
BHead *bhead = NULL;
|
|
|
|
|
const bool is_valid = BKE_idcode_is_linkable(GS(id->name)) || ((id->tag & LIB_TAG_EXTERN) == 0);
|
|
|
|
|
|
|
|
|
|
if (fd) {
|
|
|
|
|
bhead = find_bhead_from_idname(fd, id->name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
id->tag &= ~LIB_TAG_ID_ID;
|
|
|
|
|
|
|
|
|
|
if (!is_valid) {
|
|
|
|
|
blo_reportf_wrap(
|
|
|
|
|
reports, RPT_ERROR,
|
|
|
|
|
TIP_("LIB: %s: '%s' is directly linked from '%s' (parent '%s'), but is a non-linkable data type"),
|
|
|
|
|
BKE_idcode_to_name(GS(id->name)),
|
|
|
|
|
id->name + 2,
|
|
|
|
|
mainvar->curlib->filepath,
|
|
|
|
|
library_parent_filepath(mainvar->curlib));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bhead) {
|
|
|
|
|
id->tag |= LIB_TAG_NEED_EXPAND;
|
|
|
|
|
// printf("read lib block %s\n", id->name);
|
|
|
|
|
read_libblock(fd, mainvar, bhead, id->tag, r_id);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
blo_reportf_wrap(
|
|
|
|
|
reports, RPT_WARNING,
|
|
|
|
|
TIP_("LIB: %s: '%s' missing from '%s', parent '%s'"),
|
|
|
|
|
BKE_idcode_to_name(GS(id->name)),
|
|
|
|
|
id->name + 2,
|
|
|
|
|
mainvar->curlib->filepath,
|
|
|
|
|
library_parent_filepath(mainvar->curlib));
|
|
|
|
|
|
|
|
|
|
/* Generate a placeholder for this ID (simplified version of read_libblock actually...). */
|
|
|
|
|
if (r_id) {
|
|
|
|
|
*r_id = is_valid ? create_placeholder(mainvar, GS(id->name), id->name + 2, id->tag) : NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* common routine to append/link something from a library */
|
|
|
|
|
|
|
|
|
|
static Main *library_link_begin(Main *mainvar, FileData **fd, const char *filepath)
|
|
|
|
|
@@ -11293,167 +11260,239 @@ void *BLO_library_read_struct(FileData *fd, BHead *bh, const char *blockname)
|
|
|
|
|
/** \name Library Reading
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
static int mainvar_id_tag_any_check(Main *mainvar, const int tag)
|
|
|
|
|
static int has_linked_ids_to_read(Main *mainvar)
|
|
|
|
|
{
|
|
|
|
|
ListBase *lbarray[MAX_LIBARRAY];
|
|
|
|
|
int a;
|
|
|
|
|
int a = set_listbasepointers(mainvar, lbarray);
|
|
|
|
|
|
|
|
|
|
a = set_listbasepointers(mainvar, lbarray);
|
|
|
|
|
while (a--) {
|
|
|
|
|
ID *id;
|
|
|
|
|
|
|
|
|
|
for (id = lbarray[a]->first; id; id = id->next) {
|
|
|
|
|
if (id->tag & tag) {
|
|
|
|
|
for (ID *id = lbarray[a]->first; id; id = id->next) {
|
|
|
|
|
if (id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void read_library_linked_id(ReportList *reports, FileData *fd, Main *mainvar, ID *id, ID **r_id)
|
|
|
|
|
{
|
|
|
|
|
BHead *bhead = NULL;
|
|
|
|
|
const bool is_valid = BKE_idcode_is_linkable(GS(id->name)) || ((id->tag & LIB_TAG_EXTERN) == 0);
|
|
|
|
|
|
|
|
|
|
if (fd) {
|
|
|
|
|
bhead = find_bhead_from_idname(fd, id->name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!is_valid) {
|
|
|
|
|
blo_reportf_wrap(
|
|
|
|
|
reports, RPT_ERROR,
|
|
|
|
|
TIP_("LIB: %s: '%s' is directly linked from '%s' (parent '%s'), but is a non-linkable data type"),
|
|
|
|
|
BKE_idcode_to_name(GS(id->name)),
|
|
|
|
|
id->name + 2,
|
|
|
|
|
mainvar->curlib->filepath,
|
|
|
|
|
library_parent_filepath(mainvar->curlib));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
id->tag &= ~LIB_TAG_ID_LINK_PLACEHOLDER;
|
|
|
|
|
|
|
|
|
|
if (bhead) {
|
|
|
|
|
id->tag |= LIB_TAG_NEED_EXPAND;
|
|
|
|
|
// printf("read lib block %s\n", id->name);
|
|
|
|
|
read_libblock(fd, mainvar, bhead, id->tag, r_id);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
blo_reportf_wrap(
|
|
|
|
|
reports, RPT_WARNING,
|
|
|
|
|
TIP_("LIB: %s: '%s' missing from '%s', parent '%s'"),
|
|
|
|
|
BKE_idcode_to_name(GS(id->name)),
|
|
|
|
|
id->name + 2,
|
|
|
|
|
mainvar->curlib->filepath,
|
|
|
|
|
library_parent_filepath(mainvar->curlib));
|
|
|
|
|
|
|
|
|
|
/* Generate a placeholder for this ID (simplified version of read_libblock actually...). */
|
|
|
|
|
if (r_id) {
|
|
|
|
|
*r_id = is_valid ? create_placeholder(mainvar, GS(id->name), id->name + 2, id->tag) : NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void read_library_linked_ids(FileData *basefd, FileData *fd, ListBase *mainlist, Main *mainvar)
|
|
|
|
|
{
|
|
|
|
|
GHash *loaded_ids = BLI_ghash_str_new(__func__);
|
|
|
|
|
|
|
|
|
|
ListBase *lbarray[MAX_LIBARRAY];
|
|
|
|
|
int a = set_listbasepointers(mainvar, lbarray);
|
|
|
|
|
|
|
|
|
|
while (a--) {
|
|
|
|
|
ID *id = lbarray[a]->first;
|
|
|
|
|
ListBase pending_free_ids = {NULL};
|
|
|
|
|
|
|
|
|
|
while (id) {
|
|
|
|
|
ID *id_next = id->next;
|
|
|
|
|
if (id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) {
|
|
|
|
|
BLI_remlink(lbarray[a], id);
|
|
|
|
|
|
|
|
|
|
/* When playing with lib renaming and such, you may end with cases where
|
|
|
|
|
* you have more than one linked ID of the same data-block from same
|
|
|
|
|
* library. This is absolutely horrible, hence we use a ghash to ensure
|
|
|
|
|
* we go back to a single linked data when loading the file. */
|
|
|
|
|
ID **realid = NULL;
|
|
|
|
|
if (!BLI_ghash_ensure_p(loaded_ids, id->name, (void ***)&realid)) {
|
|
|
|
|
read_library_linked_id(basefd->reports, fd, mainvar, id, realid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* realid shall never be NULL - unless some source file/lib is broken
|
|
|
|
|
* (known case: some directly linked shapekey from a missing lib...). */
|
|
|
|
|
/* BLI_assert(*realid != NULL); */
|
|
|
|
|
|
|
|
|
|
/* Now that we have a real ID, replace all pointers to placeholders in
|
|
|
|
|
* fd->libmap with pointers to the real datablocks. We do this for all
|
|
|
|
|
* libraries since multiple might be referencing this ID. */
|
|
|
|
|
change_link_placeholder_to_real_ID_pointer(mainlist, basefd, id, *realid);
|
|
|
|
|
|
|
|
|
|
/* We cannot free old lib-ref placeholder ID here anymore, since we use
|
|
|
|
|
* its name as key in loaded_ids hash. */
|
|
|
|
|
BLI_addtail(&pending_free_ids, id);
|
|
|
|
|
}
|
|
|
|
|
id = id_next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Clear GHash and free link placeholder IDs of the current type. */
|
|
|
|
|
BLI_ghash_clear(loaded_ids, NULL, NULL);
|
|
|
|
|
BLI_freelistN(&pending_free_ids);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BLI_ghash_free(loaded_ids, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static FileData *read_library_file_data(FileData *basefd, ListBase *mainlist, Main *mainl, Main *mainptr)
|
|
|
|
|
{
|
|
|
|
|
FileData *fd = mainptr->curlib->filedata;
|
|
|
|
|
|
|
|
|
|
if (fd != NULL) {
|
|
|
|
|
/* File already open. */
|
|
|
|
|
return fd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mainptr->curlib->packedfile) {
|
|
|
|
|
/* Read packed file. */
|
|
|
|
|
PackedFile *pf = mainptr->curlib->packedfile;
|
|
|
|
|
|
|
|
|
|
blo_reportf_wrap(
|
|
|
|
|
basefd->reports, RPT_INFO, TIP_("Read packed library: '%s', parent '%s'"),
|
|
|
|
|
mainptr->curlib->name,
|
|
|
|
|
library_parent_filepath(mainptr->curlib));
|
|
|
|
|
fd = blo_filedata_from_memory(pf->data, pf->size, basefd->reports);
|
|
|
|
|
|
|
|
|
|
/* Needed for library_append and read_libraries. */
|
|
|
|
|
BLI_strncpy(fd->relabase, mainptr->curlib->filepath, sizeof(fd->relabase));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Read file on disk. */
|
|
|
|
|
blo_reportf_wrap(
|
|
|
|
|
basefd->reports, RPT_INFO, TIP_("Read library: '%s', '%s', parent '%s'"),
|
|
|
|
|
mainptr->curlib->filepath,
|
|
|
|
|
mainptr->curlib->name,
|
|
|
|
|
library_parent_filepath(mainptr->curlib));
|
|
|
|
|
fd = blo_filedata_from_file(mainptr->curlib->filepath, basefd->reports);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fd) {
|
|
|
|
|
/* Share the mainlist, so all libraries are added immediately in a
|
|
|
|
|
* single list. It used to be that all FileData's had their own list,
|
|
|
|
|
* but with indirectly linking this meant we didn't catch duplicate
|
|
|
|
|
* libraries properly. */
|
|
|
|
|
fd->mainlist = mainlist;
|
|
|
|
|
|
|
|
|
|
fd->reports = basefd->reports;
|
|
|
|
|
|
|
|
|
|
if (fd->libmap)
|
|
|
|
|
oldnewmap_free(fd->libmap);
|
|
|
|
|
|
|
|
|
|
fd->libmap = oldnewmap_new();
|
|
|
|
|
|
|
|
|
|
mainptr->curlib->filedata = fd;
|
|
|
|
|
mainptr->versionfile = fd->fileversion;
|
|
|
|
|
|
|
|
|
|
/* subversion */
|
|
|
|
|
read_file_version(fd, mainptr);
|
|
|
|
|
#ifdef USE_GHASH_BHEAD
|
|
|
|
|
read_file_bhead_idname_map_create(fd);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
mainptr->curlib->filedata = NULL;
|
|
|
|
|
mainptr->curlib->id.tag |= LIB_TAG_MISSING;
|
|
|
|
|
/* Set lib version to current main one... Makes assert later happy. */
|
|
|
|
|
mainptr->versionfile = mainptr->curlib->versionfile = mainl->versionfile;
|
|
|
|
|
mainptr->subversionfile = mainptr->curlib->subversionfile = mainl->subversionfile;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fd == NULL) {
|
|
|
|
|
blo_reportf_wrap(basefd->reports, RPT_WARNING, TIP_("Cannot find lib '%s'"),
|
|
|
|
|
mainptr->curlib->filepath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void read_libraries(FileData *basefd, ListBase *mainlist)
|
|
|
|
|
{
|
|
|
|
|
Main *mainl = mainlist->first;
|
|
|
|
|
Main *mainptr;
|
|
|
|
|
ListBase *lbarray[MAX_LIBARRAY];
|
|
|
|
|
GHash *loaded_ids = BLI_ghash_str_new(__func__);
|
|
|
|
|
int a;
|
|
|
|
|
bool do_it = true;
|
|
|
|
|
|
|
|
|
|
/* expander now is callback function */
|
|
|
|
|
/* Expander is now callback function. */
|
|
|
|
|
BLO_main_expander(expand_doit_library);
|
|
|
|
|
|
|
|
|
|
/* At this point the base blend file has been read, and each library blend
|
|
|
|
|
* encountered so far has a main with placeholders for linked datablocks.
|
|
|
|
|
*
|
|
|
|
|
* Now we will read the library blend files and replace the placeholders
|
|
|
|
|
* with actual datablocks. We loop over library mains multiple times in
|
|
|
|
|
* case a library needs to link additional datablocks from another library
|
|
|
|
|
* that had been read previously. */
|
|
|
|
|
while (do_it) {
|
|
|
|
|
do_it = false;
|
|
|
|
|
|
|
|
|
|
/* test 1: read libdata */
|
|
|
|
|
mainptr = mainl->next;
|
|
|
|
|
while (mainptr) {
|
|
|
|
|
if (mainvar_id_tag_any_check(mainptr, LIB_TAG_ID_ID)) {
|
|
|
|
|
// printf("found LIB_TAG_ID_ID %s (%s)\n", mainptr->curlib->id.name, mainptr->curlib->name);
|
|
|
|
|
/* Loop over mains of all library blend files encountered so far. Note
|
|
|
|
|
* this list gets longer as more indirectly library blends are found. */
|
|
|
|
|
for (Main *mainptr = mainl->next; mainptr; mainptr = mainptr->next) {
|
|
|
|
|
/* Does this library have any more linked datablocks we need to read? */
|
|
|
|
|
if (has_linked_ids_to_read(mainptr)) {
|
|
|
|
|
// printf("Reading linked datablocks from %s (%s)\n", mainptr->curlib->id.name, mainptr->curlib->name);
|
|
|
|
|
|
|
|
|
|
FileData *fd = mainptr->curlib->filedata;
|
|
|
|
|
/* Open file if it has not been done yet. */
|
|
|
|
|
FileData *fd = read_library_file_data(basefd, mainlist, mainl, mainptr);
|
|
|
|
|
|
|
|
|
|
if (fd == NULL) {
|
|
|
|
|
/* printf and reports for now... its important users know this */
|
|
|
|
|
|
|
|
|
|
/* if packed file... */
|
|
|
|
|
if (mainptr->curlib->packedfile) {
|
|
|
|
|
PackedFile *pf = mainptr->curlib->packedfile;
|
|
|
|
|
|
|
|
|
|
blo_reportf_wrap(
|
|
|
|
|
basefd->reports, RPT_INFO, TIP_("Read packed library: '%s', parent '%s'"),
|
|
|
|
|
mainptr->curlib->name,
|
|
|
|
|
library_parent_filepath(mainptr->curlib));
|
|
|
|
|
fd = blo_filedata_from_memory(pf->data, pf->size, basefd->reports);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* needed for library_append and read_libraries */
|
|
|
|
|
BLI_strncpy(fd->relabase, mainptr->curlib->filepath, sizeof(fd->relabase));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
blo_reportf_wrap(
|
|
|
|
|
basefd->reports, RPT_INFO, TIP_("Read library: '%s', '%s', parent '%s'"),
|
|
|
|
|
mainptr->curlib->filepath,
|
|
|
|
|
mainptr->curlib->name,
|
|
|
|
|
library_parent_filepath(mainptr->curlib));
|
|
|
|
|
fd = blo_filedata_from_file(mainptr->curlib->filepath, basefd->reports);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fd) {
|
|
|
|
|
/* share the mainlist, so all libraries are added immediately in a
|
|
|
|
|
* single list. it used to be that all FileData's had their own list,
|
|
|
|
|
* but with indirectly linking this meant we didn't catch duplicate
|
|
|
|
|
* libraries properly */
|
|
|
|
|
fd->mainlist = mainlist;
|
|
|
|
|
|
|
|
|
|
fd->reports = basefd->reports;
|
|
|
|
|
|
|
|
|
|
if (fd->libmap)
|
|
|
|
|
oldnewmap_free(fd->libmap);
|
|
|
|
|
|
|
|
|
|
fd->libmap = oldnewmap_new();
|
|
|
|
|
|
|
|
|
|
mainptr->curlib->filedata = fd;
|
|
|
|
|
mainptr->versionfile = fd->fileversion;
|
|
|
|
|
|
|
|
|
|
/* subversion */
|
|
|
|
|
read_file_version(fd, mainptr);
|
|
|
|
|
#ifdef USE_GHASH_BHEAD
|
|
|
|
|
read_file_bhead_idname_map_create(fd);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
mainptr->curlib->filedata = NULL;
|
|
|
|
|
mainptr->curlib->id.tag |= LIB_TAG_MISSING;
|
|
|
|
|
/* Set lib version to current main one... Makes assert later happy. */
|
|
|
|
|
mainptr->versionfile = mainptr->curlib->versionfile = mainl->versionfile;
|
|
|
|
|
mainptr->subversionfile = mainptr->curlib->subversionfile = mainl->subversionfile;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fd == NULL) {
|
|
|
|
|
blo_reportf_wrap(basefd->reports, RPT_WARNING, TIP_("Cannot find lib '%s'"),
|
|
|
|
|
mainptr->curlib->filepath);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (fd) {
|
|
|
|
|
do_it = true;
|
|
|
|
|
}
|
|
|
|
|
a = set_listbasepointers(mainptr, lbarray);
|
|
|
|
|
while (a--) {
|
|
|
|
|
ID *id = lbarray[a]->first;
|
|
|
|
|
ListBase pending_free_ids = {NULL};
|
|
|
|
|
|
|
|
|
|
while (id) {
|
|
|
|
|
ID *idn = id->next;
|
|
|
|
|
if (id->tag & LIB_TAG_ID_ID) {
|
|
|
|
|
BLI_remlink(lbarray[a], id);
|
|
|
|
|
/* Read linked datablocks for each link placeholder, and replace
|
|
|
|
|
* the placeholder with the real datablock. */
|
|
|
|
|
read_library_linked_ids(basefd, fd, mainlist, mainptr);
|
|
|
|
|
|
|
|
|
|
/* When playing with lib renaming and such, you may end with cases where you have
|
|
|
|
|
* more than one linked ID of the same data-block from same library.
|
|
|
|
|
* This is absolutely horrible, hence we use a ghash to ensure we go back to a single
|
|
|
|
|
* linked data when loading the file... */
|
|
|
|
|
ID **realid = NULL;
|
|
|
|
|
if (!BLI_ghash_ensure_p(loaded_ids, id->name, (void ***)&realid)) {
|
|
|
|
|
link_id_part(basefd->reports, fd, mainptr, id, realid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* realid shall never be NULL - unless some source file/lib is broken
|
|
|
|
|
* (known case: some directly linked shapekey from a missing lib...). */
|
|
|
|
|
/* BLI_assert(*realid != NULL); */
|
|
|
|
|
|
|
|
|
|
change_idid_adr(mainlist, basefd, id, *realid);
|
|
|
|
|
|
|
|
|
|
/* We cannot free old lib-ref placeholder ID here anymore, since we use its name
|
|
|
|
|
* as key in loaded_ids has. */
|
|
|
|
|
BLI_addtail(&pending_free_ids, id);
|
|
|
|
|
}
|
|
|
|
|
id = idn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Clear GHash and free all lib-ref placeholders IDs of that type now. */
|
|
|
|
|
BLI_ghash_clear(loaded_ids, NULL, NULL);
|
|
|
|
|
BLI_freelistN(&pending_free_ids);
|
|
|
|
|
}
|
|
|
|
|
/* Test if linked datablocks need to read further linked datablocks
|
|
|
|
|
* and create link placeholders for them. */
|
|
|
|
|
BLO_expand_main(fd, mainptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mainptr = mainptr->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BLI_ghash_free(loaded_ids, NULL, NULL);
|
|
|
|
|
loaded_ids = NULL;
|
|
|
|
|
|
|
|
|
|
/* do versions, link, and free */
|
|
|
|
|
Main *main_newid = BKE_main_new();
|
|
|
|
|
for (mainptr = mainl->next; mainptr; mainptr = mainptr->next) {
|
|
|
|
|
/* some mains still have to be read, then versionfile is still zero! */
|
|
|
|
|
for (Main *mainptr = mainl->next; mainptr; mainptr = mainptr->next) {
|
|
|
|
|
/* Do versioning for newly added linked datablocks. If no datablocks
|
|
|
|
|
* were read from a library versionfile will still be zero and we can
|
|
|
|
|
* skip it. */
|
|
|
|
|
if (mainptr->versionfile) {
|
|
|
|
|
/* We need to split out IDs already existing, or they will go again through do_versions - bad, very bad! */
|
|
|
|
|
/* Split out already existing IDs to avoid them going through
|
|
|
|
|
* do_versions multiple times, which would have bad consequences. */
|
|
|
|
|
split_main_newid(mainptr, main_newid);
|
|
|
|
|
|
|
|
|
|
if (mainptr->curlib->filedata) // can be zero... with shift+f1 append
|
|
|
|
|
/* File data can be zero with link/append. */
|
|
|
|
|
if (mainptr->curlib->filedata)
|
|
|
|
|
do_versions(mainptr->curlib->filedata, mainptr->curlib, main_newid);
|
|
|
|
|
else
|
|
|
|
|
do_versions(basefd, NULL, main_newid);
|
|
|
|
|
@@ -11461,10 +11500,13 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
|
|
|
|
|
add_main_to_main(mainptr, main_newid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Lib linking. */
|
|
|
|
|
if (mainptr->curlib->filedata)
|
|
|
|
|
lib_link_all(mainptr->curlib->filedata, mainptr);
|
|
|
|
|
|
|
|
|
|
if (mainptr->curlib->filedata) blo_filedata_free(mainptr->curlib->filedata);
|
|
|
|
|
/* Free file data we no longer need. */
|
|
|
|
|
if (mainptr->curlib->filedata)
|
|
|
|
|
blo_filedata_free(mainptr->curlib->filedata);
|
|
|
|
|
mainptr->curlib->filedata = NULL;
|
|
|
|
|
}
|
|
|
|
|
BKE_main_free(main_newid);
|
|
|
|
|
|