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