/* 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; }
/** * \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; }
/* 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); } }
/* 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); } }
/* 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); } }
/* 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); } }
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); } }
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); } } } }
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; } } }
/* 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; } } }
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); }
/** * 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); } } } }
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); }
/** * 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 }
/* 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; }
/** * \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; }
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); }