Blender  V2.93
blendfile.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "MEM_guardedalloc.h"
28 
29 #include "DNA_scene_types.h"
30 #include "DNA_screen_types.h"
31 #include "DNA_workspace_types.h"
32 
33 #include "BLI_listbase.h"
34 #include "BLI_path_util.h"
35 #include "BLI_string.h"
36 #include "BLI_system.h"
37 #include "BLI_utildefines.h"
38 
39 #include "IMB_colormanagement.h"
40 
41 #include "BKE_addon.h"
42 #include "BKE_appdir.h"
43 #include "BKE_blender.h"
44 #include "BKE_blender_version.h"
45 #include "BKE_blendfile.h"
46 #include "BKE_bpath.h"
47 #include "BKE_colorband.h"
48 #include "BKE_context.h"
49 #include "BKE_global.h"
50 #include "BKE_ipo.h"
51 #include "BKE_keyconfig.h"
52 #include "BKE_layer.h"
53 #include "BKE_lib_id.h"
54 #include "BKE_lib_override.h"
55 #include "BKE_main.h"
56 #include "BKE_preferences.h"
57 #include "BKE_report.h"
58 #include "BKE_scene.h"
59 #include "BKE_screen.h"
60 #include "BKE_studiolight.h"
61 #include "BKE_undo_system.h"
62 #include "BKE_workspace.h"
63 
64 #include "BLO_readfile.h"
65 #include "BLO_writefile.h"
66 
67 #include "RNA_access.h"
68 
69 #include "RE_pipeline.h"
70 
71 #ifdef WITH_PYTHON
72 # include "BPY_extern.h"
73 #endif
74 
75 /* -------------------------------------------------------------------- */
79 static bool clean_paths_visit_cb(void *UNUSED(userdata), char *path_dst, const char *path_src)
80 {
81  strcpy(path_dst, path_src);
82  BLI_path_slash_native(path_dst);
83  return !STREQ(path_dst, path_src);
84 }
85 
86 /* make sure path names are correct for OS */
87 static void clean_paths(Main *main)
88 {
89  Scene *scene;
90 
92 
93  for (scene = main->scenes.first; scene; scene = scene->id.next) {
95  }
96 }
97 
99 {
100  wmWindow *win;
101  for (win = wm->windows.first; win; win = win->next) {
102  if (win->scene == scene) {
103  return true;
104  }
105  }
106  return false;
107 }
108 
110 {
111  if (bfd->user) {
112  /* only here free userdef themes... */
114  bfd->user = NULL;
115 
116  /* Security issue: any blend file could include a USER block.
117  *
118  * Currently we load prefs from BLENDER_STARTUP_FILE and later on load BLENDER_USERPREF_FILE,
119  * to load the preferences defined in the users home dir.
120  *
121  * This means we will never accidentally (or maliciously)
122  * enable scripts auto-execution by loading a '.blend' file.
123  */
125  }
126 }
127 
136 static void setup_app_data(bContext *C,
137  BlendFileData *bfd,
138  const struct BlendFileReadParams *params,
139  ReportList *reports)
140 {
141  Main *bmain = G_MAIN;
142  Scene *curscene = NULL;
143  const bool recover = (G.fileflags & G_FILE_RECOVER_READ) != 0;
144  const bool is_startup = params->is_startup;
145  enum {
146  LOAD_UI = 1,
147  LOAD_UI_OFF,
148  LOAD_UNDO,
149  } mode;
150 
151  if (params->undo_direction != STEP_INVALID) {
152  BLI_assert(bfd->curscene != NULL);
153  mode = LOAD_UNDO;
154  }
155  /* may happen with library files - UNDO file should never have NULL curscene (but may have a
156  * NULL curscreen)... */
157  else if (ELEM(NULL, bfd->curscreen, bfd->curscene)) {
158  BKE_report(reports, RPT_WARNING, "Library file, loading empty scene");
159  mode = LOAD_UI_OFF;
160  }
161  else if (G.fileflags & G_FILE_NO_UI) {
162  mode = LOAD_UI_OFF;
163  }
164  else {
165  mode = LOAD_UI;
166  }
167 
168  /* Free all render results, without this stale data gets displayed after loading files */
169  if (mode != LOAD_UNDO) {
171  }
172 
173  /* Only make filepaths compatible when loading for real (not undo) */
174  if (mode != LOAD_UNDO) {
175  clean_paths(bfd->main);
176  }
177 
178  /* XXX here the complex windowmanager matching */
179 
180  /* no load screens? */
181  if (mode != LOAD_UI) {
182  /* Logic for 'track_undo_scene' is to keep using the scene which the active screen has,
183  * as long as the scene associated with the undo operation is visible
184  * in one of the open windows.
185  *
186  * - 'curscreen->scene' - scene the user is currently looking at.
187  * - 'bfd->curscene' - scene undo-step was created in.
188  *
189  * This means users can have 2+ windows open and undo in both without screens switching.
190  * But if they close one of the screens,
191  * undo will ensure that the scene being operated on will be activated
192  * (otherwise we'd be undoing on an off-screen scene which isn't acceptable).
193  * see: T43424
194  */
195  wmWindow *win;
196  bScreen *curscreen = NULL;
197  ViewLayer *cur_view_layer;
198  bool track_undo_scene;
199 
200  /* comes from readfile.c */
201  SWAP(ListBase, bmain->wm, bfd->main->wm);
202  SWAP(ListBase, bmain->workspaces, bfd->main->workspaces);
203  SWAP(ListBase, bmain->screens, bfd->main->screens);
204 
205  /* In case of actual new file reading without loading UI, we need to regenerate the session
206  * uuid of the UI-related datablocks we are keeping from previous session, otherwise their uuid
207  * will collide with some generated for newly read data. */
208  if (mode != LOAD_UNDO) {
209  ID *id;
210  FOREACH_MAIN_LISTBASE_ID_BEGIN (&bfd->main->wm, id) {
212  }
214 
217  }
219 
222  }
224  }
225 
226  /* we re-use current window and screen */
227  win = CTX_wm_window(C);
228  curscreen = CTX_wm_screen(C);
229  /* but use Scene pointer from new file */
230  curscene = bfd->curscene;
231  cur_view_layer = bfd->cur_view_layer;
232 
233  track_undo_scene = (mode == LOAD_UNDO && curscreen && curscene && bfd->main->wm.first);
234 
235  if (curscene == NULL) {
236  curscene = bfd->main->scenes.first;
237  }
238  /* empty file, we add a scene to make Blender work */
239  if (curscene == NULL) {
240  curscene = BKE_scene_add(bfd->main, "Empty");
241  }
242  if (cur_view_layer == NULL) {
243  /* fallback to scene layer */
244  cur_view_layer = BKE_view_layer_default_view(curscene);
245  }
246 
247  if (track_undo_scene) {
248  /* keep the old (free'd) scene, let 'blo_lib_link_screen_restore'
249  * replace it with 'curscene' if its needed */
250  }
251  /* and we enforce curscene to be in current screen */
252  else if (win) { /* can run in bgmode */
253  win->scene = curscene;
254  }
255 
256  /* BKE_blender_globals_clear will free G_MAIN, here we can still restore pointers */
257  blo_lib_link_restore(bmain, bfd->main, CTX_wm_manager(C), curscene, cur_view_layer);
258  if (win) {
259  curscene = win->scene;
260  }
261 
262  if (track_undo_scene) {
263  wmWindowManager *wm = bfd->main->wm.first;
264  if (wm_scene_is_visible(wm, bfd->curscene) == false) {
265  curscene = bfd->curscene;
266  win->scene = curscene;
267  BKE_screen_view3d_scene_sync(curscreen, curscene);
268  }
269  }
270 
271  /* We need to tag this here because events may be handled immediately after.
272  * only the current screen is important because we wont have to handle
273  * events from multiple screens at once.*/
274  if (curscreen) {
275  BKE_screen_gizmo_tag_refresh(curscreen);
276  }
277  }
278 
279  /* free G_MAIN Main database */
280  // CTX_wm_manager_set(C, NULL);
282 
283  bmain = G_MAIN = bfd->main;
284  bfd->main = NULL;
285 
286  CTX_data_main_set(C, bmain);
287 
288  /* case G_FILE_NO_UI or no screens in file */
289  if (mode != LOAD_UI) {
290  /* leave entire context further unaltered? */
291  CTX_data_scene_set(C, curscene);
292  }
293  else {
294  CTX_wm_manager_set(C, bmain->wm.first);
300  curscene = bfd->curscene;
301  }
302 
303  /* Keep state from preferences. */
304  const int fileflags_keep = G_FILE_FLAG_ALL_RUNTIME;
305  G.fileflags = (G.fileflags & fileflags_keep) | (bfd->fileflags & ~fileflags_keep);
306 
307  /* this can happen when active scene was lib-linked, and doesn't exist anymore */
308  if (CTX_data_scene(C) == NULL) {
309  wmWindow *win = CTX_wm_window(C);
310 
311  /* in case we don't even have a local scene, add one */
312  if (!bmain->scenes.first) {
313  BKE_scene_add(bmain, "Empty");
314  }
315 
316  CTX_data_scene_set(C, bmain->scenes.first);
317  win->scene = CTX_data_scene(C);
318  curscene = CTX_data_scene(C);
319  }
320 
321  BLI_assert(curscene == CTX_data_scene(C));
322 
323  /* special cases, override loaded flags: */
324  if (G.f != bfd->globalf) {
325  const int flags_keep = G_FLAG_ALL_RUNTIME;
327  bfd->globalf = (bfd->globalf & ~flags_keep) | (G.f & flags_keep);
328  }
329 
330  G.f = bfd->globalf;
331 
332 #ifdef WITH_PYTHON
333  /* let python know about new main */
334  if (CTX_py_init_get(C)) {
336  }
337 #endif
338 
339  /* FIXME: this version patching should really be part of the file-reading code,
340  * but we still get too many unrelated data-corruption crashes otherwise... */
341  if (bmain->versionfile < 250) {
343  }
344 
345  bmain->recovered = 0;
346 
347  /* startup.blend or recovered startup */
348  if (is_startup) {
349  bmain->name[0] = '\0';
350  }
351  else if (recover) {
352  /* In case of autosave or quit.blend, use original filename instead. */
353  bmain->recovered = 1;
354  BLI_strncpy(bmain->name, bfd->filename, FILE_MAX);
355  }
356 
357  /* baseflags, groups, make depsgraph, etc */
358  /* first handle case if other windows have different scenes visible */
359  if (mode == LOAD_UI) {
360  wmWindowManager *wm = bmain->wm.first;
361 
362  if (wm) {
363  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
364  if (win->scene && win->scene != curscene) {
365  BKE_scene_set_background(bmain, win->scene);
366  }
367  }
368  }
369  }
370 
371  /* Setting scene might require having a dependency graph, with copy on write
372  * we need to make sure we ensure scene has correct color management before
373  * constructing dependency graph.
374  */
375  if (mode != LOAD_UNDO) {
377  }
378 
379  BKE_scene_set_background(bmain, curscene);
380 
381  if (mode != LOAD_UNDO) {
382  /* TODO(sergey): Can this be also move above? */
384  }
385 
386  if (mode == LOAD_UNDO) {
387  /* In undo/redo case, we do a whole lot of magic tricks to avoid having to re-read linked
388  * data-blocks from libraries (since those are not supposed to change). Unfortunately, that
389  * means that we do not reset their user count, however we do increase that one when doing
390  * lib_link on local IDs using linked ones.
391  * There is no real way to predict amount of changes here, so we have to fully redo
392  * refcounting.
393  * Now that we re-use (and do not liblink in readfile.c) most local datablocks as well, we have
394  * to recompute refcount for all local IDs too. */
395  BKE_main_id_refcount_recompute(bmain, false);
396  }
397 
398  if (mode != LOAD_UNDO && !USER_EXPERIMENTAL_TEST(&U, no_override_auto_resync)) {
400  bmain,
401  curscene,
403  /* We need to rebuild some of the deleted override rules (for UI feedback purpose). */
405  }
406 }
407 
409  BlendFileData *bfd,
410  const struct BlendFileReadParams *params,
411  ReportList *reports)
412 {
413  if ((params->skip_flags & BLO_READ_SKIP_USERDEF) == 0) {
414  setup_app_userdef(bfd);
415  }
416  if ((params->skip_flags & BLO_READ_SKIP_DATA) == 0) {
417  setup_app_data(C, bfd, params, reports);
418  }
419 }
420 
422 {
423  if (main->minversionfile > BLENDER_FILE_VERSION ||
424  (main->minversionfile == BLENDER_FILE_VERSION &&
425  main->minsubversionfile > BLENDER_FILE_SUBVERSION)) {
426  BKE_reportf(reports,
427  RPT_ERROR,
428  "File written by newer Blender binary (%d.%d), expect loss of data!",
429  main->minversionfile,
430  main->minsubversionfile);
431  }
432 }
433 
443  BlendFileData *bfd,
444  const struct BlendFileReadParams *params,
445  ReportList *reports,
446  /* Extra args. */
447  const bool startup_update_defaults,
448  const char *startup_app_template)
449 {
450  if (startup_update_defaults) {
451  if ((params->skip_flags & BLO_READ_SKIP_DATA) == 0) {
452  BLO_update_defaults_startup_blend(bfd->main, startup_app_template);
453  }
454  }
455  setup_app_blend_file_data(C, bfd, params, reports);
457 }
458 
460  BlendFileData *bfd,
461  const struct BlendFileReadParams *params,
462  ReportList *reports)
463 {
464  BKE_blendfile_read_setup_ex(C, bfd, params, reports, false, NULL);
465 }
466 
470 struct BlendFileData *BKE_blendfile_read(const char *filepath,
471  const struct BlendFileReadParams *params,
472  ReportList *reports)
473 {
474  /* Don't print startup file loading. */
475  if (params->is_startup == false) {
476  printf("Read blend: %s\n", filepath);
477  }
478 
479  BlendFileData *bfd = BLO_read_from_file(filepath, params->skip_flags, reports);
480  if (bfd) {
481  handle_subversion_warning(bfd->main, reports);
482  }
483  else {
484  BKE_reports_prependf(reports, "Loading '%s' failed: ", filepath);
485  }
486  return bfd;
487 }
488 
492 struct BlendFileData *BKE_blendfile_read_from_memory(const void *filebuf,
493  int filelength,
494  const struct BlendFileReadParams *params,
495  ReportList *reports)
496 {
497  BlendFileData *bfd = BLO_read_from_memory(filebuf, filelength, params->skip_flags, reports);
498  if (bfd) {
499  /* Pass. */
500  }
501  else {
502  BKE_reports_prepend(reports, "Loading failed: ");
503  }
504  return bfd;
505 }
506 
512  struct MemFile *memfile,
513  const struct BlendFileReadParams *params,
514  ReportList *reports)
515 {
517  bmain, BKE_main_blendfile_path(bmain), memfile, params, reports);
518  if (bfd) {
519  /* Removing the unused workspaces, screens and wm is useless here, setup_app_data will switch
520  * those lists with the ones from old bmain, which freeing is much more efficient than
521  * individual calls to `BKE_id_free()`.
522  * Further more, those are expected to be empty anyway with new memfile reading code. */
526  }
527  else {
528  BKE_reports_prepend(reports, "Loading failed: ");
529  }
530  return bfd;
531 }
532 
538 {
539  Main *bmain = CTX_data_main(C);
540  ListBase *lb;
541  ID *id;
542 
543  FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb) {
545  if (ELEM(GS(id->name), ID_SCE, ID_SCR, ID_WM, ID_WS)) {
546  break;
547  }
548  BKE_id_delete(bmain, id);
549  }
551  }
553 }
554 
555 /* only read the userdef from a .blend */
556 UserDef *BKE_blendfile_userdef_read(const char *filepath, ReportList *reports)
557 {
558  BlendFileData *bfd;
559  UserDef *userdef = NULL;
560 
561  bfd = BLO_read_from_file(filepath, BLO_READ_SKIP_ALL & ~BLO_READ_SKIP_USERDEF, reports);
562  if (bfd) {
563  if (bfd->user) {
564  userdef = bfd->user;
565  }
566  BKE_main_free(bfd->main);
567  MEM_freeN(bfd);
568  }
569 
570  return userdef;
571 }
572 
574  int filelength,
575  ReportList *reports)
576 {
577  BlendFileData *bfd;
578  UserDef *userdef = NULL;
579 
580  bfd = BLO_read_from_memory(
581  filebuf, filelength, BLO_READ_SKIP_ALL & ~BLO_READ_SKIP_USERDEF, reports);
582  if (bfd) {
583  if (bfd->user) {
584  userdef = bfd->user;
585  }
586  BKE_main_free(bfd->main);
587  MEM_freeN(bfd);
588  }
589  else {
590  BKE_reports_prepend(reports, "Loading failed: ");
591  }
592 
593  return userdef;
594 }
595 
597 {
598  UserDef *userdef = MEM_mallocN(sizeof(*userdef), __func__);
599  memcpy(userdef, &U_default, sizeof(*userdef));
600 
601  /* Add-ons. */
602  {
603  const char *addons[] = {
604  "io_anim_bvh",
605  "io_curve_svg",
606  "io_mesh_ply",
607  "io_mesh_stl",
608  "io_mesh_uv_layout",
609  "io_scene_fbx",
610  "io_scene_gltf2",
611  "io_scene_obj",
612  "io_scene_x3d",
613  "cycles",
614  };
615  for (int i = 0; i < ARRAY_SIZE(addons); i++) {
616  bAddon *addon = BKE_addon_new();
617  STRNCPY(addon->module, addons[i]);
618  BLI_addtail(&userdef->addons, addon);
619  }
620  }
621 
622  /* Theme. */
623  {
624  bTheme *btheme = MEM_mallocN(sizeof(*btheme), __func__);
625  memcpy(btheme, &U_theme_default, sizeof(*btheme));
626 
627  BLI_addtail(&userdef->themes, btheme);
628  }
629 
630 #ifdef WITH_PYTHON_SECURITY
631  /* use alternative setting for security nuts
632  * otherwise we'd need to patch the binary blob - startup.blend.c */
634 #else
635  userdef->flag &= ~USER_SCRIPT_AUTOEXEC_DISABLE;
636 #endif
637 
638  /* System-specific fonts directory. */
640 
642  userdef->memcachelimit);
643 
644  /* Init weight paint range. */
645  BKE_colorband_init(&userdef->coba_weight, true);
646 
647  /* Default studio light. */
649 
651  /* Enable asset browser features by default for alpha testing.
652  * BLO_sanitize_experimental_features_userpref_blend() will disable it again for non-alpha
653  * builds. */
654  userdef->experimental.use_asset_browser = true;
655 
656  /*
657  * Enable translation by default. ALT Linux specific patch.
658  * See ALT#31561
659  */
660 
661  userdef->language = ULANGUAGE_AUTO;
662  userdef->transopts |= USER_TR_IFACE;
663  userdef->transopts |= USER_TR_TOOLTIPS;
664  userdef->transopts |= USER_TR_NEWDATANAME;
665 
666  return userdef;
667 }
668 
673 bool BKE_blendfile_userdef_write(const char *filepath, ReportList *reports)
674 {
675  Main *mainb = MEM_callocN(sizeof(Main), "empty main");
676  bool ok = false;
677 
678  if (BLO_write_file(mainb,
679  filepath,
680  0,
681  &(const struct BlendFileWriteParams){
682  .use_userdef = true,
683  },
684  reports)) {
685  ok = true;
686  }
687 
688  MEM_freeN(mainb);
689 
690  return ok;
691 }
692 
700 bool BKE_blendfile_userdef_write_app_template(const char *filepath, ReportList *reports)
701 {
702  /* if it fails, overwrite is OK. */
703  UserDef *userdef_default = BKE_blendfile_userdef_read(filepath, NULL);
704  if (userdef_default == NULL) {
705  return BKE_blendfile_userdef_write(filepath, reports);
706  }
707 
709  bool ok = BKE_blendfile_userdef_write(filepath, reports);
711  BKE_blender_userdef_data_free(userdef_default, false);
712  MEM_freeN(userdef_default);
713  return ok;
714 }
715 
717 {
718  char filepath[FILE_MAX];
719  const char *cfgdir;
720  bool ok = true;
721  const bool use_template_userpref = BKE_appdir_app_template_has_userpref(U.app_template);
722 
724  bool ok_write;
725  BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL);
726 
727  printf("Writing userprefs: '%s' ", filepath);
728  if (use_template_userpref) {
729  ok_write = BKE_blendfile_userdef_write_app_template(filepath, reports);
730  }
731  else {
732  ok_write = BKE_blendfile_userdef_write(filepath, reports);
733  }
734 
735  if (ok_write) {
736  printf("ok\n");
737  }
738  else {
739  printf("fail\n");
740  ok = false;
741  }
742  }
743  else {
744  BKE_report(reports, RPT_ERROR, "Unable to create userpref path");
745  }
746 
747  if (use_template_userpref) {
748  if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, U.app_template))) {
749  /* Also save app-template prefs */
750  BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL);
751 
752  printf("Writing userprefs app-template: '%s' ", filepath);
753  if (BKE_blendfile_userdef_write(filepath, reports) != 0) {
754  printf("ok\n");
755  }
756  else {
757  printf("fail\n");
758  ok = false;
759  }
760  }
761  else {
762  BKE_report(reports, RPT_ERROR, "Unable to create app-template userpref path");
763  ok = false;
764  }
765  }
766 
767  if (ok) {
768  U.runtime.is_dirty = false;
769  }
770  return ok;
771 }
772 
774  const void *filebuf,
775  int filelength,
776  ReportList *reports)
777 {
778  BlendFileData *bfd;
779  WorkspaceConfigFileData *workspace_config = NULL;
780 
781  if (filepath) {
782  bfd = BLO_read_from_file(filepath, BLO_READ_SKIP_USERDEF, reports);
783  }
784  else {
785  bfd = BLO_read_from_memory(filebuf, filelength, BLO_READ_SKIP_USERDEF, reports);
786  }
787 
788  if (bfd) {
789  workspace_config = MEM_callocN(sizeof(*workspace_config), __func__);
790  workspace_config->main = bfd->main;
791 
792  /* Only 2.80+ files have actual workspaces, don't try to use screens
793  * from older versions. */
794  if (bfd->main->versionfile >= 280) {
795  workspace_config->workspaces = bfd->main->workspaces;
796  }
797 
798  MEM_freeN(bfd);
799  }
800 
801  return workspace_config;
802 }
803 
804 bool BKE_blendfile_workspace_config_write(Main *bmain, const char *filepath, ReportList *reports)
805 {
806  const int fileflags = G.fileflags & ~G_FILE_NO_UI;
807  bool retval = false;
808 
810 
811  for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
812  BKE_blendfile_write_partial_tag_ID(&workspace->id, true);
813  }
814 
816  bmain, filepath, fileflags, BLO_WRITE_PATH_REMAP_NONE, reports)) {
817  retval = true;
818  }
819 
821 
822  return retval;
823 }
824 
826 {
827  BKE_main_free(workspace_config->main);
828  MEM_freeN(workspace_config);
829 }
830 
833 /* -------------------------------------------------------------------- */
838 {
840 }
841 
843 {
844  if (set) {
845  id->tag |= LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT;
846  }
847  else {
848  id->tag &= ~(LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT);
849  }
850 }
851 
852 static void blendfile_write_partial_cb(void *UNUSED(handle), Main *UNUSED(bmain), void *vid)
853 {
854  if (vid) {
855  ID *id = vid;
856  /* only tag for need-expand if not done, prevents eternal loops */
857  if ((id->tag & LIB_TAG_DOIT) == 0) {
859  }
860 
861  if (id->lib && (id->lib->id.tag & LIB_TAG_DOIT) == 0) {
862  id->lib->id.tag |= LIB_TAG_DOIT;
863  }
864  }
865 }
866 
872  const char *filepath,
873  const int write_flags,
874  const int remap_mode,
875  ReportList *reports)
876 {
877  Main *bmain_dst = MEM_callocN(sizeof(Main), "copybuffer");
878  ListBase *lbarray_dst[INDEX_ID_MAX], *lbarray_src[INDEX_ID_MAX];
879  int a, retval;
880 
881  void *path_list_backup = NULL;
883 
884  /* This is needed to be able to load that file as a real one later
885  * (otherwise main->name will not be set at read time). */
886  BLI_strncpy(bmain_dst->name, bmain_src->name, sizeof(bmain_dst->name));
887 
889  BLO_expand_main(NULL, bmain_src);
890 
891  /* move over all tagged blocks */
892  set_listbasepointers(bmain_src, lbarray_src);
893  a = set_listbasepointers(bmain_dst, lbarray_dst);
894  while (a--) {
895  ID *id, *nextid;
896  ListBase *lb_dst = lbarray_dst[a], *lb_src = lbarray_src[a];
897 
898  for (id = lb_src->first; id; id = nextid) {
899  nextid = id->next;
900  if (id->tag & LIB_TAG_DOIT) {
901  BLI_remlink(lb_src, id);
902  BLI_addtail(lb_dst, id);
903  }
904  }
905  }
906 
907  /* Backup paths because remap relative will overwrite them.
908  *
909  * NOTE: we do this only on the list of data-blocks that we are writing
910  * because the restored full list is not guaranteed to be in the same
911  * order as before, as expected by BKE_bpath_list_restore.
912  *
913  * This happens because id_sort_by_name does not take into account
914  * string case or the library name, so the order is not strictly
915  * defined for two linked data-blocks with the same name! */
916  if (remap_mode != BLO_WRITE_PATH_REMAP_NONE) {
917  path_list_backup = BKE_bpath_list_backup(bmain_dst, path_list_flag);
918  }
919 
920  /* save the buffer */
921  retval = BLO_write_file(bmain_dst,
922  filepath,
923  write_flags,
924  &(const struct BlendFileWriteParams){
925  .remap_mode = remap_mode,
926  },
927  reports);
928 
929  if (path_list_backup) {
930  BKE_bpath_list_restore(bmain_dst, path_list_flag, path_list_backup);
931  BKE_bpath_list_free(path_list_backup);
932  }
933 
934  /* move back the main, now sorted again */
935  set_listbasepointers(bmain_src, lbarray_dst);
936  a = set_listbasepointers(bmain_dst, lbarray_src);
937  while (a--) {
938  ID *id;
939  ListBase *lb_dst = lbarray_dst[a], *lb_src = lbarray_src[a];
940 
941  while ((id = BLI_pophead(lb_src))) {
942  BLI_addtail(lb_dst, id);
943  id_sort_by_name(lb_dst, id, NULL);
944  }
945  }
946 
947  MEM_freeN(bmain_dst);
948 
949  return retval;
950 }
951 
953 {
955 }
956 
struct bAddon * BKE_addon_new(void)
Definition: addon.c:47
@ BLENDER_USER_CONFIG
Definition: BKE_appdir.h:81
const char * BKE_appdir_folder_id_create(const int folder_id, const char *subfolder)
Definition: appdir.c:735
bool BKE_appdir_font_folder_default(char *dir)
Definition: appdir.c:224
#define BLENDER_USERPREF_FILE
Definition: BKE_appdir.h:100
bool BKE_appdir_app_template_has_userpref(const char *app_template)
Definition: appdir.c:1013
Blender util stuff.
void BKE_blender_globals_clear(void)
Definition: blender.c:180
void BKE_blender_userdef_data_free(struct UserDef *userdef, bool clear_fonts)
Definition: blender.c:280
void BKE_blender_userdef_data_set_and_free(struct UserDef *userdef)
Definition: blender.c:214
void BKE_blender_userdef_app_template_data_swap(struct UserDef *userdef_a, struct UserDef *userdef_b)
Definition: blender.c:318
#define BLENDER_FILE_SUBVERSION
#define BLENDER_FILE_VERSION
void BKE_bpath_traverse_main(struct Main *bmain, BPathVisitor visit_cb, const int flag, void *bpath_user_data)
Definition: bpath.c:781
void BKE_bpath_list_restore(struct Main *bmain, const int flag, void *ls_handle)
Definition: bpath.c:882
void BKE_bpath_list_free(void *ls_handle)
Definition: bpath.c:889
@ BKE_BPATH_TRAVERSE_SKIP_MULTIFILE
Definition: BKE_bpath.h:70
@ BKE_BPATH_TRAVERSE_SKIP_LIBRARY
Definition: BKE_bpath.h:63
void * BKE_bpath_list_backup(struct Main *bmain, const int flag)
Definition: bpath.c:873
void BKE_colorband_init(struct ColorBand *coba, bool rangetype)
Definition: colorband.c:38
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
void CTX_wm_region_set(bContext *C, struct ARegion *region)
Definition: context.c:985
void CTX_data_scene_set(bContext *C, struct Scene *scene)
Definition: context.c:1197
bool CTX_py_init_get(bContext *C)
Definition: context.c:215
void CTX_wm_menu_set(bContext *C, struct ARegion *menu)
Definition: context.c:996
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:689
struct bScreen * CTX_wm_screen(const bContext *C)
Definition: context.c:709
void CTX_wm_screen_set(bContext *C, struct bScreen *screen)
Definition: context.c:960
void CTX_data_main_set(bContext *C, struct Main *bmain)
Definition: context.c:1028
void CTX_wm_area_set(bContext *C, struct ScrArea *area)
Definition: context.c:973
void CTX_wm_manager_set(bContext *C, struct wmWindowManager *wm)
Definition: context.c:926
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:699
@ G_FILE_RECOVER_READ
Definition: BKE_global.h:182
@ G_FILE_NO_UI
Definition: BKE_global.h:170
#define G_FLAG_ALL_READFILE
Definition: BKE_global.h:129
#define G_MAIN
Definition: BKE_global.h:232
#define G_FILE_FLAG_ALL_RUNTIME
Definition: BKE_global.h:200
#define G_FLAG_ALL_RUNTIME
Definition: BKE_global.h:124
void do_versions_ipos_to_animato(struct Main *main)
Definition: ipo.c:2055
struct ViewLayer * BKE_view_layer_default_view(const struct Scene *scene)
void BKE_lib_libblock_session_uuid_renew(struct ID *id)
Definition: lib_id.c:1166
void BKE_main_id_tag_all(struct Main *mainvar, const int tag, const bool value)
Definition: lib_id.c:923
void BKE_id_delete(struct Main *bmain, void *idv) ATTR_NONNULL()
void BKE_main_id_refcount_recompute(struct Main *bmain, const bool do_linked_only)
Definition: lib_id.c:1773
void id_sort_by_name(struct ListBase *lb, struct ID *id, struct ID *id_sorting_hint)
Definition: lib_id.c:1348
bool BKE_lib_override_library_main_operations_create(struct Main *bmain, const bool force_auto)
void BKE_lib_override_library_main_resync(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer)
#define FOREACH_MAIN_LISTBASE_ID_END
Definition: BKE_main.h:219
int set_listbasepointers(struct Main *main, struct ListBase *lb[])
#define FOREACH_MAIN_LISTBASE_ID_BEGIN(_lb, _id)
Definition: BKE_main.h:213
#define FOREACH_MAIN_LISTBASE_END
Definition: BKE_main.h:231
const char * BKE_main_blendfile_path(const struct Main *bmain) ATTR_NONNULL()
#define FOREACH_MAIN_LISTBASE_BEGIN(_bmain, _lb)
Definition: BKE_main.h:224
void BKE_main_free(struct Main *mainvar)
Definition: main.c:53
void BKE_preferences_asset_library_default_add(struct UserDef *userdef) ATTR_NONNULL()
Definition: preferences.c:103
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
void BKE_reports_prependf(ReportList *reports, const char *prepend,...) ATTR_PRINTF_FORMAT(2
void void BKE_reports_prepend(ReportList *reports, const char *prepend)
Definition: report.c:167
void BKE_reportf(ReportList *reports, ReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_scene_set_background(struct Main *bmain, struct Scene *sce)
Definition: scene.c:2120
struct Scene * BKE_scene_add(struct Main *bmain, const char *name)
Definition: scene.c:2078
void BKE_screen_view3d_scene_sync(struct bScreen *screen, struct Scene *scene)
Definition: screen.c:1041
void BKE_screen_gizmo_tag_refresh(struct bScreen *screen)
Definition: screen.c:616
void BKE_studiolight_default(SolidLight lights[4], float light_ambient[4])
Definition: studiolight.c:1355
@ STEP_INVALID
#define BLI_assert(a)
Definition: BLI_assert.h:58
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:257
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
MINLINE int min_ii(int a, int b)
#define FILE_MAX
size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *path_first,...) ATTR_NONNULL(1
void BLI_path_slash_native(char *path) ATTR_NONNULL()
Definition: path_util.c:2012
#define STRNCPY(dst, src)
Definition: BLI_string.h:163
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
int BLI_system_memory_max_in_megabytes_int(void)
Definition: system.c:192
#define ARRAY_SIZE(arr)
#define SWAP(type, a, b)
#define UNUSED(x)
#define ELEM(...)
#define STREQ(a, b)
external readfile function prototypes.
const struct UserDef U_default
void BLO_update_defaults_startup_blend(struct Main *bmain, const char *app_template)
@ BLO_READ_SKIP_DATA
Definition: BLO_readfile.h:96
@ BLO_READ_SKIP_USERDEF
Definition: BLO_readfile.h:95
void BLO_main_expander(BLOExpandDoitCallback expand_doit_func)
Definition: readfile.c:4575
BlendFileData * BLO_read_from_memfile(struct Main *oldmain, const char *filename, struct MemFile *memfile, const struct BlendFileReadParams *params, struct ReportList *reports)
void BLO_expand_main(void *fdhandle, struct Main *mainvar)
Definition: readfile.c:4587
void blo_lib_link_restore(struct Main *oldmain, struct Main *newmain, struct wmWindowManager *curwm, struct Scene *curscene, struct ViewLayer *cur_view_layer)
Definition: readfile.c:3030
#define BLO_READ_SKIP_ALL
Definition: BLO_readfile.h:100
BlendFileData * BLO_read_from_file(const char *filepath, eBLOReadSkip skip_flags, struct ReportList *reports)
const struct bTheme U_theme_default
BlendFileData * BLO_read_from_memory(const void *mem, int memsize, eBLOReadSkip skip_flags, struct ReportList *reports)
void BLO_blendfiledata_free(BlendFileData *bfd)
external writefile function prototypes.
bool BLO_write_file(struct Main *mainvar, const char *filepath, const int write_flags, const struct BlendFileWriteParams *params, struct ReportList *reports)
Definition: writefile.c:1128
@ BLO_WRITE_PATH_REMAP_NONE
Definition: BLO_writefile.h:43
void BPY_context_update(struct bContext *C)
@ LIB_TAG_DOIT
Definition: DNA_ID.h:554
@ LIB_TAG_NEED_EXPAND
Definition: DNA_ID.h:528
@ INDEX_ID_MAX
Definition: DNA_ID.h:859
@ ID_WM
Definition: DNA_ID_enums.h:84
@ ID_WS
Definition: DNA_ID_enums.h:91
@ ID_SCE
Definition: DNA_ID_enums.h:57
@ ID_SCR
Definition: DNA_ID_enums.h:72
@ USER_TR_NEWDATANAME
@ USER_TR_TOOLTIPS
@ USER_TR_IFACE
@ USER_SCRIPT_AUTOEXEC_DISABLE
@ ULANGUAGE_AUTO
#define USER_EXPERIMENTAL_TEST(userdef, member)
void IMB_colormanagement_check_file_config(struct Main *bmain)
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:39
struct BlendFileData * BKE_blendfile_read_from_memory(const void *filebuf, int filelength, const struct BlendFileReadParams *params, ReportList *reports)
Definition: blendfile.c:492
struct BlendFileData * BKE_blendfile_read_from_memfile(Main *bmain, struct MemFile *memfile, const struct BlendFileReadParams *params, ReportList *reports)
Definition: blendfile.c:511
bool BKE_blendfile_userdef_write_all(ReportList *reports)
Definition: blendfile.c:716
UserDef * BKE_blendfile_userdef_read_from_memory(const void *filebuf, int filelength, ReportList *reports)
Definition: blendfile.c:573
void BKE_blendfile_read_setup_ex(bContext *C, BlendFileData *bfd, const struct BlendFileReadParams *params, ReportList *reports, const bool startup_update_defaults, const char *startup_app_template)
Definition: blendfile.c:442
struct BlendFileData * BKE_blendfile_read(const char *filepath, const struct BlendFileReadParams *params, ReportList *reports)
Definition: blendfile.c:470
bool BKE_blendfile_userdef_write(const char *filepath, ReportList *reports)
Definition: blendfile.c:673
static void clean_paths(Main *main)
Definition: blendfile.c:87
void BKE_blendfile_read_make_empty(bContext *C)
Definition: blendfile.c:537
void BKE_blendfile_workspace_config_data_free(WorkspaceConfigFileData *workspace_config)
Definition: blendfile.c:825
static void setup_app_blend_file_data(bContext *C, BlendFileData *bfd, const struct BlendFileReadParams *params, ReportList *reports)
Definition: blendfile.c:408
UserDef * BKE_blendfile_userdef_from_defaults(void)
Definition: blendfile.c:596
static void blendfile_write_partial_cb(void *UNUSED(handle), Main *UNUSED(bmain), void *vid)
Definition: blendfile.c:852
void BKE_blendfile_write_partial_end(Main *bmain_src)
Definition: blendfile.c:952
UserDef * BKE_blendfile_userdef_read(const char *filepath, ReportList *reports)
Definition: blendfile.c:556
bool BKE_blendfile_write_partial(Main *bmain_src, const char *filepath, const int write_flags, const int remap_mode, ReportList *reports)
Definition: blendfile.c:871
void BKE_blendfile_write_partial_begin(Main *bmain_src)
Definition: blendfile.c:837
static void handle_subversion_warning(Main *main, ReportList *reports)
Definition: blendfile.c:421
static void setup_app_data(bContext *C, BlendFileData *bfd, const struct BlendFileReadParams *params, ReportList *reports)
Definition: blendfile.c:136
static bool wm_scene_is_visible(wmWindowManager *wm, Scene *scene)
Definition: blendfile.c:98
void BKE_blendfile_read_setup(bContext *C, BlendFileData *bfd, const struct BlendFileReadParams *params, ReportList *reports)
Definition: blendfile.c:459
bool BKE_blendfile_userdef_write_app_template(const char *filepath, ReportList *reports)
Definition: blendfile.c:700
static bool clean_paths_visit_cb(void *UNUSED(userdata), char *path_dst, const char *path_src)
Definition: blendfile.c:79
bool BKE_blendfile_workspace_config_write(Main *bmain, const char *filepath, ReportList *reports)
Definition: blendfile.c:804
static void setup_app_userdef(BlendFileData *bfd)
Definition: blendfile.c:109
void BKE_blendfile_write_partial_tag_ID(ID *id, bool set)
Definition: blendfile.c:842
WorkspaceConfigFileData * BKE_blendfile_workspace_config_read(const char *filepath, const void *filebuf, int filelength, ReportList *reports)
Definition: blendfile.c:773
unsigned int U
Definition: btGjkEpa3.h:78
Scene scene
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
#define GS(x)
Definition: iris.c:241
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
int main(int argc, char **argv)
Definition: msgfmt.c:457
static unsigned a[3]
Definition: RandGen.cpp:92
void RE_FreeAllPersistentData(void)
Definition: pipeline.c:679
void RE_FreeAllRenderResults(void)
Definition: pipeline.c:666
struct bScreen * curscreen
Definition: BLO_readfile.h:77
struct Scene * curscene
Definition: BLO_readfile.h:78
struct ViewLayer * cur_view_layer
Definition: BLO_readfile.h:79
struct Main * main
Definition: BLO_readfile.h:70
struct UserDef * user
Definition: BLO_readfile.h:71
char filename[1024]
Definition: BLO_readfile.h:75
Definition: DNA_ID.h:273
int tag
Definition: DNA_ID.h:292
struct Library * lib
Definition: DNA_ID.h:277
void * next
Definition: DNA_ID.h:274
char name[66]
Definition: DNA_ID.h:283
ID id
Definition: DNA_ID.h:349
void * first
Definition: DNA_listBase.h:47
Definition: BKE_main.h:116
char recovered
Definition: BKE_main.h:123
ListBase scenes
Definition: BKE_main.h:146
ListBase wm
Definition: BKE_main.h:175
char name[1024]
Definition: BKE_main.h:118
ListBase screens
Definition: BKE_main.h:161
short versionfile
Definition: BKE_main.h:119
ListBase workspaces
Definition: BKE_main.h:181
char pic[1024]
struct RenderData r
struct ListBase addons
float light_ambient[3]
UserDef_Experimental experimental
struct ListBase themes
char fontdir[768]
struct SolidLight light_param[4]
struct ColorBand coba_weight
struct ListBase workspaces
Definition: BLO_readfile.h:54
char module[64]
struct Scene * scene
struct wmWindow * next
#define G(x, y, z)