Exemple #1
0
/* frees main in end */
int BKE_copybuffer_save(const char *filename, ReportList *reports)
{
	Main *mainb = MEM_callocN(sizeof(Main), "copybuffer");
	ListBase *lbarray[MAX_LIBARRAY], *fromarray[MAX_LIBARRAY];
	int a, retval;
	
	/* path backup/restore */
	void     *path_list_backup;
	const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);

	path_list_backup = BKE_bpath_list_backup(G.main, path_list_flag);

	BLO_main_expander(copybuffer_doit);
	BLO_expand_main(NULL, G.main);
	
	/* move over all tagged blocks */
	set_listbasepointers(G.main, fromarray);
	a = set_listbasepointers(mainb, lbarray);
	while (a--) {
		ID *id, *nextid;
		ListBase *lb1 = lbarray[a], *lb2 = fromarray[a];
		
		for (id = lb2->first; id; id = nextid) {
			nextid = id->next;
			if (id->flag & LIB_DOIT) {
				BLI_remlink(lb2, id);
				BLI_addtail(lb1, id);
			}
		}
	}
	
	
	/* save the buffer */
	retval = BLO_write_file(mainb, filename, G_FILE_RELATIVE_REMAP, reports, NULL);
	
	/* move back the main, now sorted again */
	set_listbasepointers(G.main, lbarray);
	a = set_listbasepointers(mainb, fromarray);
	while (a--) {
		ID *id;
		ListBase *lb1 = lbarray[a], *lb2 = fromarray[a];
		
		while ((id = BLI_pophead(lb2))) {
			BLI_addtail(lb1, id);
			id_sort_by_name(lb1, id);
		}
	}
	
	MEM_freeN(mainb);
	
	/* set id flag to zero; */
	BKE_main_id_flag_all(G.main, LIB_NEED_EXPAND | LIB_DOIT, false);
	
	if (path_list_backup) {
		BKE_bpath_list_restore(G.main, path_list_flag, path_list_backup);
		BKE_bpath_list_free(path_list_backup);
	}

	return retval;
}
Exemple #2
0
/**
 * \return Success.
 */
bool BKE_blendfile_write_partial(
        Main *bmain_src, const char *filepath, const int write_flags, ReportList *reports)
{
	Main *bmain_dst = MEM_callocN(sizeof(Main), "copybuffer");
	ListBase *lbarray_dst[MAX_LIBARRAY], *lbarray_src[MAX_LIBARRAY];
	int a, retval;

	void     *path_list_backup = NULL;
	const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);

	if (write_flags & G_FILE_RELATIVE_REMAP) {
		path_list_backup = BKE_bpath_list_backup(bmain_src, path_list_flag);
	}

	BLO_main_expander(blendfile_write_partial_cb);
	BLO_expand_main(NULL, bmain_src);

	/* move over all tagged blocks */
	set_listbasepointers(bmain_src, lbarray_src);
	a = set_listbasepointers(bmain_dst, lbarray_dst);
	while (a--) {
		ID *id, *nextid;
		ListBase *lb_dst = lbarray_dst[a], *lb_src = lbarray_src[a];
		
		for (id = lb_src->first; id; id = nextid) {
			nextid = id->next;
			if (id->tag & LIB_TAG_DOIT) {
				BLI_remlink(lb_src, id);
				BLI_addtail(lb_dst, id);
			}
		}
	}
	
	
	/* save the buffer */
	retval = BLO_write_file(bmain_dst, filepath, write_flags, reports, NULL);
	
	/* move back the main, now sorted again */
	set_listbasepointers(bmain_src, lbarray_dst);
	a = set_listbasepointers(bmain_dst, lbarray_src);
	while (a--) {
		ID *id;
		ListBase *lb_dst = lbarray_dst[a], *lb_src = lbarray_src[a];
		
		while ((id = BLI_pophead(lb_src))) {
			BLI_addtail(lb_dst, id);
			id_sort_by_name(lb_dst, id);
		}
	}
	
	MEM_freeN(bmain_dst);
	
	if (path_list_backup) {
		BKE_bpath_list_restore(bmain_src, path_list_flag, path_list_backup);
		BKE_bpath_list_free(path_list_backup);
	}

	return retval;
}
Exemple #3
0
/* if lib!=NULL, only all from lib local */
void all_local(Library *lib, int untagged_only)
{
	ListBase *lbarray[MAX_LIBARRAY], tempbase={NULL, NULL};
	ID *id, *idn;
	int a;

	a= set_listbasepointers(G.main, lbarray);
	while(a--) {
		id= lbarray[a]->first;
		
		while(id) {
			id->newid= NULL;
			idn= id->next;		/* id is possibly being inserted again */
			
			/* The check on the second line (LIB_PRE_EXISTING) is done so its
			 * possible to tag data you dont want to be made local, used for
			 * appending data, so any libdata already linked wont become local
			 * (very nasty to discover all your links are lost after appending)  
			 * */
			if(id->flag & (LIB_EXTERN|LIB_INDIRECT|LIB_NEW) &&
			  (untagged_only==0 || !(id->flag & LIB_PRE_EXISTING)))
			{
				if(lib==NULL || id->lib==lib) {
					id->flag &= ~(LIB_EXTERN|LIB_INDIRECT|LIB_NEW);

					if(id->lib) {
						/* relative file patch */
						if(GS(id->name)==ID_IM)
							image_fix_relative_path((Image *)id);
						
						id->lib= NULL;
						new_id(lbarray[a], id, NULL);	/* new_id only does it with double names */
						sort_alpha_id(lbarray[a], id);
					}
				}
			}
			id= idn;
		}
		
		/* patch2: make it aphabetically */
		while( (id=tempbase.first) ) {
			BLI_remlink(&tempbase, id);
			BLI_addtail(lbarray[a], id);
			new_id(lbarray[a], id, NULL);
		}
	}

	/* patch 3: make sure library data isn't indirect falsely... */
	a= set_listbasepointers(G.main, lbarray);
	while(a--) {
		for(id= lbarray[a]->first; id; id=id->next)
			lib_indirect_test_id(id, lib);
	}
}
Exemple #4
0
/* if lib!=NULL, only all from lib local
 * bmain is almost certainly G.main */
void BKE_library_make_local(Main *bmain, Library *lib, int untagged_only)
{
    ListBase *lbarray[MAX_LIBARRAY], tempbase = {NULL, NULL};
    ID *id, *idn;
    int a;

    a = set_listbasepointers(bmain, lbarray);
    while (a--) {
        id = lbarray[a]->first;

        while (id) {
            id->newid = NULL;
            idn = id->next;      /* id is possibly being inserted again */

            /* The check on the second line (LIB_PRE_EXISTING) is done so its
             * possible to tag data you don't want to be made local, used for
             * appending data, so any libdata already linked wont become local
             * (very nasty to discover all your links are lost after appending)
             * */
            if (id->flag & (LIB_EXTERN | LIB_INDIRECT | LIB_NEW) &&
                    (untagged_only == 0 || !(id->flag & LIB_PRE_EXISTING)))
            {
                if (lib == NULL || id->lib == lib) {
                    if (id->lib) {
                        id_clear_lib_data(bmain, id); /* sets 'id->flag' */

                        /* why sort alphabetically here but not in
                         * id_clear_lib_data() ? - campbell */
                        id_sort_by_name(lbarray[a], id);
                    }
                    else {
                        id->flag &= ~(LIB_EXTERN | LIB_INDIRECT | LIB_NEW);
                    }
                }
            }
            id = idn;
        }

        /* patch2: make it aphabetically */
        while ( (id = tempbase.first) ) {
            BLI_remlink(&tempbase, id);
            BLI_addtail(lbarray[a], id);
            new_id(lbarray[a], id, NULL);
        }
    }

    /* patch 3: make sure library data isn't indirect falsely... */
    a = set_listbasepointers(bmain, lbarray);
    while (a--) {
        for (id = lbarray[a]->first; id; id = id->next)
            lib_indirect_test_id(id, lib);
    }
}
Exemple #5
0
/* frees main in end */
int BKE_copybuffer_save(char *filename, ReportList *reports)
{
	Main *mainb = MEM_callocN(sizeof(Main), "copybuffer");
	ListBase *lbarray[MAX_LIBARRAY], *fromarray[MAX_LIBARRAY];
	int a, retval;
	
	BLO_main_expander(copybuffer_doit);
	BLO_expand_main(NULL, G.main);
	
	/* move over all tagged blocks */
	set_listbasepointers(G.main, fromarray);
	a = set_listbasepointers(mainb, lbarray);
	while (a--) {
		ID *id, *nextid;
		ListBase *lb1 = lbarray[a], *lb2 = fromarray[a];
		
		for (id = lb2->first; id; id = nextid) {
			nextid = id->next;
			if (id->flag & LIB_DOIT) {
				BLI_remlink(lb2, id);
				BLI_addtail(lb1, id);
			}
		}
	}
	
	
	/* save the buffer */
	retval = BLO_write_file(mainb, filename, 0, reports, NULL);
	
	/* move back the main, now sorted again */
	set_listbasepointers(G.main, lbarray);
	a = set_listbasepointers(mainb, fromarray);
	while (a--) {
		ID *id;
		ListBase *lb1 = lbarray[a], *lb2 = fromarray[a];
		
		while (lb2->first) {
			id = lb2->first;
			BLI_remlink(lb2, id);
			BLI_addtail(lb1, id);
			id_sort_by_name(lb1, id);
		}
	}
	
	MEM_freeN(mainb);
	
	/* set id flag to zero; */
	flag_all_listbases_ids(LIB_NEED_EXPAND | LIB_DOIT, 0);
	
	return retval;
}
/* if lib!=NULL, only all from lib local
 * bmain is almost certainly G.main */
void BKE_library_make_local(Main *bmain, Library *lib, bool untagged_only)
{
	ListBase *lbarray[MAX_LIBARRAY];
	ID *id, *idn;
	int a;

	a = set_listbasepointers(bmain, lbarray);
	while (a--) {
		id = lbarray[a]->first;
		
		while (id) {
			id->newid = NULL;
			idn = id->next;      /* id is possibly being inserted again */
			
			/* The check on the second line (LIB_PRE_EXISTING) is done so its
			 * possible to tag data you don't want to be made local, used for
			 * appending data, so any libdata already linked wont become local
			 * (very nasty to discover all your links are lost after appending)  
			 * */
			if (id->flag & (LIB_EXTERN | LIB_INDIRECT | LIB_NEW) &&
			    ((untagged_only == false) || !(id->flag & LIB_PRE_EXISTING)))
			{
				if (lib == NULL || id->lib == lib) {
					if (id->lib) {
						/* for Make Local > All we should be calling id_make_local,
						 * but doing that breaks append (see #36003 and #36006), we
						 * we should make it work with all datablocks and id.us==0 */
						id_clear_lib_data(bmain, id); /* sets 'id->flag' */

						/* why sort alphabetically here but not in
						 * id_clear_lib_data() ? - campbell */
						id_sort_by_name(lbarray[a], id);
					}
					else {
						id->flag &= ~(LIB_EXTERN | LIB_INDIRECT | LIB_NEW);
					}
				}
			}
			id = idn;
		}
	}

	a = set_listbasepointers(bmain, lbarray);
	while (a--) {
		for (id = lbarray[a]->first; id; id = id->next)
			lib_indirect_test_id(id, lib);
	}
}
Exemple #7
0
/* Flag all ids in listbase */
void flag_all_listbases_ids(short flag, short value)
{
	ListBase *lbarray[MAX_LIBARRAY];
	int a;
	a= set_listbasepointers(G.main, lbarray);
	while(a--)	flag_listbase_ids(lbarray[a], flag, value);
}
/* Flag all ids in listbase */
void BKE_main_id_flag_all(Main *bmain, const short flag, const bool value)
{
	ListBase *lbarray[MAX_LIBARRAY];
	int a;
	a = set_listbasepointers(bmain, lbarray);
	while (a--) {
		BKE_main_id_flag_listbase(lbarray[a], flag, value);
	}
}
void BKE_main_id_tag_all(struct Main *mainvar, const bool tag)
{
	ListBase *lbarray[MAX_LIBARRAY];
	int a;

	a = set_listbasepointers(mainvar, lbarray);
	while (a--) {
		BKE_main_id_tag_listbase(lbarray[a], tag);
	}
}
Exemple #10
0
void tag_main(struct Main *mainvar, const short tag)
{
	ListBase *lbarray[MAX_LIBARRAY];
	int a;

	a= set_listbasepointers(mainvar, lbarray);
	while(a--) {
		tag_main_lb(lbarray[a], tag);
	}
}
Exemple #11
0
void BKE_libblock_delete(Main *bmain, void *idv)
{
	ListBase *lbarray[MAX_LIBARRAY];
	int base_count, i;

	base_count = set_listbasepointers(bmain, lbarray);
	BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);

	/* First tag all datablocks directly from target lib.
	 * Note that we go forward here, since we want to check dependencies before users (e.g. meshes before objects).
	 * Avoids to have to loop twice. */
	for (i = 0; i < base_count; i++) {
		ListBase *lb = lbarray[i];
		ID *id;

		for (id = lb->first; id; id = id->next) {
			/* Note: in case we delete a library, we also delete all its datablocks! */
			if ((id == (ID *)idv) || (id->lib == (Library *)idv) || (id->tag & LIB_TAG_DOIT)) {
				id->tag |= LIB_TAG_DOIT;
				/* Will tag 'never NULL' users of this ID too.
				 * Note that we cannot use BKE_libblock_unlink() here, since it would ignore indirect (and proxy!)
				 * links, this can lead to nasty crashing here in second, actual deleting loop.
				 * Also, this will also flag users of deleted data that cannot be unlinked
				 * (object using deleted obdata, etc.), so that they also get deleted. */
				BKE_libblock_remap(bmain, id, NULL, ID_REMAP_FLAG_NEVER_NULL_USAGE | ID_REMAP_FORCE_NEVER_NULL_USAGE);
			}
		}
	}

	/* In usual reversed order, such that all usage of a given ID, even 'never NULL' ones, have been already cleared
	 * when we reach it (e.g. Objects being processed before meshes, they'll have already released their 'reference'
	 * over meshes when we come to freeing obdata). */
	for (i = base_count; i--; ) {
		ListBase *lb = lbarray[i];
		ID *id, *id_next;

		for (id = lb->first; id; id = id_next) {
			id_next = id->next;
			if (id->tag & LIB_TAG_DOIT) {
				if (id->us != 0) {
#ifdef DEBUG_PRINT
					printf("%s: deleting %s (%d)\n", __func__, id->name, id->us);
#endif
					BLI_assert(id->us == 0);
				}
				BKE_libblock_free(bmain, id);
			}
		}
	}
}
Exemple #12
0
void tag_main(struct Main *mainvar, int tag)
{
	ListBase *lbarray[MAX_LIBARRAY];
	ID *id;
	int a;

	a= set_listbasepointers(mainvar, lbarray);
	while(a--) {
		for(id= lbarray[a]->first; id; id= id->next) {
			if(tag)	id->flag |= LIB_DOIT;
			else	id->flag &= ~LIB_DOIT;
		}
	}
}
Exemple #13
0
/* next to indirect usage in read/writefile also in editobject.c scene.c */
void clear_id_newpoins(void)
{
	ListBase *lbarray[MAX_LIBARRAY];
	ID *id;
	int a;

	a= set_listbasepointers(G.main, lbarray);
	while(a--) {
		id= lbarray[a]->first;
		while(id) {
			id->newid= NULL;
			id->flag &= ~LIB_NEW;
			id= id->next;
		}
	}
}
Exemple #14
0
void free_main(Main *mainvar)
{
	/* also call when reading a file, erase all, etc */
	ListBase *lbarray[MAX_LIBARRAY];
	int a;

	a= set_listbasepointers(mainvar, lbarray);
	while(a--) {
		ListBase *lb= lbarray[a];
		ID *id;
		
		while ( (id= lb->first) ) {
			free_libblock(lb, id);
		}
	}

	MEM_freeN(mainvar);
}
Exemple #15
0
/**
 * Utility to make a file 'empty' used for startup to optionally give an empty file.
 * Handy for tests.
 */
void BKE_blendfile_read_make_empty(bContext *C)
{
	Main *bmain = CTX_data_main(C);

	ListBase *lbarray[MAX_LIBARRAY];
	ID *id;
	int a;

	a = set_listbasepointers(bmain, lbarray);
	while (a--) {
		id = lbarray[a]->first;
		if (id != NULL) {
			if (ELEM(GS(id->name), ID_SCE, ID_SCR, ID_WM)) {
				continue;
			}
			while ((id = lbarray[a]->first)) {
				BKE_libblock_delete(bmain, id);
			}
		}
	}
}
Exemple #16
0
void BKE_main_free(Main *mainvar)
{
  /* also call when reading a file, erase all, etc */
  ListBase *lbarray[MAX_LIBARRAY];
  int a;

  /* Since we are removing whole main, no need to bother 'properly'
   * (and slowly) removing each ID from it. */
  const int free_flag = (LIB_ID_FREE_NO_MAIN | LIB_ID_FREE_NO_UI_USER |
                         LIB_ID_FREE_NO_USER_REFCOUNT | LIB_ID_FREE_NO_DEG_TAG);

  MEM_SAFE_FREE(mainvar->blen_thumb);

  a = set_listbasepointers(mainvar, lbarray);
  while (a--) {
    ListBase *lb = lbarray[a];
    ID *id, *id_next;

    for (id = lb->first; id != NULL; id = id_next) {
      id_next = id->next;
#if 1
      BKE_id_free_ex(mainvar, id, free_flag, false);
#else
      /* errors freeing ID's can be hard to track down,
       * enable this so valgrind will give the line number in its error log */
      switch (a) {
        case 0:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 1:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 2:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 3:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 4:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 5:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 6:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 7:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 8:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 9:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 10:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 11:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 12:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 13:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 14:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 15:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 16:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 17:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 18:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 19:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 20:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 21:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 22:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 23:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 24:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 25:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 26:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 27:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 28:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 29:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 30:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 31:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 32:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 33:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        case 34:
          BKE_id_free_ex(mainvar, id, free_flag, false);
          break;
        default:
          BLI_assert(0);
          break;
      }
#endif
    }
    BLI_listbase_clear(lb);
  }

  if (mainvar->relations) {
    BKE_main_relations_free(mainvar);
  }

  BLI_spin_end((SpinLock *)mainvar->lock);
  MEM_freeN(mainvar->lock);
  MEM_freeN(mainvar);
}
Exemple #17
0
/**
 * Execute the 'data' part of the remapping (that is, all ID pointers from other ID datablocks).
 *
 * Behavior differs depending on whether given \a id is NULL or not:
 * - \a id NULL: \a old_id must be non-NULL, \a new_id may be NULL (unlinking \a old_id) or not
 *   (remapping \a old_id to \a new_id). The whole \a bmain database is checked, and all pointers to \a old_id
 *   are remapped to \a new_id.
 * - \a id is non-NULL:
 *   + If \a old_id is NULL, \a new_id must also be NULL, and all ID pointers from \a id are cleared (i.e. \a id
 *     does not references any other datablock anymore).
 *   + If \a old_id is non-NULL, behavior is as with a NULL \a id, but only within given \a id.
 *
 * \param bmain: the Main data storage to operate on (must never be NULL).
 * \param id: the datablock to operate on (can be NULL, in which case we operate over all IDs from given bmain).
 * \param old_id: the datablock to dereference (may be NULL if \a id is non-NULL).
 * \param new_id: the new datablock to replace \a old_id references with (may be NULL).
 * \param r_id_remap_data: if non-NULL, the IDRemap struct to use (uselful to retrieve info about remapping process).
 */
ATTR_NONNULL(1) static void libblock_remap_data(
        Main *bmain, ID *id, ID *old_id, ID *new_id, const short remap_flags, IDRemap *r_id_remap_data)
{
	IDRemap id_remap_data;
	ListBase *lb_array[MAX_LIBARRAY];
	int i;

	if (r_id_remap_data == NULL) {
		r_id_remap_data = &id_remap_data;
	}
	r_id_remap_data->bmain = bmain;
	r_id_remap_data->old_id = old_id;
	r_id_remap_data->new_id = new_id;
	r_id_remap_data->id = NULL;
	r_id_remap_data->flag = remap_flags;
	r_id_remap_data->status = 0;
	r_id_remap_data->skipped_direct = 0;
	r_id_remap_data->skipped_indirect = 0;
	r_id_remap_data->skipped_refcounted = 0;

	if (id) {
#ifdef DEBUG_PRINT
		printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib);
#endif
		r_id_remap_data->id = id;
		libblock_remap_data_preprocess(r_id_remap_data);
		BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
	}
	else {
		i = set_listbasepointers(bmain, lb_array);

		/* Note that this is a very 'bruteforce' approach, maybe we could use some depsgraph to only process
		 * objects actually using given old_id... sounds rather unlikely currently, though, so this will do for now. */

		while (i--) {
			ID *id_curr = lb_array[i]->first;

			if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(old_id->name))) {
				continue;
			}

			for (; id_curr; id_curr = id_curr->next) {
				/* Note that we cannot skip indirect usages of old_id here (if requested), we still need to check it for
				 * the user count handling...
				 * XXX No more true (except for debug usage of those skipping counters). */
				r_id_remap_data->id = id_curr;
				libblock_remap_data_preprocess(r_id_remap_data);
				BKE_library_foreach_ID_link(
				            id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
			}
		}
	}

	if (old_id && GS(old_id->name) == ID_OB) {
		BKE_sca_logic_links_remap(bmain, (Object *)old_id, (Object *)new_id);
	}

	/* XXX We may not want to always 'transfer' fakeuser from old to new id... Think for now it's desired behavior
	 *     though, we can always add an option (flag) to control this later if needed. */
	if (old_id && (old_id->flag & LIB_FAKEUSER)) {
		id_fake_user_clear(old_id);
		id_fake_user_set(new_id);
	}

	id_us_clear_real(old_id);

	if (new_id && (new_id->tag & LIB_TAG_INDIRECT) && (r_id_remap_data->status & ID_REMAP_IS_LINKED_DIRECT)) {
		new_id->tag &= ~LIB_TAG_INDIRECT;
		new_id->tag |= LIB_TAG_EXTERN;
	}

#ifdef DEBUG_PRINT
	printf("%s: %d occurences skipped (%d direct and %d indirect ones)\n", __func__,
	       r_id_remap_data->skipped_direct + r_id_remap_data->skipped_indirect,
	       r_id_remap_data->skipped_direct, r_id_remap_data->skipped_indirect);
#endif
}
Exemple #18
0
/* Does not fix anything, but checks that all linked data-blocks are still valid (i.e. pointing to the right library). */
bool BLO_main_validate_libraries(struct Main *bmain, struct ReportList *reports)
{
	ListBase mainlist;
	bool is_valid = true;

	BKE_main_lock(bmain);

	blo_split_main(&mainlist, bmain);

	ListBase *lbarray[MAX_LIBARRAY];
	int i = set_listbasepointers(bmain, lbarray);
	while (i--) {
		for (ID *id = lbarray[i]->first; id != NULL; id = id->next) {
			if (id->lib != NULL) {
				is_valid = false;
				BKE_reportf(reports, RPT_ERROR,
				            "ID %s is in local database while being linked from library %s!\n", id->name, id->lib->name);
			}
		}
	}

	for (Main *curmain = bmain->next; curmain != NULL; curmain = curmain->next) {
		Library *curlib = curmain->curlib;
		if (curlib == NULL) {
			BKE_reportf(reports, RPT_ERROR,
			            "Library database with NULL library datablock!\n");
			continue;
		}

		BKE_library_filepath_set(bmain, curlib, curlib->name);
		BlendHandle *bh = BLO_blendhandle_from_file(curlib->filepath, reports);

		if (bh == NULL) {
			BKE_reportf(reports, RPT_ERROR,
			            "Library ID %s not found at expected path %s!\n", curlib->id.name, curlib->filepath);
			continue;
		}

		i = set_listbasepointers(curmain, lbarray);
		while (i--) {
			ID *id = lbarray[i]->first;
			if (id == NULL) {
				continue;
			}

			if (GS(id->name) == ID_LI) {
				is_valid = false;
				BKE_reportf(reports, RPT_ERROR,
				            "Library ID %s in library %s, this should not happen!\n", id->name, curlib->name);
				continue;
			}

			int totnames = 0;
			LinkNode *names = BLO_blendhandle_get_datablock_names(bh, GS(id->name), &totnames);
			for (; id != NULL; id = id->next) {
				if (id->lib == NULL) {
					is_valid = false;
					BKE_reportf(reports, RPT_ERROR,
					            "ID %s has NULL lib pointer while being in library %s!\n", id->name, curlib->name);
					continue;
				}
				if (id->lib != curlib) {
					is_valid = false;
					BKE_reportf(reports, RPT_ERROR,
					            "ID %s has mismatched lib pointer!\n", id->name);
					continue;
				}

				LinkNode *name = names;
				for (; name; name = name->next) {
					char *str_name = (char *)name->link;
					if (id->name[2] == str_name[0] && STREQ(str_name, id->name + 2)) {
						break;
					}
				}

				if (name == NULL) {
					is_valid = false;
					BKE_reportf(reports, RPT_ERROR,
					            "ID %s not found in library %s anymore!\n", id->name, id->lib->name);
					continue;
				}
			}

			BLI_linklist_free(names, free);
		}

		BLO_blendhandle_close(bh);
	}

	blo_join_main(&mainlist);

	BLI_assert(BLI_listbase_is_single(&mainlist));
	BLI_assert(mainlist.first == (void *)bmain);

	BKE_main_unlock(bmain);

	return is_valid;
}
Exemple #19
0
/**
 * \return Success.
 */
bool BKE_blendfile_write_partial(
        Main *bmain_src, const char *filepath, const int write_flags, ReportList *reports)
{
	Main *bmain_dst = MEM_callocN(sizeof(Main), "copybuffer");
	ListBase *lbarray_dst[MAX_LIBARRAY], *lbarray_src[MAX_LIBARRAY];
	int a, retval;

	void     *path_list_backup = NULL;
	const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);

	/* This is needed to be able to load that file as a real one later
	 * (otherwise main->name will not be set at read time). */
	BLI_strncpy(bmain_dst->name, bmain_src->name, sizeof(bmain_dst->name));

	BLO_main_expander(blendfile_write_partial_cb);
	BLO_expand_main(NULL, bmain_src);

	/* move over all tagged blocks */
	set_listbasepointers(bmain_src, lbarray_src);
	a = set_listbasepointers(bmain_dst, lbarray_dst);
	while (a--) {
		ID *id, *nextid;
		ListBase *lb_dst = lbarray_dst[a], *lb_src = lbarray_src[a];

		for (id = lb_src->first; id; id = nextid) {
			nextid = id->next;
			if (id->tag & LIB_TAG_DOIT) {
				BLI_remlink(lb_src, id);
				BLI_addtail(lb_dst, id);
			}
		}
	}

	/* Backup paths because remap relative will overwrite them.
	 *
	 * NOTE: we do this only on the list of datablocks that we are writing
	 * because the restored full list is not guaranteed to be in the same
	 * order as before, as expected by BKE_bpath_list_restore.
	 *
	 * This happens because id_sort_by_name does not take into account
	 * string case or the library name, so the order is not strictly
	 * defined for two linked datablocks with the same name! */
	if (write_flags & G_FILE_RELATIVE_REMAP) {
		path_list_backup = BKE_bpath_list_backup(bmain_dst, path_list_flag);
	}

	/* save the buffer */
	retval = BLO_write_file(bmain_dst, filepath, write_flags, reports, NULL);

	if (path_list_backup) {
		BKE_bpath_list_restore(bmain_dst, path_list_flag, path_list_backup);
		BKE_bpath_list_free(path_list_backup);
	}

	/* move back the main, now sorted again */
	set_listbasepointers(bmain_src, lbarray_dst);
	a = set_listbasepointers(bmain_dst, lbarray_src);
	while (a--) {
		ID *id;
		ListBase *lb_dst = lbarray_dst[a], *lb_src = lbarray_src[a];

		while ((id = BLI_pophead(lb_src))) {
			BLI_addtail(lb_dst, id);
			id_sort_by_name(lb_dst, id);
		}
	}

	MEM_freeN(bmain_dst);

	return retval;
}
static PyObject *bpy_user_map(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
{
#if 0  /* If someone knows how to get a proper 'self' in that case... */
	BPy_StructRNA *pyrna = (BPy_StructRNA *)self;
	Main *bmain = pyrna->ptr.data;
#else
	Main *bmain = G.main;  /* XXX Ugly, but should work! */
#endif

	static const char *kwlist[] = {"subset", "key_types", "value_types", NULL};
	PyObject *subset = NULL;

	PyObject *key_types = NULL;
	PyObject *val_types = NULL;
	BLI_bitmap *key_types_bitmap = NULL;
	BLI_bitmap *val_types_bitmap = NULL;

	PyObject *ret = NULL;


	if (!PyArg_ParseTupleAndKeywords(
	        args, kwds, "|O$O!O!:user_map", (char **)kwlist,
	        &subset,
	        &PySet_Type, &key_types,
	        &PySet_Type, &val_types))
	{
		return NULL;
	}

	if (key_types) {
		key_types_bitmap = pyrna_set_to_enum_bitmap(
		        rna_enum_id_type_items, key_types, sizeof(short), true, USHRT_MAX, "key types");
		if (key_types_bitmap == NULL) {
			goto error;
		}
	}

	if (val_types) {
		val_types_bitmap = pyrna_set_to_enum_bitmap(
		        rna_enum_id_type_items, val_types, sizeof(short), true, USHRT_MAX, "value types");
		if (val_types_bitmap == NULL) {
			goto error;
		}
	}

	IDUserMapData data_cb = {NULL};

	if (subset) {
		PyObject *subset_fast = PySequence_Fast(subset, "user_map");
		if (subset_fast == NULL) {
			goto error;
		}

		PyObject **subset_array = PySequence_Fast_ITEMS(subset_fast);
		Py_ssize_t subset_len = PySequence_Fast_GET_SIZE(subset_fast);

		data_cb.user_map = _PyDict_NewPresized(subset_len);
		data_cb.is_subset = true;
		for (; subset_len; subset_array++, subset_len--) {
			PyObject *set = PySet_New(NULL);
			PyDict_SetItem(data_cb.user_map, *subset_array, set);
			Py_DECREF(set);
		}
		Py_DECREF(subset_fast);
	}
	else {
		data_cb.user_map = PyDict_New();
	}

	data_cb.types_bitmap = key_types_bitmap;

	ListBase *lb_array[MAX_LIBARRAY];
	int lb_index;
	lb_index = set_listbasepointers(bmain, lb_array);

	while (lb_index--) {

		if (val_types_bitmap && lb_array[lb_index]->first) {
			if (!id_check_type(lb_array[lb_index]->first, val_types_bitmap)) {
				continue;
			}
		}

		for (ID *id = lb_array[lb_index]->first; id; id = id->next) {
			/* One-time init, ID is just used as placeholder here, we abuse this in iterator callback
			 * to avoid having to rebuild a complete bpyrna object each time for the key searching
			 * (where only ID pointer value is used). */
			if (data_cb.py_id_key_lookup_only == NULL) {
				data_cb.py_id_key_lookup_only = pyrna_id_CreatePyObject(id);
			}

			if (!data_cb.is_subset) {
				PyObject *key = data_cb.py_id_key_lookup_only;
				PyObject *set;

				RNA_id_pointer_create(id, &((BPy_StructRNA *)key)->ptr);

				/* We have to insert the key now, otherwise ID unused would be missing from final dict... */
				if ((set = PyDict_GetItem(data_cb.user_map, key)) == NULL) {
					/* Cannot use our placeholder key here! */
					key = pyrna_id_CreatePyObject(id);
					set = PySet_New(NULL);
					PyDict_SetItem(data_cb.user_map, key, set);
					Py_DECREF(set);
					Py_DECREF(key);
				}
			}

			data_cb.id_curr = id;
			BKE_library_foreach_ID_link(id, foreach_libblock_id_user_map_callback, &data_cb, IDWALK_NOP);

			if (data_cb.py_id_curr) {
				Py_DECREF(data_cb.py_id_curr);
				data_cb.py_id_curr = NULL;
			}
		}
	}

	ret = data_cb.user_map;


error:

	Py_XDECREF(data_cb.py_id_key_lookup_only);

	if (key_types_bitmap) {
		MEM_freeN(key_types_bitmap);
	}

	if (val_types_bitmap) {
		MEM_freeN(val_types_bitmap);
	}

	return ret;

}
Exemple #21
0
void BKE_main_free(Main *mainvar)
{
	/* also call when reading a file, erase all, etc */
	ListBase *lbarray[MAX_LIBARRAY];
	int a;

	a = set_listbasepointers(mainvar, lbarray);
	while (a--) {
		ListBase *lb = lbarray[a];
		ID *id;
		
		while ( (id = lb->first) ) {
#if 1
			BKE_libblock_free_ex(mainvar, id, false);
#else
			/* errors freeing ID's can be hard to track down,
			 * enable this so valgrind will give the line number in its error log */
			switch (a) {
				case   0: BKE_libblock_free_ex(mainvar, id, false); break;
				case   1: BKE_libblock_free_ex(mainvar, id, false); break;
				case   2: BKE_libblock_free_ex(mainvar, id, false); break;
				case   3: BKE_libblock_free_ex(mainvar, id, false); break;
				case   4: BKE_libblock_free_ex(mainvar, id, false); break;
				case   5: BKE_libblock_free_ex(mainvar, id, false); break;
				case   6: BKE_libblock_free_ex(mainvar, id, false); break;
				case   7: BKE_libblock_free_ex(mainvar, id, false); break;
				case   8: BKE_libblock_free_ex(mainvar, id, false); break;
				case   9: BKE_libblock_free_ex(mainvar, id, false); break;
				case  10: BKE_libblock_free_ex(mainvar, id, false); break;
				case  11: BKE_libblock_free_ex(mainvar, id, false); break;
				case  12: BKE_libblock_free_ex(mainvar, id, false); break;
				case  13: BKE_libblock_free_ex(mainvar, id, false); break;
				case  14: BKE_libblock_free_ex(mainvar, id, false); break;
				case  15: BKE_libblock_free_ex(mainvar, id, false); break;
				case  16: BKE_libblock_free_ex(mainvar, id, false); break;
				case  17: BKE_libblock_free_ex(mainvar, id, false); break;
				case  18: BKE_libblock_free_ex(mainvar, id, false); break;
				case  19: BKE_libblock_free_ex(mainvar, id, false); break;
				case  20: BKE_libblock_free_ex(mainvar, id, false); break;
				case  21: BKE_libblock_free_ex(mainvar, id, false); break;
				case  22: BKE_libblock_free_ex(mainvar, id, false); break;
				case  23: BKE_libblock_free_ex(mainvar, id, false); break;
				case  24: BKE_libblock_free_ex(mainvar, id, false); break;
				case  25: BKE_libblock_free_ex(mainvar, id, false); break;
				case  26: BKE_libblock_free_ex(mainvar, id, false); break;
				case  27: BKE_libblock_free_ex(mainvar, id, false); break;
				case  28: BKE_libblock_free_ex(mainvar, id, false); break;
				case  29: BKE_libblock_free_ex(mainvar, id, false); break;
				case  30: BKE_libblock_free_ex(mainvar, id, false); break;
				case  31: BKE_libblock_free_ex(mainvar, id, false); break;
				case  32: BKE_libblock_free_ex(mainvar, id, false); break;
				default:
					BLI_assert(0);
					break;
			}
#endif
		}
	}

	MEM_freeN(mainvar->eval_ctx);
	MEM_freeN(mainvar);
}